| /* |
| * 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.password; |
| |
| import static androidx.test.InstrumentationRegistry.getInstrumentation; |
| import static androidx.test.InstrumentationRegistry.getTargetContext; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assert.assertTrue; |
| |
| import android.app.Activity; |
| import android.app.ActivityManager; |
| import android.app.ActivityManager.AppTask; |
| import android.app.KeyguardManager; |
| import android.app.admin.DevicePolicyManager; |
| import android.content.Context; |
| import android.content.Intent; |
| 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.WindowManager; |
| |
| import androidx.test.filters.MediumTest; |
| import androidx.test.rule.ActivityTestRule; |
| import androidx.test.runner.AndroidJUnit4; |
| import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; |
| import androidx.test.runner.lifecycle.Stage; |
| |
| import com.android.internal.widget.LockPatternUtils; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.util.Collection; |
| import java.util.List; |
| |
| /** |
| * 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.password.ChooseLockGenericTest \ |
| * -w com.android.settings.tests/androidx.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; |
| |
| @Rule |
| public ActivityTestRule<ChooseLockGeneric> 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(); |
| } |
| |
| @Test |
| public void testConfirmLockPasswordShown_deviceWithPassword() throws Throwable { |
| setPassword(); |
| try { |
| // 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. |
| final Activity activity = getCurrentActivity(); |
| assertThat(isSecureWindow(activity)).isTrue(); |
| assertThat(activity) |
| .isInstanceOf(ConfirmLockPassword.InternalActivity.class); |
| } finally { |
| finishAllAppTasks(); |
| mDevice.waitForIdle(); |
| clearPassword(); |
| } |
| } |
| |
| @Test |
| public void testConfirmLockPasswordShown_deviceWithPassword_phishingAttack() throws Throwable { |
| setPassword(); |
| try { |
| // 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. |
| final Activity activity = getCurrentActivity(); |
| assertThat(isSecureWindow(activity)).isTrue(); |
| assertThat(activity) |
| .isInstanceOf(ConfirmLockPassword.InternalActivity.class); |
| } finally { |
| finishAllAppTasks(); |
| mDevice.waitForIdle(); |
| clearPassword(); |
| } |
| } |
| |
| @Test |
| public void testForFingerprint_inflateLayout() { |
| mChooseLockGenericActivityRule.launchActivity(new Intent() |
| .putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true)); |
| |
| assertThat(mChooseLockGenericActivityRule.getActivity().isResumed()).isTrue(); |
| } |
| |
| private Activity getCurrentActivity() throws Throwable { |
| getInstrumentation().waitForIdleSync(); |
| final Activity[] activity = new Activity[1]; |
| getInstrumentation().runOnMainSync(() -> { |
| Collection<Activity> activities = ActivityLifecycleMonitorRegistry.getInstance() |
| .getActivitiesInStage(Stage.RESUMED); |
| activity[0] = activities.iterator().next(); |
| }); |
| return activity[0]; |
| } |
| |
| /** Sets a PIN password, 12345, for testing. */ |
| private void setPassword() throws Exception { |
| Intent newPasswordIntent = new Intent(getTargetContext(), ChooseLockGeneric.class) |
| .putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, |
| DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) |
| .putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, |
| "12345") |
| .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| getInstrumentation().getContext().startActivity(newPasswordIntent); |
| mDevice.waitForIdle(); |
| |
| |
| // Ignore any interstitial options |
| UiObject view = new UiObject(new UiSelector() |
| .resourceId(mSettingPackage + ":id/encrypt_dont_require_password")); |
| 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(view); |
| enterTestPin(view); |
| |
| // Dismiss notifications setting |
| view = new UiObject(new UiSelector() |
| .resourceId(mSettingPackage + ":id/redaction_done_button")); |
| if (view.waitForExists(TIMEOUT)) { |
| view.click(); |
| mDevice.waitForIdle(); |
| } |
| |
| mDevice.pressBack(); |
| |
| assertThat(getTargetContext().getSystemService(KeyguardManager.class).isDeviceSecure()) |
| .isTrue(); |
| } |
| |
| /** Clears the previous set PIN password. */ |
| private void clearPassword() throws Exception { |
| Intent newPasswordIntent = new Intent(getTargetContext(), ChooseLockGeneric.class) |
| .putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, |
| DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) |
| .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
| | Intent.FLAG_ACTIVITY_CLEAR_TASK); |
| getInstrumentation().getContext().startActivity(newPasswordIntent); |
| mDevice.waitForIdle(); |
| |
| // 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(view); |
| |
| mDevice.pressBack(); |
| |
| assertThat(getTargetContext().getSystemService(KeyguardManager.class).isDeviceSecure()) |
| .isFalse(); |
| } |
| |
| private void finishAllAppTasks() { |
| final ActivityManager activityManager = |
| getTargetContext().getSystemService(ActivityManager.class); |
| final List<AppTask> appTasks = activityManager.getAppTasks(); |
| for (ActivityManager.AppTask task : appTasks) { |
| task.finishAndRemoveTask(); |
| } |
| } |
| |
| private void enterTestPin(UiObject view) throws Exception { |
| mDevice.waitForIdle(); |
| view.setText("12345"); |
| mDevice.pressEnter(); |
| mDevice.waitForIdle(); |
| } |
| |
| private boolean isSecureWindow(Activity activity) { |
| return (activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_SECURE) |
| != 0; |
| } |
| } |