Merge "Test TextView autosize and maxline" into oc-dev
diff --git a/apps/CameraITS/pymodules/its/objects.py b/apps/CameraITS/pymodules/its/objects.py
index 0883482..1269b84 100644
--- a/apps/CameraITS/pymodules/its/objects.py
+++ b/apps/CameraITS/pymodules/its/objects.py
@@ -108,7 +108,8 @@
"android.colorCorrection.gains": [1,1,1,1],
"android.lens.focusDistance" : f_distance,
"android.tonemap.mode": 1,
- "android.shading.mode": 1
+ "android.shading.mode": 1,
+ "android.lens.opticalStabilizationMode": 0
}
if linear_tonemap:
assert(props is not None)
diff --git a/apps/CameraITS/tools/turn_off_screen.py b/apps/CameraITS/tools/turn_off_screen.py
index 207042b..1faef9e 100644
--- a/apps/CameraITS/tools/turn_off_screen.py
+++ b/apps/CameraITS/tools/turn_off_screen.py
@@ -15,6 +15,9 @@
import re
import subprocess
import sys
+import time
+
+TURN_OFF_DELAY = 1 # seconds. Needed for back to back runs
def main():
@@ -38,5 +41,7 @@
else:
pwrdn = ('adb -s %s shell input keyevent POWER' % screen_id)
subprocess.Popen(pwrdn.split())
+ time.sleep(TURN_OFF_DELAY)
+
if __name__ == '__main__':
main()
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 18a8764..8648aae 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -118,32 +118,6 @@
android:value="android.software.device_admin" />
</activity>
- <activity android:name=".admin.tapjacking.DeviceAdminTapjackingTestActivity"
- android:label="@string/da_tapjacking_test"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <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_device_admin" />
- <meta-data android:name="test_required_features"
- android:value="android.software.device_admin" />
- </activity>
-
- <receiver android:name=".admin.tapjacking.EmptyDeviceAdminReceiver"
- android:permission="android.permission.BIND_DEVICE_ADMIN">
- <meta-data android:name="android.app.device_admin"
- android:resource="@xml/tapjacking_device_admin" />
- <intent-filter>
- <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
- </intent-filter>
- </receiver>
-
- <activity
- android:name=".admin.tapjacking.OverlayingActivity"
- android:theme="@style/OverlayTheme"
- android:label="Overlaying Activity"/>
-
<activity android:name=".companion.CompanionDeviceTestActivity"
android:label="@string/companion_test"
android:configChanges="keyboardHidden|orientation|screenSize">
diff --git a/apps/CtsVerifier/res/drawable/border.xml b/apps/CtsVerifier/res/drawable/border.xml
deleted file mode 100644
index b419618..0000000
--- a/apps/CtsVerifier/res/drawable/border.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Copyright (C) 2017 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners
- android:radius="4dp"/>
- <stroke
- android:width="4dp"
- android:color="@android:color/black" />
-</shape>
diff --git a/apps/CtsVerifier/res/layout/da_tapjacking_overlay_activity.xml b/apps/CtsVerifier/res/layout/da_tapjacking_overlay_activity.xml
deleted file mode 100644
index 5583fce..0000000
--- a/apps/CtsVerifier/res/layout/da_tapjacking_overlay_activity.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Copyright (C) 2017 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/border"
- android:padding="8dp" >
-
- <TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:text="@string/da_tapjacking_overlay_app_description" />
-</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/da_tapjacking_test_main.xml b/apps/CtsVerifier/res/layout/da_tapjacking_test_main.xml
deleted file mode 100644
index 2ee9ea9..0000000
--- a/apps/CtsVerifier/res/layout/da_tapjacking_test_main.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 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.
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/RootLayoutPadding"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <!-- Enable device admin -->
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/admin_tapjacking_instructions"
- style="@style/InstructionsSmallFont"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:text="@string/da_tapjacking_instructions" />
-
- <Button
- android:id="@+id/enable_admin_overlay_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/admin_tapjacking_instructions"
- android:layout_marginLeft="20dip"
- android:layout_marginRight="20dip"
- android:text="@string/da_tapjacking_button_text" />
- </RelativeLayout>
-
- <include layout="@layout/pass_fail_buttons" />
- </LinearLayout>
-
-</ScrollView>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 69b9900..046d426 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -79,10 +79,6 @@
can be easily uninstalled from the application details screen in a way similar to other
apps.
</string>
- <string name="da_tapjacking_test">Device Admin Tapjacking Test</string>
- <string name="da_tapjacking_test_info">This test checks that an activity cannot tapjack the
- user by obscuring the device admin details while prompting the user to activate the admin.
- </string>
<string name="car_dock_test">Car Dock Test</string>
<string name="car_dock_test_desc">This test ensures that car mode opens the app associated with
car dock when going into car mode.\n\n
@@ -138,18 +134,6 @@
</string>
<string name="da_uninstall_admin_button_text">Launch settings</string>
- <string name="da_tapjacking_overlay_app_description">This activity attempts to tapjack the activity below.\n
- Any security sensitive controls below should not respond to taps as long as this activity is visible.</string>
- <string name="da_tapjacking_instructions">
- 1. Launch the device admin add screen by pressing the button below.\n
- 2. Wait for an overlaying transparent activity to show up obscuring the device admin details window.\n
- 3. Attempt to activate the admin with the transparent activity still obscuring the window.
- The button should discard any taps while showing a toast warning to the user.\n
- 4. Return to this screen and pass the test if the device admin could not be activated while the details
- window was being obscured.
- </string>
- <string name="da_tapjacking_button_text">Enable device admin</string>
-
<!-- Strings for lock bound keys test -->
<string name="sec_lock_bound_key_test">Lock Bound Keys Test</string>
<string name="sec_lock_bound_key_test_info">
diff --git a/apps/CtsVerifier/res/values/styles.xml b/apps/CtsVerifier/res/values/styles.xml
index 64fd4fe..0e05817 100644
--- a/apps/CtsVerifier/res/values/styles.xml
+++ b/apps/CtsVerifier/res/values/styles.xml
@@ -13,9 +13,4 @@
<style name="RootLayoutPadding">
<item name="android:padding">10dip</item>
</style>
- <style name="OverlayTheme" parent="android:Theme.Dialog">
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowBackground">@android:color/transparent</item>
- </style>
</resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/DeviceAdminTapjackingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/DeviceAdminTapjackingTestActivity.java
deleted file mode 100644
index 6a81cba..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/DeviceAdminTapjackingTestActivity.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2017 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.admin.tapjacking;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Test that checks that device admin activate button does not allow taps when another window
- * is obscuring the device admin details
- */
-public class DeviceAdminTapjackingTestActivity extends PassFailButtons.Activity implements
- View.OnClickListener {
-
- private static final String TAG = DeviceAdminTapjackingTestActivity.class.getSimpleName();
- private static final String ADMIN_ACTIVATED_BUNDLE_KEY = "admin_activated";
- private static final String ACTIVITIES_FINISHED_IN_ORDER_KEY = "activities_finished_in_order";
- private static final int REQUEST_ENABLE_ADMIN = 0;
- private static final int REQUEST_OVERLAY_ACTIVITY = 1;
- private static final long REMOVE_ADMIN_TIMEOUT = 5000;
-
- private DevicePolicyManager mDevicePolicyManager;
- private Button mAddDeviceAdminButton;
- private boolean mAdminActivated;
- private boolean mActivitiesFinishedInOrder;
- private boolean mOverlayFinished;
- private ComponentName mAdmin;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.da_tapjacking_test_main);
- setInfoResources(R.string.da_tapjacking_test, R.string.da_tapjacking_test_info, -1);
- setPassFailButtonClickListeners();
-
- mAdmin = new ComponentName(this, EmptyDeviceAdminReceiver.class);
- mDevicePolicyManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
-
- if (savedInstanceState != null) {
- mAdminActivated = savedInstanceState.getBoolean(ADMIN_ACTIVATED_BUNDLE_KEY, false);
- mActivitiesFinishedInOrder = savedInstanceState.getBoolean(ACTIVITIES_FINISHED_IN_ORDER_KEY, false);
- } else if (isActiveAdminAfterTimeout()) {
- Log.e(TAG, "Could not remove active admin. Cannot proceed with test");
- finish();
- }
- mAddDeviceAdminButton = findViewById(R.id.enable_admin_overlay_button);
- mAddDeviceAdminButton.setOnClickListener(this);
- }
-
- private boolean isActiveAdminAfterTimeout() {
- final long startTime = SystemClock.uptimeMillis();
- while (mDevicePolicyManager.isAdminActive(mAdmin)
- && SystemClock.uptimeMillis() < startTime + REMOVE_ADMIN_TIMEOUT) {
- try {
- Thread.sleep(1000);
- } catch(InterruptedException exc) {
- }
- }
- return mDevicePolicyManager.isAdminActive(mAdmin);
- }
-
- @Override
- public void onClick(View v) {
- if (v == mAddDeviceAdminButton) {
- Intent securitySettingsIntent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
- securitySettingsIntent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdmin);
- startActivityForResult(securitySettingsIntent, REQUEST_ENABLE_ADMIN);
- try {
- Thread.sleep(2000);
- } catch (InterruptedException exc) {
- }
- startActivityForResult(new Intent(this, OverlayingActivity.class), REQUEST_OVERLAY_ACTIVITY);
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_ENABLE_ADMIN) {
- mActivitiesFinishedInOrder = mOverlayFinished;
- if (resultCode == RESULT_OK) {
- mAdminActivated = true;
- Log.e(TAG, "Admin was activated. Restart the Test");
- }
- }
- else if (requestCode == REQUEST_OVERLAY_ACTIVITY) {
- mOverlayFinished = true;
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- updateWidgets();
- }
-
- @Override
- public void onSaveInstanceState(Bundle icicle) {
- icicle.putBoolean(ADMIN_ACTIVATED_BUNDLE_KEY, mAdminActivated);
- icicle.putBoolean(ACTIVITIES_FINISHED_IN_ORDER_KEY, mActivitiesFinishedInOrder);
- }
-
- private void updateWidgets() {
- mAddDeviceAdminButton.setEnabled(!mActivitiesFinishedInOrder && !mAdminActivated);
- getPassButton().setEnabled(!mAdminActivated && mActivitiesFinishedInOrder);
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/EmptyDeviceAdminReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/EmptyDeviceAdminReceiver.java
deleted file mode 100644
index 42dd9ac..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/EmptyDeviceAdminReceiver.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 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.admin.tapjacking;
-
-import android.app.admin.DeviceAdminReceiver;
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-
-public class EmptyDeviceAdminReceiver extends DeviceAdminReceiver {
-
- @Override
- public void onEnabled(Context context, Intent intent) {
- DevicePolicyManager dpm =
- (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
- dpm.removeActiveAdmin(new ComponentName(context, this.getClass()));
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
deleted file mode 100644
index 52c7ed5..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2017 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.admin.tapjacking;
-
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-import com.android.cts.verifier.R;
-
-
-public class OverlayingActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.da_tapjacking_overlay_activity);
- WindowManager.LayoutParams params = getWindow().getAttributes();
- params.flags = FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE
- | FLAG_KEEP_SCREEN_ON;
- }
-}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index cd80500..72f0987 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -37,6 +37,8 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.DeviceUnresponsiveException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.invoker.InvocationContext;
import com.android.tradefed.log.ITestLogger;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ITestInvocationListener;
@@ -48,6 +50,7 @@
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IInvocationContextReceiver;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IShardableTest;
import com.android.tradefed.testtype.IStrictShardableTest;
@@ -79,7 +82,8 @@
*/
@OptionClass(alias = "compatibility")
public class CompatibilityTest implements IDeviceTest, IShardableTest, IBuildReceiver,
- IStrictShardableTest, ISystemStatusCheckerReceiver, ITestCollector {
+ IStrictShardableTest, ISystemStatusCheckerReceiver, ITestCollector,
+ IInvocationContextReceiver {
public static final String INCLUDE_FILTER_OPTION = "include-filter";
public static final String EXCLUDE_FILTER_OPTION = "exclude-filter";
@@ -274,6 +278,8 @@
private static CountDownLatch sPreparedLatch;
private boolean mIsLocalSharding = false;
+ private IInvocationContext mInvocationContext;
+
/**
* Create a new {@link CompatibilityTest} that will run the default list of
* modules.
@@ -467,6 +473,12 @@
if (checkers != null && !checkers.isEmpty()) {
runPreModuleCheck(module.getName(), checkers, mDevice, listener);
}
+ IInvocationContext moduleContext = new InvocationContext();
+ moduleContext.setConfigurationDescriptor(module.getConfigurationDescriptor());
+ moduleContext.addInvocationAttribute(IModuleDef.MODULE_NAME, module.getName());
+ moduleContext.addInvocationAttribute(IModuleDef.MODULE_ABI,
+ module.getAbi().getName());
+ mInvocationContext.setModuleInvocationContext(moduleContext);
try {
module.run(listener);
} catch (DeviceUnresponsiveException due) {
@@ -480,6 +492,10 @@
stack.toString());
CLog.w("This may be due to incorrect timeout setting on module %s",
module.getName());
+ } finally {
+ // clear out module invocation context since we are now done with module
+ // execution
+ mInvocationContext.setModuleInvocationContext(null);
}
long duration = System.currentTimeMillis() - start;
long expected = module.getRuntimeHint();
@@ -773,4 +789,9 @@
public void setCollectTestsOnly(boolean collectTestsOnly) {
mCollectTestsOnly = collectTestsOnly;
}
+
+ @Override
+ public void setInvocationContext(IInvocationContext invocationContext) {
+ mInvocationContext = invocationContext;
+ }
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
index edb241a..69e8393 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
@@ -15,7 +15,9 @@
*/
package com.android.compatibility.common.tradefed.testtype;
+import com.android.tradefed.config.ConfigurationDescriptor;
import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IDeviceTest;
@@ -32,6 +34,10 @@
public interface IModuleDef extends Comparable<IModuleDef>, IBuildReceiver, IDeviceTest,
IRemoteTest, IRuntimeHintProvider, ITestCollector {
+ /** key names used for saving module info into {@link IInvocationContext} */
+ public static String MODULE_NAME = "module-name";
+ public static String MODULE_ABI = "module-abi";
+
/**
* @return The name of this module.
*/
@@ -75,4 +81,8 @@
boolean prepare(boolean skipPrep, List<String> preconditionArgs)
throws DeviceNotAvailableException;
+ /**
+ * Retrieves the {@link ConfigurationDescriptor} associated with module config
+ */
+ ConfigurationDescriptor getConfigurationDescriptor();
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
index 29009f1..5198ec1 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
@@ -21,6 +21,7 @@
import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
import com.android.compatibility.common.tradefed.targetprep.TokenRequirement;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationDescriptor;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.OptionSetter;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -66,13 +67,15 @@
private IBuildInfo mBuild;
private ITestDevice mDevice;
private Set<String> mPreparerWhitelist = new HashSet<>();
+ private ConfigurationDescriptor mConfigurationDescriptor;
public ModuleDef(String name, IAbi abi, IRemoteTest test,
- List<ITargetPreparer> preparers) {
+ List<ITargetPreparer> preparers, ConfigurationDescriptor configurationDescriptor) {
mId = AbiUtils.createId(abi.getName(), name);
mName = name;
mAbi = abi;
mTest = test;
+ mConfigurationDescriptor = configurationDescriptor;
boolean hasAbiReceiver = false;
for (ITargetPreparer preparer : preparers) {
if (preparer instanceof IAbiReceiver) {
@@ -354,4 +357,9 @@
}
}
}
+
+ @Override
+ public ConfigurationDescriptor getConfigurationDescriptor() {
+ return mConfigurationDescriptor;
+ }
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index ea76919..4238508 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -341,7 +341,8 @@
String[] configPaths) throws ConfigurationException {
// Invokes parser to process the test module config file
IConfiguration config = mConfigFactory.createConfigurationFromArgs(configPaths);
- addModuleDef(new ModuleDef(name, abi, test, config.getTargetPreparers()));
+ addModuleDef(new ModuleDef(name, abi, test, config.getTargetPreparers(),
+ config.getConfigurationDescription()));
}
private void addModuleDef(IModuleDef moduleDef) {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
index 8ef909e..609fe6b 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
@@ -22,8 +22,10 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.result.ResultReporter;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.TestStatus;
+import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.ConfigurationFactory;
import com.android.tradefed.config.OptionSetter;
@@ -36,6 +38,7 @@
import com.android.tradefed.result.ResultForwarder;
import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IInvocationContextReceiver;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.util.AbiUtils;
import com.android.tradefed.util.FileUtil;
@@ -67,6 +70,7 @@
private static final String CONFIG =
"<configuration description=\"Auto Generated File\">\n" +
+ "<option name=\"config-descriptor:metadata\" key=\"component\" value=\"%s\" />\n" +
"<test class=\"com.android.compatibility.common.tradefed.testtype.%s\">\n" +
" <option name=\"report-test\" value=\"%s\" />\n" +
" <option name=\"run-complete\" value=\"%s\" />\n" +
@@ -75,7 +79,8 @@
"</test>\n" +
"</configuration>";
private static final String FILENAME = "%s.config";
- private static final String TEST_STUB = "TestStub"; // Trivial test stub
+ private static final String TEST_STUB = "TestStub"; // Test stub
+ private static final String SIMPLE_TEST_STUB = "SimpleTestStub"; // Simple test stub
private static final String TEST_STUB_SHARDABLE = "TestStubShardable";
private static final String COMMAND_LINE = "run cts";
@@ -134,6 +139,7 @@
mContext = new InvocationContext();
mContext.addAllocatedDevice("default", mMockDevice);
mContext.addDeviceBuildInfo("default", mMockBuildInfo);
+ mTest.setInvocationContext(mContext);
}
@After
@@ -155,13 +161,33 @@
private void createConfig(File testsDir, String name, String moduleClass, boolean reportTest,
boolean runComplete, boolean doesOneTestFail, boolean internalRetry)
throws IOException {
+ createConfig(testsDir, name, moduleClass, reportTest, runComplete, doesOneTestFail,
+ internalRetry, "foo");
+
+ }
+
+ /**
+ * Create a CTS configuration with a fake tests to exercise all cases.
+ *
+ * @param testsDir The testcases/ dir where to put the module
+ * @param name the name of the module.
+ * @param moduleClass the fake test class to use.
+ * @param reportTest True if the test report some tests
+ * @param runComplete True if the test run is complete
+ * @param doesOneTestFail True if one of the test is going to fail
+ * @param internalRetry True if the test will retry the module itself once
+ * @param component the platform component name that the module can be categorized under
+ */
+ private void createConfig(File testsDir, String name, String moduleClass, boolean reportTest,
+ boolean runComplete, boolean doesOneTestFail, boolean internalRetry, String component)
+ throws IOException {
File config = new File(testsDir, String.format(FILENAME, name));
FileUtil.deleteFile(config);
if (!config.createNewFile()) {
throw new IOException(String.format("Failed to create '%s'", config.getAbsolutePath()));
}
- FileUtil.writeToFile(String.format(CONFIG, moduleClass, reportTest, runComplete,
+ FileUtil.writeToFile(String.format(CONFIG, component, moduleClass, reportTest, runComplete,
doesOneTestFail, internalRetry), config);
}
@@ -192,6 +218,83 @@
}
/**
+ * Verify that result reporters test run ended callback can receive component name as configured
+ * in module config metadata field.
+ */
+ @Test
+ public void testSingleModuleRun_checkMetadata() throws Exception {
+ final String moduleName = "AwsomeModule";
+ final String mAbi = "arm64-v8a";
+ final String component = "CriticalComponent";
+ final List<String> receivedComponentsTestEnded = new ArrayList<>();
+ final List<String> receivedModuleNameTestEnded = new ArrayList<>();
+ final List<String> receivedAbiTestEnded = new ArrayList<>();
+ final List<String> receivedComponentsTestRunEnded = new ArrayList<>();
+ final List<String> receivedModuleNameTestRunEnded = new ArrayList<>();
+ final List<String> receivedAbiTestRunEnded = new ArrayList<>();
+ createConfig(mTestDir, moduleName, SIMPLE_TEST_STUB, true, true, true, false, component);
+ EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi);
+
+ mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS),
+ EasyMock.eq(AbiUtils.createId(mAbi, moduleName)));
+ EasyMock.expectLastCall();
+
+ EasyMock.replay(mMockDevice, mMockBuildInfo);
+ ITestInvocationListener myListener = new ITestInvocationListener() {
+ private IInvocationContext myContext;
+ @Override
+ public void invocationStarted(IInvocationContext context) {
+ myContext = context;
+ }
+ @Override
+ public void testRunEnded(long elapsedTimeMillis, Map<String, String> runMetrics) {
+ receivedComponentsTestRunEnded.addAll(myContext.getModuleInvocationContext()
+ .getConfigurationDescriptor().getMetaData("component"));
+ receivedModuleNameTestRunEnded.addAll(myContext.getModuleInvocationContext()
+ .getAttributes().get(IModuleDef.MODULE_NAME));
+ receivedAbiTestRunEnded.addAll(myContext.getModuleInvocationContext()
+ .getAttributes().get(IModuleDef.MODULE_ABI));
+ }
+ @Override
+ public void testEnded(TestIdentifier test, long endTime,
+ Map<String, String> testMetrics) {
+ receivedComponentsTestEnded.addAll(myContext.getModuleInvocationContext()
+ .getConfigurationDescriptor().getMetaData("component"));
+ receivedModuleNameTestEnded.addAll(myContext.getModuleInvocationContext()
+ .getAttributes().get(IModuleDef.MODULE_NAME));
+ receivedAbiTestEnded.addAll(myContext.getModuleInvocationContext()
+ .getAttributes().get(IModuleDef.MODULE_ABI));
+ }
+ };
+ myListener.invocationStarted(mContext);
+ mTest.run(myListener);
+ myListener.invocationEnded(500);
+ EasyMock.verify(mMockDevice, mMockBuildInfo);
+ // verify metadata was retrieved during testRunEnded callbacks
+ assertEquals("[testRunEnded] wrong number of metadata collected",
+ 1, receivedComponentsTestRunEnded.size());
+ assertEquals("[testRunEnded] wrong component metadata field received",
+ component, receivedComponentsTestRunEnded.get(0));
+ assertEquals("[testRunEnded] wrong number of module name collected",
+ 1, receivedModuleNameTestRunEnded.size());
+ assertEquals(moduleName, receivedModuleNameTestRunEnded.get(0));
+ assertEquals("[testEnded] wrong number of module abi collected",
+ 1, receivedAbiTestRunEnded.size());
+ assertEquals(mAbi, receivedAbiTestRunEnded.get(0));
+ // verify metadata was retrieved during testEnded callbacks
+ assertEquals("[testEnded] wrong number of metadata collected",
+ 1, receivedComponentsTestEnded.size());
+ assertEquals("[testEnded] wrong component metadata field received",
+ component, receivedComponentsTestEnded.get(0));
+ assertEquals("[testEnded] wrong number of module name collected",
+ 1, receivedModuleNameTestEnded.size());
+ assertEquals(moduleName, receivedModuleNameTestEnded.get(0));
+ assertEquals("[testEnded] wrong number of module abi collected",
+ 1, receivedAbiTestEnded.size());
+ assertEquals(mAbi, receivedAbiTestEnded.get(0));
+ }
+
+ /**
* Simple tests running in one module that run some tests but not all of them.
*/
@Test
@@ -297,6 +400,7 @@
};
mTest.setDevice(mMockDevice);
mTest.setBuild(mMockBuildInfo);
+ mTest.setInvocationContext(mContext);
OptionSetter setter = new OptionSetter(mTest, mReporter);
setter.setOptionValue("retry", "0");
@@ -370,6 +474,7 @@
};
mTest.setDevice(mMockDevice);
mTest.setBuild(mMockBuildInfo);
+ mTest.setInvocationContext(mContext);
OptionSetter setter = new OptionSetter(mTest, mReporter);
setter.setOptionValue("retry", "0");
@@ -426,6 +531,7 @@
ITestInvocationListener listener = getShardListener(mMasterReporter);
((IBuildReceiver)mShardTest).setBuild(mBuild);
((IDeviceTest)mShardTest).setDevice(mDevice);
+ ((IInvocationContextReceiver)mShardTest).setInvocationContext(mContext);
listener.invocationStarted(mShardContext);
try {
mShardTest.run(listener);
@@ -572,6 +678,7 @@
((IBuildReceiver)tests.get(0)).setBuild(mMockBuildInfo);
((IDeviceTest)tests.get(0)).setDevice(mMockDevice);
+ ((IInvocationContextReceiver)tests.get(0)).setInvocationContext(mContext);
mReporter.invocationStarted(mContext);
try {
tests.get(0).run(mReporter);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
index 4aa67ac..af44c29 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
@@ -16,6 +16,7 @@
package com.android.compatibility.common.tradefed.testtype;
+import com.android.tradefed.config.ConfigurationDescriptor;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.targetprep.ITargetPreparer;
@@ -46,7 +47,8 @@
public void testAccessors() throws Exception {
IAbi abi = new Abi(ABI, "");
MockRemoteTest mockTest = new MockRemoteTest();
- IModuleDef def = new ModuleDef(NAME, abi, mockTest, new ArrayList<ITargetPreparer>());
+ IModuleDef def = new ModuleDef(NAME, abi, mockTest, new ArrayList<ITargetPreparer>(),
+ new ConfigurationDescriptor());
assertEquals("Incorrect ID", ID, def.getId());
assertEquals("Incorrect ABI", ABI, def.getAbi().getName());
assertEquals("Incorrect Name", NAME, def.getName());
@@ -55,7 +57,8 @@
public void testModuleFinisher() throws Exception {
IAbi abi = new Abi(ABI, "");
MockRemoteTest mockTest = new MockRemoteTest();
- IModuleDef def = new ModuleDef(NAME, abi, mockTest, new ArrayList<ITargetPreparer>());
+ IModuleDef def = new ModuleDef(NAME, abi, mockTest,
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor());
ITestInvocationListener mockListener = EasyMock.createMock(ITestInvocationListener.class);
// listener should receive testRunStarted/testRunEnded events even for no-op run() method
mockListener.testRunStarted(ID, 0);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
index 504d5e9..76ea433 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -19,6 +19,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.testtype.ModuleRepo.ConfigFilter;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationDescriptor;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.targetprep.ITargetPreparer;
@@ -440,22 +441,22 @@
TestRuntime test1 = new TestRuntime();
test1.runtimeHint = 100l;
IModuleDef mod1 = new ModuleDef("test1", new Abi("arm", "32"), test1,
- new ArrayList<ITargetPreparer>());
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor());
testList.add(mod1);
TestRuntime test2 = new TestRuntime();
test2.runtimeHint = 100l;
IModuleDef mod2 = new ModuleDef("test2", new Abi("arm", "32"), test2,
- new ArrayList<ITargetPreparer>());
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor());
testList.add(mod2);
TestRuntime test3 = new TestRuntime();
test3.runtimeHint = 100l;
IModuleDef mod3 = new ModuleDef("test3", new Abi("arm", "32"), test3,
- new ArrayList<ITargetPreparer>());
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor());
testList.add(mod3);
TestRuntime test4 = new TestRuntime();
test4.runtimeHint = 100l;
IModuleDef mod4 = new ModuleDef("test4", new Abi("arm", "32"), test4,
- new ArrayList<ITargetPreparer>());
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor());
testList.add(mod4);
// if we don't shard everything is in one shard.
List<IModuleDef> res = mRepo.getShard(testList, 0, 1);
@@ -480,7 +481,7 @@
TestRuntime test1 = new TestRuntime();
test1.runtimeHint = 100l;
IModuleDef mod1 = new ModuleDef("test1", new Abi("arm", "32"), test1,
- new ArrayList<ITargetPreparer>());
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor());
testList.add(mod1);
List<IModuleDef> res = mRepo.getShard(testList, 1, 2);
assertNull(res);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SimpleTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SimpleTestStub.java
new file mode 100644
index 0000000..331f978
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SimpleTestStub.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 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.compatibility.common.tradefed.testtype;
+
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IRuntimeHintProvider;
+import com.android.tradefed.testtype.ITestCollector;
+import com.android.tradefed.testtype.ITestFilterReceiver;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * A test Stub that can be used to fake some runs.
+ */
+public class SimpleTestStub implements IRemoteTest, IAbiReceiver, IRuntimeHintProvider,
+ ITestCollector, ITestFilterReceiver {
+
+ // options below are unused
+ @Option(name = "report-test")
+ protected boolean mReportTest = false;
+ @Option(name = "run-complete")
+ protected boolean mIsComplete = true;
+ @Option(name = "test-fail")
+ protected boolean mDoesOneTestFail = true;
+ @Option(name = "internal-retry")
+ protected boolean mRetry = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ // We report 1 passing tes
+ listener.testRunStarted("module-run", 1);
+ TestIdentifier tid = new TestIdentifier("TestStub", "test1");
+ listener.testStarted(tid);
+ listener.testEnded(tid, Collections.emptyMap());
+ listener.testRunEnded(0, Collections.emptyMap());
+ }
+
+ @Override
+ public void setAbi(IAbi abi) {
+ // Do nothing
+ }
+
+ @Override
+ public long getRuntimeHint() {
+ return 1L;
+ }
+
+ @Override
+ public void setCollectTestsOnly(boolean shouldCollectTest) {
+ // Do nothing
+ }
+
+ @Override
+ public void addIncludeFilter(String filter) {
+
+ }
+
+ @Override
+ public void addAllIncludeFilters(Set<String> filters) {
+
+ }
+
+ @Override
+ public void addExcludeFilter(String filter) {
+
+ }
+
+ @Override
+ public void addAllExcludeFilters(Set<String> filters) {
+
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
index 799cff3..8e20133 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
@@ -20,6 +20,7 @@
import com.android.compatibility.common.tradefed.testtype.IModuleDef;
import com.android.compatibility.common.tradefed.testtype.ModuleDef;
import com.android.compatibility.common.tradefed.testtype.TestStub;
+import com.android.tradefed.config.ConfigurationDescriptor;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.testtype.Abi;
@@ -43,9 +44,9 @@
public void testCount_2uniquesModules() {
List<IModuleDef> list = new ArrayList<>();
list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
assertEquals(2, UniqueModuleCountUtil.countUniqueModules(list));
}
@@ -53,9 +54,9 @@
public void testCount_2subModules() {
List<IModuleDef> list = new ArrayList<>();
list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
assertEquals(1, UniqueModuleCountUtil.countUniqueModules(list));
}
@@ -63,21 +64,21 @@
public void testCount_mix() {
List<IModuleDef> list = new ArrayList<>();
list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleB", new Abi("arm64", "64"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleB", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleC", new Abi("arm64", "64"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
- new ArrayList<ITargetPreparer>()));
+ new ArrayList<ITargetPreparer>(), new ConfigurationDescriptor()));
assertEquals(6, UniqueModuleCountUtil.countUniqueModules(list));
}
}
diff --git a/hostsidetests/appsecurity/AndroidTest.xml b/hostsidetests/appsecurity/AndroidTest.xml
index d1989e6..418d363 100644
--- a/hostsidetests/appsecurity/AndroidTest.xml
+++ b/hostsidetests/appsecurity/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for the CTS App Security host tests">
+ <target_preparer class="android.appsecurity.cts.AppSecurityPreparer" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsAppSecurityHostTestCases.jar" />
<option name="runtime-hint" value="20m" />
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index 16e2765..a1bcc30 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -55,6 +55,7 @@
protected void setUp() throws Exception {
super.setUp();
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mCtsBuild);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityPreparer.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityPreparer.java
new file mode 100644
index 0000000..b1ac744
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityPreparer.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+/**
+ * Creates secondary and tertiary users for use during a test suite.
+ */
+public class AppSecurityPreparer implements ITargetPreparer, ITargetCleaner {
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws TargetSetupError, BuildError, DeviceNotAvailableException {
+ // Clean up any lingering users from other tests to ensure that we have
+ // best shot at creating the users we need below.
+ removeSecondaryUsers(device);
+
+ final int maxUsers = device.getMaxNumberOfUsersSupported();
+ if (maxUsers > 1) {
+ CLog.logAndDisplay(LogLevel.INFO,
+ "Created secondary user " + device.createUser("CTS_" + System.nanoTime()));
+ }
+ if (maxUsers > 2) {
+ CLog.logAndDisplay(LogLevel.INFO,
+ "Created secondary user " + device.createUser("CTS_" + System.nanoTime()));
+ }
+ }
+
+ @Override
+ public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable throwable)
+ throws DeviceNotAvailableException {
+ removeSecondaryUsers(device);
+ }
+
+ private void removeSecondaryUsers(ITestDevice device) throws DeviceNotAvailableException {
+ final int[] userIds = Utils.getAllUsers(device);
+ for (int i = 1; i < userIds.length; i++) {
+ device.removeUser(userIds[i]);
+ CLog.logAndDisplay(LogLevel.INFO, "Destroyed secondary user " + userIds[i]);
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index 36b0921..390064d 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -110,7 +110,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- // ensure build has been set before test is run
+
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mCtsBuild);
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
index 69ff55e..920e0a5 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
@@ -17,29 +17,17 @@
package android.appsecurity.cts;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.ddmlib.testrunner.TestResult;
-import com.android.ddmlib.testrunner.TestRunResult;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
import java.util.ArrayList;
-import java.util.Map;
/**
* Base class.
*/
public class BaseAppSecurityTest extends DeviceTestCase implements IBuildReceiver {
- protected static final int USER_SYSTEM = 0; // From the UserHandle class.
-
- private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
-
protected IBuildInfo mBuildInfo;
/** Whether multi-user is supported. */
@@ -62,49 +50,12 @@
mSupportsMultiUser = getDevice().getMaxNumberOfUsersSupported() > 1;
mIsSplitSystemUser = checkIfSplitSystemUser();
mPrimaryUserId = getDevice().getPrimaryUserId();
- mFixedUsers = new ArrayList();
+ mFixedUsers = new ArrayList<>();
mFixedUsers.add(mPrimaryUserId);
- if (mPrimaryUserId != USER_SYSTEM) {
- mFixedUsers.add(USER_SYSTEM);
+ if (mPrimaryUserId != Utils.USER_SYSTEM) {
+ mFixedUsers.add(Utils.USER_SYSTEM);
}
getDevice().switchUser(mPrimaryUserId);
- removeTestUsers();
- }
-
- @Override
- protected void tearDown() throws Exception {
- removeTestUsers();
- super.tearDown();
- }
-
- /**
- * @return the userid of the created user
- */
- protected int createUser() throws DeviceNotAvailableException, IllegalStateException {
- final String command = "pm create-user "
- + "TestUser_" + System.currentTimeMillis();
- CLog.d("Starting command: " + command);
- final String output = getDevice().executeShellCommand(command);
- CLog.d("Output for command " + command + ": " + output);
-
- if (output.startsWith("Success")) {
- try {
- return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
- } catch (NumberFormatException e) {
- CLog.e("Failed to parse result: %s", output);
- }
- } else {
- CLog.e("Failed to create user: %s", output);
- }
- throw new IllegalStateException();
- }
-
- private void removeTestUsers() throws Exception {
- for (int userId : getDevice().listUsers()) {
- if (!mFixedUsers.contains(userId)) {
- getDevice().removeUser(userId);
- }
- }
}
private boolean checkIfSplitSystemUser() throws DeviceNotAvailableException {
@@ -131,37 +82,4 @@
String output = getDevice().executeShellCommand(command);
return output.contains(packageName);
}
-
- private void printTestResult(TestRunResult runResult) {
- for (Map.Entry<TestIdentifier, TestResult> testEntry :
- runResult.getTestResults().entrySet()) {
- TestResult testResult = testEntry.getValue();
- CLog.d("Test " + testEntry.getKey() + ": " + testResult.getStatus());
- if (testResult.getStatus() != TestStatus.PASSED) {
- CLog.d(testResult.getStackTrace());
- }
- }
- }
-
- protected boolean runDeviceTestsAsUser(String packageName,
- String testClassName, String testMethodName, int userId) throws Exception {
- if (testClassName != null && testClassName.startsWith(".")) {
- testClassName = packageName + testClassName;
- }
-
- RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
- packageName, RUNNER, getDevice().getIDevice());
- if (testClassName != null && testMethodName != null) {
- testRunner.setMethodName(testClassName, testMethodName);
- } else if (testClassName != null) {
- testRunner.setClassName(testClassName);
- }
-
- CollectingTestListener listener = new CollectingTestListener();
- assertTrue(getDevice().runInstrumentationTestsAsUser(testRunner, userId, listener));
-
- TestRunResult runResult = listener.getCurrentRunResults();
- printTestResult(runResult);
- return !runResult.hasFailedTests() && runResult.getNumTestsInState(TestStatus.PASSED) > 0;
- }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index 6a6c27d..2174fa0 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -54,6 +54,7 @@
private String mFeatureList = null;
+ private int[] mUsers;
private IAbi mAbi;
private IBuildInfo mCtsBuild;
@@ -71,6 +72,7 @@
protected void setUp() throws Exception {
super.setUp();
+ mUsers = Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mCtsBuild);
@@ -148,11 +150,8 @@
}
public void doDirectBootTest(String mode) throws Exception {
- int[] users = {};
boolean doTest = true;
try {
- users = createUsersForTest();
-
// Set up test app and secure lock screens
new InstallMultiple().addApk(APK).run();
new InstallMultiple().addApk(OTHER_APK).run();
@@ -164,7 +163,7 @@
// Give enough time for PackageManager to persist stopped state
Thread.sleep(15000);
- runDeviceTests(PKG, CLASS, "testSetUp", users);
+ runDeviceTests(PKG, CLASS, "testSetUp", mUsers);
// Give enough time for vold to update keys
Thread.sleep(15000);
@@ -184,19 +183,18 @@
if (doTest) {
if (MODE_NONE.equals(mode)) {
- runDeviceTests(PKG, CLASS, "testVerifyUnlockedAndDismiss", users);
+ runDeviceTests(PKG, CLASS, "testVerifyUnlockedAndDismiss", mUsers);
} else {
- runDeviceTests(PKG, CLASS, "testVerifyLockedAndDismiss", users);
+ runDeviceTests(PKG, CLASS, "testVerifyLockedAndDismiss", mUsers);
}
}
} finally {
try {
// Remove secure lock screens and tear down test app
- runDeviceTests(PKG, CLASS, "testTearDown", users);
+ runDeviceTests(PKG, CLASS, "testTearDown", mUsers);
} finally {
getDevice().uninstallPackage(PKG);
- removeUsersForTest(users);
// Get ourselves back into a known-good state
if (MODE_EMULATED.equals(mode)) {
@@ -211,16 +209,6 @@
}
}
- private int[] createUsersForTest() throws DeviceNotAvailableException {
- // TODO: enable test for multiple users
- return new int[] { 0 };
-// return Utils.createUsersForTest(getDevice());
- }
-
- private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
- Utils.removeUsersForTest(getDevice(), users);
- }
-
private void runDeviceTests(String packageName, String testClassName, String testMethodName,
int... users) throws DeviceNotAvailableException {
for (int user : users) {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
index ceb7539..7bdd128 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
@@ -48,6 +48,7 @@
protected void setUp() throws Exception {
super.setUp();
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mCtsBuild);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
index 915f147..235179b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
@@ -70,6 +70,7 @@
public void setUp() throws Exception {
super.setUp();
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mBuildInfo);
@@ -156,6 +157,14 @@
runDeviceTests(EPHEMERAL_1_PKG, WEBVIEW_TEST_CLASS, "testWebViewLoads");
}
+ public void testInstallPermissionNotGranted() throws Exception {
+ runDeviceTests(EPHEMERAL_1_PKG, TEST_CLASS, "testInstallPermissionNotGranted");
+ }
+
+ public void testInstallPermissionGranted() throws Exception {
+ runDeviceTests(EPHEMERAL_1_PKG, TEST_CLASS, "testInstallPermissionGranted");
+ }
+
private void runDeviceTests(String packageName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index e8dca57..87d8bd6 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -52,6 +52,7 @@
private static final String MULTIUSER_PKG = "com.android.cts.multiuserstorageapp";
private static final String MULTIUSER_CLASS = ".MultiUserStorageTest";
+ private int[] mUsers;
private IAbi mAbi;
private IBuildInfo mCtsBuild;
@@ -74,6 +75,7 @@
protected void setUp() throws Exception {
super.setUp();
+ mUsers = Utils.prepareMultipleUsers(getDevice());
assertNotNull(mAbi);
assertNotNull(mCtsBuild);
}
@@ -87,7 +89,6 @@
* Verify that app with no external storage permissions works correctly.
*/
public void testExternalStorageNone() throws Exception {
- final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage();
@@ -95,13 +96,12 @@
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(NONE_PKG, COMMON_CLASS, user);
runDeviceTests(NONE_PKG, NONE_CLASS, user);
}
} finally {
getDevice().uninstallPackage(NONE_PKG);
- removeUsersForTest(users);
}
}
@@ -111,7 +111,6 @@
* correctly.
*/
public void testExternalStorageRead() throws Exception {
- final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage();
@@ -119,13 +118,12 @@
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(READ_PKG, COMMON_CLASS, user);
runDeviceTests(READ_PKG, READ_CLASS, user);
}
} finally {
getDevice().uninstallPackage(READ_PKG);
- removeUsersForTest(users);
}
}
@@ -135,7 +133,6 @@
* correctly.
*/
public void testExternalStorageWrite() throws Exception {
- final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage();
@@ -143,13 +140,12 @@
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(WRITE_PKG, COMMON_CLASS, user);
runDeviceTests(WRITE_PKG, WRITE_CLASS, user);
}
} finally {
getDevice().uninstallPackage(WRITE_PKG);
- removeUsersForTest(users);
}
}
@@ -158,7 +154,6 @@
* directories belonging to other apps, and those apps can read.
*/
public void testExternalStorageGifts() throws Exception {
- final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage();
@@ -170,13 +165,13 @@
// We purposefully delay the installation of the reading apps to
// verify that the daemon correctly invalidates any caches.
assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(WRITE_PKG, ".WriteGiftTest", user);
}
assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(READ_PKG, ".ReadGiftTest", user);
runDeviceTests(NONE_PKG, ".GiftTest", user);
}
@@ -184,7 +179,6 @@
getDevice().uninstallPackage(NONE_PKG);
getDevice().uninstallPackage(READ_PKG);
getDevice().uninstallPackage(WRITE_PKG);
- removeUsersForTest(users);
}
}
@@ -193,15 +187,14 @@
* isolated storage.
*/
public void testMultiUserStorageIsolated() throws Exception {
- final int[] users = createUsersForTest();
try {
- if (users.length == 1) {
+ if (mUsers.length == 1) {
Log.d(TAG, "Single user device; skipping isolated storage tests");
return;
}
- final int owner = users[0];
- final int secondary = users[1];
+ final int owner = mUsers[0];
+ final int secondary = mUsers[1];
// Install our test app
getDevice().uninstallPackage(MULTIUSER_PKG);
@@ -231,7 +224,6 @@
runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testMediaProviderUserIsolation", secondary);
} finally {
getDevice().uninstallPackage(MULTIUSER_PKG);
- removeUsersForTest(users);
}
}
@@ -240,7 +232,6 @@
* when apps with r/w permission levels move around their files.
*/
public void testMultiViewMoveConsistency() throws Exception {
- final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage();
@@ -252,37 +243,35 @@
assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testFolderSetup", user);
}
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testRWAccess", user);
}
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(WRITE_PKG, ".WriteMultiViewTest", "testMoveAway", user);
}
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testROAccess", user);
}
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(WRITE_PKG, ".WriteMultiViewTest", "testMoveBack", user);
}
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testRWAccess", user);
}
} finally {
getDevice().uninstallPackage(NONE_PKG);
getDevice().uninstallPackage(READ_PKG);
getDevice().uninstallPackage(WRITE_PKG);
- removeUsersForTest(users);
}
}
/** Verify that app without READ_EXTERNAL can play default URIs in external storage. */
public void testExternalStorageReadDefaultUris() throws Exception {
- final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage();
@@ -293,7 +282,7 @@
assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
- for (int user : users) {
+ for (int user : mUsers) {
enableWriteSettings(WRITE_PKG, user);
runDeviceTests(
WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testChangeDefaultUris", user);
@@ -303,13 +292,12 @@
}
} finally {
// Make sure the provider and uris are reset on failure.
- for (int user : users) {
+ for (int user : mUsers) {
runDeviceTests(
WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testResetDefaultUris", user);
}
getDevice().uninstallPackage(NONE_PKG);
getDevice().uninstallPackage(WRITE_PKG);
- removeUsersForTest(users);
}
}
@@ -334,14 +322,6 @@
getDevice().executeShellCommand("rm -rf /sdcard/MUST_*");
}
- private int[] createUsersForTest() throws DeviceNotAvailableException {
- return Utils.createUsersForTest(getDevice());
- }
-
- private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
- Utils.removeUsersForTest(getDevice(), users);
- }
-
private void runDeviceTests(String packageName, String testClassName, int userId)
throws DeviceNotAvailableException {
Utils.runDeviceTests(getDevice(), packageName, testClassName, userId);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java
index fb5dffa..4609e8a 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java
@@ -19,8 +19,6 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IAbiReceiver;
@@ -73,8 +71,9 @@
assertNotNull(mAbi);
assertNotNull(mBuildInfo);
- mSupportsMultiUser =
- getDevice().getMaxNumberOfUsersSupported() - getDevice().listUsers().size() >= 2;
+ // This test only runs when we have at least 3 users to work with
+ final int[] users = Utils.prepareMultipleUsers(getDevice(), 3);
+ mSupportsMultiUser = (users.length == 3);
if (mSupportsMultiUser) {
mPrimaryUserId = getDevice().getPrimaryUserId();
mFixedUsers = new ArrayList<>();
@@ -83,8 +82,9 @@
mFixedUsers.add(USER_SYSTEM);
}
getDevice().switchUser(mPrimaryUserId);
- removeTestUsers();
- createTestUsers();
+
+ mTestUser[0] = users[1];
+ mTestUser[1] = users[2];
uninstallTestPackages();
installTestPackages();
@@ -93,7 +93,6 @@
public void tearDown() throws Exception {
if (mSupportsMultiUser) {
- removeTestUsers();
uninstallTestPackages();
}
super.tearDown();
@@ -180,19 +179,6 @@
getDevice().uninstallPackage(USER_PKG);
}
- private void createTestUsers() throws Exception {
- mTestUser[0] = getDevice().createUser("TestUser_" + System.currentTimeMillis());
- mTestUser[1] = getDevice().createUser("TestUser_" + System.currentTimeMillis());
- }
-
- private void removeTestUsers() throws Exception {
- for (int userId : getDevice().listUsers()) {
- if (!mFixedUsers.contains(userId)) {
- getDevice().removeUser(userId);
- }
- }
- }
-
private void runDeviceTests(String packageName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java
index e5a483c..fd599ea 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java
@@ -39,6 +39,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+
+ Utils.prepareSingleUser(getDevice());
uninstallPackage(INSTANT_COOKIE_APP_PKG);
clearUserData(INSTANT_COOKIE_APP_PKG);
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
index ed05837..8795fe8 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
@@ -43,6 +43,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+
+ Utils.prepareSingleUser(getDevice());
getDevice().uninstallPackage(PKG);
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
index 1f7c6be..3574191 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
@@ -236,10 +236,13 @@
}
@Override
- protected void setUp() throws Exception {
+ protected void setUp() throws Exception {
super.setUp();
- mDevice = getDevice();
+
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mCtsBuild);
+
+ mDevice = getDevice();
}
/**
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java
index 115ebf4..fde9f10 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java
@@ -32,10 +32,13 @@
private static final boolean MATCH_UNINSTALLED = true;
private static final boolean MATCH_NORMAL = false;
+ private int[] mUsers;
private String mOldVerifierValue;
public void setUp() throws Exception {
super.setUp();
+
+ mUsers = Utils.prepareMultipleUsers(getDevice());
mOldVerifierValue =
getDevice().executeShellCommand("settings get global package_verifier_enable");
getDevice().executeShellCommand("settings put global package_verifier_enable 0");
@@ -54,7 +57,7 @@
return;
}
- int userId = createUser();
+ int userId = mUsers[1];
assertTrue(userId > 0);
getDevice().startUser(userId);
installTestAppForUser(TEST_APK, userId);
@@ -67,23 +70,23 @@
assertTrue(isAppVisibleForUser(TINY_PKG, mPrimaryUserId, MATCH_UNINSTALLED));
// Try the same from an app
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
- ".PackageAccessTest", "testPackageAccess_inUser", mPrimaryUserId));
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
- ".PackageAccessTest", "testPackageAccess_inUserUninstalled", mPrimaryUserId));
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
+ ".PackageAccessTest", "testPackageAccess_inUser", mPrimaryUserId);
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
+ ".PackageAccessTest", "testPackageAccess_inUserUninstalled", mPrimaryUserId);
// It is not visible for the other user using shell commands
assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_NORMAL));
assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_UNINSTALLED));
// Try the same from an app
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
- ".PackageAccessTest", "testPackageAccess_notInOtherUser", userId));
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
- ".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled", userId));
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
+ ".PackageAccessTest", "testPackageAccess_notInOtherUser", userId);
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
+ ".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled", userId);
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
- ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", userId));
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
+ ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", userId);
getDevice().uninstallPackage(TINY_PKG);
@@ -105,14 +108,14 @@
assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_NORMAL));
assertTrue(isAppVisibleForUser(TINY_PKG, userId, MATCH_UNINSTALLED));
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
- ".PackageAccessTest", "testPackageAccess_getPackagesCanSeeTiny", userId));
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
+ ".PackageAccessTest", "testPackageAccess_getPackagesCanSeeTiny", userId);
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled",
- mPrimaryUserId));
- assertTrue(runDeviceTestsAsUser(TEST_PKG,
- ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", mPrimaryUserId));
+ mPrimaryUserId);
+ Utils.runDeviceTests(getDevice(), TEST_PKG,
+ ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", mPrimaryUserId);
getDevice().uninstallPackage(TINY_PKG);
getDevice().uninstallPackage(TEST_PKG);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index b7f7f88..9ba3c82 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -58,6 +58,7 @@
protected void setUp() throws Exception {
super.setUp();
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mBuildHelper);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
index 93d683f..e87c390 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -16,6 +16,11 @@
package android.appsecurity.cts;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -24,12 +29,6 @@
import java.io.OutputStream;
import java.util.Locale;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
/**
* Tests for APK signature verification during installation.
*/
@@ -44,10 +43,6 @@
private static final String[] RSA_KEY_NAMES_2048_AND_LARGER =
{"2048", "3072", "4096", "8192", "16384"};
-
- /** Device under test. */
- private ITestDevice mDevice;
-
private IBuildInfo mCtsBuild;
@Override
@@ -58,7 +53,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mDevice = getDevice();
+
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mCtsBuild);
uninstallPackage();
}
@@ -582,9 +578,9 @@
}
}
if (ephemeral) {
- return mDevice.installPackage(apkFile, true, "--ephemeral");
+ return getDevice().installPackage(apkFile, true, "--ephemeral");
} else {
- return mDevice.installPackage(apkFile, true);
+ return getDevice().installPackage(apkFile, true);
}
} finally {
apkFile.delete();
@@ -602,6 +598,6 @@
}
private String uninstallPackage() throws DeviceNotAvailableException {
- return mDevice.uninstallPackage(TEST_PKG);
+ return getDevice().uninstallPackage(TEST_PKG);
}
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
index ca218ef..630f351 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
@@ -63,6 +63,7 @@
protected void setUp() throws Exception {
super.setUp();
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mBuildHelper);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index 21bfca1..9474ba8 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -96,6 +96,7 @@
protected void setUp() throws Exception {
super.setUp();
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mCtsBuild);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
index f679e83..f08e4fe 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
@@ -16,18 +16,22 @@
package android.appsecurity.cts;
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityHostTestBase;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Tests that exercise various storage APIs.
*/
-public class StorageHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class StorageHostTest extends CompatibilityHostTestBase {
private static final String PKG_STATS = "com.android.cts.storagestatsapp";
private static final String PKG_A = "com.android.cts.storageapp_a";
private static final String PKG_B = "com.android.cts.storageapp_b";
@@ -37,49 +41,15 @@
private static final String CLASS_STATS = "com.android.cts.storagestatsapp.StorageStatsTest";
private static final String CLASS = "com.android.cts.storageapp.StorageTest";
- private IAbi mAbi;
- private IBuildInfo mCtsBuild;
-
private int[] mUsers;
- @Override
- public void setAbi(IAbi abi) {
- mAbi = abi;
- }
+ @Before
+ public void setUp() throws Exception {
+ mUsers = Utils.prepareMultipleUsers(getDevice());
- @Override
- public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mUsers = Utils.createUsersForTest(getDevice());
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
-
- getDevice().uninstallPackage(PKG_STATS);
- getDevice().uninstallPackage(PKG_A);
- getDevice().uninstallPackage(PKG_B);
-
- Utils.removeUsersForTest(getDevice(), mUsers);
- mUsers = null;
- }
-
- private void prepareTestApps() throws Exception {
- getDevice().uninstallPackage(PKG_STATS);
- getDevice().uninstallPackage(PKG_A);
- getDevice().uninstallPackage(PKG_B);
-
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
- assertNull(getDevice().installPackage(buildHelper.getTestFile(APK_STATS), false));
- assertNull(getDevice().installPackage(buildHelper.getTestFile(APK_A), false));
- assertNull(getDevice().installPackage(buildHelper.getTestFile(APK_B), false));
+ installPackage(APK_STATS);
+ installPackage(APK_A);
+ installPackage(APK_B);
for (int user : mUsers) {
getDevice().executeShellCommand("appops set --user " + user + " " + PKG_STATS
@@ -87,26 +57,20 @@
}
}
- public void testEverything() throws Exception {
- prepareTestApps(); doVerifyQuota();
- prepareTestApps(); doVerifyAppStats();
- prepareTestApps(); doVerifyAppQuota();
- prepareTestApps(); doVerifyAppAllocate();
- prepareTestApps(); doVerifySummary();
- prepareTestApps(); doVerifyStats();
- prepareTestApps(); doVerifyStatsMultiple();
- prepareTestApps(); doVerifyStatsExternal();
- prepareTestApps(); doVerifyStatsExternalConsistent();
- prepareTestApps(); doVerifyCategory();
- prepareTestApps(); doCache();
- prepareTestApps(); doFullDisk();
+ @After
+ public void tearDown() throws Exception {
+ getDevice().uninstallPackage(PKG_STATS);
+ getDevice().uninstallPackage(PKG_A);
+ getDevice().uninstallPackage(PKG_B);
}
- public void doVerifyQuota() throws Exception {
- runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyQuota", Utils.USER_OWNER);
+ @Test
+ public void testVerifyQuota() throws Exception {
+ Utils.runDeviceTests(getDevice(), PKG_STATS, CLASS_STATS, "testVerifyQuota");
}
- public void doVerifyAppStats() throws Exception {
+ @Test
+ public void testVerifyAppStats() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_A, CLASS, "testAllocate", user);
}
@@ -120,31 +84,36 @@
}
}
- public void doVerifyAppQuota() throws Exception {
+ @Test
+ public void testVerifyAppQuota() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_A, CLASS, "testVerifyQuotaApi", user);
}
}
- public void doVerifyAppAllocate() throws Exception {
+ @Test
+ public void testVerifyAppAllocate() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_A, CLASS, "testVerifyAllocateApi", user);
}
}
- public void doVerifySummary() throws Exception {
+ @Test
+ public void testVerifySummary() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifySummary", user);
}
}
- public void doVerifyStats() throws Exception {
+ @Test
+ public void testVerifyStats() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyStats", user);
}
}
- public void doVerifyStatsMultiple() throws Exception {
+ @Test
+ public void testVerifyStatsMultiple() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_A, CLASS, "testAllocate", user);
runDeviceTests(PKG_A, CLASS, "testAllocate", user);
@@ -157,25 +126,29 @@
}
}
- public void doVerifyStatsExternal() throws Exception {
+ @Test
+ public void testVerifyStatsExternal() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyStatsExternal", user);
}
}
- public void doVerifyStatsExternalConsistent() throws Exception {
+ @Test
+ public void testVerifyStatsExternalConsistent() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyStatsExternalConsistent", user);
}
}
- public void doVerifyCategory() throws Exception {
+ @Test
+ public void testVerifyCategory() throws Exception {
for (int user : mUsers) {
runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyCategory", user);
}
}
- public void doCache() throws Exception {
+ @Test
+ public void testCache() throws Exception {
// To make the cache clearing logic easier to verify, ignore any cache
// and low space reserved space.
getDevice().executeShellCommand("settings put global sys_storage_threshold_max_bytes 0");
@@ -197,7 +170,8 @@
}
}
- public void doFullDisk() throws Exception {
+ @Test
+ public void testFullDisk() throws Exception {
waitForIdle();
// Clear all other cached and external storage data to give ourselves a
@@ -209,9 +183,18 @@
final String lastEvent = getDevice().executeShellCommand("logcat -d -b events -t 1");
final String sinceTime = lastEvent.trim().substring(0, 18);
- // Try our hardest to fill up the entire disk
- runDeviceTests(PKG_A, CLASS, "testFullDisk", Utils.USER_OWNER);
- runDeviceTests(PKG_A, CLASS, "testTweakComponent", Utils.USER_OWNER);
+ try {
+ // Try our hardest to fill up the entire disk
+ Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testFullDisk");
+ } catch (Throwable t) {
+ // If we had trouble filling the disk, don't bother going any
+ // further; we failed because we either don't have quota support, or
+ // because disk was more than 10% full.
+ return;
+ }
+
+ // Tweak something that causes PackageManager to persist data
+ Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testTweakComponent");
// Try poking around a couple of settings apps
getDevice().executeShellCommand("input keyevent KEY_HOME");
@@ -234,7 +217,7 @@
troubleLogs = troubleLogs.trim().replaceAll("\\-+ beginning of [a-z]+", "");
if (troubleLogs.length() > 4) {
- fail("Unexpected crashes while disk full: " + troubleLogs);
+ throw new AssertionFailedError("Unexpected crashes while disk full: " + troubleLogs);
}
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
index cf8a354..4afeb9bf 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
@@ -51,6 +51,7 @@
protected void setUp() throws Exception {
super.setUp();
+ Utils.prepareSingleUser(getDevice());
assertNotNull(mAbi);
assertNotNull(mBuildHelper);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
index 37aaeaf..8e83c87 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
@@ -16,7 +16,6 @@
package android.appsecurity.cts;
-import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestResult;
@@ -26,16 +25,15 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.result.CollectingTestListener;
+import java.util.Arrays;
import java.util.Map;
public class Utils {
- private static final String TAG = "AppSecurity";
-
- public static final int USER_OWNER = 0;
+ public static final int USER_SYSTEM = 0;
public static void runDeviceTests(ITestDevice device, String packageName)
throws DeviceNotAvailableException {
- runDeviceTests(device, packageName, null, null, USER_OWNER);
+ runDeviceTests(device, packageName, null, null, USER_SYSTEM);
}
public static void runDeviceTests(ITestDevice device, String packageName, int userId)
@@ -45,7 +43,7 @@
public static void runDeviceTests(ITestDevice device, String packageName, String testClassName)
throws DeviceNotAvailableException {
- runDeviceTests(device, packageName, testClassName, null, USER_OWNER);
+ runDeviceTests(device, packageName, testClassName, null, USER_SYSTEM);
}
public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
@@ -55,7 +53,7 @@
public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
String testMethodName) throws DeviceNotAvailableException {
- runDeviceTests(device, packageName, testClassName, testMethodName, USER_OWNER);
+ runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM);
}
public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
@@ -72,13 +70,8 @@
testRunner.setClassName(testClassName);
}
- if (userId != USER_OWNER) {
- // TODO: move this to RemoteAndroidTestRunner once it supports users
- testRunner.addInstrumentationArg("hack_key", "hack_value --user " + userId);
- }
-
final CollectingTestListener listener = new CollectingTestListener();
- device.runInstrumentationTests(testRunner, listener);
+ device.runInstrumentationTestsAsUser(testRunner, userId, listener);
final TestRunResult result = listener.getCurrentRunResults();
if (result.isRunFailure()) {
@@ -103,65 +96,55 @@
}
}
- private static boolean isMultiUserSupportedOnDevice(ITestDevice device)
+ /**
+ * Prepare and return a single user relevant for testing.
+ */
+ public static int[] prepareSingleUser(ITestDevice device)
throws DeviceNotAvailableException {
- // TODO: move this to ITestDevice once it supports users
- final String output = device.executeShellCommand("pm get-max-users");
- try {
- return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim()) > 1;
- } catch (NumberFormatException e) {
- throw new AssertionError("Failed to parse result: " + output);
- }
+ return prepareMultipleUsers(device, 1);
}
/**
- * Return set of users that test should be run for, creating a secondary
- * user if the device supports it. Always call
- * {@link #removeUsersForTest(ITestDevice, int[])} when finished.
+ * Prepare and return two users relevant for testing.
*/
- public static int[] createUsersForTest(ITestDevice device) throws DeviceNotAvailableException {
- if (isMultiUserSupportedOnDevice(device)) {
- return new int[] { USER_OWNER, createUserOnDevice(device) };
- } else {
- Log.d(TAG, "Single user device; skipping isolated storage tests");
- return new int[] { USER_OWNER };
- }
+ public static int[] prepareMultipleUsers(ITestDevice device)
+ throws DeviceNotAvailableException {
+ return prepareMultipleUsers(device, 2);
}
- public static void removeUsersForTest(ITestDevice device, int[] users)
+ /**
+ * Prepare and return multiple users relevant for testing.
+ */
+ public static int[] prepareMultipleUsers(ITestDevice device, int maxUsers)
throws DeviceNotAvailableException {
- for (int user : users) {
- if (user != USER_OWNER) {
- removeUserOnDevice(device, user);
+ final int[] userIds = getAllUsers(device);
+ for (int i = 1; i < userIds.length; i++) {
+ if (i < maxUsers) {
+ device.startUser(userIds[i]);
+ } else {
+ device.stopUser(userIds[i]);
}
}
- }
-
- private static int createUserOnDevice(ITestDevice device) throws DeviceNotAvailableException {
- // TODO: move this to ITestDevice once it supports users
- final String name = "CTS_" + System.currentTimeMillis();
- final String output = device.executeShellCommand("pm create-user " + name);
- if (output.startsWith("Success")) {
- try {
- final int userId = Integer.parseInt(
- output.substring(output.lastIndexOf(" ")).trim());
- device.executeShellCommand("am start-user " + userId);
- return userId;
- } catch (NumberFormatException e) {
- throw new AssertionError("Failed to parse result: " + output);
- }
+ if (userIds.length > maxUsers) {
+ return Arrays.copyOf(userIds, maxUsers);
} else {
- throw new AssertionError("Failed to create user: " + output);
+ return userIds;
}
}
- private static void removeUserOnDevice(ITestDevice device, int userId)
+ public static int[] getAllUsers(ITestDevice device)
throws DeviceNotAvailableException {
- // TODO: move this to ITestDevice once it supports users
- final String output = device.executeShellCommand("pm remove-user " + userId);
- if (output.startsWith("Error")) {
- throw new AssertionError("Failed to remove user: " + output);
+ Integer primary = device.getPrimaryUserId();
+ if (primary == null) {
+ primary = USER_SYSTEM;
}
+ int[] users = new int[] { primary };
+ for (Integer user : device.listUsers()) {
+ if ((user != USER_SYSTEM) && (user != primary)) {
+ users = Arrays.copyOf(users, users.length + 1);
+ users[users.length - 1] = user;
+ }
+ }
+ return users;
}
-
}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
index b0f53e0..ed3c3cf 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
@@ -20,6 +20,8 @@
<uses-sdk
android:minSdkVersion="25" />
+ <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+ <uses-permission android:name="android.permission.INTERNET" />
<application
android:label="@string/app_name">
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
index c9d0e45..32e0ce7 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
+import android.Manifest;
import android.annotation.Nullable;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -86,9 +87,6 @@
* Intents that we expect the system to expose activities to ephemeral apps to handle.
*/
private static final Intent[] EXPECTED_EXPOSED_SYSTEM_INTENTS = new Intent[] {
- // Camera
- makeIntent(MediaStore.ACTION_IMAGE_CAPTURE, null, null, null),
- makeIntent(MediaStore.ACTION_VIDEO_CAPTURE, null, null, null),
// Contacts
makeIntent(Intent.ACTION_PICK, null, ContactsContract.Contacts.CONTENT_TYPE, null),
makeIntent(Intent.ACTION_PICK, null,
@@ -109,6 +107,14 @@
makeIntent(Intent.ACTION_CHOOSER, null, null, null),
};
+ /**
+ * Camera Intents that we expect the system to expose (if the system has FEATURE_CAMERA).
+ */
+ private static final Intent[] EXPECTED_EXPOSED_CAMERA_INTENTS = new Intent[] {
+ makeIntent(MediaStore.ACTION_IMAGE_CAPTURE, null, null, null),
+ makeIntent(MediaStore.ACTION_VIDEO_CAPTURE, null, null, null),
+ };
+
private BroadcastReceiver mReceiver;
private final SynchronousQueue<TestResult> mResultQueue = new SynchronousQueue<>();
@@ -954,10 +960,30 @@
}
@Test
+ public void testInstallPermissionNotGranted() throws Exception {
+ assertThat(InstrumentationRegistry.getContext()
+ .checkCallingOrSelfPermission(Manifest.permission.SET_ALARM),
+ is(PackageManager.PERMISSION_DENIED));
+ }
+
+ @Test
+ public void testInstallPermissionGranted() throws Exception {
+ assertThat(InstrumentationRegistry.getContext()
+ .checkCallingOrSelfPermission(Manifest.permission.INTERNET),
+ is(PackageManager.PERMISSION_GRANTED));
+ }
+
+ @Test
public void testExposedSystemActivities() throws Exception {
for (Intent queryIntent : EXPECTED_EXPOSED_SYSTEM_INTENTS) {
assertIntentHasExposedActivities(queryIntent);
}
+ if (InstrumentationRegistry.getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
+ for (Intent queryIntent : EXPECTED_EXPOSED_CAMERA_INTENTS) {
+ assertIntentHasExposedActivities(queryIntent);
+ }
+ }
}
private void assertIntentHasExposedActivities(Intent queryIntent) throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 4a4eef1..9d0dec6 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -23,7 +23,6 @@
import static com.android.cts.storageapp.Utils.DATA_INT;
import static com.android.cts.storageapp.Utils.MB_IN_BYTES;
import static com.android.cts.storageapp.Utils.PKG_B;
-import static com.android.cts.storageapp.Utils.TAG;
import static com.android.cts.storageapp.Utils.assertMostlyEquals;
import static com.android.cts.storageapp.Utils.getSizeManual;
import static com.android.cts.storageapp.Utils.makeUniqueFile;
@@ -42,7 +41,6 @@
import android.os.storage.StorageManager;
import android.system.Os;
import android.test.InstrumentationTestCase;
-import android.util.Log;
import java.io.File;
import java.io.IOException;
@@ -62,9 +60,19 @@
public void testFullDisk() throws Exception {
if (shouldHaveQuota(Os.uname())) {
- Hoarder.doBlocks(getContext().getDataDir(), true);
+ final File dataDir = getContext().getDataDir();
+
+ // Pre-flight to see if we have enough disk space to test with
+ final long total = dataDir.getTotalSpace();
+ final long free = dataDir.getFreeSpace();
+ final long required = ((total * 9) / 10) + MB_IN_BYTES;
+ if (free < required) {
+ fail("Skipping full disk test; only found " + free + " free out of " + total);
+ }
+
+ Hoarder.doBlocks(dataDir, true);
} else {
- Log.d(TAG, "Skipping full disk test due to missing quota support");
+ fail("Skipping full disk test due to missing quota support");
}
}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index f994169..c5342ba 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -782,7 +782,7 @@
}
protected void assertAppIdle(boolean enabled) throws Exception {
- assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 10, 2, "Idle=" + enabled);
+ assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled);
}
/**
@@ -848,6 +848,8 @@
return;
} else if (type == TYPE_COMPONENT_ACTIVTIY) {
turnScreenOn();
+ // Wait for screen-on state to propagate through the system.
+ SystemClock.sleep(2000);
final CountDownLatch latch = new CountDownLatch(1);
final Intent launchIntent = getIntentForComponent(type);
final Bundle extras = new Bundle();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerTransitionSelectionTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerTransitionSelectionTests.java
index 7b366d4..63aa1ab 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerTransitionSelectionTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerTransitionSelectionTests.java
@@ -16,6 +16,8 @@
package android.server.cts;
+import android.platform.test.annotations.Presubmit;
+
import static android.server.cts.WindowManagerState.TRANSIT_ACTIVITY_CLOSE;
import static android.server.cts.WindowManagerState.TRANSIT_ACTIVITY_OPEN;
import static android.server.cts.WindowManagerState.TRANSIT_TASK_CLOSE;
@@ -38,6 +40,7 @@
* Build: mmma -j32 cts/hostsidetests/services
* Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.ActivityManagerTransitionSelectionTests
*/
+@Presubmit
public class ActivityManagerTransitionSelectionTests extends ActivityManagerTestBase {
private static final String BOTTOM_ACTIVITY_NAME = "BottomActivity";
diff --git a/tests/acceleration/AndroidTest.xml b/tests/acceleration/AndroidTest.xml
index 9bf8136..60e4bae 100644
--- a/tests/acceleration/AndroidTest.xml
+++ b/tests/acceleration/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Acceleration test cases">
+ <option name="config-descriptor:metadata" key="component" value="framework" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAccelerationTestCases.apk" />
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java
index 3e2f207..56ae652 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationActivity.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import android.app.Activity;
import android.app.PendingIntent;
import android.app.assist.AssistStructure;
import android.autofillservice.cts.CannedFillResponse.CannedDataset;
@@ -48,7 +49,13 @@
private static final SparseArray<CannedFillResponse> sResponses = new SparseArray<>();
private static final ArrayList<PendingIntent> sPendingIntents = new ArrayList<>();
+ private static Object sLock = new Object();
+
+ // Guarded by sLock
+ private static int sResultCode;
+
static void resetStaticState() {
+ setResultCode(RESULT_OK);
sDatasets.clear();
sResponses.clear();
for (int i = 0; i < sPendingIntents.size(); i++) {
@@ -104,6 +111,16 @@
return data;
}
+ /**
+ * Sets the value that's passed to {@link Activity#setResult(int, Intent)} when on
+ * {@link Activity#onCreate(Bundle)}.
+ */
+ public static void setResultCode(int resultCode) {
+ synchronized (sLock) {
+ sResultCode = resultCode;
+ }
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -133,7 +150,12 @@
// Pass on the auth result
final Intent intent = new Intent();
intent.putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, result);
- setResult(RESULT_OK, intent);
+ final int resultCode;
+ synchronized (sLock) {
+ resultCode = sResultCode;
+ }
+ Log.d(TAG, "Returning code " + resultCode);
+ setResult(resultCode, intent);
// Done
finish();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 8029748..2aa8c45 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -16,12 +16,16 @@
package android.autofillservice.cts;
+import static android.autofillservice.cts.Helper.runShellCommand;
+import static android.provider.Settings.Secure.AUTOFILL_SERVICE;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.WindowNode;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.icu.util.Calendar;
import android.os.UserManager;
@@ -47,6 +51,9 @@
private static final String TAG = "AutoFillCtsHelper";
+ // TODO: should static import Settings.Secure instead, but that's not a @TestApi
+ private static String USER_SETUP_COMPLETE = "user_setup_complete";
+
static final boolean VERBOSE = false;
static final String ID_USERNAME_LABEL = "username_label";
@@ -187,6 +194,38 @@
runShellCommand("pm set-user-restriction no_autofill %d", restricted ? 1 : 0);
}
+ /**
+ * Sets whether the user completed the initial setup.
+ */
+ static void setUserComplete(Context context, boolean complete) {
+ if (isUserComplete() == complete) return;
+
+ final OneTimeSettingsListener observer = new OneTimeSettingsListener(context,
+ USER_SETUP_COMPLETE);
+ final String newValue = complete ? "1" : null;
+ runShellCommand("settings put secure %s %s default", USER_SETUP_COMPLETE, newValue);
+ observer.assertCalled();
+
+ assertIsUserComplete(complete);
+ }
+
+ /**
+ * Gets whether the user completed the initial setup.
+ */
+ static boolean isUserComplete() {
+ final String isIt = runShellCommand("settings get secure %s", USER_SETUP_COMPLETE);
+ return "1".equals(isIt);
+ }
+
+ /**
+ * Assets that user completed (or not) the initial setup.
+ */
+ static void assertIsUserComplete(boolean expected) {
+ final boolean actual = isUserComplete();
+ assertWithMessage("Invalid value for secure setting %s", USER_SETUP_COMPLETE)
+ .that(actual).isEqualTo(expected);
+ }
+
private static void dump(StringBuffer buffer, ViewNode node, String prefix, int childId) {
final int childrenSize = node.getChildCount();
buffer.append("\n").append(prefix)
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index c157b38..b03966e 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -16,6 +16,8 @@
package android.autofillservice.cts;
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
import static android.autofillservice.cts.Helper.ID_PASSWORD;
import static android.autofillservice.cts.Helper.ID_PASSWORD_LABEL;
@@ -28,6 +30,7 @@
import static android.autofillservice.cts.Helper.eventually;
import static android.autofillservice.cts.Helper.findNodeByResourceId;
import static android.autofillservice.cts.Helper.runShellCommand;
+import static android.autofillservice.cts.Helper.setUserComplete;
import static android.autofillservice.cts.Helper.setUserRestrictionForAutofill;
import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilConnected;
import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilDisconnected;
@@ -64,7 +67,6 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.os.Bundle;
-import android.platform.test.annotations.Presubmit;
import android.service.autofill.FillEventHistory;
import android.service.autofill.SaveInfo;
import android.support.test.rule.ActivityTestRule;
@@ -496,7 +498,6 @@
}
@Test
- @Presubmit
public void testAutoFillOneDatasetAndSave() throws Exception {
// Set service.
enableService();
@@ -1264,6 +1265,15 @@
@Test
public void testFillResponseAuthBothFields() throws Exception {
+ fillResponseAuthBothFields(false);
+ }
+
+ @Test
+ public void testFillResponseAuthBothFieldsUserCancelsFirstAttempt() throws Exception {
+ fillResponseAuthBothFields(true);
+ }
+
+ private void fillResponseAuthBothFields(boolean cancelFirstAttempt) throws Exception {
// Set service.
enableService();
final MyAutofillCallback callback = mActivity.registerCallback();
@@ -1298,29 +1308,49 @@
sReplier.getNextFillRequest();
final View username = mActivity.getUsername();
callback.assertUiShownEvent(username);
- sUiBot.assertShownByText("Tap to auth response");
+ sUiBot.assertDatasets("Tap to auth response");
// Make sure UI is show on 2nd field as well
final View password = mActivity.getPassword();
mActivity.onPassword(View::requestFocus);
callback.assertUiHiddenEvent(username);
callback.assertUiShownEvent(password);
- sUiBot.assertShownByText("Tap to auth response");
+ sUiBot.assertDatasets("Tap to auth response");
// Now tap on 1st field to show it again...
mActivity.onUsername(View::requestFocus);
callback.assertUiHiddenEvent(password);
callback.assertUiShownEvent(username);
- sUiBot.selectByText("Tap to auth response");
- callback.assertUiHiddenEvent(username);
- sUiBot.assertNotShownByText("Tap to auth response");
+
+ if (cancelFirstAttempt) {
+ // Trigger the auth dialog, but emulate cancel.
+ AuthenticationActivity.setResultCode(RESULT_CANCELED);
+ sUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(username);
+ sUiBot.assertDatasets("Tap to auth response");
+
+ // Make sure it's still shown on other fields...
+ mActivity.onPassword(View::requestFocus);
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(password);
+ sUiBot.assertDatasets("Tap to auth response");
+
+ // Tap on 1st field to show it again...
+ mActivity.onUsername(View::requestFocus);
+ callback.assertUiHiddenEvent(password);
+ callback.assertUiShownEvent(username);
+ }
// ...and select it this time
+ AuthenticationActivity.setResultCode(RESULT_OK);
+ sUiBot.selectDataset("Tap to auth response");
+ callback.assertUiHiddenEvent(username);
callback.assertUiShownEvent(username);
+ sUiBot.assertNotShownByText("Tap to auth response");
sUiBot.selectDataset("Dataset");
callback.assertUiHiddenEvent(username);
sUiBot.assertNoDatasets();
- sUiBot.assertNotShownByText("Tap to auth response");
// Check the results.
mActivity.assertAutoFilled();
@@ -1367,18 +1397,18 @@
sReplier.getNextFillRequest();
final View username = mActivity.getUsername();
callback.assertUiShownEvent(username);
- sUiBot.assertShownByText("Tap to auth response");
+ sUiBot.assertDatasets("Tap to auth response");
// Make sure UI is not show on 2nd field
mActivity.onPassword(View::requestFocus);
callback.assertUiHiddenEvent(username);
- sUiBot.assertNotShownByText("Tap to auth response");
+ sUiBot.assertNoDatasets();
// Now tap on 1st field to show it again...
mActivity.onUsername(View::requestFocus);
callback.assertUiShownEvent(username);
// ...and select it this time
- sUiBot.selectByText("Tap to auth response");
+ sUiBot.selectDataset("Tap to auth response");
callback.assertUiHiddenEvent(username);
sUiBot.assertNotShownByText("Tap to auth response");
@@ -1386,7 +1416,6 @@
sUiBot.selectDataset("Dataset");
callback.assertUiHiddenEvent(username);
sUiBot.assertNoDatasets();
- sUiBot.assertNotShownByText("Tap to auth response");
// Check the results.
mActivity.assertAutoFilled();
@@ -1423,14 +1452,26 @@
callback.assertUiShownEvent(username);
// Select the authentication dialog.
- sUiBot.selectByText("Tap to auth response");
+ sUiBot.selectDataset("Tap to auth response");
callback.assertUiHiddenEvent(username);
- sUiBot.assertNotShownByText("Tap to auth response");
sUiBot.assertNoDatasets();
}
@Test
public void testDatasetAuthTwoFields() throws Exception {
+ datasetAuthTwoFields(false);
+ }
+
+ @Test
+ public void testDatasetAuthTwoFieldsUserCancelsFirstAttempt() throws Exception {
+ datasetAuthTwoFields(true);
+ }
+
+ private void datasetAuthTwoFields(boolean cancelFirstAttempt) throws Exception {
+ // TODO: current API requires these fields...
+ final RemoteViews bogusPresentation = createPresentation("Whatever man, I'm not used...");
+ final String bogusValue = "Y U REQUIRE IT?";
+
// Set service.
enableService();
final MyAutofillCallback callback = mActivity.registerCallback();
@@ -1440,14 +1481,14 @@
new CannedDataset.Builder()
.setField(ID_USERNAME, "dude")
.setField(ID_PASSWORD, "sweet")
- .setPresentation(createPresentation("Dataset"))
+ .setPresentation(bogusPresentation)
.build());
// Configure the service behavior
sReplier.addResponse(new CannedFillResponse.Builder()
.addDataset(new CannedDataset.Builder()
- .setField(ID_USERNAME, "dude")
- .setField(ID_PASSWORD, "sweet")
+ .setField(ID_USERNAME, bogusValue)
+ .setField(ID_PASSWORD, bogusValue)
.setPresentation(createPresentation("Tap to auth dataset"))
.setAuthentication(authentication)
.build())
@@ -1462,12 +1503,47 @@
// Wait for onFill() before proceeding.
sReplier.getNextFillRequest();
final View username = mActivity.getUsername();
-
- // Authenticate
callback.assertUiShownEvent(username);
- sUiBot.selectByText("Tap to auth dataset");
+ sUiBot.assertDatasets("Tap to auth dataset");
+
+ // Make sure UI is show on 2nd field as well
+ final View password = mActivity.getPassword();
+ mActivity.onPassword(View::requestFocus);
callback.assertUiHiddenEvent(username);
- sUiBot.assertNotShownByText("Tap to auth dataset");
+ callback.assertUiShownEvent(password);
+ sUiBot.assertDatasets("Tap to auth dataset");
+
+ // Now tap on 1st field to show it again...
+ mActivity.onUsername(View::requestFocus);
+ callback.assertUiHiddenEvent(password);
+ callback.assertUiShownEvent(username);
+ sUiBot.assertDatasets("Tap to auth dataset");
+
+ if (cancelFirstAttempt) {
+ // Trigger the auth dialog, but emulate cancel.
+ AuthenticationActivity.setResultCode(RESULT_CANCELED);
+ sUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(username);
+ sUiBot.assertDatasets("Tap to auth dataset");
+
+ // Make sure it's still shown on other fields...
+ mActivity.onPassword(View::requestFocus);
+ callback.assertUiHiddenEvent(username);
+ callback.assertUiShownEvent(password);
+ sUiBot.assertDatasets("Tap to auth dataset");
+
+ // Tap on 1st field to show it again...
+ mActivity.onUsername(View::requestFocus);
+ callback.assertUiHiddenEvent(password);
+ callback.assertUiShownEvent(username);
+ }
+
+ // ...and select it this time
+ AuthenticationActivity.setResultCode(RESULT_OK);
+ sUiBot.selectDataset("Tap to auth dataset");
+ callback.assertUiHiddenEvent(username);
+ sUiBot.assertNoDatasets();
// Check the results.
mActivity.assertAutoFilled();
@@ -1516,14 +1592,14 @@
// Authenticate
callback.assertUiShownEvent(username);
- sUiBot.selectByText("Tap to auth dataset");
+ sUiBot.selectDataset("Tap to auth dataset");
callback.assertUiHiddenEvent(username);
// Select a dataset from the new response
callback.assertUiShownEvent(username);
- sUiBot.selectByText("Dataset");
+ sUiBot.selectDataset("Dataset");
callback.assertUiHiddenEvent(username);
- sUiBot.assertNotShownByText("Dataset");
+ sUiBot.assertNoDatasets();
// Check the results.
mActivity.assertAutoFilled();
@@ -1570,9 +1646,9 @@
// Authenticate
callback.assertUiShownEvent(username);
- sUiBot.selectByText("Tap to auth dataset");
+ sUiBot.selectDataset("Tap to auth dataset");
callback.assertUiHiddenEvent(username);
- sUiBot.assertNotShownByText("Tap to auth dataset");
+ sUiBot.assertNoDatasets();
// Check the results.
mActivity.assertAutoFilled();
@@ -2495,4 +2571,21 @@
disableService();
}
}
+
+ @Test
+ public void testSetupComplete() throws Exception {
+ enableService();
+
+ // Sanity check.
+ final AutofillManager afm = mActivity.getAutofillManager();
+ assertThat(afm.isEnabled()).isTrue();
+
+ // Now disable user_complete and try again.
+ try {
+ setUserComplete(getContext(), false);
+ assertThat(afm.isEnabled()).isFalse();
+ } finally {
+ setUserComplete(getContext(), true);
+ }
+ }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index b60840d..756b6e9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -2223,22 +2223,22 @@
// Finally, autofill and check them.
mActivity.focusCell(2, 1);
- sUiBot.selectByText("Auth 2");
+ sUiBot.selectDataset("Auth 2");
sUiBot.selectDataset("Partition 2");
expectation2.assertAutoFilled();
mActivity.focusCell(4, 1);
- sUiBot.selectByText("Auth 4");
+ sUiBot.selectDataset("Auth 4");
sUiBot.selectDataset("Partition 4");
expectation4.assertAutoFilled();
mActivity.focusCell(3, 1);
- sUiBot.selectByText("Auth 3");
+ sUiBot.selectDataset("Auth 3");
sUiBot.selectDataset("Partition 3");
expectation3.assertAutoFilled();
mActivity.focusCell(1, 1);
- sUiBot.selectByText("Auth 1");
+ sUiBot.selectDataset("Auth 1");
sUiBot.selectDataset("Partition 1");
expectation1.assertAutoFilled();
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index d1f01e1..987ddbe 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -152,6 +152,9 @@
/**
* Selects a view by text.
+ *
+ * <p><b>NOTE:</b> when selecting an option in dataset picker is shown, prefer
+ * {@link #selectDataset(String)}.
*/
void selectByText(String name) {
Log.v(TAG, "selectByText(): " + name);
@@ -161,7 +164,10 @@
}
/**
- * Asserts a text is not shown.
+ * Asserts a text is shown.
+ *
+ * <p><b>NOTE:</b> when asserting the dataset picker is shown, prefer
+ * {@link #assertDatasets(String...)}.
*/
public void assertShownByText(String text) {
final UiObject2 object = waitForObject(By.text(text));
@@ -169,7 +175,10 @@
}
/**
- * Asserts a text is now shown.
+ * Asserts a text is not shown.
+ *
+ * <p><b>NOTE:</b> when asserting the dataset picker is not shown, prefer
+ * {@link #assertNoDatasets()}.
*/
public void assertNotShownByText(String text) {
final UiObject2 uiObject = mDevice.findObject(By.text(text));
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
index 1358c34..656b96d 100644
--- a/tests/camera/AndroidTest.xml
+++ b/tests/camera/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Camera test cases">
+ <option name="config-descriptor:metadata" key="component" value="camera" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsCameraTestCases.apk" />
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index ed48c82..00ec95b 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -809,6 +809,53 @@
}
/**
+ * Check that retained fragments in the backstack correctly restored after two "configChanges"
+ */
+ @Test
+ public void retainedFragmentInBackstack() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, null);
+ FragmentManager fm = fc.getFragmentManager();
+
+ Fragment fragment1 = new StrictFragment();
+ fm.beginTransaction()
+ .add(fragment1, "1")
+ .addToBackStack(null)
+ .commit();
+ fm.executePendingTransactions();
+
+ Fragment child = new StrictFragment();
+ child.setRetainInstance(true);
+ fragment1.getChildFragmentManager().beginTransaction()
+ .add(child, "child").commit();
+ fragment1.getChildFragmentManager().executePendingTransactions();
+
+ Fragment fragment2 = new StrictFragment();
+ fm.beginTransaction()
+ .remove(fragment1)
+ .add(fragment2, "2")
+ .addToBackStack(null)
+ .commit();
+ fm.executePendingTransactions();
+
+ Pair<Parcelable, FragmentManagerNonConfig> savedState =
+ FragmentTestUtil.destroy(mActivityRule, fc);
+
+ fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, savedState);
+ savedState = FragmentTestUtil.destroy(mActivityRule, fc);
+ fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, savedState);
+ fm = fc.getFragmentManager();
+ fm.popBackStackImmediate();
+ Fragment retainedChild = fm.findFragmentByTag("1")
+ .getChildFragmentManager().findFragmentByTag("child");
+ assertEquals(child, retainedChild);
+ });
+ }
+
+ /**
* When a fragment has been optimized out, it state should still be saved during
* save and restore instance state.
*/
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index 6821a39..5d5d025 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -26,18 +26,19 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 \
- android-support-multidex \
- compatibility-device-util \
- ctstestrunner \
- services.core \
- junit \
- legacy-android-test \
- truth-prebuilt
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ compatibility-device-util \
+ ctstestrunner \
+ services.core \
+ junit \
+ legacy-android-test \
+ truth-prebuilt
+
+LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4
# Use multi-dex as the compatibility-common-util-devicesidelib dependency
# on compatibility-device-util pushes us beyond 64k methods.
-LOCAL_JACK_FLAGS := --multi-dex legacy
+LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_DX_FLAGS := --multi-dex
# Resource unit tests use a private locale and some densities
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 33c184a..cbf3e93 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -59,6 +59,7 @@
private static MySync mMySync;
private List<ScanResult> mScanResults = null;
private NetworkInfo mNetworkInfo;
+ private Object mLOHSLock = new Object();
// Please refer to WifiManager
private static final int MIN_RSSI = -100;
@@ -173,14 +174,25 @@
private void setWifiEnabled(boolean enable) throws Exception {
synchronized (mMySync) {
- assertTrue(mWifiManager.setWifiEnabled(enable));
if (mWifiManager.isWifiEnabled() != enable) {
+ // the new state is different, we expect it to change
mMySync.expectedState = STATE_WIFI_CHANGING;
- long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
- int expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
- while (System.currentTimeMillis() < timeout
- && mMySync.expectedState != expectedState)
- mMySync.wait(WAIT_MSEC);
+ } else {
+ mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
+ }
+ // now trigger the change
+ assertTrue(mWifiManager.setWifiEnabled(enable));
+ waitForExpectedWifiState(enable);
+ }
+ }
+
+ private void waitForExpectedWifiState(boolean enabled) throws InterruptedException {
+ synchronized (mMySync) {
+ long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+ int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
+ while (System.currentTimeMillis() < timeout
+ && mMySync.expectedState != expected) {
+ mMySync.wait(WAIT_MSEC);
}
}
}
@@ -517,6 +529,13 @@
}
assertTrue(mWifiManager.isWifiEnabled());
+ // give the test a chance to autoconnect
+ Thread.sleep(DURATION);
+ if (mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) {
+ // this test requires a connectable network be configured
+ fail("This test requires a wifi network connection.");
+ }
+
// This will generate a distinct stack trace if the initial connection fails.
connectWifi();
@@ -686,4 +705,148 @@
// Passpoint build config |config_wifi_hotspot2_enabled| is disabled, so noop.
}
}
+
+ public class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback {
+ Object hotspotLock;
+ WifiManager.LocalOnlyHotspotReservation reservation = null;
+ boolean onStartedCalled = false;
+ boolean onStoppedCalled = false;
+ boolean onFailedCalled = false;
+ int failureReason = -1;
+
+ TestLocalOnlyHotspotCallback(Object lock) {
+ hotspotLock = lock;
+ }
+
+ @Override
+ public void onStarted(WifiManager.LocalOnlyHotspotReservation r) {
+ synchronized (hotspotLock) {
+ reservation = r;
+ onStartedCalled = true;
+ hotspotLock.notify();
+ }
+ }
+
+ @Override
+ public void onStopped() {
+ synchronized (hotspotLock) {
+ onStoppedCalled = true;
+ hotspotLock.notify();
+ }
+ }
+
+ @Override
+ public void onFailed(int reason) {
+ synchronized (hotspotLock) {
+ onFailedCalled = true;
+ failureReason = reason;
+ hotspotLock.notify();
+ }
+ }
+ }
+
+ private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() {
+ // Location mode must be enabled for this test
+ if (!isLocationEnabled()) {
+ fail("Please enable location for this test");
+ }
+
+ TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLOHSLock);
+ synchronized (mLOHSLock) {
+ try {
+ mWifiManager.startLocalOnlyHotspot(callback, null);
+ // now wait for callback
+ mLOHSLock.wait(DURATION);
+ } catch (InterruptedException e) {
+ }
+ // check if we got the callback
+ assertTrue(callback.onStartedCalled);
+ assertNotNull(callback.reservation.getWifiConfiguration());
+ assertFalse(callback.onFailedCalled);
+ assertFalse(callback.onStoppedCalled);
+ }
+ return callback;
+ }
+
+ private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) {
+ synchronized (mMySync) {
+ // we are expecting a new state
+ mMySync.expectedState = STATE_WIFI_CHANGING;
+
+ // now shut down LocalOnlyHotspot
+ callback.reservation.close();
+
+ try {
+ waitForExpectedWifiState(wifiEnabled);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ /**
+ * Verify that calls to startLocalOnlyHotspot succeed with proper permissions.
+ *
+ * Note: Location mode must be enabled for this test.
+ */
+ public void testStartLocalOnlyHotspotSuccess() {
+ boolean wifiEnabled = mWifiManager.isWifiEnabled();
+
+ TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
+
+ // at this point, wifi should be off
+ assertFalse(mWifiManager.isWifiEnabled());
+
+ stopLocalOnlyHotspot(callback, wifiEnabled);
+ assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
+ }
+
+ /**
+ * Verify calls to setWifiEnabled from a non-settings app while softap mode is active do not
+ * exit softap mode.
+ *
+ * This test uses the LocalOnlyHotspot API to enter softap mode. This should also be true when
+ * tethering is started.
+ * Note: Location mode must be enabled for this test.
+ */
+ public void testSetWifiEnabledByAppDoesNotStopHotspot() {
+ boolean wifiEnabled = mWifiManager.isWifiEnabled();
+
+ TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
+ // at this point, wifi should be off
+ assertFalse(mWifiManager.isWifiEnabled());
+
+ // now we should fail to turn on wifi
+ assertFalse(mWifiManager.setWifiEnabled(true));
+
+ stopLocalOnlyHotspot(callback, wifiEnabled);
+ assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
+ }
+
+ /**
+ * Verify that applications can only have one registered LocalOnlyHotspot request at a time.
+ *
+ * Note: Location mode must be enabled for this test.
+ */
+ public void testStartLocalOnlyHotspotSingleRequestByApps() {
+ boolean caughtException = false;
+
+ boolean wifiEnabled = mWifiManager.isWifiEnabled();
+
+ TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
+
+ // at this point, wifi should be off
+ assertFalse(mWifiManager.isWifiEnabled());
+
+ // now make a second request - this should fail.
+ TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLOHSLock);
+ try {
+ mWifiManager.startLocalOnlyHotspot(callback2, null);
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice");
+ caughtException = true;
+ }
+ assertTrue(caughtException);
+
+ stopLocalOnlyHotspot(callback, wifiEnabled);
+ assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
+ }
}
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
index fecc067..21730c6 100644
--- a/tests/tests/os/src/android/os/cts/StrictModeTest.java
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -22,15 +22,12 @@
import android.net.TrafficStats;
import android.net.Uri;
import android.os.StrictMode;
-import android.os.SystemClock;
+import android.os.StrictMode.ViolationListener;
import android.system.Os;
import android.system.OsConstants;
import android.test.InstrumentationTestCase;
import android.util.Log;
-import libcore.io.Streams;
-
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -38,8 +35,8 @@
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
/**
* Tests for {@link StrictMode}
@@ -66,6 +63,10 @@
StrictMode.setVmPolicy(mVmPolicy);
}
+ public interface ThrowingRunnable {
+ public void run() throws Exception;
+ }
+
/**
* Insecure connection should be detected
*/
@@ -80,10 +81,10 @@
.penaltyLog()
.build());
- long mark = System.currentTimeMillis();
- ((HttpURLConnection) new URL("http://example.com/").openConnection()).getResponseCode();
- assertLogged("Detected cleartext network traffic from UID "
- + android.os.Process.myUid(), mark, 5000);
+ assertViolation("Detected cleartext network traffic from UID", () -> {
+ ((HttpURLConnection) new URL("http://example.com/").openConnection())
+ .getResponseCode();
+ });
}
/**
@@ -100,10 +101,10 @@
.penaltyLog()
.build());
- long mark = System.currentTimeMillis();
- ((HttpURLConnection) new URL("https://example.com/").openConnection()).getResponseCode();
- assertNotLogged("Detected cleartext network traffic from UID "
- + android.os.Process.myUid(), mark, 5000);
+ assertNoViolation(() -> {
+ ((HttpURLConnection) new URL("https://example.com/").openConnection())
+ .getResponseCode();
+ });
}
public void testFileUriExposure() throws Exception {
@@ -112,19 +113,21 @@
.penaltyLog()
.build());
- long mark = System.currentTimeMillis();
- Uri uri = Uri.fromFile(new File("/sdcard/meow.jpg"));
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(uri, "image/jpeg");
- getContext().startActivity(intent);
- assertLogged(uri + " exposed beyond app", mark);
+ final Uri badUri = Uri.fromFile(new File("/sdcard/meow.jpg"));
+ assertViolation(badUri + " exposed beyond app", () -> {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setDataAndType(badUri, "image/jpeg");
+ getContext().startActivity(intent);
+ });
- mark = System.currentTimeMillis();
- uri = Uri.parse("content://com.example/foobar");
- intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(uri, "image/jpeg");
- getContext().startActivity(intent);
- assertNotLogged(uri + " exposed beyond app", mark);
+ final Uri goodUri = Uri.parse("content://com.example/foobar");
+ assertNoViolation(() -> {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setDataAndType(goodUri, "image/jpeg");
+ getContext().startActivity(intent);
+ });
}
public void testContentUriWithoutPermission() throws Exception {
@@ -133,19 +136,21 @@
.penaltyLog()
.build());
- long mark = System.currentTimeMillis();
final Uri uri = Uri.parse("content://com.example/foobar");
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(uri, "image/jpeg");
- getContext().startActivity(intent);
- assertLogged(uri + " exposed beyond app", mark);
+ assertViolation(uri + " exposed beyond app", () -> {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setDataAndType(uri, "image/jpeg");
+ getContext().startActivity(intent);
+ });
- mark = System.currentTimeMillis();
- intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(uri, "image/jpeg");
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- getContext().startActivity(intent);
- assertNotLogged(uri + " exposed beyond app", mark);
+ assertNoViolation(() -> {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setDataAndType(uri, "image/jpeg");
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ getContext().startActivity(intent);
+ });
}
public void testUntaggedSocketsHttp() throws Exception {
@@ -159,18 +164,20 @@
.penaltyLog()
.build());
- long mark = System.currentTimeMillis();
- ((HttpURLConnection) new URL("http://example.com/").openConnection()).getResponseCode();
- assertLogged("Untagged socket detected", mark);
+ assertViolation("Untagged socket detected", () -> {
+ ((HttpURLConnection) new URL("http://example.com/").openConnection())
+ .getResponseCode();
+ });
- mark = System.currentTimeMillis();
- TrafficStats.setThreadStatsTag(0xDECAFBAD);
- try {
- ((HttpURLConnection) new URL("http://example.com/").openConnection()).getResponseCode();
- } finally {
- TrafficStats.clearThreadStatsTag();
- }
- assertNotLogged("Untagged socket detected", mark);
+ assertNoViolation(() -> {
+ TrafficStats.setThreadStatsTag(0xDECAFBAD);
+ try {
+ ((HttpURLConnection) new URL("http://example.com/").openConnection())
+ .getResponseCode();
+ } finally {
+ TrafficStats.clearThreadStatsTag();
+ }
+ });
}
public void testUntaggedSocketsRaw() throws Exception {
@@ -184,99 +191,95 @@
.penaltyLog()
.build());
- long mark = System.currentTimeMillis();
- TrafficStats.setThreadStatsTag(0xDECAFBAD);
- try (Socket socket = new Socket("example.com", 80)) {
- socket.getOutputStream().close();
- } finally {
- TrafficStats.clearThreadStatsTag();
- }
- assertNotLogged("Untagged socket detected", mark);
+ assertNoViolation(() -> {
+ TrafficStats.setThreadStatsTag(0xDECAFBAD);
+ try (Socket socket = new Socket("example.com", 80)) {
+ socket.getOutputStream().close();
+ } finally {
+ TrafficStats.clearThreadStatsTag();
+ }
+ });
- mark = System.currentTimeMillis();
- try (Socket socket = new Socket("example.com", 80)) {
- socket.getOutputStream().close();
- }
- assertLogged("Untagged socket detected", mark);
+ assertViolation("Untagged socket detected", () -> {
+ try (Socket socket = new Socket("example.com", 80)) {
+ socket.getOutputStream().close();
+ }
+ });
}
public void testRead() throws Exception {
final File test = File.createTempFile("foo", "bar");
final File dir = test.getParentFile();
- FileInputStream is = null;
- FileDescriptor fd = null;
+ final FileInputStream is = new FileInputStream(test);
+ final FileDescriptor fd = Os.open(test.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.penaltyLog()
.build());
- SystemClock.sleep(1500);
-
- try (AssertDiskReadLogged l = new AssertDiskReadLogged()) {
+ assertViolation("StrictModeDiskReadViolation", () -> {
test.exists();
- }
- try (AssertDiskReadLogged l = new AssertDiskReadLogged()) {
+ });
+ assertViolation("StrictModeDiskReadViolation", () -> {
test.length();
- }
- try (AssertDiskReadLogged l = new AssertDiskReadLogged()) {
+ });
+ assertViolation("StrictModeDiskReadViolation", () -> {
dir.list();
- }
- try (AssertDiskReadLogged l = new AssertDiskReadLogged()) {
- is = new FileInputStream(test);
- }
- try (AssertDiskReadLogged l = new AssertDiskReadLogged()) {
+ });
+ assertViolation("StrictModeDiskReadViolation", () -> {
+ new FileInputStream(test);
+ });
+ assertViolation("StrictModeDiskReadViolation", () -> {
is.read();
- }
- try (AssertDiskReadLogged l = new AssertDiskReadLogged()) {
- fd = Os.open(test.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
- }
- try (AssertDiskReadLogged l = new AssertDiskReadLogged()) {
+ });
+ assertViolation("StrictModeDiskReadViolation", () -> {
+ Os.open(test.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
+ });
+ assertViolation("StrictModeDiskReadViolation", () -> {
Os.read(fd, new byte[10], 0, 1);
- }
+ });
}
public void testWrite() throws Exception {
- File file = null;
+ File file = File.createTempFile("foo", "bar");
- FileOutputStream os = null;
- FileDescriptor fd = null;
+ final FileOutputStream os = new FileOutputStream(file);
+ final FileDescriptor fd = Os.open(file.getAbsolutePath(), OsConstants.O_RDWR, 0600);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskWrites()
.penaltyLog()
.build());
- SystemClock.sleep(1500);
-
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
- file = File.createTempFile("foo", "bar");
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
+ assertViolation("StrictModeDiskWriteViolation", () -> {
+ File.createTempFile("foo", "bar");
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
file.delete();
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
file.createNewFile();
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
- os = new FileOutputStream(file);
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
+ new FileOutputStream(file);
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
os.write(32);
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
- fd = Os.open(file.getAbsolutePath(), OsConstants.O_RDWR, 0600);
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
+ Os.open(file.getAbsolutePath(), OsConstants.O_RDWR, 0600);
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
Os.write(fd, new byte[10], 0, 1);
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
Os.fsync(fd);
- }
- try (AssertDiskWriteLogged l = new AssertDiskWriteLogged()) {
+ });
+ assertViolation("StrictModeDiskWriteViolation", () -> {
file.renameTo(new File(file.getParent(), "foobar"));
- }
+ });
}
public void testNetwork() throws Exception {
@@ -290,75 +293,66 @@
.penaltyLog()
.build());
- long mark = System.currentTimeMillis();
- try (Socket socket = new Socket("example.com", 80)) {
- socket.getOutputStream().close();
- }
- assertLogged("StrictModeNetworkViolation", mark);
+ assertViolation("StrictModeNetworkViolation", () -> {
+ try (Socket socket = new Socket("example.com", 80)) {
+ socket.getOutputStream().close();
+ }
+ });
- mark = System.currentTimeMillis();
- ((HttpURLConnection) new URL("http://example.com/").openConnection()).getResponseCode();
- assertLogged("StrictModeNetworkViolation", mark);
+ assertViolation("StrictModeNetworkViolation", () -> {
+ ((HttpURLConnection) new URL("http://example.com/").openConnection())
+ .getResponseCode();
+ });
}
- private static class AssertLogged implements AutoCloseable {
- private final String mMessage;
- private final long mStart;
+ private static void assertViolation(String expected, ThrowingRunnable r) throws Exception {
+ final LinkedBlockingQueue<String> violations = new LinkedBlockingQueue<>();
+ StrictMode.setViolationListener(new ViolationListener() {
+ @Override
+ public void onViolation(String message) {
+ violations.add(message);
+ }
+ });
- public AssertLogged(String message) {
- mMessage = message;
- mStart = System.currentTimeMillis();
- }
-
- @Override
- public void close() throws Exception {
- assertLogged(mMessage, mStart);
+ try {
+ r.run();
+ while (true) {
+ final String violation = violations.poll(5, TimeUnit.SECONDS);
+ if (violation == null) {
+ fail("Expected violation not found: " + expected);
+ } else if (violation.contains(expected)) {
+ return;
+ }
+ }
+ } finally {
+ StrictMode.setViolationListener(null);
}
}
- private static class AssertDiskReadLogged extends AssertLogged {
- public AssertDiskReadLogged() {
- super("StrictModeDiskReadViolation");
+ private static void assertNoViolation(ThrowingRunnable r) throws Exception {
+ final LinkedBlockingQueue<String> violations = new LinkedBlockingQueue<>();
+ StrictMode.setViolationListener(new ViolationListener() {
+ @Override
+ public void onViolation(String message) {
+ violations.add(message);
+ }
+ });
+
+ try {
+ r.run();
+ while (true) {
+ final String violation = violations.poll(5, TimeUnit.SECONDS);
+ if (violation == null) {
+ return;
+ } else {
+ fail("Unexpected violation found: " + violation);
+ }
+ }
+ } finally {
+ StrictMode.setViolationListener(null);
}
}
- private static class AssertDiskWriteLogged extends AssertLogged {
- public AssertDiskWriteLogged() {
- super("StrictModeDiskWriteViolation");
- }
- }
-
- private static void assertLogged(String msg, long since) throws Exception {
- assertLogged(msg, since, 1100);
- }
-
- private static void assertLogged(String msg, long since, long wait) throws Exception {
- SystemClock.sleep(wait);
- assertTrue("Expected message not found: " + msg, readLogSince(since).contains(msg));
- }
-
- private static void assertNotLogged(String msg, long since) throws Exception {
- assertNotLogged(msg, since, 1100);
- }
-
- private static void assertNotLogged(String msg, long since, long wait) throws Exception {
- SystemClock.sleep(wait);
- assertFalse("Unexpected message found: " + msg, readLogSince(since).contains(msg));
- }
-
- private static String readLogSince(long millis) throws Exception {
- final SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
- final Process proc = new ProcessBuilder("logcat", "-t", format.format(new Date(millis)))
- .redirectErrorStream(true).start();
-
- final ByteArrayOutputStream buf = new ByteArrayOutputStream();
- Streams.copy(proc.getInputStream(), buf);
- final int res = proc.waitFor();
-
- Log.d(TAG, "Log output was " + buf.size() + " bytes, exit code " + res);
- return new String(buf.toByteArray());
- }
-
private boolean hasInternetConnection() {
final PackageManager pm = getContext().getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 284841b..380ddd0 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -33,6 +33,8 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
+ <uses-permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL" />
+ <uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
@@ -94,6 +96,27 @@
android:exported="false"
android:multiprocess="true" />
+ <service
+ android:name="android.provider.cts.contacts.StubInCallService"
+ android:permission="android.permission.BIND_INCALL_SERVICE">
+ <intent-filter>
+ <action android:name="android.telecom.InCallService"/>
+ </intent-filter>
+ <meta-data
+ android:name="android.telecom.IN_CALL_SERVICE_UI"
+ android:value="true"/>
+ </service>
+
+ <activity android:name="android.provider.cts.contacts.StubDialerActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL"/>
+ <data android:scheme="tel"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL"/>
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/StubDialerActivity.java b/tests/tests/provider/src/android/provider/cts/contacts/StubDialerActivity.java
new file mode 100644
index 0000000..b87343c
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/contacts/StubDialerActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts.contacts;
+
+import android.app.Activity;
+
+/**
+ * Does nothing. Listens to the dial intent to make the test eligible to be set as the default
+ * dialer.
+ */
+public class StubDialerActivity extends Activity {
+
+
+}
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/StubInCallService.java b/tests/tests/provider/src/android/provider/cts/contacts/StubInCallService.java
new file mode 100644
index 0000000..4d84782
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/contacts/StubInCallService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts.contacts;
+
+import android.telecom.InCallService;
+
+/**
+ * An in-call service that does nothing except allowing CTS provider to be set as a default dialer.
+ */
+public class StubInCallService extends InCallService {
+
+}
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/VoicemailContractTest.java b/tests/tests/provider/src/android/provider/cts/contacts/VoicemailContractTest.java
index 4861669..75561f9 100644
--- a/tests/tests/provider/src/android/provider/cts/contacts/VoicemailContractTest.java
+++ b/tests/tests/provider/src/android/provider/cts/contacts/VoicemailContractTest.java
@@ -16,16 +16,25 @@
package android.provider.cts.contacts;
+import android.app.Instrumentation;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.provider.VoicemailContract;
import android.provider.VoicemailContract.Status;
import android.provider.VoicemailContract.Voicemails;
import android.test.InstrumentationTestCase;
+import android.text.TextUtils;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
/**
* CTS tests for voicemail provider accessed through {@link VoicemailContract}.
@@ -38,6 +47,15 @@
private Uri mStatusContentUri;
private String mSourcePackageName;
+ private String mPreviousDefaultDialer;
+
+ private static final String COMMAND_SET_DEFAULT_DIALER = "telecom set-default-dialer ";
+ private static final String COMMAND_GET_DEFAULT_DIALER = "telecom get-default-dialer";
+
+ private static final String PACKAGE = "android.provider.cts";
+
+ private final String FOREIGN_SOURCE = "android.provider.cts.contacts.foreign_source";
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -56,6 +74,9 @@
// entries inserted by this package.
mStatusProvider.delete(mStatusContentUri, null, null);
mVoicemailProvider.delete(mVoicemailContentUri, null, null);
+ if (!TextUtils.isEmpty(mPreviousDefaultDialer)) {
+ setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
+ }
super.tearDown();
}
@@ -169,8 +190,7 @@
assertEquals(updateDate, cursor.getLong(DATE_INDEX));
assertEquals(updateCallsDuration, cursor.getLong(DURATION_INDEX));
assertEquals(updateSourceData, cursor.getString(SOURCE_DATA_INDEX));
- // Self modifying so DIRTY should be overridden to 0
- assertEquals(0,cursor.getInt(DIRTY_INDEX));
+ assertEquals(1,cursor.getInt(DIRTY_INDEX));
assertEquals(1,cursor.getInt(DELETED_INDEX));
assertEquals(1,cursor.getInt(BACKED_UP_INDEX));
assertEquals(1,cursor.getInt(RESTORED_INDEX));
@@ -186,6 +206,95 @@
cursor.close();
}
+ public void testForeignUpdate_dirty() throws Exception {
+ // only the default dialer has WRITE_VOICEMAIL permission, which can modify voicemails of
+ // a foreign source package.
+ setTestAsDefaultDialer();
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE);
+
+ Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values);
+
+ mVoicemailProvider.update(uri, new ContentValues(), null, null);
+
+ try (Cursor cursor = mVoicemailProvider
+ .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) {
+ cursor.moveToFirst();
+ assertEquals(1, cursor.getInt(0));
+ }
+ }
+
+ public void testForeignUpdate_explicitNotDirty() throws Exception {
+ setTestAsDefaultDialer();
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE);
+
+ Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values);
+
+ ContentValues updateValues = new ContentValues();
+ updateValues.put(Voicemails.DIRTY,0);
+ mVoicemailProvider.update(uri, updateValues, null, null);
+
+ try (Cursor cursor = mVoicemailProvider
+ .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) {
+ cursor.moveToFirst();
+ assertEquals(0, cursor.getInt(0));
+ }
+ }
+
+ public void testForeignUpdate_null_dirty() throws Exception {
+ setTestAsDefaultDialer();
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE);
+
+ Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values);
+
+ ContentValues updateValues = new ContentValues();
+ updateValues.put(Voicemails.DIRTY, (Integer) null);
+ mVoicemailProvider.update(uri, updateValues, null, null);
+
+ try (Cursor cursor = mVoicemailProvider
+ .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) {
+ cursor.moveToFirst();
+ assertEquals(1, cursor.getInt(0));
+ }
+ }
+
+ public void testForeignUpdate_NotNormalized_normalized() throws Exception {
+ setTestAsDefaultDialer();
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE);
+
+ Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values);
+
+ ContentValues updateValues = new ContentValues();
+ updateValues.put(Voicemails.DIRTY, 2);
+ mVoicemailProvider.update(uri, updateValues, null, null);
+
+ try (Cursor cursor = mVoicemailProvider
+ .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) {
+ cursor.moveToFirst();
+ assertEquals(1, cursor.getInt(0));
+ }
+ }
+
+ public void testLocalUpdate_notDirty() throws Exception {
+
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.DIRTY,1);
+
+ Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(mSourcePackageName), values);
+
+ mVoicemailProvider.update(uri, new ContentValues(), null, null);
+
+ try (Cursor cursor = mVoicemailProvider
+ .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) {
+ cursor.moveToFirst();
+ assertEquals(cursor.getInt(0), 0);
+ }
+ }
+
+
// Data column should be automatically generated during insert.
public void testInsert_doesNotUpdateDataColumn() throws Exception {
@@ -356,4 +465,57 @@
// Expected result.
}
}
+
+ private void setTestAsDefaultDialer() throws Exception{
+ assertTrue(mPreviousDefaultDialer == null);
+ mPreviousDefaultDialer = getDefaultDialer(getInstrumentation());
+ setDefaultDialer(getInstrumentation(),PACKAGE);
+ }
+
+ private static String setDefaultDialer(Instrumentation instrumentation, String packageName)
+ throws Exception {
+ return executeShellCommand(instrumentation, COMMAND_SET_DEFAULT_DIALER + packageName);
+ }
+
+ private static String getDefaultDialer(Instrumentation instrumentation) throws Exception {
+ return executeShellCommand(instrumentation, COMMAND_GET_DEFAULT_DIALER);
+ }
+
+ /**
+ * Executes the given shell command and returns the output in a string. Note that even if we
+ * don't care about the output, we have to read the stream completely to make the command
+ * execute.
+ */
+ private static String executeShellCommand(Instrumentation instrumentation,
+ String command) throws Exception {
+ final ParcelFileDescriptor parcelFileDescriptor =
+ instrumentation.getUiAutomation().executeShellCommand(command);
+ BufferedReader bufferedReader = null;
+ try (InputStream in = new FileInputStream(parcelFileDescriptor.getFileDescriptor())) {
+ bufferedReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ String string = null;
+ StringBuilder out = new StringBuilder();
+ while ((string = bufferedReader.readLine()) != null) {
+ out.append(string);
+ }
+ return out.toString();
+ } finally {
+ if (bufferedReader != null) {
+ closeQuietly(bufferedReader);
+ }
+ closeQuietly(parcelFileDescriptor);
+ }
+ }
+
+ private static void closeQuietly(AutoCloseable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ // Quietly.
+ }
+ }
+ }
}
diff --git a/tests/tests/view/res/layout/default_focus_highlight_layout.xml b/tests/tests/view/res/layout/default_focus_highlight_layout.xml
index 827de43..44a0f68 100644
--- a/tests/tests/view/res/layout/default_focus_highlight_layout.xml
+++ b/tests/tests/view/res/layout/default_focus_highlight_layout.xml
@@ -89,5 +89,16 @@
android:orientation="vertical">
</LinearLayout>
+ <Button
+ android:id="@+id/button_to_test_highlight_needed"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/id_ok"/>
+
+ <ImageView
+ android:id="@+id/image_view_to_test_highlight_needed"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/id_ok"/>
</LinearLayout>
diff --git a/apps/CtsVerifier/res/xml/tapjacking_device_admin.xml b/tests/tests/view/res/layout/include_layout_explicit.xml
similarity index 60%
copy from apps/CtsVerifier/res/xml/tapjacking_device_admin.xml
copy to tests/tests/view/res/layout/include_layout_explicit.xml
index d884663..e13301e 100644
--- a/apps/CtsVerifier/res/xml/tapjacking_device_admin.xml
+++ b/tests/tests/view/res/layout/include_layout_explicit.xml
@@ -5,7 +5,7 @@
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
+ 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,
@@ -14,15 +14,7 @@
limitations under the License.
-->
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <encrypted-storage />
- <wipe-data />
- <reset-password />
- <disable-keyguard-features />
- <force-lock />
- <limit-password />
- </uses-policies>
-</device-admin>
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/include_layout_explicit" />
diff --git a/apps/CtsVerifier/res/xml/tapjacking_device_admin.xml b/tests/tests/view/res/layout/include_layout_from_attr.xml
similarity index 60%
rename from apps/CtsVerifier/res/xml/tapjacking_device_admin.xml
rename to tests/tests/view/res/layout/include_layout_from_attr.xml
index d884663..e0e8fd3 100644
--- a/apps/CtsVerifier/res/xml/tapjacking_device_admin.xml
+++ b/tests/tests/view/res/layout/include_layout_from_attr.xml
@@ -5,7 +5,7 @@
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
+ 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,
@@ -14,15 +14,7 @@
limitations under the License.
-->
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <encrypted-storage />
- <wipe-data />
- <reset-password />
- <disable-keyguard-features />
- <force-lock />
- <limit-password />
- </uses-policies>
-</device-admin>
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/include_layout_from_attr" />
diff --git a/apps/CtsVerifier/res/xml/tapjacking_device_admin.xml b/tests/tests/view/res/layout/inflater_layout_include.xml
similarity index 60%
copy from apps/CtsVerifier/res/xml/tapjacking_device_admin.xml
copy to tests/tests/view/res/layout/inflater_layout_include.xml
index d884663..7423830 100644
--- a/apps/CtsVerifier/res/xml/tapjacking_device_admin.xml
+++ b/tests/tests/view/res/layout/inflater_layout_include.xml
@@ -5,7 +5,7 @@
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
+ 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,
@@ -14,15 +14,12 @@
limitations under the License.
-->
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <encrypted-storage />
- <wipe-data />
- <reset-password />
- <disable-keyguard-features />
- <force-lock />
- <limit-password />
- </uses-policies>
-</device-admin>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <include layout="@layout/include_layout_explicit" />
+
+ <include layout="?attr/includeLayout" />
+
+</LinearLayout>
diff --git a/tests/tests/view/res/layout/view_padding.xml b/tests/tests/view/res/layout/view_padding.xml
index e3b0deb..c0e6e90 100644
--- a/tests/tests/view/res/layout/view_padding.xml
+++ b/tests/tests/view/res/layout/view_padding.xml
@@ -132,10 +132,12 @@
<LinearLayout
android:orientation="horizontal"
android:padding="@dimen/insetAll"
- android:paddingLeft="0dp"
- android:paddingTop="0dp"
- android:paddingRight="0dp"
- android:paddingBottom="0dp"
+ android:paddingHorizontal="@dimen/insetHorizontal"
+ android:paddingVertical="@dimen/insetVertical"
+ android:paddingLeft="@dimen/insetLeft"
+ android:paddingTop="@dimen/insetTop"
+ android:paddingRight="@dimen/insetRight"
+ android:paddingBottom="@dimen/insetBottom"
android:layout_width="match_parent"
android:layout_height="100dp">
<View
@@ -144,5 +146,32 @@
android:id="@+id/view10"/>
</LinearLayout>
+ <LinearLayout
+ android:orientation="horizontal"
+ android:padding="@dimen/insetAll"
+ android:paddingStart="@dimen/insetStart"
+ android:paddingEnd="@dimen/insetEnd"
+ android:layout_width="match_parent"
+ android:layout_height="100dp">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/view11"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/insetHorizontal"
+ android:paddingStart="@dimen/insetStart"
+ android:paddingEnd="@dimen/insetEnd"
+ android:layout_width="match_parent"
+ android:layout_height="100dp">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/view12"/>
+ </LinearLayout>
+
+
</LinearLayout>
diff --git a/tests/tests/view/res/layout/viewgroup_margin_layout_verticalhorizontal.xml b/tests/tests/view/res/layout/viewgroup_margin_layout_verticalhorizontal.xml
index a1c4051..3049623 100644
--- a/tests/tests/view/res/layout/viewgroup_margin_layout_verticalhorizontal.xml
+++ b/tests/tests/view/res/layout/viewgroup_margin_layout_verticalhorizontal.xml
@@ -36,7 +36,7 @@
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="10dp"
+ android:layout_marginHorizontal="@dimen/marginHorizontal"
android:id="@+id/view2"/>
</LinearLayout>
@@ -47,7 +47,7 @@
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginVertical="10dp"
+ android:layout_marginVertical="@dimen/marginVertical"
android:id="@+id/view3"/>
</LinearLayout>
@@ -58,8 +58,8 @@
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="10dp"
- android:layout_marginVertical="10dp"
+ android:layout_marginHorizontal="@dimen/marginHorizontal"
+ android:layout_marginVertical="@dimen/marginVertical"
android:id="@+id/view4"/>
</LinearLayout>
@@ -70,16 +70,15 @@
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="10dp"
- android:layout_marginLeft="5dp"
- android:layout_marginRight="2dp"
- android:layout_marginVertical="10dp"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="2dp"
+ android:layout_marginHorizontal="@dimen/marginHorizontal"
+ android:layout_marginLeft="@dimen/marginLeft"
+ android:layout_marginRight="@dimen/marginRight"
+ android:layout_marginVertical="@dimen/marginVertical"
+ android:layout_marginTop="@dimen/marginTop"
+ android:layout_marginBottom="@dimen/marginBottom"
android:id="@+id/view5"/>
</LinearLayout>
-
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
@@ -87,12 +86,26 @@
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="10dp"
- android:layout_marginStart="5dp"
- android:layout_marginEnd="2dp"
- android:layout_marginVertical="10dp"
+ android:layout_marginHorizontal="@dimen/marginHorizontal"
+ android:layout_marginStart="@dimen/marginStart"
+ android:layout_marginEnd="@dimen/marginEnd"
+ android:layout_marginVertical="@dimen/marginVertical"
android:id="@+id/view6"/>
</LinearLayout>
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="100dp">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/marginAll"
+ android:layout_marginStart="@dimen/marginStart"
+ android:layout_marginEnd="@dimen/marginEnd"
+ android:layout_marginVertical="@dimen/marginVertical"
+ android:id="@+id/view7"/>
+ </LinearLayout>
+
</LinearLayout>
diff --git a/tests/tests/view/res/values/attrs.xml b/tests/tests/view/res/values/attrs.xml
index 4c3d9db..e7181fc 100644
--- a/tests/tests/view/res/values/attrs.xml
+++ b/tests/tests/view/res/values/attrs.xml
@@ -129,7 +129,6 @@
<attr name="themeType" format="integer"/>
<!-- Theme reference used to override parent theme. -->
<attr name="themeOverrideAttr" format="reference"/>
-
<!-- Drawable theming attributes -->
<attr name="themeBoolean" />
<attr name="themeColor" />
@@ -142,4 +141,6 @@
<attr name="themeGravity" />
<attr name="themeTileMode" />
<attr name="themeAngle" />
+ <!-- Used by LayoutInflaterTest to specify layout from ?attr. -->
+ <attr name="includeLayout" format="reference" />
</resources>
diff --git a/tests/tests/view/res/values/dimens.xml b/tests/tests/view/res/values/dimens.xml
index 59369a7..5680de0 100644
--- a/tests/tests/view/res/values/dimens.xml
+++ b/tests/tests/view/res/values/dimens.xml
@@ -24,9 +24,20 @@
<dimen name="insetTop">6dp</dimen>
<dimen name="insetRight">7dp</dimen>
<dimen name="insetBottom">8dp</dimen>
- <dimen name="insetAll">9dp</dimen>
- <dimen name="insetHorizontal">10dp</dimen>
- <dimen name="insetVertical">11dp</dimen>
+ <dimen name="insetStart">9dp</dimen>
+ <dimen name="insetEnd">10dp</dimen>
+ <dimen name="insetAll">11dp</dimen>
+ <dimen name="insetHorizontal">12dp</dimen>
+ <dimen name="insetVertical">13dp</dimen>
+ <dimen name="marginLeft">5dp</dimen>
+ <dimen name="marginTop">6dp</dimen>
+ <dimen name="marginRight">7dp</dimen>
+ <dimen name="marginBottom">8dp</dimen>
+ <dimen name="marginStart">9dp</dimen>
+ <dimen name="marginEnd">10dp</dimen>
+ <dimen name="marginAll">11dp</dimen>
+ <dimen name="marginHorizontal">12dp</dimen>
+ <dimen name="marginVertical">13dp</dimen>
<dimen name="hover_target_margin">4dp</dimen>
<dimen name="hover_target_size">8dp</dimen>
<dimen name="hover_target_size_double">16dp</dimen>
diff --git a/tests/tests/view/res/values/styles.xml b/tests/tests/view/res/values/styles.xml
index 4979241..17bc2a3 100644
--- a/tests/tests/view/res/values/styles.xml
+++ b/tests/tests/view/res/values/styles.xml
@@ -136,6 +136,7 @@
<item name="android:windowNoTitle">true</item>
<item name="android:panelColorForeground">#ff000000</item>
<item name="android:panelColorBackground">#ffffffff</item>
+ <item name="includeLayout">@layout/include_layout_from_attr</item>
</style>
<style name="Theme_OverrideOuter">
diff --git a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
index b445165..3460525 100644
--- a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
@@ -37,6 +37,7 @@
import android.util.AttributeSet;
import android.util.TypedValue;
import android.util.Xml;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.InflateException;
import android.view.LayoutInflater;
@@ -395,6 +396,22 @@
assertEquals(tagId + " has tag " + expectedValue, expectedValue, tag);
}
+ @Test
+ public void testInclude() {
+ final Context themedContext = new ContextThemeWrapper(mContext, R.style.Test_Theme);
+ final LayoutInflater inflater = LayoutInflater.from(themedContext);
+
+ final View container = inflater.inflate(R.layout.inflater_layout_include, null);
+ assertNotNull(container.findViewById(R.id.include_layout_explicit));
+ assertNotNull(container.findViewById(R.id.include_layout_from_attr));
+ }
+
+ @Test(expected = InflateException.class)
+ public void testIncludeMissingAttr() {
+ final View container = mLayoutInflater.inflate(R.layout.inflater_layout_include, null);
+ assertNotNull(container.findViewById(R.id.include_layout_from_attr));
+ }
+
static class MockLayoutInflater extends LayoutInflater {
public MockLayoutInflater(Context c) {
diff --git a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
index 34a6020..0867338 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.res.XmlResourceParser;
+import android.graphics.Rect;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -234,27 +235,32 @@
View view4 = viewGroup.findViewById(R.id.view4);
View view5 = viewGroup.findViewById(R.id.view5);
View view6 = viewGroup.findViewById(R.id.view6);
+ View view7 = viewGroup.findViewById(R.id.view7);
- int defaultWidth = view1.getWidth();
- int defaultHeight = view1.getHeight();
- int marginPixels = (int) (mContext.getResources().getDisplayMetrics().density * 10 + .5f);
+ Rect defaultBounds = new Rect(view1.getLeft(), view1.getTop(), view1.getRight(),
+ view1.getBottom());
+ int marginStart = mContext.getResources().getDimensionPixelSize(R.dimen.marginStart);
+ int marginEnd = mContext.getResources().getDimensionPixelSize(R.dimen.marginEnd);
+ int marginAll = mContext.getResources().getDimensionPixelSize(R.dimen.marginAll);
+ int marginHorizontal =
+ mContext.getResources().getDimensionPixelSize(R.dimen.marginHorizontal);
+ int marginVertical = mContext.getResources().getDimensionPixelSize(R.dimen.marginVertical);
- assertEquals("Width value", defaultWidth, view1.getWidth());
- assertEquals("Height value", defaultHeight, view1.getHeight());
+ checkBounds(view2, defaultBounds, marginHorizontal, 0, marginHorizontal, 0);
+ checkBounds(view3, defaultBounds, 0, marginVertical, 0, marginVertical);
+ checkBounds(view4, defaultBounds, marginHorizontal, marginVertical,
+ marginHorizontal, marginVertical);
+ checkBounds(view5, defaultBounds, marginHorizontal, marginVertical,
+ marginHorizontal, marginVertical);
+ checkBounds(view6, defaultBounds, marginStart, marginVertical, marginEnd, marginVertical);
+ checkBounds(view7, defaultBounds, marginAll, marginAll, marginAll, marginAll);
+ }
- assertEquals("Width value", defaultWidth - 2 * marginPixels, view2.getWidth());
- assertEquals("Height value", defaultHeight, view2.getHeight());
-
- assertEquals("Width value", defaultWidth, view3.getWidth());
- assertEquals("Height value", defaultHeight - 2 * marginPixels, view3.getHeight());
-
- assertEquals("Width value", defaultWidth - 2 * marginPixels, view4.getWidth());
- assertEquals("Height value", defaultHeight - 2 * marginPixels, view4.getHeight());
-
- assertEquals("Width value", defaultWidth - 2 * marginPixels, view5.getWidth());
- assertEquals("Height value", defaultHeight - 2 * marginPixels, view5.getHeight());
-
- assertEquals("Width value", defaultWidth - 2 * marginPixels, view6.getWidth());
- assertEquals("Height value", defaultHeight - 2 * marginPixels, view6.getHeight());
+ private void checkBounds(View view, Rect defaultBounds,
+ int insetLeft, int insetTop, int insetRight, int insetBottom) {
+ assertEquals("Left", defaultBounds.left + insetLeft, view.getLeft());
+ assertEquals("Top", defaultBounds.top + insetTop, view.getTop());
+ assertEquals("Right", defaultBounds.right - insetRight, view.getRight());
+ assertEquals("Bottom", defaultBounds.bottom - insetBottom, view.getBottom());
}
}
diff --git a/tests/tests/view/src/android/view/cts/ViewPaddingTest.java b/tests/tests/view/src/android/view/cts/ViewPaddingTest.java
index b146f9d..60fa170 100644
--- a/tests/tests/view/src/android/view/cts/ViewPaddingTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewPaddingTest.java
@@ -61,6 +61,8 @@
View view8 = viewGroup.findViewById(R.id.view8);
View view9 = viewGroup.findViewById(R.id.view9);
View view10 = viewGroup.findViewById(R.id.view10);
+ View view11 = viewGroup.findViewById(R.id.view11);
+ View view12 = viewGroup.findViewById(R.id.view12);
Rect defaultBounds = new Rect(view1.getLeft(), view1.getTop(), view1.getRight(),
view1.getBottom());
@@ -68,6 +70,8 @@
int insetRight = mContext.getResources().getDimensionPixelSize(R.dimen.insetRight);
int insetTop = mContext.getResources().getDimensionPixelSize(R.dimen.insetTop);
int insetBottom = mContext.getResources().getDimensionPixelSize(R.dimen.insetBottom);
+ int insetStart = mContext.getResources().getDimensionPixelSize(R.dimen.insetStart);
+ int insetEnd = mContext.getResources().getDimensionPixelSize(R.dimen.insetEnd);
int insetAll = mContext.getResources().getDimensionPixelSize(R.dimen.insetAll);
int insetHorizontal =
mContext.getResources().getDimensionPixelSize(R.dimen.insetHorizontal);
@@ -84,6 +88,8 @@
checkBounds(view9, defaultBounds, insetHorizontal, insetVertical, insetHorizontal,
insetVertical);
checkBounds(view10, defaultBounds, insetAll, insetAll, insetAll, insetAll);
+ checkBounds(view11, defaultBounds, insetStart, insetAll, insetEnd, insetAll);
+ checkBounds(view12, defaultBounds, insetStart, 0, insetEnd, 0);
}
private void checkBounds(View view, Rect defaultBounds,
diff --git a/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java b/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java
index 5e362cf..b019fb1 100644
--- a/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java
+++ b/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java
@@ -20,6 +20,11 @@
import static org.junit.Assert.assertTrue;
import android.app.Activity;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
@@ -27,6 +32,7 @@
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
@@ -90,4 +96,59 @@
assertFalse(button.getDefaultFocusHighlightEnabled());
assertFalse(linearLayout.getDefaultFocusHighlightEnabled());
}
+
+ @UiThreadTest
+ @Test
+ public void testIsDefaultFocusHighlightNeeded() {
+ Activity activity = mActivityRule.getActivity();
+ final Button button = (Button) activity.findViewById(R.id.button_to_test_highlight_needed);
+ final ImageView imageView =
+ (ImageView) activity.findViewById(R.id.image_view_to_test_highlight_needed);
+
+ final Drawable[] drawables = new Drawable[] {
+ null, // null
+ new ColorDrawable(Color.WHITE), // not stateful
+ new RippleDrawable(ColorStateList.valueOf(Color.WHITE), null, null) // stateful
+ };
+ final boolean[] lackFocusState = new boolean[]{
+ true, // for null
+ true, // for not stateful
+ false, // for stateful
+ };
+
+ boolean isNeeded, expected;
+
+ // View
+ for (int i = 0; i < drawables.length; i++) {
+ for (int j = 0; j < drawables.length; j++) {
+ // Turn on default focus highlight.
+ button.setDefaultFocusHighlightEnabled(true);
+ isNeeded = button.isDefaultFocusHighlightNeeded(drawables[i], drawables[j]);
+ expected = lackFocusState[i] && lackFocusState[j];
+ assertTrue(isNeeded == expected);
+ // Turn off default focus highlight.
+ button.setDefaultFocusHighlightEnabled(false);
+ isNeeded = button.isDefaultFocusHighlightNeeded(drawables[i], drawables[j]);
+ assertFalse(isNeeded);
+ }
+ }
+
+ // ImageView
+ for (int k = 0; k < drawables.length; k++) {
+ imageView.setImageDrawable(drawables[k]);
+ for (int i = 0; i < drawables.length; i++) {
+ for (int j = 0; j < drawables.length; j++) {
+ // Turn on default focus highlight.
+ imageView.setDefaultFocusHighlightEnabled(true);
+ isNeeded = imageView.isDefaultFocusHighlightNeeded(drawables[i], drawables[j]);
+ expected = lackFocusState[i] && lackFocusState[j] && lackFocusState[k];
+ assertTrue(isNeeded == expected);
+ // Turn off default focus highlight.
+ imageView.setDefaultFocusHighlightEnabled(false);
+ isNeeded = imageView.isDefaultFocusHighlightNeeded(drawables[i], drawables[j]);
+ assertFalse(isNeeded);
+ }
+ }
+ }
+ }
}
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
index 94a9923..cc86808 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -36,6 +36,7 @@
import android.content.Context;
import android.os.Parcelable;
import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
@@ -290,6 +291,9 @@
ViewGroup.LayoutParams.MATCH_PARENT)), true);
mActivityRule.runOnUiThread(() -> setArrayAdapter(mAdapterView));
+ // Wait for the UI to "settle down" since selection is fired asynchronously
+ // on the next layout pass, and we don't want to trigger the listener too early
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
AdapterView.OnItemSelectedListener mockSelectedListener =
mock(AdapterView.OnItemSelectedListener.class);
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarDrawableContainerTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarDrawableContainerTest.java
new file mode 100644
index 0000000..2acf8ecd
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarDrawableContainerTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.graphics.drawable.DrawableContainer;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.widget.ProgressBar;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ProgressBarDrawableContainerTest {
+ private Activity mActivity;
+
+ @Rule
+ public ActivityTestRule<RadioGroupCtsActivity> mActivityRule =
+ new ActivityTestRule<>(RadioGroupCtsActivity.class);
+
+ @Before
+ public void setup() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @UiThreadTest
+ @Test
+ public void testMutate() {
+ DrawableContainer d = (DrawableContainer) new ProgressBar(
+ mActivity).getIndeterminateDrawable().mutate();
+
+ boolean mirrored = d.isAutoMirrored();
+ d.setAutoMirrored(!mirrored);
+
+ ProgressBar newBar = new ProgressBar(mActivity);
+ DrawableContainer d2 = (DrawableContainer) newBar.getIndeterminateDrawable();
+ boolean newMirrored = d2.isAutoMirrored();
+ assertEquals(newMirrored, mirrored);
+ }
+
+}