1 /*
2  * Copyright (C) 2024 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.development.test;
18 
19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
20 
21 import static org.junit.Assert.assertTrue;
22 
23 import android.content.Context;
24 import android.os.RemoteException;
25 import android.provider.Settings;
26 import android.system.helpers.SettingsHelper;
27 
28 import androidx.test.runner.AndroidJUnit4;
29 import androidx.test.uiautomator.By;
30 import androidx.test.uiautomator.BySelector;
31 import androidx.test.uiautomator.Direction;
32 import androidx.test.uiautomator.UiDevice;
33 import androidx.test.uiautomator.UiObject2;
34 import androidx.test.uiautomator.Until;
35 
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 
40 @RunWith(AndroidJUnit4.class)
41 public class Enable16KbDeviceTest {
42     private static final long TIMEOUT = 2000;
43 
44     private static final String ENABLE_16K_TOGGLE = "Boot with 16KB page size";
45     private static final String BUILD_NUMBER = "Build number";
46     private static final String USE_DEVELOPER_OPTIONS = "Use developer options";
47     private static final String EXT4_CONFIRMATION = "Erase all data";
48     private static final String EXT4_TITLE = "Reformat device to ext4? (required for 16KB mode)";
49     private static final String TOGGLE_16K_TITLE = "Switch from 4KB mode to 16KB mode";
50     private static final String TOGGLE_4K_TITLE = "Switch from 16KB mode to 4KB mode";
51     private static final String ANDROID_WIDGET_SCROLLVIEW = "android.widget.ScrollView";
52     private static final String OKAY = "OK";
53     private static final String NOTIFICATION_TITLE_4K = "Using 4KB page-agnostic mode";
54     private static final String NOTIFICATION_TITLE_16K = "Using 16KB page-agnostic mode";
55 
56     private Context mContext;
57     private UiDevice mDevice;
58     private SettingsHelper mHelper;
59 
60     @Before
setUp()61     public void setUp() throws Exception {
62         mContext = getInstrumentation().getTargetContext();
63         mDevice = UiDevice.getInstance(getInstrumentation());
64         mHelper = SettingsHelper.getInstance();
65         try {
66             mDevice.setOrientationNatural();
67         } catch (RemoteException e) {
68             throw new RuntimeException("failed to freeze device orientation", e);
69         }
70 
71         mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
72         mDevice.executeShellCommand("wm dismiss-keyguard");
73     }
74 
unlockDeveloperOptions()75     private void unlockDeveloperOptions() throws Exception {
76         SettingsHelper.launchSettingsPage(mContext, Settings.ACTION_DEVICE_INFO_SETTINGS);
77         // Click 7 times on build number to unlock the dev options
78         for (int i = 0; i < 7; i++) {
79             mHelper.clickSetting(BUILD_NUMBER);
80         }
81     }
82 
83     @Test
enable16k_switchToExt4()84     public void enable16k_switchToExt4() throws Exception {
85         unlockDeveloperOptions();
86         SettingsHelper.launchSettingsPage(
87                 mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
88         clickOnObject(By.text(ENABLE_16K_TOGGLE));
89 
90         // Verify that ext4 toggle is visible
91         verifyTextOnScreen(EXT4_TITLE);
92 
93         mDevice.wait(Until.findObject(By.text(EXT4_CONFIRMATION)), TIMEOUT).click();
94     }
95 
96     @Test
enable16k_switchTo16Kb()97     public void enable16k_switchTo16Kb() throws Exception {
98         // Device will be in 4kb mode
99         openPersistentNotification(NOTIFICATION_TITLE_4K);
100         unlockDeveloperOptions();
101         SettingsHelper.launchSettingsPage(
102                 mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
103 
104         clickOnObject(By.text(ENABLE_16K_TOGGLE));
105         // Verify that text is displayed to switch to 16kb
106         verifyTextOnScreen(TOGGLE_16K_TITLE);
107 
108         mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
109     }
110 
111     @Test
enable16k_switchTo4Kb()112     public void enable16k_switchTo4Kb() throws Exception {
113         // Device will be in 16kb mode
114         openPersistentNotification(NOTIFICATION_TITLE_16K);
115         SettingsHelper.launchSettingsPage(
116                 mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
117 
118         clickOnObject(By.text(ENABLE_16K_TOGGLE));
119         //  Verify that text is displayed to switch to 4kb
120         verifyTextOnScreen(TOGGLE_4K_TITLE);
121 
122         mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
123     }
124 
clickOnObject(BySelector target)125     private void clickOnObject(BySelector target) {
126         mDevice.waitForWindowUpdate(null, TIMEOUT);
127         UiObject2 scrollView =
128                 mDevice.wait(
129                         Until.findObject(By.scrollable(true).clazz(ANDROID_WIDGET_SCROLLVIEW)),
130                         TIMEOUT);
131         UiObject2 targetObject = scrollTo(scrollView, target, Direction.DOWN);
132         assertTrue(targetObject != null);
133         targetObject.click();
134     }
135 
scrollTo(UiObject2 scrollable, BySelector target, Direction direction)136     private UiObject2 scrollTo(UiObject2 scrollable, BySelector target, Direction direction) {
137         while (!mDevice.hasObject(target) && scrollable.scroll(direction, 1.0f)) {
138             // continue
139         }
140         if (!mDevice.hasObject(target)) {
141             scrollable.scroll(direction, 1.0f);
142         }
143         return mDevice.findObject(target);
144     }
145 
verifyTextOnScreen(String displayedText)146     private void verifyTextOnScreen(String displayedText) {
147         UiObject2 targetObject = mDevice.wait(Until.findObject(By.text(displayedText)), TIMEOUT);
148         assertTrue(targetObject != null);
149     }
150 
openPersistentNotification(String title)151     private void openPersistentNotification(String title) {
152         mDevice.openNotification();
153         verifyTextOnScreen(title);
154         mDevice.wait(Until.findObject(By.text(title)), TIMEOUT).click();
155         mDevice.waitForWindowUpdate(null, TIMEOUT);
156         verifyTextOnScreen(title);
157         mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
158         mDevice.waitForWindowUpdate(null, TIMEOUT);
159     }
160 
161     @Test
enable16k_disableDeveloperOption()162     public void enable16k_disableDeveloperOption() throws Exception {
163         // Device will be in 4KB mode when this test will be run
164         SettingsHelper.launchSettingsPage(
165                 mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
166         mDevice.wait(Until.findObject(By.text(USE_DEVELOPER_OPTIONS)), TIMEOUT).click();
167         verifyTextOnScreen(NOTIFICATION_TITLE_4K);
168         mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
169     }
170 }
171