Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.preference.cts;
     18 
     19 import android.app.Instrumentation;
     20 import android.app.UiAutomation;
     21 import android.app.UiModeManager;
     22 import android.content.Context;
     23 import android.content.res.Configuration;
     24 import android.graphics.Bitmap;
     25 import android.support.test.uiautomator.By;
     26 import android.support.test.uiautomator.UiDevice;
     27 import android.support.test.uiautomator.UiObject2;
     28 import android.support.test.uiautomator.UiObjectNotFoundException;
     29 import android.support.test.uiautomator.UiScrollable;
     30 import android.support.test.uiautomator.UiSelector;
     31 import android.support.test.uiautomator.Until;
     32 
     33 import androidx.test.platform.app.InstrumentationRegistry;
     34 
     35 /**
     36  * Collection of helper utils for testing preferences.
     37  */
     38 public class TestUtils {
     39 
     40     public final UiDevice mDevice;
     41 
     42     private final Context mContext;
     43     private final Instrumentation mInstrumentation;
     44     private final String mPackageName;
     45     private final UiAutomation mAutomation;
     46     private int mStatusBarHeight = -1;
     47     private int mNavigationBarHeight = -1;
     48 
     49     TestUtils() {
     50         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     51         mContext = mInstrumentation.getTargetContext();
     52         mPackageName = mContext.getPackageName();
     53         mDevice = UiDevice.getInstance(mInstrumentation);
     54         mAutomation = mInstrumentation.getUiAutomation();
     55     }
     56 
     57     void waitForIdle() {
     58         mDevice.waitForIdle(1000);
     59     }
     60 
     61     Bitmap takeScreenshot() {
     62         // Only take a screenshot once the screen is stable enough.
     63         waitForIdle();
     64 
     65         Bitmap bt = mAutomation.takeScreenshot();
     66 
     67         // Crop-out the status bar to avoid flakiness with changing notifications / time.
     68         int statusBarHeight = getStatusBarHeight();
     69 
     70         // Crop-out the navigation bar to avoid flakiness with button animations.
     71         int navigationBarHeight = getNavigationBarHeight();
     72 
     73         // Crop-out the right side for the scrollbar which may or may not be visible.
     74         // On wearable devices the scroll bar is a curve and occupies 20% of the right side.
     75         int xToCut = isOnWatchUiMode() ? bt.getWidth() / 5 : bt.getWidth() / 20;
     76         int yToCut = statusBarHeight;
     77 
     78         if (isLandscape()) {
     79             xToCut += navigationBarHeight;
     80         } else {
     81             yToCut += navigationBarHeight;
     82         }
     83 
     84         bt = Bitmap.createBitmap(
     85             bt, 0, statusBarHeight, bt.getWidth() - xToCut, bt.getHeight() - yToCut);
     86 
     87         return bt;
     88     }
     89 
     90     void tapOnViewWithText(String text) {
     91         UiObject2 object2 = getTextObject(text);
     92         if (object2 != null) {
     93             object2.click();
     94         } else {
     95             scrollToAndGetTextObject(text);
     96             getTextObject(text).click();
     97         }
     98         waitForIdle();
     99     }
    100 
    101     boolean isTextShown(String text) {
    102         if (getTextObject(text) != null) {
    103             return true;
    104         }
    105 
    106         return scrollToAndGetTextObject(text);
    107     }
    108 
    109     boolean isTextHidden(String text) {
    110         return getTextObject(text) == null;
    111     }
    112 
    113     boolean isTextFocused(String text) {
    114         UiObject2 object = getTextObject(text);
    115         return object != null && object.isFocused();
    116     }
    117 
    118     boolean isOnWatchUiMode() {
    119         UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
    120         return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_WATCH;
    121     }
    122 
    123     private int getStatusBarHeight() {
    124         // Cache the result to keep it fast.
    125         if (mStatusBarHeight >= 0) {
    126             return mStatusBarHeight;
    127         }
    128 
    129         int resourceId = mInstrumentation.getTargetContext().getResources()
    130                 .getIdentifier("status_bar_height", "dimen", "android");
    131         if (resourceId > 0) {
    132             mStatusBarHeight = mInstrumentation.getTargetContext().getResources()
    133                     .getDimensionPixelSize(resourceId);
    134         } else {
    135             mStatusBarHeight = 0;
    136         }
    137         return mStatusBarHeight;
    138     }
    139 
    140     private int getNavigationBarHeight() {
    141         // Cache the result to keep it fast.
    142         if (mNavigationBarHeight >= 0) {
    143             return mNavigationBarHeight;
    144         }
    145 
    146         int resourceId = mInstrumentation.getTargetContext().getResources()
    147                 .getIdentifier("navigation_bar_height", "dimen", "android");
    148         if (resourceId > 0) {
    149             mNavigationBarHeight = mInstrumentation.getTargetContext().getResources()
    150                     .getDimensionPixelSize(resourceId);
    151         } else {
    152             mNavigationBarHeight = 0;
    153         }
    154         return mNavigationBarHeight;
    155     }
    156 
    157     private boolean isLandscape() {
    158         return mInstrumentation.getTargetContext().getResources().getConfiguration().orientation
    159             == Configuration.ORIENTATION_LANDSCAPE;
    160     }
    161 
    162     private UiObject2 getTextObject(String text) {
    163         // Wait for up to 1 second to find the object. Returns null if the object cannot be found.
    164         return mDevice.wait(Until.findObject(By.text(text).pkg(mPackageName)), 1000);
    165     }
    166 
    167     private boolean scrollToAndGetTextObject(String text) {
    168         UiScrollable scroller = new UiScrollable(new UiSelector().scrollable(true));
    169         try {
    170             // Swipe far away from the edges to avoid triggering navigation gestures
    171             scroller.setSwipeDeadZonePercentage(0.25);
    172             return scroller.scrollTextIntoView(text);
    173         } catch (UiObjectNotFoundException e) {
    174             throw new AssertionError("View with text '" + text + "' was not found!", e);
    175         }
    176     }
    177 }
    178