diff options
| author | 2019-12-30 17:29:50 +0100 | |
|---|---|---|
| committer | 2019-12-31 13:47:16 +0100 | |
| commit | 40e979e60af1c5a46a59dd618e9216e9ce59133f (patch) | |
| tree | 05206fd33788ccda7068c92b3e81b73babb30ea5 | |
| parent | e1dfcf69eba0ae17b628f5e5d36dcf6dd89962b8 (diff) | |
Improve ResolverActivity UX on TV
The following problems were fixed:
1. It's not possible to select "Just once" / "Always" buttons when the list doesn't fit all the items;
2. The list doesn't automatically scroll when selecting an item that's out of the view;
3. When there's a default action assigned, the dialog has an interactive "Use a different app" header, that's selected by default and does nothing.
Bug: 119841729
Test: atest ChooserActivityTest ResolverActivityTest
Change-Id: Ib143636ea009f9f155942af68c3a3a6250ec8261
3 files changed, 41 insertions, 7 deletions
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 8dc3a072b47e..203840abb066 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -353,7 +353,11 @@ public class ResolverActivity extends Activity implements finish(); } }); - if (isVoiceInteraction()) { + + boolean hasTouchScreen = getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN); + + if (isVoiceInteraction() || !hasTouchScreen) { rdl.setCollapsed(false); } @@ -1283,10 +1287,11 @@ public class ResolverActivity extends Activity implements // In case this method is called again (due to activity recreation), avoid adding a new // header if one is already present. - if (useHeader && listView != null && listView.getHeaderViewsCount() == 0) { + if (useHeader && listView.getHeaderViewsCount() == 0) { listView.setHeaderDividersEnabled(true); listView.addHeaderView(LayoutInflater.from(this).inflate( - R.layout.resolver_different_item_header, listView, false)); + R.layout.resolver_different_item_header, listView, false), + null, false); } } @@ -1349,6 +1354,8 @@ public class ResolverActivity extends Activity implements if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) { setAlwaysButtonEnabled(true, filteredPosition, false); mOnceButton.setEnabled(true); + // Focus the button if we already have the default option + mOnceButton.requestFocus(); return; } @@ -1481,6 +1488,7 @@ public class ResolverActivity extends Activity implements mOnceButton.setEnabled(hasValidSelection); if (hasValidSelection) { currentAdapterView.smoothScrollToPosition(checkedPos); + mOnceButton.requestFocus(); } mLastSelected = checkedPos; } else { diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index 1bb2ba293186..e0c3823b40ef 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -187,7 +187,7 @@ public class ResolverDrawerLayout extends ViewGroup { public void setCollapsed(boolean collapsed) { if (!isLaidOut()) { - mOpenOnLayout = collapsed; + mOpenOnLayout = !collapsed; } else { smoothScrollTo(collapsed ? mCollapsibleHeight : 0, 0); } diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 8622b7efeee7..c086421501b5 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -54,6 +54,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; +import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -977,6 +978,7 @@ public class ChooserActivityTest { serviceTargets, TARGET_TYPE_CHOOSER_TARGET) ); + // Thread.sleep shouldn't be a thing in an integration test but it's // necessary here because of the way the code is structured // TODO: restructure the tests b/129870719 @@ -1075,7 +1077,29 @@ public class ChooserActivityTest { // This test is too long and too slow and should not be taken as an example for future tests. @Test - public void testDirectTargetLoggingWithAppTargetNotRanked() throws InterruptedException { + public void testDirectTargetLoggingWithAppTargetNotRankedPortrait() + throws InterruptedException { + testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_PORTRAIT, 4); + } + + @Test + public void testDirectTargetLoggingWithAppTargetNotRankedLandscape() + throws InterruptedException { + testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_LANDSCAPE, 8); + } + + private void testDirectTargetLoggingWithAppTargetNotRanked( + int orientation, int appTargetsExpected + ) throws InterruptedException { + Configuration configuration = + new Configuration(InstrumentationRegistry.getInstrumentation().getContext() + .getResources().getConfiguration()); + configuration.orientation = orientation; + + sOverrides.resources = Mockito.spy( + InstrumentationRegistry.getInstrumentation().getContext().getResources()); + when(sOverrides.resources.getConfiguration()).thenReturn(configuration); + Intent sendIntent = createSendTextIntent(); // We need app targets for direct targets to get displayed List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15); @@ -1111,8 +1135,10 @@ public class ChooserActivityTest { // TODO: restructure the tests b/129870719 Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS); - assertThat("Chooser should have 20 targets (4 apps, 1 direct, 15 A-Z)", - activity.getAdapter().getCount(), is(20)); + assertThat( + String.format("Chooser should have %d targets (%d apps, 1 direct, 15 A-Z)", + appTargetsExpected + 16, appTargetsExpected), + activity.getAdapter().getCount(), is(appTargetsExpected + 16)); assertThat("Chooser should have exactly one selectable direct target", activity.getAdapter().getSelectableServiceTargetCount(), is(1)); assertThat("The resolver info must match the resolver info used to create the target", |