Merge "Removing unnecessary search header duplication" into tm-qpr-dev

This commit is contained in:
Sunny Goyal
2023-02-10 23:10:49 +00:00
committed by Android (Google) Code Review
16 changed files with 107 additions and 433 deletions

View File

@@ -19,7 +19,6 @@
<item type="id" name="view_type_widgets_space" />
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
<item type="id" name="view_type_widgets_search_header" />
<!-- Used for A11y actions in staged split to identify each task uniquely -->
<item type="id" name="split_topLeft_appInfo" />
<item type="id" name="split_bottomRight_appInfo" />

View File

@@ -59,27 +59,12 @@ public abstract class WidgetsListBaseEntry {
@Rank
public abstract int getRank();
/**
* Marker interface for subclasses that are headers for widget list items.
*
* @param <T> The type of this class.
*/
public interface Header<T extends WidgetsListBaseEntry & Header<T>> {
/** Returns whether the widget list is currently expanded. */
boolean isWidgetListShown();
/** Returns a copy of the item with the widget list shown. */
T withWidgetListShown();
}
@Retention(SOURCE)
@IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_SEARCH_HEADER,
RANK_WIDGETS_LIST_CONTENT})
@IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_CONTENT})
public @interface Rank {
}
public static final int RANK_WIDGETS_TOP_SPACE = 1;
public static final int RANK_WIDGETS_LIST_HEADER = 2;
public static final int RANK_WIDGETS_LIST_SEARCH_HEADER = 3;
public static final int RANK_WIDGETS_LIST_CONTENT = 4;
public static final int RANK_WIDGETS_LIST_CONTENT = 3;
}

View File

@@ -15,35 +15,67 @@
*/
package com.android.launcher3.widget.model;
import android.content.Context;
import android.content.res.Resources;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.PluralMessageFormat;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/** An information holder for an app which has widgets or/and shortcuts. */
public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry
implements WidgetsListBaseEntry.Header<WidgetsListHeaderEntry> {
public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
public final int widgetsCount;
public final int shortcutsCount;
private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_SEARCH =
(context, entry) -> entry.mWidgets.stream()
.map(item -> item.label).sorted().collect(Collectors.joining(", "));
private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_DEFAULT =
(context, entry) -> {
List<WidgetItem> items = entry.mWidgets;
int wc = (int) items.stream().filter(item -> item.widgetInfo != null).count();
int sc = Math.max(0, items.size() - wc);
Resources resources = context.getResources();
if (wc == 0 && sc == 0) {
return null;
}
String subtitle;
if (wc > 0 && sc > 0) {
String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
R.string.widgets_count, wc);
String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
R.string.shortcuts_count, sc);
subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
widgetsCount, shortcutsCount);
} else if (wc > 0) {
subtitle = PluralMessageFormat.getIcuPluralString(context,
R.string.widgets_count, wc);
} else {
subtitle = PluralMessageFormat.getIcuPluralString(context,
R.string.shortcuts_count, sc);
}
return subtitle;
};
private final boolean mIsWidgetListShown;
public WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
List<WidgetItem> items) {
this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
}
private final boolean mIsSearchEntry;
private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
List<WidgetItem> items, boolean isWidgetListShown) {
List<WidgetItem> items, boolean isSearchEntry, boolean isWidgetListShown) {
super(pkgItem, titleSectionName, items);
widgetsCount = (int) items.stream().filter(item -> item.widgetInfo != null).count();
shortcutsCount = Math.max(0, items.size() - widgetsCount);
mIsSearchEntry = isSearchEntry;
mIsWidgetListShown = isWidgetListShown;
}
/** Returns {@code true} if the widgets list associated with this header is shown. */
@Override
public boolean isWidgetListShown() {
return mIsWidgetListShown;
}
@@ -59,23 +91,54 @@ public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry
return RANK_WIDGETS_LIST_HEADER;
}
public boolean isSearchEntry() {
return mIsSearchEntry;
}
@Nullable
public String getSubtitle(Context context) {
return mIsSearchEntry
? SUBTITLE_SEARCH.apply(context, this) : SUBTITLE_DEFAULT.apply(context, this);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof WidgetsListHeaderEntry)) return false;
WidgetsListHeaderEntry otherEntry = (WidgetsListHeaderEntry) obj;
return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
&& mTitleSectionName.equals(otherEntry.mTitleSectionName)
&& mIsWidgetListShown == otherEntry.mIsWidgetListShown;
&& mIsWidgetListShown == otherEntry.mIsWidgetListShown
&& mIsSearchEntry == otherEntry.mIsSearchEntry;
}
/** Returns a copy of this {@link WidgetsListHeaderEntry} with the widget list shown. */
@Override
public WidgetsListHeaderEntry withWidgetListShown() {
if (mIsWidgetListShown) return this;
return new WidgetsListHeaderEntry(
mPkgItem,
mTitleSectionName,
mWidgets,
mIsSearchEntry,
/* isWidgetListShown= */ true);
}
public static WidgetsListHeaderEntry create(PackageItemInfo pkgItem, String titleSectionName,
List<WidgetItem> items) {
return new WidgetsListHeaderEntry(
pkgItem,
titleSectionName,
items,
/* forSearch */ false,
/* isWidgetListShown= */ false);
}
public static WidgetsListHeaderEntry createForSearch(PackageItemInfo pkgItem,
String titleSectionName, List<WidgetItem> items) {
return new WidgetsListHeaderEntry(
pkgItem,
titleSectionName,
items,
/* forSearch */ true,
/* isWidgetListShown= */ false);
}
}

View File

@@ -1,76 +0,0 @@
/*
* Copyright (C) 2021 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.launcher3.widget.model;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import java.util.List;
/** An information holder for an app which has widgets or/and shortcuts, to be shown in search. */
public final class WidgetsListSearchHeaderEntry extends WidgetsListBaseEntry
implements WidgetsListBaseEntry.Header<WidgetsListSearchHeaderEntry> {
private final boolean mIsWidgetListShown;
public WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
List<WidgetItem> items) {
this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
}
private WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
List<WidgetItem> items, boolean isWidgetListShown) {
super(pkgItem, titleSectionName, items);
mIsWidgetListShown = isWidgetListShown;
}
/** Returns {@code true} if the widgets list associated with this header is shown. */
@Override
public boolean isWidgetListShown() {
return mIsWidgetListShown;
}
@Override
public String toString() {
return "SearchHeader:" + mPkgItem.packageName + ":" + mWidgets.size();
}
@Override
@Rank
public int getRank() {
return RANK_WIDGETS_LIST_SEARCH_HEADER;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof WidgetsListSearchHeaderEntry)) return false;
WidgetsListSearchHeaderEntry otherEntry = (WidgetsListSearchHeaderEntry) obj;
return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
&& mTitleSectionName.equals(otherEntry.mTitleSectionName)
&& mIsWidgetListShown == otherEntry.mIsWidgetListShown;
}
/** Returns a copy of this {@link WidgetsListSearchHeaderEntry} with the widget list shown. */
@Override
public WidgetsListSearchHeaderEntry withWidgetListShown() {
if (mIsWidgetListShown) return this;
return new WidgetsListSearchHeaderEntry(
mPkgItem,
mTitleSectionName,
mWidgets,
/* isWidgetListShown= */ true);
}
}

View File

@@ -25,7 +25,6 @@ import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import com.android.launcher3.widget.picker.WidgetsListAdapter.WidgetListBaseRowEntryComparator;
import java.util.ArrayList;
@@ -175,12 +174,8 @@ public class WidgetsDiffReporter {
*/
private boolean hasHeaderUpdated(WidgetsListBaseEntry curRow, WidgetsListBaseEntry newRow) {
if (newRow instanceof WidgetsListHeaderEntry && curRow instanceof WidgetsListHeaderEntry) {
return !curRow.equals(newRow);
}
if (newRow instanceof WidgetsListSearchHeaderEntry
&& curRow instanceof WidgetsListSearchHeaderEntry) {
// Always refresh search header entries to reset rounded corners in their view holder.
return true;
return !curRow.equals(newRow) || ((WidgetsListHeaderEntry) curRow).isSearchEntry();
}
return false;
}

View File

@@ -286,7 +286,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
};
packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
WidgetsListHeaderEntry widgetsListHeaderEntry = new WidgetsListHeaderEntry(
WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
packageItemInfo,
getContext().getString(R.string.suggested_widgets_header_title),
mActivityContext.getPopupDataProvider().getRecommendedWidgets())

View File

@@ -48,7 +48,6 @@ import com.android.launcher3.widget.model.WidgetListSpaceEntry;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
import java.util.Arrays;
@@ -81,7 +80,6 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
public static final int VIEW_TYPE_WIDGETS_SPACE = R.id.view_type_widgets_space;
public static final int VIEW_TYPE_WIDGETS_LIST = R.id.view_type_widgets_list;
public static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
public static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
private final Context mContext;
private final WidgetsDiffReporter mDiffReporter;
@@ -96,7 +94,6 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
private Predicate<WidgetsListBaseEntry> mHeaderAndSelectedContentFilter = entry ->
entry instanceof WidgetsListHeaderEntry
|| entry instanceof WidgetsListSearchHeaderEntry
|| PackageUserKey.fromPackageItemInfo(entry.mPkgItem)
.equals(mWidgetsContentVisiblePackageUserKey);
@Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
@@ -124,12 +121,6 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
layoutInflater,
/* onHeaderClickListener= */ this,
listDrawableFactory));
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_SEARCH_HEADER,
new WidgetsListSearchHeaderViewHolderBinder(
layoutInflater,
/* onHeaderClickListener= */ this,
listDrawableFactory));
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_SPACE,
new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
@@ -205,10 +196,10 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
&& (mHeaderChangeListener == null
|| !(entry instanceof WidgetsListContentEntry)))
.map(entry -> {
if (entry instanceof WidgetsListBaseEntry.Header<?>
if (entry instanceof WidgetsListHeaderEntry
&& matchesKey(entry, mWidgetsContentVisiblePackageUserKey)) {
// Adjust the original entries to expand headers for the selected content.
return ((WidgetsListBaseEntry.Header<?>) entry).withWidgetListShown();
return ((WidgetsListHeaderEntry) entry).withWidgetListShown();
} else if (entry instanceof WidgetsListContentEntry) {
// Adjust the original content entries to accommodate for the current
// maxSpanSize.
@@ -233,7 +224,7 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
/** Returns whether {@code entry} matches {@code key}. */
private static boolean isHeaderForPackageUserKey(
@NonNull WidgetsListBaseEntry entry, @Nullable PackageUserKey key) {
return entry instanceof WidgetsListBaseEntry.Header && matchesKey(entry, key);
return entry instanceof WidgetsListHeaderEntry && matchesKey(entry, key);
}
private static boolean matchesKey(@NonNull WidgetsListBaseEntry entry,
@@ -276,16 +267,11 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
* first header in the new list that gets generated as we search.
*/
void selectFirstHeaderEntry() {
WidgetsListSearchHeaderEntry firstEntry = null;
for (WidgetsListBaseEntry entry: mVisibleEntries) {
if (entry instanceof WidgetsListSearchHeaderEntry) {
firstEntry = (WidgetsListSearchHeaderEntry) entry;
break;
}
}
if (firstEntry != null) {
onHeaderClicked(true, PackageUserKey.fromPackageItemInfo(firstEntry.mPkgItem));
}
mVisibleEntries.stream()
.filter(entry -> entry instanceof WidgetsListHeaderEntry)
.findFirst()
.ifPresent(entry ->
onHeaderClicked(true, PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
}
@Override
@@ -325,8 +311,6 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
return VIEW_TYPE_WIDGETS_LIST;
} else if (entry instanceof WidgetsListHeaderEntry) {
return VIEW_TYPE_WIDGETS_HEADER;
} else if (entry instanceof WidgetsListSearchHeaderEntry) {
return VIEW_TYPE_WIDGETS_SEARCH_HEADER;
} else if (entry instanceof WidgetListSpaceEntry) {
return VIEW_TYPE_WIDGETS_SPACE;
}

View File

@@ -18,12 +18,12 @@ package com.android.launcher3.widget.picker;
import static com.android.launcher3.config.FeatureFlags.LARGE_SCREEN_WIDGET_PICKER;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
@@ -45,13 +45,9 @@ import com.android.launcher3.icons.PlaceHolderIconDrawable;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.PluralMessageFormat;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.stream.Collectors;
/**
* A UI represents a header of an app shown in the full widgets tray.
@@ -201,11 +197,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
/** Apply app icon, labels and tag using a generic {@link WidgetsListHeaderEntry}. */
@UiThread
public void applyFromItemInfoWithIcon(WidgetsListHeaderEntry entry) {
applyIconAndLabel(entry);
}
@UiThread
private void applyIconAndLabel(WidgetsListHeaderEntry entry) {
PackageItemInfo info = entry.mPkgItem;
setIcon(info.newIcon(getContext()));
setTitles(entry);
@@ -247,55 +238,13 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
private void setTitles(WidgetsListHeaderEntry entry) {
mTitle.setText(entry.mPkgItem.title);
Resources resources = getContext().getResources();
if (entry.widgetsCount == 0 && entry.shortcutsCount == 0) {
String subtitle = entry.getSubtitle(getContext());
if (TextUtils.isEmpty(subtitle)) {
mSubtitle.setVisibility(GONE);
return;
}
String subtitle;
if (entry.widgetsCount > 0 && entry.shortcutsCount > 0) {
String widgetsCount = PluralMessageFormat.getIcuPluralString(getContext(),
R.string.widgets_count, entry.widgetsCount);
String shortcutsCount = PluralMessageFormat.getIcuPluralString(getContext(),
R.string.shortcuts_count, entry.shortcutsCount);
subtitle = resources.getString(R.string.widgets_and_shortcuts_count, widgetsCount,
shortcutsCount);
} else if (entry.widgetsCount > 0) {
subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
R.string.widgets_count, entry.widgetsCount);
} else {
subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
R.string.shortcuts_count, entry.shortcutsCount);
mSubtitle.setText(subtitle);
mSubtitle.setVisibility(VISIBLE);
}
mSubtitle.setText(subtitle);
mSubtitle.setVisibility(VISIBLE);
}
/** Apply app icon, labels and tag using a generic {@link WidgetsListSearchHeaderEntry}. */
@UiThread
public void applyFromItemInfoWithIcon(WidgetsListSearchHeaderEntry entry) {
applyIconAndLabel(entry);
}
@UiThread
private void applyIconAndLabel(WidgetsListSearchHeaderEntry entry) {
PackageItemInfo info = entry.mPkgItem;
setIcon(info.newIcon(getContext()));
setTitles(entry);
setExpanded(entry.isWidgetListShown());
super.setTag(info);
verifyHighRes();
}
private void setTitles(WidgetsListSearchHeaderEntry entry) {
mTitle.setText(entry.mPkgItem.title);
mSubtitle.setText(entry.mWidgets.stream()
.map(item -> item.label).sorted().collect(Collectors.joining(", ")));
mSubtitle.setVisibility(VISIBLE);
}
@Override

View File

@@ -1,70 +0,0 @@
/*
* Copyright (C) 2021 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.launcher3.widget.picker;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.android.launcher3.R;
import com.android.launcher3.recyclerview.ViewHolderBinder;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.List;
/**
* Binds data from {@link WidgetsListHeaderEntry} to UI elements in {@link WidgetsListHeaderHolder}.
*/
public final class WidgetsListSearchHeaderViewHolderBinder implements
ViewHolderBinder<WidgetsListSearchHeaderEntry, WidgetsListSearchHeaderHolder> {
private final LayoutInflater mLayoutInflater;
private final OnHeaderClickListener mOnHeaderClickListener;
private final WidgetsListDrawableFactory mListDrawableFactory;
public WidgetsListSearchHeaderViewHolderBinder(LayoutInflater layoutInflater,
OnHeaderClickListener onHeaderClickListener,
WidgetsListDrawableFactory listDrawableFactory) {
mLayoutInflater = layoutInflater;
mOnHeaderClickListener = onHeaderClickListener;
mListDrawableFactory = listDrawableFactory;
}
@Override
public WidgetsListSearchHeaderHolder newViewHolder(ViewGroup parent) {
WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
R.layout.widgets_list_row_header, parent, false);
header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
return new WidgetsListSearchHeaderHolder(header);
}
@Override
public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
WidgetsListSearchHeaderEntry data, @ListPosition int position, List<Object> payloads) {
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
widgetsListHeader.applyFromItemInfoWithIcon(data);
widgetsListHeader.setSelected(data.isWidgetListShown());
widgetsListHeader.setExpanded(data.isWidgetListShown());
widgetsListHeader.setListDrawableState(
WidgetsListDrawableState.obtain(
(position & POSITION_FIRST) != 0,
(position & POSITION_LAST) != 0,
/* isExpanded= */ data.isWidgetListShown()));
widgetsListHeader.setOnExpandChangeListener(isExpanded ->
mOnHeaderClickListener.onHeaderClicked(isExpanded,
PackageUserKey.fromPackageItemInfo(data.mPkgItem)));
}
}

View File

@@ -28,7 +28,6 @@ import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
import java.util.List;
@@ -72,7 +71,7 @@ public final class SimpleWidgetsSearchAlgorithm implements SearchAlgorithm<Widge
List<WidgetItem> matchedWidgetItems = filterWidgetItems(
input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
if (matchedWidgetItems.size() > 0) {
results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
results.add(WidgetsListHeaderEntry.createForSearch(headerEntry.mPkgItem,
headerEntry.mTitleSectionName, matchedWidgetItems));
results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
headerEntry.mTitleSectionName, matchedWidgetItems));

View File

@@ -87,7 +87,7 @@ public class WidgetsModel {
List<WidgetItem> widgetItems = entry.getValue();
String sectionName = (pkgItem.title == null) ? "" :
indexer.computeSectionName(pkgItem.title);
result.add(new WidgetsListHeaderEntry(pkgItem, sectionName, widgetItems));
result.add(WidgetsListHeaderEntry.create(pkgItem, sectionName, widgetItems));
result.add(new WidgetsListContentEntry(pkgItem, sectionName, widgetItems));
}
return result;

View File

@@ -229,7 +229,7 @@ public final class WidgetsDiffReporterTest {
List.of(mHeaderA, mHeaderB, mContentE));
// GIVEN the new list has one of the headers widgets list modified.
List<WidgetsListBaseEntry> newList = List.of(
new WidgetsListHeaderEntry(
WidgetsListHeaderEntry.create(
mHeaderA.mPkgItem, mHeaderA.mTitleSectionName,
mHeaderA.mWidgets.subList(0, 1)),
mHeaderB, mContentE);
@@ -274,7 +274,7 @@ public final class WidgetsDiffReporterTest {
PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
widgetItems.get(0).user);
return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
}
private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,

View File

@@ -270,7 +270,8 @@ public final class WidgetsListAdapterTest {
pInfo.title = pInfo.packageName;
pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
result.add(new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems));
result.add(WidgetsListHeaderEntry.create(
pInfo, /* titleSectionName= */ "", widgetItems));
result.add(new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems));
}

View File

@@ -134,7 +134,7 @@ public final class WidgetsListHeaderViewHolderBinderTest {
appInfo.title = appName;
appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
return new WidgetsListHeaderEntry(appInfo,
return WidgetsListHeaderEntry.create(appInfo,
/* titleSectionName= */ "",
generateWidgetItems(packageName, numOfWidgets));
}

View File

@@ -1,154 +0,0 @@
/*
* Copyright (C) 2021 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.launcher3.widget.picker;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static java.util.Collections.EMPTY_LIST;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.UserHandle;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.ActivityContextWrapper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.WidgetUtils;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class WidgetsListSearchHeaderViewHolderBinderTest {
private static final String TEST_PACKAGE = "com.google.test";
private static final String APP_NAME = "Test app";
private Context mContext;
private WidgetsListSearchHeaderViewHolderBinder mViewHolderBinder;
private InvariantDeviceProfile mTestProfile;
@Mock
private IconCache mIconCache;
@Mock
private OnHeaderClickListener mOnHeaderClickListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = new ActivityContextWrapper(getApplicationContext());
mTestProfile = new InvariantDeviceProfile();
mTestProfile.numRows = 5;
mTestProfile.numColumns = 5;
doAnswer(invocation -> {
ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
return componentWithLabel.getComponent().getShortClassName();
}).when(mIconCache).getTitleNoCache(any());
mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
LayoutInflater.from(mContext),
mOnHeaderClickListener,
new WidgetsListDrawableFactory(mContext));
}
@Test
public void bindViewHolder_appWith3Widgets_shouldShowTheCorrectAppNameAndSubtitle() {
WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
new FrameLayout(mContext));
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
APP_NAME,
TEST_PACKAGE,
/* numOfWidgets= */ 3);
mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
TextView appTitle = widgetsListHeader.findViewById(R.id.app_title);
TextView appSubtitle = widgetsListHeader.findViewById(R.id.app_subtitle);
assertThat(appTitle.getText()).isEqualTo(APP_NAME);
assertThat(appSubtitle.getText())
.isEqualTo(".SampleWidget0, .SampleWidget1, .SampleWidget2");
}
@Test
public void bindViewHolder_shouldAttachOnHeaderClickListener() {
WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
new FrameLayout(mContext));
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
APP_NAME,
TEST_PACKAGE,
/* numOfWidgets= */ 3);
mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
widgetsListHeader.callOnClick();
verify(mOnHeaderClickListener).onHeaderClicked(eq(true),
eq(PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
}
private WidgetsListSearchHeaderEntry generateSampleSearchHeader(String appName,
String packageName, int numOfWidgets) {
PackageItemInfo appInfo = new PackageItemInfo(packageName, UserHandle.CURRENT);
appInfo.title = appName;
appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
return new WidgetsListSearchHeaderEntry(appInfo,
/* titleSectionName= */ "",
generateWidgetItems(packageName, numOfWidgets));
}
private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
ArrayList<WidgetItem> widgetItems = new ArrayList<>();
for (int i = 0; i < numOfWidgets; i++) {
ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
widgetItems.add(new WidgetItem(
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
mTestProfile, mIconCache));
}
return widgetItems;
}
}

View File

@@ -50,7 +50,6 @@ import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import org.junit.Before;
import org.junit.Test;
@@ -117,12 +116,12 @@ public class SimpleWidgetsSearchAlgorithmTest {
.getAllWidgets();
assertEquals(List.of(
new WidgetsListSearchHeaderEntry(
WidgetsListHeaderEntry.createForSearch(
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets),
mCalendarContentEntry,
new WidgetsListSearchHeaderEntry(
WidgetsListHeaderEntry.createForSearch(
mCameraHeaderEntry.mPkgItem,
mCameraHeaderEntry.mTitleSectionName,
mCameraHeaderEntry.mWidgets),
@@ -138,7 +137,7 @@ public class SimpleWidgetsSearchAlgorithmTest {
.getAllWidgets();
assertEquals(List.of(
new WidgetsListSearchHeaderEntry(
WidgetsListHeaderEntry.createForSearch(
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
@@ -146,7 +145,7 @@ public class SimpleWidgetsSearchAlgorithmTest {
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
new WidgetsListSearchHeaderEntry(
WidgetsListHeaderEntry.createForSearch(
mCameraHeaderEntry.mPkgItem,
mCameraHeaderEntry.mTitleSectionName,
mCameraHeaderEntry.mWidgets.subList(1, 3)),
@@ -175,7 +174,7 @@ public class SimpleWidgetsSearchAlgorithmTest {
PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
widgetItems.get(0).user);
return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
}
private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,