• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.documentsui;
18 
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import android.app.Activity;
25 import android.app.Instrumentation;
26 import android.app.UiAutomation;
27 import android.content.Intent;
28 import android.content.pm.ActivityInfo;
29 import android.graphics.Paint;
30 import android.os.Build;
31 import android.os.ParcelFileDescriptor;
32 import android.support.test.uiautomator.UiDevice;
33 import android.view.KeyEvent;
34 
35 import androidx.fragment.app.FragmentManager;
36 import androidx.test.filters.LargeTest;
37 import androidx.test.platform.app.InstrumentationRegistry;
38 import androidx.test.rule.ActivityTestRule;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.documentsui.base.DocumentInfo;
42 import com.android.documentsui.dirlist.RenameDocumentFragment;
43 import com.android.documentsui.files.DeleteDocumentFragment;
44 import com.android.documentsui.files.FilesActivity;
45 import com.android.documentsui.queries.SearchFragment;
46 import com.android.documentsui.sorting.SortListFragment;
47 import com.android.documentsui.sorting.SortModel;
48 
49 import com.google.android.material.textfield.TextInputEditText;
50 
51 import org.junit.After;
52 import org.junit.Before;
53 import org.junit.Rule;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 import org.mockito.Mockito;
57 
58 import java.io.FileInputStream;
59 import java.io.IOException;
60 
61 @LargeTest
62 @RunWith(AndroidJUnit4.class)
63 public class DialogUiTest {
64 
65     private static final String CREATE_FRAGEMENT_TAG = "create_directory";
66     CreateDirectoryFragment mCreateDirectoryFragment;
67     FragmentManager mFragmentManager;
68     ScreenDensitySession mScreenDensitySession;
69     Intent mFileActivityIntent;
70 
71     @Rule
72     public ActivityTestRule<FilesActivity> mActivityTestRule = new ActivityTestRule<>(
73             FilesActivity.class);
74 
75     @Before
setup()76     public void setup() {
77         mFileActivityIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
78         mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
79         mScreenDensitySession = new ScreenDensitySession();
80 
81         final UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
82         device.pressKeyCode(KeyEvent.KEYCODE_WAKEUP);
83         device.pressKeyCode(KeyEvent.KEYCODE_MENU);
84     }
85 
86     @After
tearDown()87     public void tearDown() {
88         mScreenDensitySession.close();
89         mCreateDirectoryFragment = null;
90     }
91 
92     @Test
testCreateDialogShows()93     public void testCreateDialogShows() throws Throwable {
94         mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager));
95         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
96         mCreateDirectoryFragment =
97                 (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG);
98 
99         assertNotNull("Dialog was null", mCreateDirectoryFragment.getDialog());
100         assertTrue("Dialog was not being shown", mCreateDirectoryFragment.getDialog().isShowing());
101     }
102 
103     @Test
testCreateDialogShowsDismiss()104     public void testCreateDialogShowsDismiss() throws Throwable {
105         mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager));
106         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
107         mCreateDirectoryFragment =
108                 (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG);
109 
110         assertNotNull("Dialog was null", mCreateDirectoryFragment.getDialog());
111         assertTrue("Dialog was not being shown", mCreateDirectoryFragment.getDialog().isShowing());
112 
113         mActivityTestRule.runOnUiThread(() -> mCreateDirectoryFragment.getDialog().dismiss());
114         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
115 
116         assertNull("Dialog should be null after dismiss()", mCreateDirectoryFragment.getDialog());
117     }
118 
119     @Test
testCreateDialogShows_textInputEditText_shouldNotTruncateOnPortrait()120     public void testCreateDialogShows_textInputEditText_shouldNotTruncateOnPortrait()
121             throws Throwable {
122         mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager));
123         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
124         mCreateDirectoryFragment =
125                 (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG);
126 
127         final TextInputEditText inputView =
128                 mCreateDirectoryFragment.getDialog().findViewById(android.R.id.text1);
129 
130         assertTrue(inputView.getHeight() > getInputTextHeight(inputView));
131     }
132 
133     @Test
testCreateDialog_textInputEditText_shouldNotTruncateOnLargeDensity()134     public void testCreateDialog_textInputEditText_shouldNotTruncateOnLargeDensity()
135             throws Throwable {
136 
137         mScreenDensitySession.setLargeDensity();
138         mActivityTestRule.finishActivity();
139         mActivityTestRule.launchActivity(mFileActivityIntent);
140         mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
141 
142         mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager));
143         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
144         mCreateDirectoryFragment =
145                 (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG);
146 
147         final TextInputEditText inputView =
148                 mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1);
149 
150         assertTrue(inputView.getHeight() > getInputTextHeight(inputView));
151 
152     }
153 
154     @Test
testCreateDialog_textInputEditText_shouldNotTruncateOnLargerDensity()155     public void testCreateDialog_textInputEditText_shouldNotTruncateOnLargerDensity()
156             throws Throwable {
157 
158         mScreenDensitySession.setLargerDensity();
159         mActivityTestRule.finishActivity();
160         mActivityTestRule.launchActivity(mFileActivityIntent);
161         mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
162 
163         mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager));
164         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
165         mCreateDirectoryFragment =
166                 (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG);
167 
168         final TextInputEditText inputView =
169                 mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1);
170 
171         assertTrue(inputView.getHeight() > getInputTextHeight(inputView));
172     }
173 
174     @Test
testCreateDialog_textInputEditText_shouldNotTruncateOnLargestDensity()175     public void testCreateDialog_textInputEditText_shouldNotTruncateOnLargestDensity()
176             throws Throwable {
177 
178         mScreenDensitySession.setLargestDensity();
179         mActivityTestRule.finishActivity();
180         mActivityTestRule.launchActivity(mFileActivityIntent);
181         mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
182 
183         mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager));
184         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
185         mCreateDirectoryFragment =
186                 (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG);
187 
188         final TextInputEditText inputView =
189                 mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1);
190 
191         assertTrue(inputView.getHeight() > getInputTextHeight(inputView));
192     }
193 
194     @Test
testCreateDirectoryFragmentShows_textInputEditText_shouldNotTruncateOnLandscape()195     public void testCreateDirectoryFragmentShows_textInputEditText_shouldNotTruncateOnLandscape()
196             throws Throwable {
197         switchOrientation(mActivityTestRule.getActivity());
198         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
199         mScreenDensitySession.setLargestDensity();
200         mActivityTestRule.finishActivity();
201         mActivityTestRule.launchActivity(mFileActivityIntent);
202         mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager();
203 
204         mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager));
205         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
206         mCreateDirectoryFragment =
207                 (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG);
208 
209         final TextInputEditText inputView =
210                 mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1);
211 
212         assertTrue(
213                 "Failed with inputView height " + inputView.getHeight() + " and input text height "
214                         + getInputTextHeight(inputView),
215                 inputView.getHeight() > getInputTextHeight(inputView));
216 
217         switchOrientation(mActivityTestRule.getActivity());
218     }
219 
220     @Test
testCreateDirectoryFragmentShows_skipWhenStateSaved()221     public void testCreateDirectoryFragmentShows_skipWhenStateSaved() {
222         mFragmentManager = Mockito.mock(FragmentManager.class);
223         Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
224 
225         // Use mock FragmentManager will cause NPE then test fail when DialogFragment.show is
226         // called, so test pass means it skip.
227         CreateDirectoryFragment.show(mFragmentManager);
228     }
229 
230     @Test
testDeleteDocumentFragmentShows_skipWhenStateSaved()231     public void testDeleteDocumentFragmentShows_skipWhenStateSaved() {
232         mFragmentManager = Mockito.mock(FragmentManager.class);
233         Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
234 
235         DeleteDocumentFragment.show(mFragmentManager, null, null);
236     }
237 
238     @Test
testRenameDocumentFragmentShows_skipWhenStateSaved()239     public void testRenameDocumentFragmentShows_skipWhenStateSaved() {
240         mFragmentManager = Mockito.mock(FragmentManager.class);
241         Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
242 
243         RenameDocumentFragment.show(mFragmentManager, new DocumentInfo());
244     }
245 
246     @Test
testSearchFragmentShows_skipWhenStateSaved()247     public void testSearchFragmentShows_skipWhenStateSaved() {
248         mFragmentManager = Mockito.mock(FragmentManager.class);
249         Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
250 
251         SearchFragment.showFragment(mFragmentManager, "");
252     }
253 
254     @Test
testSortListFragmentShows_skipWhenStateSaved()255     public void testSortListFragmentShows_skipWhenStateSaved() {
256         mFragmentManager = Mockito.mock(FragmentManager.class);
257         Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
258         SortModel sortModel = Mockito.mock(SortModel.class);
259 
260         SortListFragment.show(mFragmentManager, sortModel);
261     }
262 
getInputTextHeight(TextInputEditText v)263     private static int getInputTextHeight(TextInputEditText v) {
264         Paint paint = v.getPaint();
265         final float textSize = paint.getTextSize();
266         final float textSpace = paint.getFontSpacing();
267         return Math.round(textSize + textSpace);
268     }
269 
switchOrientation(final Activity activity)270     private static void switchOrientation(final Activity activity) {
271         final int[] orientations = getOrientations(activity);
272         activity.setRequestedOrientation(orientations[1]);
273     }
274 
getOrientations(final Activity activity)275     private static int[] getOrientations(final Activity activity) {
276         final int originalOrientation = activity.getResources().getConfiguration().orientation;
277         final int newOrientation = originalOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
278                 ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
279                 : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
280         return new int[]{originalOrientation, newOrientation};
281     }
282 
283     private static class ScreenDensitySession implements AutoCloseable {
284         private static final String DENSITY_PROP_DEVICE = "ro.sf.lcd_density";
285         private static final String DENSITY_PROP_EMULATOR = "qemu.sf.lcd_density";
286 
287         private static final float DENSITY_DEFAULT = 1f;
288         private static final float DENSITY_LARGE = 1.09f;
289         private static final float DENSITY_LARGER = 1.19f;
290         private static final float DENSITY_LARGEST = 1.29f;
291 
setDefaultDensity()292         void setDefaultDensity() {
293             final int stableDensity = getStableDensity();
294             final int targetDensity = (int) (stableDensity * DENSITY_DEFAULT);
295             setDensity(targetDensity);
296         }
297 
setLargeDensity()298         void setLargeDensity() {
299             final int stableDensity = getStableDensity();
300             final int targetDensity = (int) (stableDensity * DENSITY_LARGE);
301             setDensity(targetDensity);
302         }
303 
setLargerDensity()304         void setLargerDensity() {
305             final int stableDensity = getStableDensity();
306             final int targetDensity = (int) (stableDensity * DENSITY_LARGER);
307             setDensity(targetDensity);
308         }
309 
setLargestDensity()310         void setLargestDensity() {
311             final int stableDensity = getStableDensity();
312             final int targetDensity = (int) (stableDensity * DENSITY_LARGEST);
313             setDensity(targetDensity);
314         }
315 
316         @Override
close()317         public void close() {
318             resetDensity();
319         }
320 
getStableDensity()321         private int getStableDensity() {
322             final String densityProp;
323             if (Build.IS_EMULATOR) {
324                 densityProp = DENSITY_PROP_EMULATOR;
325             } else {
326                 densityProp = DENSITY_PROP_DEVICE;
327             }
328 
329             return Integer.parseInt(executeShellCommand("getprop " + densityProp).trim());
330         }
331 
setDensity(int targetDensity)332         private void setDensity(int targetDensity) {
333             executeShellCommand("wm density " + targetDensity);
334 
335             // Verify that the density is changed.
336             final String output = executeShellCommand("wm density");
337             final boolean success = output.contains("Override density: " + targetDensity);
338 
339             assertTrue("Failed to set density to " + targetDensity, success);
340         }
341 
resetDensity()342         private void resetDensity() {
343             executeShellCommand("wm density reset");
344         }
345     }
346 
executeShellCommand(String cmd)347     public static String executeShellCommand(String cmd) {
348         try {
349             return runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
350         } catch (IOException e) {
351             fail("Failed reading command output: " + e);
352             return "";
353         }
354     }
355 
runShellCommand(Instrumentation instrumentation, String cmd)356     public static String runShellCommand(Instrumentation instrumentation, String cmd)
357             throws IOException {
358         return runShellCommand(instrumentation.getUiAutomation(), cmd);
359     }
360 
runShellCommand(UiAutomation automation, String cmd)361     public static String runShellCommand(UiAutomation automation, String cmd)
362             throws IOException {
363         if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) {
364             throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() "
365                     + "or revokeRuntimePermission() directly, which are more robust.");
366         }
367         ParcelFileDescriptor pfd = automation.executeShellCommand(cmd);
368         byte[] buf = new byte[512];
369         int bytesRead;
370         FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
371         StringBuffer stdout = new StringBuffer();
372         while ((bytesRead = fis.read(buf)) != -1) {
373             stdout.append(new String(buf, 0, bytesRead));
374         }
375         fis.close();
376         return stdout.toString();
377     }
378 }
379