diff --git a/res/layout/widgets_full_sheet_large_screen.xml b/res/layout/widgets_full_sheet_large_screen.xml
index 0626e60cc5..f563baa70e 100644
--- a/res/layout/widgets_full_sheet_large_screen.xml
+++ b/res/layout/widgets_full_sheet_large_screen.xml
@@ -12,8 +12,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
+
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index cfd241c130..07c6ba4628 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -32,7 +32,6 @@ import android.view.WindowInsets;
import android.view.animation.Interpolator;
import android.widget.Toast;
-import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.core.view.ViewCompat;
@@ -182,7 +181,6 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView
* Measures the dimension of this view and its children by taking system insets, navigation bar,
* status bar, into account.
*/
- @GuardedBy("MainThread")
protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int widthUsed;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index bd75ce6061..5293c3dda0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -30,7 +30,6 @@ import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Build;
import android.os.Process;
@@ -43,13 +42,10 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
import android.view.WindowInsets;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import android.widget.TextView;
import android.window.BackEvent;
@@ -68,10 +64,7 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.model.UserManagerState;
import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.recyclerview.ViewHolderBinder;
-import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
@@ -80,8 +73,6 @@ import com.android.launcher3.views.WidgetsEduView;
import com.android.launcher3.widget.BaseWidgetSheet;
import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
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.picker.search.SearchModeListener;
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
import com.android.launcher3.widget.util.WidgetsTableUtils;
@@ -89,7 +80,6 @@ import com.android.launcher3.workprofile.PersonalWorkPagedView;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.IntStream;
@@ -105,27 +95,22 @@ public class WidgetsFullSheet extends BaseWidgetSheet
private static final long EDUCATION_TIP_DELAY_MS = 200;
private static final long EDUCATION_DIALOG_DELAY_MS = 500;
private static final float VERTICAL_START_POSITION = 0.3f;
- private static final int PERSONAL_TAB = 0;
- private static final int WORK_TAB = 1;
- private static final String SUGGESTIONS_PACKAGE_NAME = "widgets_list_suggestions_entry";
// The widget recommendation table can easily take over the entire screen on devices with small
// resolution or landscape on phone. This ratio defines the max percentage of content area that
// the table can display.
private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
-
private static final String KEY_WIDGETS_EDUCATION_DIALOG_SEEN =
"launcher.widgets_education_dialog_seen";
private final UserManagerState mUserManagerState = new UserManagerState();
-
- private final boolean mHasWorkProfile;
- private final SparseArray mAdapters = new SparseArray();
private final UserHandle mCurrentUser = Process.myUserHandle();
private final Predicate mPrimaryWidgetsFilter =
entry -> mCurrentUser.equals(entry.mPkgItem.user);
private final Predicate mWorkWidgetsFilter =
entry -> !mCurrentUser.equals(entry.mPkgItem.user)
&& !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
+ protected final boolean mHasWorkProfile;
+ protected final SparseArray mAdapters = new SparseArray();
@Nullable private ArrowTipView mLatestEducationalTip;
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
new OnLayoutChangeListener() {
@@ -175,52 +160,27 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Px private final int mTabsHeight;
@Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
- @Nullable private PersonalWorkPagedView mViewPager;
+ @Nullable private WidgetsRecyclerView mCurrentTouchEventRecyclerView;
+ @Nullable PersonalWorkPagedView mViewPager;
private boolean mIsInSearchMode;
private boolean mIsNoWidgetsViewNeeded;
@Px private int mMaxSpanPerRow;
- private TextView mNoWidgetsView;
-
- private StickyHeaderLayout mSearchScrollView;
- private WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
- private LinearLayout mSuggestedWidgetsContainer;
- private WidgetsListHeader mSuggestedWidgetsHeader;
- private View mTabBar;
- private View mSearchBarContainer;
- private WidgetsSearchBar mSearchBar;
- private TextView mHeaderTitle;
- private LinearLayout mRightPane;
- private FrameLayout mRightPaneScrollView;
- private WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
private DeviceProfile mDeviceProfile;
- private final boolean mIsTwoPane;
private int mOrientation;
- private @Nullable WidgetsRecyclerView mCurrentTouchEventRecyclerView;
- private RecyclerViewFastScroller mFastScroller;
-
- private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(
- 0,
- 0,
- view.getMeasuredWidth(),
- view.getMeasuredHeight() - getResources().getDimensionPixelSize(
- R.dimen.widget_list_horizontal_margin_large_screen),
- view.getResources().getDimensionPixelSize(
- R.dimen.widget_list_top_bottom_corner_radius)
- );
- }
- };
+ protected TextView mNoWidgetsView;
+ protected StickyHeaderLayout mSearchScrollView;
+ protected WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
+ protected View mTabBar;
+ protected View mSearchBarContainer;
+ protected WidgetsSearchBar mSearchBar;
+ protected TextView mHeaderTitle;
+ protected RecyclerViewFastScroller mFastScroller;
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile();
- mIsTwoPane = mDeviceProfile.isTablet
- && mDeviceProfile.isLandscape
- && LARGE_SCREEN_WIDGET_PICKER.get();
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
mOrientation = Launcher.getLauncher(context).getOrientation();
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
@@ -243,37 +203,39 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+
mContent = findViewById(R.id.container);
setContentBackgroundWithParent(getContext().getDrawable(R.drawable.bg_widgets_full_sheet),
mContent);
-
mContent.setOutlineProvider(mViewOutlineProvider);
mContent.setClipToOutline(true);
+ setupSheet();
+ }
+ protected void setupSheet() {
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+ int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view
+ : R.layout.widgets_full_sheet_recyclerview;
+ layoutInflater.inflate(contentLayoutRes, mContent, true);
- if (mIsTwoPane) {
- layoutInflater.inflate(
- mHasWorkProfile
- ? R.layout.widgets_full_sheet_paged_view_large_screen
- : R.layout.widgets_full_sheet_recyclerview_large_screen,
- findViewById(R.id.recycler_view_container),
- true);
- } else {
- layoutInflater.inflate(
- mHasWorkProfile
- ? R.layout.widgets_full_sheet_paged_view
- : R.layout.widgets_full_sheet_recyclerview,
- mContent,
- true);
- }
+ setupViews();
+ mRecommendedWidgetsTable = mSearchScrollView.findViewById(R.id.recommended_widget_table);
+ mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
+ mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+ mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
+
+ onRecommendedWidgetsBound();
+ onWidgetsBound();
+ setUpEducationViewsIfNeeded();
+ }
+
+ protected void setupViews() {
+ mSearchScrollView = findViewById(R.id.search_and_recommendations_container);
+ mSearchScrollView.setCurrentRecyclerView(findViewById(R.id.primary_widgets_list_view));
+ mNoWidgetsView = findViewById(R.id.no_widgets_text);
mFastScroller = findViewById(R.id.fast_scroller);
- if (mIsTwoPane) {
- mFastScroller.setVisibility(GONE);
- }
mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
-
mAdapters.get(AdapterHolder.PRIMARY).setup(findViewById(R.id.primary_widgets_list_view));
mAdapters.get(AdapterHolder.SEARCH).setup(findViewById(R.id.search_widgets_list_view));
if (mHasWorkProfile) {
@@ -294,78 +256,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mViewPager = null;
}
- mNoWidgetsView = findViewById(R.id.no_widgets_text);
-
- mSearchScrollView = findViewById(R.id.search_and_recommendations_container);
- mSearchScrollView.setCurrentRecyclerView(findViewById(R.id.primary_widgets_list_view));
-
- mRecommendedWidgetsTable = mIsTwoPane
- ? mContent.findViewById(R.id.recommended_widget_table)
- : mSearchScrollView.findViewById(R.id.recommended_widget_table);
-
- mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
- mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
-
- // Add suggested widgets.
- if (mIsTwoPane) {
- mSuggestedWidgetsContainer = mSearchScrollView.findViewById(R.id.suggestions_header);
-
- // Inflate the suggestions header.
- mSuggestedWidgetsHeader = (WidgetsListHeader) layoutInflater.inflate(
- R.layout.widgets_list_row_header_two_pane,
- mSuggestedWidgetsContainer,
- false);
- mSuggestedWidgetsHeader.setExpanded(true);
-
- PackageItemInfo packageItemInfo = new PackageItemInfo(
- /* packageName= */ SUGGESTIONS_PACKAGE_NAME,
- Process.myUserHandle()) {
- @Override
- public boolean usingLowResIcon() {
- return false;
- }
- };
- packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
- WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
- packageItemInfo,
- getContext().getString(R.string.suggested_widgets_header_title),
- mActivityContext.getPopupDataProvider().getRecommendedWidgets())
- .withWidgetListShown();
-
- mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry);
- mSuggestedWidgetsHeader.setIcon(
- getContext().getDrawable(R.drawable.widget_suggestions_icon));
- mSuggestedWidgetsHeader.setOnClickListener(view -> {
- mSuggestedWidgetsHeader.setExpanded(true);
- resetExpandedHeaders();
- mRightPane.removeAllViews();
- mRightPane.addView(mRecommendedWidgetsTable);
- });
- mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
- }
-
mTabBar = mSearchScrollView.findViewById(R.id.tabs);
mSearchBarContainer = mSearchScrollView.findViewById(R.id.search_bar_container);
mSearchBar = mSearchScrollView.findViewById(R.id.widgets_search_bar);
- mHeaderTitle = mIsTwoPane
- ? mContent.findViewById(R.id.title)
- : mSearchScrollView.findViewById(R.id.title);
- mRightPane = mIsTwoPane ? mContent.findViewById(R.id.right_pane) : null;
- if (mRightPane != null) {
- mRightPane.setOutlineProvider(mViewOutlineProviderRightPane);
- }
- mRightPaneScrollView = mIsTwoPane
- ? mContent.findViewById(R.id.right_pane_scroll_view) : null;
-
- mWidgetsListTableViewHolderBinder =
- new WidgetsListTableViewHolderBinder(mActivityContext, layoutInflater, this, this);
- onRecommendedWidgetsBound();
- onWidgetsBound();
mSearchBar.initialize(
mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
-
- setUpEducationViewsIfNeeded();
}
private void setDeviceManagementResources() {
@@ -380,14 +276,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
public void onActivePageChanged(int currentActivePage) {
-
- // if the current active page changes to personal or work we set suggestions
- // to be the selected widget
- if (mIsTwoPane && mSuggestedWidgetsHeader != null
- && (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB)) {
- mSuggestedWidgetsHeader.callOnClick();
- }
-
AdapterHolder currentAdapterHolder = mAdapters.get(currentActivePage);
WidgetsRecyclerView currentRecyclerView =
mAdapters.get(currentActivePage).mWidgetsRecyclerView;
@@ -415,14 +303,9 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
}
- private void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
+ protected void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
// The first item is always an empty space entry. Look for any more items.
boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
-
- if (mIsTwoPane) {
- mRightPane.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
- }
-
adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
@@ -468,9 +351,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
super.onAttachedToWindow();
mActivityContext.getAppWidgetHolder().addProviderChangeListener(this);
notifyWidgetProvidersChanged();
- if (!mIsTwoPane) {
- onRecommendedWidgetsBound();
- }
+ onRecommendedWidgetsBound();
}
@Override
@@ -558,14 +439,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
private boolean updateMaxSpansPerRow() {
if (getMeasuredWidth() == 0) return false;
- View content = mHasWorkProfile
- ? mViewPager
- : mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
- if (mIsTwoPane && mRightPane != null) {
- content = mRightPane;
- }
-
- @Px int maxHorizontalSpan = content.getMeasuredWidth() - (2 * mContentHorizontalMargin);
+ @Px int maxHorizontalSpan = getContentView().getMeasuredWidth()
+ - (2 * mContentHorizontalMargin);
if (mMaxSpanPerRow != maxHorizontalSpan) {
mMaxSpanPerRow = maxHorizontalSpan;
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(
@@ -582,6 +457,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet
return false;
}
+ protected View getContentView() {
+ return mHasWorkProfile
+ ? mViewPager
+ : mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = r - l;
@@ -656,19 +537,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet
public void onSearchResults(List entries) {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries);
updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
- if (mIsTwoPane) {
- mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.selectFirstHeaderEntry();
- }
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
}
- private void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
+ protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
mIsInSearchMode = isInSearchMode;
if (isInSearchMode) {
mRecommendedWidgetsTable.setVisibility(GONE);
- if (mIsTwoPane) {
- mSuggestedWidgetsContainer.setVisibility(GONE);
- }
if (mHasWorkProfile) {
mViewPager.setVisibility(GONE);
mTabBar.setVisibility(GONE);
@@ -680,10 +555,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mNoWidgetsView.setVisibility(GONE);
} else {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
- if (mIsTwoPane) {
- mSuggestedWidgetsContainer.setVisibility(VISIBLE);
- mSuggestedWidgetsHeader.callOnClick();
- }
// Visibility of recommended widgets, recycler views and headers are handled in methods
// below.
onRecommendedWidgetsBound();
@@ -691,7 +562,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
}
- private void resetExpandedHeaders() {
+ protected void resetExpandedHeaders() {
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.resetExpandedHeader();
mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.resetExpandedHeader();
}
@@ -713,14 +584,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mNoWidgetsView.getText().length(), noWidgetsViewTextBounds);
noWidgetsViewHeight = noWidgetsViewTextBounds.height();
}
- doMeasure(
- makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
- MeasureSpec.EXACTLY),
- makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
- MeasureSpec.EXACTLY));
- float maxTableHeight = mIsTwoPane ? Float.MAX_VALUE : (mContent.getMeasuredHeight()
- - mTabsHeight - getHeaderViewHeight()
- - noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
+ if (!isTwoPane()) {
+ doMeasure(
+ makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
+ MeasureSpec.EXACTLY),
+ makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
+ MeasureSpec.EXACTLY));
+ }
+ float maxTableHeight = getMaxTableHeight(noWidgetsViewHeight);
List> recommendedWidgetsInTable =
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(
@@ -732,13 +603,21 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mRecommendedWidgetsTable.setRecommendedWidgets(
recommendedWidgetsInTable, maxTableHeight);
} else {
- mRecommendedWidgetsTable.setVisibility(GONE);
- if (mSuggestedWidgetsContainer != null) {
- mSuggestedWidgetsContainer.setVisibility(GONE);
- }
+ hideRecommendations();
}
}
+ protected void hideRecommendations() {
+ mRecommendedWidgetsTable.setVisibility(GONE);
+ }
+
+ protected float getMaxTableHeight(float noWidgetsViewHeight) {
+ return (mContent.getMeasuredHeight()
+ - mTabsHeight - getHeaderViewHeight()
+ - noWidgetsViewHeight)
+ * RECOMMENDATION_TABLE_HEIGHT_RATIO;
+ }
+
private void open(boolean animate) {
if (animate) {
if (getPopupContainer().getInsets().bottom > 0) {
@@ -779,37 +658,49 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- // Disable swipe down when recycler view is scrolling or scroll view is scrolling
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mNoIntercept = false;
- WidgetsRecyclerView recyclerView = getRecyclerView();
- RecyclerViewFastScroller scroller = recyclerView.getScrollbar();
-
- if (scroller.getThumbOffsetY() >= 0
- && getPopupContainer().isEventOverView(scroller, ev)) {
- mNoIntercept = true;
- } else if (getPopupContainer().isEventOverView(recyclerView, ev)) {
- mNoIntercept = !recyclerView.shouldContainerScroll(ev, getPopupContainer());
- } else if (mIsTwoPane && mRightPaneScrollView != null
- && getPopupContainer().isEventOverView(mRightPaneScrollView, ev)) {
- mNoIntercept = mRightPaneScrollView.canScrollVertically(-1);
- }
+ mNoIntercept = shouldScroll(ev);
if (mSearchBar.isSearchBarFocused()
&& !getPopupContainer().isEventOverView(mSearchBarContainer, ev)) {
mSearchBar.clearSearchBarFocus();
}
}
+
return super.onControllerInterceptTouchEvent(ev);
}
+ protected boolean shouldScroll(MotionEvent ev) {
+ boolean intercept = false;
+ WidgetsRecyclerView recyclerView = getRecyclerView();
+ RecyclerViewFastScroller scroller = recyclerView.getScrollbar();
+ // Disable swipe down when recycler view is scrolling
+ if (scroller.getThumbOffsetY() >= 0 && getPopupContainer().isEventOverView(scroller, ev)) {
+ intercept = true;
+ } else if (getPopupContainer().isEventOverView(recyclerView, ev)) {
+ intercept = !recyclerView.shouldContainerScroll(ev, getPopupContainer());
+ }
+ return intercept;
+ }
+
/** Shows the {@link WidgetsFullSheet} on the launcher. */
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
- WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
- .inflate(LARGE_SCREEN_WIDGET_PICKER.get()
- && launcher.getDeviceProfile().isTablet
- && launcher.getDeviceProfile().isLandscape
- ? R.layout.widgets_full_sheet_large_screen
- : R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
+ boolean isTwoPane = LARGE_SCREEN_WIDGET_PICKER.get()
+ && launcher.getDeviceProfile().isTablet
+ && launcher.getDeviceProfile().isLandscape;
+
+ WidgetsFullSheet sheet;
+ if (isTwoPane) {
+ sheet = (WidgetsTwoPaneSheet) launcher.getLayoutInflater().inflate(
+ R.layout.widgets_full_sheet_large_screen,
+ launcher.getDragLayer(),
+ false);
+ } else {
+ sheet = (WidgetsFullSheet) launcher.getLayoutInflater().inflate(
+ R.layout.widgets_full_sheet,
+ launcher.getDragLayer(),
+ false);
+ }
+
sheet.attachToContainer();
sheet.mIsOpen = true;
sheet.open(animate);
@@ -973,7 +864,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|| Utilities.isRunningInTestHarness();
}
- private void setUpEducationViewsIfNeeded() {
+ protected void setUpEducationViewsIfNeeded() {
if (!hasSeenEducationDialog()) {
postDelayed(() -> {
WidgetsEduView eduDialog = showEducationDialog();
@@ -991,14 +882,18 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
}
+ protected boolean isTwoPane() {
+ return false;
+ }
+
/** A holder class for holding adapters & their corresponding recycler view. */
- private final class AdapterHolder {
+ final class AdapterHolder {
static final int PRIMARY = 0;
static final int WORK = 1;
static final int SEARCH = 2;
private final int mAdapterType;
- private final WidgetsListAdapter mWidgetsListAdapter;
+ final WidgetsListAdapter mWidgetsListAdapter;
private final DefaultItemAnimator mWidgetsListItemAnimator;
private WidgetsRecyclerView mWidgetsRecyclerView;
@@ -1006,43 +901,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
AdapterHolder(int adapterType) {
mAdapterType = adapterType;
Context context = getContext();
- HeaderChangeListener headerChangeListener = new HeaderChangeListener() {
- @Override
- public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
- WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
- .getSelectedAppWidgets(selectedHeader);
- if (contentEntry == null || mRightPane == null) {
- return;
- }
-
- if (mSuggestedWidgetsHeader != null) {
- mSuggestedWidgetsHeader.setExpanded(false);
- }
- WidgetsRowViewHolder widgetsRowViewHolder =
- mWidgetsListTableViewHolderBinder.newViewHolder(mRightPane);
- mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
- contentEntry,
- ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
- Collections.EMPTY_LIST);
- widgetsRowViewHolder.mDataCallback = data -> {
- mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
- contentEntry.withMaxSpanSize(mMaxSpanPerRow),
- ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
- Collections.singletonList(data));
- };
-
- mRightPane.removeAllViews();
- mRightPane.addView(widgetsRowViewHolder.itemView);
- }
- };
mWidgetsListAdapter = new WidgetsListAdapter(
context,
LayoutInflater.from(context),
this::getEmptySpaceHeight,
/* iconClickListener= */ WidgetsFullSheet.this,
/* iconLongClickListener= */ WidgetsFullSheet.this,
- mIsTwoPane ? headerChangeListener : null);
+ isTwoPane());
mWidgetsListAdapter.setHasStableIds(true);
switch (mAdapterType) {
case PRIMARY:
@@ -1073,7 +939,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
mWidgetsRecyclerView.setItemAnimator(mWidgetsListItemAnimator);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
- if (!mIsTwoPane) {
+ if (!isTwoPane()) {
mWidgetsRecyclerView.setEdgeEffectFactory(
((SpringRelativeLayout) mContent).createEdgeEffectFactory());
}
@@ -1086,15 +952,4 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(mMaxSpanPerRow);
}
}
-
- /**
- * This is a listener for when the selected header gets changed in the left pane.
- */
- public interface HeaderChangeListener {
- /**
- * Sets the right pane to have the widgets for the currently selected header from
- * the left pane.
- */
- void onHeaderChanged(@NonNull PackageUserKey selectedHeader);
- }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index c89eea8521..723ea17147 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -89,7 +89,7 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC
private final SparseArray mViewHolderBinders = new SparseArray<>();
private final WidgetListBaseRowEntryComparator mRowComparator =
new WidgetListBaseRowEntryComparator();
- @Nullable private final WidgetsFullSheet.HeaderChangeListener mHeaderChangeListener;
+ @Nullable private WidgetsTwoPaneSheet.HeaderChangeListener mHeaderChangeListener;
private final List mAllEntries = new ArrayList<>();
private ArrayList mVisibleEntries = new ArrayList<>();
@@ -107,8 +107,7 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
IntSupplier emptySpaceHeightProvider, OnClickListener iconClickListener,
OnLongClickListener iconLongClickListener,
- WidgetsFullSheet.HeaderChangeListener headerChangeListener) {
- mHeaderChangeListener = headerChangeListener;
+ boolean isTwoPane) {
mContext = context;
mMaxHorizontalSpan = WidgetSizes.getWidgetSizePx(
ActivityContext.lookupContext(context).getDeviceProfile(),
@@ -122,12 +121,17 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC
VIEW_TYPE_WIDGETS_HEADER,
new WidgetsListHeaderViewHolderBinder(
layoutInflater, /* onHeaderClickListener= */ this,
- headerChangeListener != null));
+ isTwoPane));
mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_SPACE,
new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
}
+ public void setHeaderChangeListener(WidgetsTwoPaneSheet.HeaderChangeListener
+ headerChangeListener) {
+ mHeaderChangeListener = headerChangeListener;
+ }
+
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
mRecyclerView = recyclerView;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
new file mode 100644
index 0000000000..de7497a1a4
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2023 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.content.Context;
+import android.graphics.Outline;
+import android.os.Process;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.R;
+import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.recyclerview.ViewHolderBinder;
+import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Popup for showing the full list of available widgets with a two-pane layout.
+ */
+public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
+
+ private static final int PERSONAL_TAB = 0;
+ private static final int WORK_TAB = 1;
+ private static final String SUGGESTIONS_PACKAGE_NAME = "widgets_list_suggestions_entry";
+
+ private LinearLayout mSuggestedWidgetsContainer;
+ private WidgetsListHeader mSuggestedWidgetsHeader;
+ private LinearLayout mRightPane;
+
+ private FrameLayout mRightPaneScrollView;
+ private WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
+
+ private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(
+ 0,
+ 0,
+ view.getMeasuredWidth(),
+ view.getMeasuredHeight() - getResources().getDimensionPixelSize(
+ R.dimen.widget_list_horizontal_margin_large_screen),
+ view.getResources().getDimensionPixelSize(
+ R.dimen.widget_list_top_bottom_corner_radius)
+ );
+ }
+ };
+
+ public WidgetsTwoPaneSheet(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public WidgetsTwoPaneSheet(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void setupSheet() {
+ // Set the header change listener in the adapter
+ mAdapters.get(AdapterHolder.PRIMARY)
+ .mWidgetsListAdapter.setHeaderChangeListener(getHeaderChangeListener());
+ mAdapters.get(AdapterHolder.WORK)
+ .mWidgetsListAdapter.setHeaderChangeListener(getHeaderChangeListener());
+ mAdapters.get(AdapterHolder.SEARCH)
+ .mWidgetsListAdapter.setHeaderChangeListener(getHeaderChangeListener());
+
+ LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+
+ int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view_large_screen
+ : R.layout.widgets_full_sheet_recyclerview_large_screen;
+ layoutInflater.inflate(contentLayoutRes, findViewById(R.id.recycler_view_container), true);
+
+ setupViews();
+
+ mWidgetsListTableViewHolderBinder =
+ new WidgetsListTableViewHolderBinder(mActivityContext, layoutInflater, this, this);
+ mRecommendedWidgetsTable = mContent.findViewById(R.id.recommended_widget_table);
+ mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
+ mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+ mHeaderTitle = mContent.findViewById(R.id.title);
+ mRightPane = mContent.findViewById(R.id.right_pane);
+ mRightPane.setOutlineProvider(mViewOutlineProviderRightPane);
+ mRightPaneScrollView = mContent.findViewById(R.id.right_pane_scroll_view);
+ mRightPaneScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
+
+ setupSuggestedWidgets(layoutInflater);
+ onRecommendedWidgetsBound();
+ onWidgetsBound();
+ setUpEducationViewsIfNeeded();
+
+ // Set the fast scroller as not visible for two pane layout.
+ mFastScroller.setVisibility(GONE);
+ }
+
+ @Override
+ protected void hideRecommendations() {
+ super.hideRecommendations();
+ mSuggestedWidgetsContainer.setVisibility(GONE);
+ }
+
+ private void setupSuggestedWidgets(LayoutInflater layoutInflater) {
+ // Add suggested widgets.
+ mSuggestedWidgetsContainer = mSearchScrollView.findViewById(R.id.suggestions_header);
+
+ // Inflate the suggestions header.
+ mSuggestedWidgetsHeader = (WidgetsListHeader) layoutInflater.inflate(
+ R.layout.widgets_list_row_header_two_pane,
+ mSuggestedWidgetsContainer,
+ false);
+ mSuggestedWidgetsHeader.setExpanded(true);
+
+ PackageItemInfo packageItemInfo = new PackageItemInfo(
+ /* packageName= */ SUGGESTIONS_PACKAGE_NAME,
+ Process.myUserHandle()) {
+ @Override
+ public boolean usingLowResIcon() {
+ return false;
+ }
+ };
+ packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
+ WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
+ packageItemInfo,
+ getContext().getString(R.string.suggested_widgets_header_title),
+ mActivityContext.getPopupDataProvider().getRecommendedWidgets())
+ .withWidgetListShown();
+
+ mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry);
+ mSuggestedWidgetsHeader.setIcon(
+ getContext().getDrawable(R.drawable.widget_suggestions_icon));
+ mSuggestedWidgetsHeader.setOnClickListener(view -> {
+ mSuggestedWidgetsHeader.setExpanded(true);
+ resetExpandedHeaders();
+ mRightPane.removeAllViews();
+ mRightPane.addView(mRecommendedWidgetsTable);
+ });
+ mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
+ }
+
+ @Override
+ protected float getMaxTableHeight(float noWidgetsViewHeight) {
+ return Float.MAX_VALUE;
+ }
+
+ @Override
+ public void onActivePageChanged(int currentActivePage) {
+ // if the current active page changes to personal or work we set suggestions
+ // to be the selected widget
+ if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) {
+ mSuggestedWidgetsHeader.callOnClick();
+ }
+
+ super.onActivePageChanged(currentActivePage);
+ }
+
+ @Override
+ protected void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
+ // The first item is always an empty space entry. Look for any more items.
+ boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
+
+ mRightPane.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
+
+ super.updateRecyclerViewVisibility(adapterHolder);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mSuggestedWidgetsContainer.setVisibility(VISIBLE);
+ }
+
+ @Override
+ public void onSearchResults(List entries) {
+ super.onSearchResults(entries);
+ mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.selectFirstHeaderEntry();
+ }
+
+ @Override
+ protected boolean shouldScroll(MotionEvent ev) {
+ return getPopupContainer().isEventOverView(mRightPaneScrollView, ev)
+ ? mRightPaneScrollView.canScrollVertically(-1)
+ : super.shouldScroll(ev);
+ }
+
+ @Override
+ protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
+ if (isInSearchMode) {
+ mSuggestedWidgetsContainer.setVisibility(GONE);
+ } else {
+ mSuggestedWidgetsContainer.setVisibility(VISIBLE);
+ mSuggestedWidgetsHeader.callOnClick();
+ }
+ super.setViewVisibilityBasedOnSearch(isInSearchMode);
+ }
+
+ @Override
+ protected View getContentView() {
+ return mRightPane;
+ }
+
+ private HeaderChangeListener getHeaderChangeListener() {
+ return new HeaderChangeListener() {
+ @Override
+ public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
+ WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
+ .getSelectedAppWidgets(selectedHeader);
+
+ if (contentEntry == null || mRightPane == null) {
+ return;
+ }
+
+ if (mSuggestedWidgetsHeader != null) {
+ mSuggestedWidgetsHeader.setExpanded(false);
+ }
+ WidgetsRowViewHolder widgetsRowViewHolder =
+ mWidgetsListTableViewHolderBinder.newViewHolder(mRightPane);
+ mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
+ contentEntry,
+ ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
+ Collections.EMPTY_LIST);
+ widgetsRowViewHolder.mDataCallback = data -> {
+ mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
+ contentEntry,
+ ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
+ Collections.singletonList(data));
+ };
+ mRightPane.removeAllViews();
+ mRightPane.addView(widgetsRowViewHolder.itemView);
+ }
+ };
+ }
+
+ @Override
+ protected boolean isTwoPane() {
+ return true;
+ }
+
+ /**
+ * This is a listener for when the selected header gets changed in the left pane.
+ */
+ public interface HeaderChangeListener {
+ /**
+ * Sets the right pane to have the widgets for the currently selected header from
+ * the left pane.
+ */
+ void onHeaderChanged(@NonNull PackageUserKey selectedHeader);
+ }
+}