Loading res/values/attrs.xml +5 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,11 @@ <attr name="iconBackgroundColor" format="reference|color" /> </declare-styleable> <!-- For AppGridView --> <declare-styleable name="AppGridView"> <attr name="appCount" format="integer" /> </declare-styleable> <attr name="switchBarTheme" format="reference" /> <attr name="switchBarMarginStart" format="dimension" /> <attr name="switchBarMarginEnd" format="dimension" /> Loading src/com/android/settings/display/AppGridView.java +39 −6 Original line number Diff line number Diff line Loading @@ -20,10 +20,12 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.util.AttributeSet; import android.util.IconDrawableFactory; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; Loading @@ -31,6 +33,7 @@ import android.widget.GridView; import android.widget.ImageView; import androidx.annotation.VisibleForTesting; import androidx.core.util.Preconditions; import com.android.settings.R; Loading @@ -38,7 +41,18 @@ import java.util.ArrayList; import java.util.Collections; 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 { 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) { super(context); init(context); Loading @@ -46,24 +60,36 @@ public class AppGridView extends GridView { public AppGridView(Context context, AttributeSet attrs) { super(context, attrs); applyAttributeSet(context, attrs); init(context); } public AppGridView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); applyAttributeSet(context, attrs); init(context); } public AppGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleResId) { super(context, attrs, defStyleAttr, defStyleResId); applyAttributeSet(context, attrs); init(context); } private void init(Context context) { 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(); } /** Loading @@ -73,12 +99,15 @@ public class AppGridView extends GridView { public static class AppsAdapter extends ArrayAdapter<ActivityEntry> { private final PackageManager mPackageManager; 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); mIconResId = iconResId; mPackageManager = context.getPackageManager(); mAppCount = appCount; loadAllApps(); } Loading Loading @@ -108,20 +137,24 @@ public class AppGridView extends GridView { } private void loadAllApps() { final int needAppCount = 6; final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); final PackageManager pm = mPackageManager; final ArrayList<ActivityEntry> results = new ArrayList<>(); 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()); for (ResolveInfo info : infos) { final CharSequence label = info.loadLabel(pm); if (label != null) { results.add(new ActivityEntry(info, label.toString(), iconFactory)); } if (results.size() >= needAppCount) { if (results.size() >= mAppCount) { break; } } Loading tests/robotests/src/com/android/settings/display/AppGridViewTest.java +81 −0 Original line number Diff line number Diff line Loading @@ -18,26 +18,39 @@ package com.android.settings.display; 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.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.IconDrawableFactory; import com.android.settings.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; /** * Tests for {@link AppGridView}. */ @RunWith(RobolectricTestRunner.class) public class AppGridViewTest { Loading Loading @@ -87,4 +100,72 @@ public class AppGridViewTest { assertThat(entry1.compareTo(entry2)).isEqualTo(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; } } Loading
res/values/attrs.xml +5 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,11 @@ <attr name="iconBackgroundColor" format="reference|color" /> </declare-styleable> <!-- For AppGridView --> <declare-styleable name="AppGridView"> <attr name="appCount" format="integer" /> </declare-styleable> <attr name="switchBarTheme" format="reference" /> <attr name="switchBarMarginStart" format="dimension" /> <attr name="switchBarMarginEnd" format="dimension" /> Loading
src/com/android/settings/display/AppGridView.java +39 −6 Original line number Diff line number Diff line Loading @@ -20,10 +20,12 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.util.AttributeSet; import android.util.IconDrawableFactory; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; Loading @@ -31,6 +33,7 @@ import android.widget.GridView; import android.widget.ImageView; import androidx.annotation.VisibleForTesting; import androidx.core.util.Preconditions; import com.android.settings.R; Loading @@ -38,7 +41,18 @@ import java.util.ArrayList; import java.util.Collections; 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 { 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) { super(context); init(context); Loading @@ -46,24 +60,36 @@ public class AppGridView extends GridView { public AppGridView(Context context, AttributeSet attrs) { super(context, attrs); applyAttributeSet(context, attrs); init(context); } public AppGridView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); applyAttributeSet(context, attrs); init(context); } public AppGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleResId) { super(context, attrs, defStyleAttr, defStyleResId); applyAttributeSet(context, attrs); init(context); } private void init(Context context) { 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(); } /** Loading @@ -73,12 +99,15 @@ public class AppGridView extends GridView { public static class AppsAdapter extends ArrayAdapter<ActivityEntry> { private final PackageManager mPackageManager; 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); mIconResId = iconResId; mPackageManager = context.getPackageManager(); mAppCount = appCount; loadAllApps(); } Loading Loading @@ -108,20 +137,24 @@ public class AppGridView extends GridView { } private void loadAllApps() { final int needAppCount = 6; final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); final PackageManager pm = mPackageManager; final ArrayList<ActivityEntry> results = new ArrayList<>(); 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()); for (ResolveInfo info : infos) { final CharSequence label = info.loadLabel(pm); if (label != null) { results.add(new ActivityEntry(info, label.toString(), iconFactory)); } if (results.size() >= needAppCount) { if (results.size() >= mAppCount) { break; } } Loading
tests/robotests/src/com/android/settings/display/AppGridViewTest.java +81 −0 Original line number Diff line number Diff line Loading @@ -18,26 +18,39 @@ package com.android.settings.display; 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.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.IconDrawableFactory; import com.android.settings.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; /** * Tests for {@link AppGridView}. */ @RunWith(RobolectricTestRunner.class) public class AppGridViewTest { Loading Loading @@ -87,4 +100,72 @@ public class AppGridViewTest { assertThat(entry1.compareTo(entry2)).isEqualTo(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; } }