blob: e69e98fd95e9e917ea3990b09f3314b792e1e557 [file] [log] [blame]
/*
* 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.preference.cts;
import static org.junit.Assert.assertNotNull;
import android.app.Activity;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.app.UiModeManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.DisplayMetrics;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
/**
* Collection of helper utils for testing preferences.
*/
public class TestUtils {
public final UiDevice mDevice;
private final Context mContext;
private final Instrumentation mInstrumentation;
private final String mPackageName;
private final UiAutomation mAutomation;
private int mStatusBarHeight = -1;
private int mNavigationBarHeight = -1;
private ActivityTestRule<?> mRule;
TestUtils(ActivityTestRule<?> rule) {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mContext = mInstrumentation.getTargetContext();
mPackageName = mContext.getPackageName();
mDevice = UiDevice.getInstance(mInstrumentation);
mAutomation = mInstrumentation.getUiAutomation();
mRule = rule;
}
void waitForIdle() {
mDevice.waitForIdle(1000);
}
Bitmap takeScreenshot() {
// Only take a screenshot once the screen is stable enough.
waitForIdle();
Bitmap bt = mAutomation.takeScreenshot();
assertNotNull("Screenshot must not return null", bt);
// Crop-out the status bar to avoid flakiness with changing notifications / time.
int statusBarHeight = getStatusBarHeight();
// Crop-out the navigation bar to avoid flakiness with button animations.
int navigationBarHeight = getNavigationBarHeight();
// Crop-out the right side for the scrollbar which may or may not be visible.
// On wearable devices the scroll bar is a curve and occupies 20% of the right side.
int xToCut = isOnWatchUiMode() ? bt.getWidth() / 5 : bt.getWidth() / 20;
int yToCut = statusBarHeight;
if (hasVerticalNavBar()) {
xToCut += navigationBarHeight;
} else {
yToCut += navigationBarHeight;
}
bt = Bitmap.createBitmap(
bt, 0, statusBarHeight, bt.getWidth() - xToCut, bt.getHeight() - yToCut);
return bt;
}
void tapOnViewWithText(String text) {
UiObject2 object2 = getTextObject(text);
if (object2 != null) {
object2.click();
} else {
scrollToAndGetTextObject(text);
getTextObject(text).click();
}
waitForIdle();
}
boolean isTextShown(String text) {
if (getTextObject(text) != null) {
return true;
}
return scrollToAndGetTextObject(text);
}
boolean isTextHidden(String text) {
return getTextObject(text) == null;
}
boolean isTextFocused(String text) {
UiObject2 object = getTextObject(text);
return object != null && object.isFocused();
}
boolean isOnWatchUiMode() {
UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_WATCH;
}
private int getStatusBarHeight() {
// Cache the result to keep it fast.
if (mStatusBarHeight >= 0) {
return mStatusBarHeight;
}
int resourceId = mInstrumentation.getTargetContext().getResources()
.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
mStatusBarHeight = mInstrumentation.getTargetContext().getResources()
.getDimensionPixelSize(resourceId);
} else {
mStatusBarHeight = 0;
}
return mStatusBarHeight;
}
private int getNavigationBarHeight() {
// Cache the result to keep it fast.
if (mNavigationBarHeight >= 0) {
return mNavigationBarHeight;
}
int resourceId = mInstrumentation.getTargetContext().getResources()
.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
mNavigationBarHeight = mInstrumentation.getTargetContext().getResources()
.getDimensionPixelSize(resourceId);
} else {
mNavigationBarHeight = 0;
}
return mNavigationBarHeight;
}
private boolean hasVerticalNavBar() {
Rect displayFrame = new Rect();
final Activity activity = mRule.getActivity();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(displayFrame);
DisplayMetrics dm = new DisplayMetrics();
activity.getDisplay().getRealMetrics(dm);
return dm.heightPixels == displayFrame.bottom;
}
private UiObject2 getTextObject(String text) {
// Wait for up to 1 second to find the object. Returns null if the object cannot be found.
return mDevice.wait(Until.findObject(By.text(text).pkg(mPackageName)), 1000);
}
private boolean scrollToAndGetTextObject(String text) {
UiScrollable scroller = new UiScrollable(new UiSelector().scrollable(true));
try {
// Swipe far away from the edges to avoid triggering navigation gestures
scroller.setSwipeDeadZonePercentage(0.25);
return scroller.scrollTextIntoView(text);
} catch (UiObjectNotFoundException e) {
throw new AssertionError("View with text '" + text + "' was not found!", e);
}
}
}