Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2018 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 com.android.settings.ui;
     18 
     19 import android.content.Intent;
     20 import android.os.SystemClock;
     21 import android.os.storage.DiskInfo;
     22 import android.os.storage.VolumeInfo;
     23 import android.support.test.InstrumentationRegistry;
     24 import android.support.test.runner.AndroidJUnit4;
     25 import android.support.test.uiautomator.By;
     26 import android.support.test.uiautomator.BySelector;
     27 import android.support.test.uiautomator.UiDevice;
     28 import android.support.test.uiautomator.UiObject2;
     29 import android.support.test.uiautomator.UiObjectNotFoundException;
     30 import android.support.test.uiautomator.Until;
     31 
     32 import org.junit.After;
     33 import org.junit.Before;
     34 import org.junit.Test;
     35 import org.junit.runner.RunWith;
     36 
     37 import java.io.IOException;
     38 import java.util.regex.Pattern;
     39 
     40 /**
     41  * Verify storage wizard flows. Temporarily enables a virtual disk which enables
     42  * testing on all devices, regardless of physical SD card support.
     43  */
     44 @RunWith(AndroidJUnit4.class)
     45 public class StorageWizardTest {
     46     private static final String ANDROID_PACKAGE = "android";
     47     private static final String PACKAGE = "com.android.settings";
     48     private static final int TIMEOUT = 5000;
     49     private static final int TIMEOUT_LONG = 30000;
     50 
     51     private UiDevice mDevice;
     52 
     53     private String mDisk;
     54     private String mVolume;
     55 
     56     @Before
     57     public void setUp() throws Exception {
     58         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
     59         mDevice.executeShellCommand("setprop sys.debug.storage_slow 1");
     60         mDevice.executeShellCommand("sm set-virtual-disk true");
     61 
     62         mDisk = getAdoptableDisk();
     63         mDevice.executeShellCommand("sm partition " + mDisk + " public");
     64         mVolume = getPublicVolume();
     65     }
     66 
     67     @After
     68     public void tearDown() throws Exception {
     69         // Go back to home for next test.
     70         mDevice.pressBack();
     71         mDevice.pressBack();
     72         mDevice.pressHome();
     73         mDevice.waitForIdle(TIMEOUT);
     74 
     75         mDevice.executeShellCommand("setprop sys.debug.storage_slow 0");
     76         mDevice.executeShellCommand("sm set-virtual-disk false");
     77         mDevice.executeShellCommand("sm forget all");
     78     }
     79 
     80     /**
     81      * Test flow for adopting a storage device as internal/adopted.
     82      */
     83     @Test
     84     public void testInternal() throws Exception {
     85         InstrumentationRegistry.getContext().startActivity(buildInitIntent());
     86 
     87         // Activity: pick option to use as internal
     88         waitFor(By.res(PACKAGE, "suw_layout_title").text(containsIgnoringCase("How will you use")));
     89         waitFor(By.res(PACKAGE, "storage_wizard_init_internal")).click();
     90 
     91         // Dialog: acknowledge that we're formatting the card
     92         waitFor(By.res(ANDROID_PACKAGE, "alertTitle").textContains("Format"));
     93         waitFor(By.clickable(true).text(containsIgnoringCase("Format"))).click();
     94 
     95         // Activity: ack storage device is slow
     96         waitForLong(By.res(PACKAGE, "suw_layout_title").textContains("Slow"));
     97         waitFor(By.res(PACKAGE, "storage_next_button")).click();
     98 
     99         // Activity: choose to move content
    100         waitForLong(By.res(PACKAGE, "suw_layout_title").textContains("Move content"));
    101         waitFor(By.res(PACKAGE, "storage_next_button")).click();
    102 
    103         // Activity: yay, we're done!
    104         waitForLong(By.res(PACKAGE, "suw_layout_title").textContains("ready to use"));
    105         waitFor(By.res(PACKAGE, "storage_next_button")).click();
    106     }
    107 
    108     /**
    109      * Test flow for adopting a storage device as external/portable.
    110      */
    111     @Test
    112     public void testExternal() throws Exception {
    113         InstrumentationRegistry.getContext().startActivity(buildInitIntent());
    114 
    115         // Activity: pick option to use as external
    116         waitFor(By.res(PACKAGE, "suw_layout_title").textContains("How will you use"));
    117         waitFor(By.res(PACKAGE, "storage_wizard_init_external")).click();
    118 
    119         // Activity: yay, we're done!
    120         waitFor(By.res(PACKAGE, "suw_layout_title").textContains("ready to use"));
    121         waitFor(By.res(PACKAGE, "storage_next_button")).click();
    122     }
    123 
    124     private UiObject2 waitFor(BySelector selector) throws UiObjectNotFoundException {
    125         return waitFor(selector, TIMEOUT);
    126     }
    127 
    128     private UiObject2 waitForLong(BySelector selector) throws UiObjectNotFoundException {
    129         return waitFor(selector, TIMEOUT_LONG);
    130     }
    131 
    132     private UiObject2 waitFor(BySelector selector, long timeout) throws UiObjectNotFoundException {
    133         final UiObject2 item = mDevice.wait(Until.findObject(selector), timeout);
    134         if (item != null) {
    135             return item;
    136         } else {
    137             throw new UiObjectNotFoundException(selector.toString());
    138         }
    139     }
    140 
    141     /**
    142      * Shamelessly borrowed from AdoptableHostTest in CTS.
    143      */
    144     private String getAdoptableDisk() throws IOException {
    145         // In the case where we run multiple test we cleanup the state of the device. This
    146         // results in the execution of sm forget all which causes the MountService to "reset"
    147         // all its knowledge about available drives. This can cause the adoptable drive to
    148         // become temporarily unavailable.
    149         int attempt = 0;
    150         String disks = mDevice.executeShellCommand("sm list-disks adoptable");
    151         while ((disks == null || disks.isEmpty()) && attempt++ < 15) {
    152             SystemClock.sleep(1000);
    153             disks = mDevice.executeShellCommand("sm list-disks adoptable");
    154         }
    155 
    156         if (disks == null || disks.isEmpty()) {
    157             throw new AssertionError("Devices that claim to support adoptable storage must have "
    158                     + "adoptable media inserted during CTS to verify correct behavior");
    159         }
    160         return disks.split("\n")[0].trim();
    161     }
    162 
    163     private String getPublicVolume() throws IOException {
    164         int attempt = 0;
    165         String volumes = mDevice.executeShellCommand("sm list-volumes public");
    166         while ((volumes == null || volumes.isEmpty() || !volumes.contains("mounted"))
    167                 && attempt++ < 15) {
    168             SystemClock.sleep(1000);
    169             volumes = mDevice.executeShellCommand("sm list-volumes public");
    170         }
    171 
    172         if (volumes == null || volumes.isEmpty()) {
    173             throw new AssertionError("Devices that claim to support adoptable storage must have "
    174                     + "adoptable media inserted during CTS to verify correct behavior");
    175         }
    176         return volumes.split("[\n ]")[0].trim();
    177     }
    178 
    179     private Intent buildInitIntent() {
    180         final Intent intent = new Intent().setClassName(PACKAGE,
    181                 PACKAGE + ".deviceinfo.StorageWizardInit");
    182         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    183         intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk);
    184         intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume);
    185         return intent;
    186     }
    187 
    188     private Pattern containsIgnoringCase(String text) {
    189         return Pattern.compile("(?i)^.*" + text + ".*$");
    190     }
    191 }
    192