diff options
author | 2019-07-30 23:40:09 +0800 | |
---|---|---|
committer | 2019-09-05 12:21:38 +0800 | |
commit | f7e53bbca20f5fe857251c124711251683916b4e (patch) | |
tree | 15f17136ea36d0f82d6160c39ae0f8d7d3198ed2 | |
parent | 13ed6052adab877e64b90256db1a636ce1814cc9 (diff) |
Fix AlertDialog TextInputLayout truncated issue
Adjust background top and bottom inset through alertDialogStyle
Fixes: 136710838
Bug: 136176461
Test: manual, enlarge display size, font size and verify the dialog UI
Test: atest DocumentsUIGoogleTests
Change-Id: Id0d1ba20e908c04286d6f711c60186bc5a972c9a
-rw-r--r-- | perf-tests/Android.bp | 1 | ||||
-rw-r--r-- | res/values/styles.xml | 6 | ||||
-rw-r--r-- | src/com/android/documentsui/CreateDirectoryFragment.java | 1 | ||||
-rw-r--r-- | tests/common/com/android/documentsui/DialogFragmentTest.java | 320 |
4 files changed, 327 insertions, 1 deletions
diff --git a/perf-tests/Android.bp b/perf-tests/Android.bp index 963a6da6c..e745fdfd1 100644 --- a/perf-tests/Android.bp +++ b/perf-tests/Android.bp @@ -20,6 +20,7 @@ android_test { static_libs: [ "androidx.legacy_legacy-support-v4", + "androidx.test.rules", "androidx.test.espresso.core", "mockito-target", "ub-janktesthelper", diff --git a/res/values/styles.xml b/res/values/styles.xml index 10f9b05d0..2409ed6be 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -91,8 +91,14 @@ <item name="buttonBarNegativeButtonStyle">@style/DialogTextButton</item> </style> + <style name="MaterialAlertDialogStyle" parent="@style/MaterialAlertDialog.MaterialComponents"> + <item name="backgroundInsetTop">12dp</item> + <item name="backgroundInsetBottom">12dp</item> + </style> + <style name="MaterialAlertDialogTheme" parent="@style/ThemeOverlay.MaterialComponents.MaterialAlertDialog.Centered"> <item name="android:dialogCornerRadius">@dimen/grid_item_radius</item> + <item name="alertDialogStyle">@style/MaterialAlertDialogStyle</item> <item name="buttonBarPositiveButtonStyle">@style/DialogTextButton</item> <item name="buttonBarNegativeButtonStyle">@style/DialogTextButton</item> <item name="materialAlertDialogTitleTextStyle">@style/MaterialAlertDialogTitleStyle</item> diff --git a/src/com/android/documentsui/CreateDirectoryFragment.java b/src/com/android/documentsui/CreateDirectoryFragment.java index 756b55587..dcaa87a10 100644 --- a/src/com/android/documentsui/CreateDirectoryFragment.java +++ b/src/com/android/documentsui/CreateDirectoryFragment.java @@ -68,7 +68,6 @@ public class CreateDirectoryFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final Context context = getActivity(); - final ContentResolver resolver = context.getContentResolver(); final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context); final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext()); diff --git a/tests/common/com/android/documentsui/DialogFragmentTest.java b/tests/common/com/android/documentsui/DialogFragmentTest.java new file mode 100644 index 000000000..05ad5fbb0 --- /dev/null +++ b/tests/common/com/android/documentsui/DialogFragmentTest.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2019 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 com.android.documentsui; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.app.Activity; +import android.app.Instrumentation; +import android.app.UiAutomation; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.graphics.Paint; +import android.os.Build; +import android.os.ParcelFileDescriptor; + +import androidx.fragment.app.FragmentManager; +import androidx.test.filters.MediumTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; +import androidx.test.runner.AndroidJUnit4; + +import com.android.documentsui.files.FilesActivity; + +import com.google.android.material.textfield.TextInputEditText; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileInputStream; +import java.io.IOException; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class DialogFragmentTest { + + private static final String CREATE_FRAGEMENT_TAG = "create_directory"; + CreateDirectoryFragment mCreateDirectoryFragment; + FragmentManager mFragmentManager; + ScreenDensitySession mScreenDensitySession; + Intent mFileActivityIntent; + + @Rule + public ActivityTestRule<FilesActivity> mActivityTestRule = new ActivityTestRule<>( + FilesActivity.class); + + @Before + public void setup() { + mFileActivityIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager(); + mScreenDensitySession = new ScreenDensitySession(); + } + + @After + public void tearDown() { + mScreenDensitySession.close(); + mCreateDirectoryFragment = null; + } + + @Test + public void testCreateDialogShows() throws Throwable { + mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mCreateDirectoryFragment = + (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG); + + assertNotNull("Dialog was null", mCreateDirectoryFragment.getDialog()); + assertTrue("Dialog was not being shown", mCreateDirectoryFragment.getDialog().isShowing()); + } + + @Test + public void testCreateDialogShowsDismiss() throws Throwable { + mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mCreateDirectoryFragment = + (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG); + + assertNotNull("Dialog was null", mCreateDirectoryFragment.getDialog()); + assertTrue("Dialog was not being shown", mCreateDirectoryFragment.getDialog().isShowing()); + + mActivityTestRule.runOnUiThread(() -> mCreateDirectoryFragment.dismiss()); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + + assertNull("Dialog should be null after dismiss()", mCreateDirectoryFragment.getDialog()); + } + + @Test + public void testCreateDialogShows_textInputEditText_shouldNotTruncateOnPortrait() + throws Throwable { + mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mCreateDirectoryFragment = + (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG); + + final TextInputEditText inputView = + mCreateDirectoryFragment.getDialog().findViewById(android.R.id.text1); + + assertTrue(inputView.getHeight() > getInputTextHeight(inputView)); + } + + @Test + public void testCreateDialog_textInputEditText_shouldNotTruncateOnLargeDensity() + throws Throwable { + + mScreenDensitySession.setLargeDensity(); + mActivityTestRule.finishActivity(); + mActivityTestRule.launchActivity(mFileActivityIntent); + mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager(); + + mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mCreateDirectoryFragment = + (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG); + + final TextInputEditText inputView = + mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1); + + assertTrue(inputView.getHeight() > getInputTextHeight(inputView)); + + } + + @Test + public void testCreateDialog_textInputEditText_shouldNotTruncateOnLargerDensity() + throws Throwable { + + mScreenDensitySession.setLargerDensity(); + mActivityTestRule.finishActivity(); + mActivityTestRule.launchActivity(mFileActivityIntent); + mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager(); + + mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mCreateDirectoryFragment = + (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG); + + final TextInputEditText inputView = + mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1); + + assertTrue(inputView.getHeight() > getInputTextHeight(inputView)); + } + + @Test + public void testCreateDialog_textInputEditText_shouldNotTruncateOnLargestDensity() + throws Throwable { + + mScreenDensitySession.setLargestDensity(); + mActivityTestRule.finishActivity(); + mActivityTestRule.launchActivity(mFileActivityIntent); + mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager(); + + mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mCreateDirectoryFragment = + (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG); + + final TextInputEditText inputView = + mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1); + + assertTrue(inputView.getHeight() > getInputTextHeight(inputView)); + } + + @Test + public void testCreateDirectoryFragmentShows_textInputEditText_shouldNotTruncateOnLandscape() + throws Throwable { + switchOrientation(mActivityTestRule.getActivity()); + mScreenDensitySession.setLargestDensity(); + mActivityTestRule.finishActivity(); + mActivityTestRule.launchActivity(mFileActivityIntent); + mFragmentManager = mActivityTestRule.getActivity().getSupportFragmentManager(); + + mActivityTestRule.runOnUiThread(() -> CreateDirectoryFragment.show(mFragmentManager)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + mCreateDirectoryFragment = + (CreateDirectoryFragment) mFragmentManager.findFragmentByTag(CREATE_FRAGEMENT_TAG); + + final TextInputEditText inputView = + mCreateDirectoryFragment.getDialog().getWindow().findViewById(android.R.id.text1); + Paint paint = inputView.getPaint(); + final float textSize = paint.getTextSize(); + + assertTrue(inputView.getHeight() > Math.round(textSize)); + + switchOrientation(mActivityTestRule.getActivity()); + } + + private static int getInputTextHeight(TextInputEditText v) { + Paint paint = v.getPaint(); + final float textSize = paint.getTextSize(); + final float textSpace = paint.getFontSpacing(); + return Math.round(textSize + textSpace); + } + + private static void switchOrientation(final Activity activity) { + final int[] orientations = getOrientations(activity); + activity.setRequestedOrientation(orientations[1]); + } + + private static int[] getOrientations(final Activity activity) { + final int originalOrientation = activity.getResources().getConfiguration().orientation; + final int newOrientation = originalOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + return new int[]{originalOrientation, newOrientation}; + } + + private static class ScreenDensitySession implements AutoCloseable { + private static final String DENSITY_PROP_DEVICE = "ro.sf.lcd_density"; + private static final String DENSITY_PROP_EMULATOR = "qemu.sf.lcd_density"; + + private static final float DENSITY_DEFAULT = 1f; + private static final float DENSITY_LARGE = 1.09f; + private static final float DENSITY_LARGER = 1.19f; + private static final float DENSITY_LARGEST = 1.29f; + + void setDefaultDensity() { + final int stableDensity = getStableDensity(); + final int targetDensity = (int) (stableDensity * DENSITY_DEFAULT); + setDensity(targetDensity); + } + + void setLargeDensity() { + final int stableDensity = getStableDensity(); + final int targetDensity = (int) (stableDensity * DENSITY_LARGE); + setDensity(targetDensity); + } + + void setLargerDensity() { + final int stableDensity = getStableDensity(); + final int targetDensity = (int) (stableDensity * DENSITY_LARGER); + setDensity(targetDensity); + } + + void setLargestDensity() { + final int stableDensity = getStableDensity(); + final int targetDensity = (int) (stableDensity * DENSITY_LARGEST); + setDensity(targetDensity); + } + + @Override + public void close() { + resetDensity(); + } + + private int getStableDensity() { + final String densityProp; + if (Build.IS_EMULATOR) { + densityProp = DENSITY_PROP_EMULATOR; + } else { + densityProp = DENSITY_PROP_DEVICE; + } + + return Integer.parseInt(executeShellCommand("getprop " + densityProp).trim()); + } + + private void setDensity(int targetDensity) { + executeShellCommand("wm density " + targetDensity); + + // Verify that the density is changed. + final String output = executeShellCommand("wm density"); + final boolean success = output.contains("Override density: " + targetDensity); + + assertTrue("Failed to set density to " + targetDensity, success); + } + + private void resetDensity() { + executeShellCommand("wm density reset"); + } + } + + public static String executeShellCommand(String cmd) { + try { + return runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd); + } catch (IOException e) { + fail("Failed reading command output: " + e); + return ""; + } + } + + public static String runShellCommand(Instrumentation instrumentation, String cmd) + throws IOException { + return runShellCommand(instrumentation.getUiAutomation(), cmd); + } + + public static String runShellCommand(UiAutomation automation, String cmd) + throws IOException { + if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) { + throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() " + + "or revokeRuntimePermission() directly, which are more robust."); + } + ParcelFileDescriptor pfd = automation.executeShellCommand(cmd); + byte[] buf = new byte[512]; + int bytesRead; + FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd); + StringBuffer stdout = new StringBuffer(); + while ((bytesRead = fis.read(buf)) != -1) { + stdout.append(new String(buf, 0, bytesRead)); + } + fis.close(); + return stdout.toString(); + } +} |