/* * 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.settings; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.support.test.filters.MediumTest; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import android.support.test.runner.lifecycle.Stage; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiSelector; import android.text.format.DateUtils; import android.view.KeyEvent; import com.android.settings.R; import java.util.Collection; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import static android.support.test.InstrumentationRegistry.getInstrumentation; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertTrue; /** * Tests for {@link ChooseLockGenericTest} * * m SettingsTests && * adb install \ * -r -g ${ANDROID_PRODUCT_OUT}/data/app/SettingsTests/SettingsTests.apk && * adb shell am instrument -e class com.android.settings.ChooseLockGenericTest \ * -w com.android.settings.tests/android.support.test.runner.AndroidJUnitRunner */ @RunWith(AndroidJUnit4.class) @MediumTest public class ChooseLockGenericTest { private static final long TIMEOUT = 5 * DateUtils.SECOND_IN_MILLIS; private static final Intent PHISHING_ATTACK_INTENT = new Intent() .putExtra("confirm_credentials", false) .putExtra("password_confirmed", true); private UiDevice mDevice; private Context mTargetContext; private String mSettingPackage; private PackageManager mPackageManager; @Rule public ActivityTestRule mChooseLockGenericActivityRule = new ActivityTestRule<>( ChooseLockGeneric.class, true /* enable touch at launch */, false /* don't launch at every test */); @Before public void setUp() throws Exception { mDevice = UiDevice.getInstance(getInstrumentation()); mTargetContext = getInstrumentation().getTargetContext(); mSettingPackage = mTargetContext.getPackageName(); mPackageManager = mTargetContext.getPackageManager(); setPassword(); } @After public void tearDown() throws Exception { clearPassword(); } @Test public void testConfirmLockPasswordShown_deviceWithPassword() throws Exception, Throwable { // GIVEN a PIN password is set on this device at set up. // WHEN ChooseLockGeneric is launched with no extras. mChooseLockGenericActivityRule.launchActivity(null /* No extras */); // THEN ConfirmLockPassword.InternalActivity is shown. assertThat(getCurrentActivity()).isInstanceOf(ConfirmLockPassword.InternalActivity.class); } @Test public void testConfirmLockPasswordShown_deviceWithPassword_phishingAttack() throws Exception, Throwable { // GIVEN a PIN password is set on this device at set up. // WHEN ChooseLockGeneric is launched with extras to by-pass lock password confirmation. mChooseLockGenericActivityRule.launchActivity(PHISHING_ATTACK_INTENT); // THEN ConfirmLockPassword.InternalActivity is still shown. assertThat(getCurrentActivity()).isInstanceOf(ConfirmLockPassword.InternalActivity.class); } private Activity getCurrentActivity() throws Throwable { getInstrumentation().waitForIdleSync(); final Activity[] activity = new Activity[1]; getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { Collection activities = ActivityLifecycleMonitorRegistry.getInstance() .getActivitiesInStage(Stage.RESUMED); activity[0] = activities.iterator().next(); } }); return activity[0]; } private void launchNewPassword() throws Exception { Intent newPasswordIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD) .setPackage(mSettingPackage) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getInstrumentation().getContext().startActivity(newPasswordIntent); mDevice.waitForIdle(); } /** Sets a PIN password, 12345, for testing. */ private void setPassword() throws Exception { launchNewPassword(); if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { // Set "lock_none", but it actually means we don't want to enroll a fingerprint. UiObject view = new UiObject( new UiSelector().resourceId(mSettingPackage + ":id/lock_none")); assertTrue("lock_none", view.waitForExists(TIMEOUT)); view.click(); mDevice.waitForIdle(); } // Pick PIN from the option list UiObject view = new UiObject(new UiSelector() .resourceId(mSettingPackage + ":id/lock_pin")); assertTrue("lock_pin", view.waitForExists(TIMEOUT)); view.click(); mDevice.waitForIdle(); // Ignore any interstitial options view = new UiObject(new UiSelector() .resourceId(mSettingPackage + ":id/encrypt_dont_require_password")); if (view.waitForExists(TIMEOUT)) { view.click(); mDevice.waitForIdle(); } // Yes, we really want to view = new UiObject(new UiSelector() .resourceId(mSettingPackage + ":id/next_button")); if (view.waitForExists(TIMEOUT)) { view.click(); mDevice.waitForIdle(); } // Set our PIN view = new UiObject(new UiSelector() .resourceId(mSettingPackage + ":id/password_entry")); assertTrue("password_entry", view.waitForExists(TIMEOUT)); // Enter it twice to confirm enterTestPin(); enterTestPin(); mDevice.pressBack(); } /** Clears the previous set PIN password. */ private void clearPassword() throws Exception { launchNewPassword(); // Enter current PIN UiObject view = new UiObject( new UiSelector().resourceId(mSettingPackage + ":id/password_entry")); if (!view.waitForExists(TIMEOUT)) { // Odd, maybe there is a crash dialog showing; try dismissing it mDevice.pressBack(); mDevice.waitForIdle(); assertTrue("password_entry", view.waitForExists(TIMEOUT)); } enterTestPin(); // Set back to "none" view = new UiObject(new UiSelector().resourceId(mSettingPackage + ":id/lock_none")); assertTrue("lock_none", view.waitForExists(TIMEOUT)); view.click(); mDevice.waitForIdle(); // Yes, we really want "none" if prompted again view = new UiObject(new UiSelector().resourceId(mSettingPackage + ":id/lock_none")); if (view.waitForExists(TIMEOUT)) { view.click(); mDevice.waitForIdle(); } // Yes, we really want to view = new UiObject(new UiSelector() .resourceId("android:id/button1")); if (view.waitForExists(TIMEOUT)) { view.click(); mDevice.waitForIdle(); } mDevice.pressBack(); } private void enterTestPin() throws Exception { mDevice.waitForIdle(); mDevice.pressKeyCode(KeyEvent.KEYCODE_1); mDevice.pressKeyCode(KeyEvent.KEYCODE_2); mDevice.pressKeyCode(KeyEvent.KEYCODE_3); mDevice.pressKeyCode(KeyEvent.KEYCODE_4); mDevice.pressKeyCode(KeyEvent.KEYCODE_5); mDevice.waitForIdle(); mDevice.pressEnter(); mDevice.waitForIdle(); } }