New feature “Text and reading options” for SetupWizard, Wallpaper, and Settings (4/n).

- Extending the interface of AppGridView to be flexible. It will be used
in the TextReadingPreferenceFragment.
  1. Add a new attribute "appCounts" into the view.
  2. Default app counts as 6 if not set the attribute.

Bug: 211503117
Test: make -j64 RunSettingsRoboTests ROBOTEST_FILTER=AppGridViewTest
Change-Id: I94a5f1d037551f6faba0300a176feb11fba1f203
This commit is contained in:
Peter_Liang
2022-01-12 11:59:06 +08:00
parent 3ae979bf27
commit 93668d6002
3 changed files with 125 additions and 6 deletions

View File

@@ -103,6 +103,11 @@
<attr name="iconBackgroundColor" format="reference|color" /> <attr name="iconBackgroundColor" format="reference|color" />
</declare-styleable> </declare-styleable>
<!-- For AppGridView -->
<declare-styleable name="AppGridView">
<attr name="appCount" format="integer" />
</declare-styleable>
<attr name="switchBarTheme" format="reference" /> <attr name="switchBarTheme" format="reference" />
<attr name="switchBarMarginStart" format="dimension" /> <attr name="switchBarMarginStart" format="dimension" />
<attr name="switchBarMarginEnd" format="dimension" /> <attr name="switchBarMarginEnd" format="dimension" />

View File

@@ -20,10 +20,12 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.IconDrawableFactory; import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
@@ -31,6 +33,7 @@ import android.widget.GridView;
import android.widget.ImageView; import android.widget.ImageView;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.core.util.Preconditions;
import com.android.settings.R; import com.android.settings.R;
@@ -38,7 +41,18 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/**
* The grid view for displaying the application entries.
*
* <p> The attribute value {@code appCount} from XML should be more than or equal to 1, otherwise
* throws an {@link IllegalArgumentException}.</p>
*/
public class AppGridView extends GridView { public class AppGridView extends GridView {
private static final String TAG = "AppGridView";
private static final int APP_COUNT_DEF_VALUE = 6;
private int mAppCount = APP_COUNT_DEF_VALUE;
public AppGridView(Context context) { public AppGridView(Context context) {
super(context); super(context);
init(context); init(context);
@@ -46,24 +60,36 @@ public class AppGridView extends GridView {
public AppGridView(Context context, AttributeSet attrs) { public AppGridView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
applyAttributeSet(context, attrs);
init(context); init(context);
} }
public AppGridView(Context context, AttributeSet attrs, int defStyleAttr) { public AppGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
applyAttributeSet(context, attrs);
init(context); init(context);
} }
public AppGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleResId) { public AppGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleResId) {
super(context, attrs, defStyleAttr, defStyleResId); super(context, attrs, defStyleAttr, defStyleResId);
applyAttributeSet(context, attrs);
init(context); init(context);
} }
private void init(Context context) { private void init(Context context) {
setAdapter(new AppsAdapter(context, R.layout.screen_zoom_preview_app_icon, setAdapter(new AppsAdapter(context, R.layout.screen_zoom_preview_app_icon,
android.R.id.text1, android.R.id.icon1)); android.R.id.text1, android.R.id.icon1, mAppCount));
}
private void applyAttributeSet(Context context, AttributeSet attrs) {
final TypedArray styledAttrs =
context.obtainStyledAttributes(attrs, R.styleable.AppGridView);
mAppCount =
styledAttrs.getInteger(R.styleable.AppGridView_appCount, APP_COUNT_DEF_VALUE);
Preconditions.checkArgument(mAppCount >= 1,
/* errorMessage= */ "App count may not be negative or zero");
styledAttrs.recycle();
} }
/** /**
@@ -73,12 +99,15 @@ public class AppGridView extends GridView {
public static class AppsAdapter extends ArrayAdapter<ActivityEntry> { public static class AppsAdapter extends ArrayAdapter<ActivityEntry> {
private final PackageManager mPackageManager; private final PackageManager mPackageManager;
private final int mIconResId; private final int mIconResId;
private final int mAppCount;
public AppsAdapter(Context context, int layout, int textResId, int iconResId) { public AppsAdapter(Context context, int layout, int textResId, int iconResId,
int appCount) {
super(context, layout, textResId); super(context, layout, textResId);
mIconResId = iconResId; mIconResId = iconResId;
mPackageManager = context.getPackageManager(); mPackageManager = context.getPackageManager();
mAppCount = appCount;
loadAllApps(); loadAllApps();
} }
@@ -108,20 +137,24 @@ public class AppGridView extends GridView {
} }
private void loadAllApps() { private void loadAllApps() {
final int needAppCount = 6;
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final PackageManager pm = mPackageManager; final PackageManager pm = mPackageManager;
final ArrayList<ActivityEntry> results = new ArrayList<>(); final ArrayList<ActivityEntry> results = new ArrayList<>();
final List<ResolveInfo> infos = pm.queryIntentActivities(mainIntent, 0); final List<ResolveInfo> infos = pm.queryIntentActivities(mainIntent, 0);
if (mAppCount > infos.size()) {
Log.d(TAG, "Visible app icon count does not meet the target count.");
}
final IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(getContext()); final IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(getContext());
for (ResolveInfo info : infos) { for (ResolveInfo info : infos) {
final CharSequence label = info.loadLabel(pm); final CharSequence label = info.loadLabel(pm);
if (label != null) { if (label != null) {
results.add(new ActivityEntry(info, label.toString(), iconFactory)); results.add(new ActivityEntry(info, label.toString(), iconFactory));
} }
if (results.size() >= needAppCount) { if (results.size() >= mAppCount) {
break; break;
} }
} }

View File

@@ -18,26 +18,39 @@ package com.android.settings.display;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.IconDrawableFactory; import android.util.IconDrawableFactory;
import com.android.settings.R;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for {@link AppGridView}.
*/
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class AppGridViewTest { public class AppGridViewTest {
@@ -87,4 +100,72 @@ public class AppGridViewTest {
assertThat(entry1.compareTo(entry2)).isEqualTo(0); assertThat(entry1.compareTo(entry2)).isEqualTo(0);
assertThat(entry1.compareTo(entry3)).isNotEqualTo(0); assertThat(entry1.compareTo(entry3)).isNotEqualTo(0);
} }
@Test
public void noAppCountAttribute_matchListSize() {
final int appCountFromSystem = 8;
setUpResolveInfos(appCountFromSystem);
final AppGridView appGridView = new AppGridView(mContext, /* attrs= */ null);
assertThat(appGridView.getAdapter().getCount()).isEqualTo(/* expected= */ 6);
}
@Test
public void setAppCountAttribute_matchListSize() {
final int appCountFromSystem = 8;
final int appCountFromAttr = 7;
setUpResolveInfos(appCountFromSystem);
final AppGridView appGridView =
new AppGridView(mContext, createAttributeSet(appCountFromAttr));
assertThat(appGridView.getAdapter().getCount()).isEqualTo(appCountFromAttr);
}
@Test(expected = IllegalArgumentException.class)
public void setAppCountAttribute_belowLowerBound_matchListSize() {
final int appCountFromSystem = 9;
final int appCountFromAttr = -1; // The num is just for the test.
setUpResolveInfos(appCountFromSystem);
new AppGridView(mContext, createAttributeSet(appCountFromAttr));
}
@Test
public void setAppCountAttribute_aboveUpperBound_matchListSize() {
final int appCountFromSystem = 10;
final int appCountFromAttr = 15;
setUpResolveInfos(appCountFromSystem);
final AppGridView appGridView =
new AppGridView(mContext, createAttributeSet(appCountFromAttr));
assertThat(appGridView.getAdapter().getCount()).isEqualTo(appCountFromSystem);
}
private AttributeSet createAttributeSet(int appCount) {
return Robolectric.buildAttributeSet()
.addAttribute(R.attr.appCount, String.valueOf(appCount))
.build();
}
private void setUpResolveInfos(int appCount) {
when(mContext.getPackageManager().queryIntentActivities(
any(Intent.class), anyInt()))
.thenReturn(createFakeResolveInfos(appCount));
}
private List<ResolveInfo> createFakeResolveInfos(int count) {
final List<ResolveInfo> list = new ArrayList<>();
for (int i = 0; i < count; i++) {
final ResolveInfo info = new ResolveInfo();
info.nonLocalizedLabel = String.valueOf(i);
list.add(info);
}
return list;
}
} }