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:
@@ -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" />
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user