Merge "Add subclass for two pane widget picker" into udc-dev am: 94b5eada28
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/22213528 Change-Id: Ieb05606e30be3f01a5bc4d0cf17c63d046d421d7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -12,8 +12,8 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<com.android.launcher3.widget.picker.WidgetsFullSheet xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.android.launcher3.widget.picker.WidgetsTwoPaneSheet
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@@ -125,4 +125,4 @@
|
|||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.android.launcher3.views.SpringRelativeLayout>
|
</com.android.launcher3.views.SpringRelativeLayout>
|
||||||
</com.android.launcher3.widget.picker.WidgetsFullSheet>
|
</com.android.launcher3.widget.picker.WidgetsTwoPaneSheet>
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import android.view.WindowInsets;
|
|||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.GuardedBy;
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.Px;
|
import androidx.annotation.Px;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
@@ -182,7 +181,6 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
|
|||||||
* Measures the dimension of this view and its children by taking system insets, navigation bar,
|
* Measures the dimension of this view and its children by taking system insets, navigation bar,
|
||||||
* status bar, into account.
|
* status bar, into account.
|
||||||
*/
|
*/
|
||||||
@GuardedBy("MainThread")
|
|
||||||
protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
|
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
|
||||||
int widthUsed;
|
int widthUsed;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import android.content.Context;
|
|||||||
import android.content.pm.LauncherApps;
|
import android.content.pm.LauncherApps;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Outline;
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
@@ -43,13 +42,10 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewOutlineProvider;
|
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.window.BackEvent;
|
import android.window.BackEvent;
|
||||||
|
|
||||||
@@ -68,10 +64,7 @@ import com.android.launcher3.anim.PendingAnimation;
|
|||||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||||
import com.android.launcher3.model.UserManagerState;
|
import com.android.launcher3.model.UserManagerState;
|
||||||
import com.android.launcher3.model.WidgetItem;
|
import com.android.launcher3.model.WidgetItem;
|
||||||
import com.android.launcher3.model.data.PackageItemInfo;
|
|
||||||
import com.android.launcher3.pm.UserCache;
|
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.ArrowTipView;
|
||||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||||
import com.android.launcher3.views.SpringRelativeLayout;
|
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.BaseWidgetSheet;
|
||||||
import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
|
import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
|
||||||
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
|
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.SearchModeListener;
|
||||||
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
|
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
|
||||||
import com.android.launcher3.widget.util.WidgetsTableUtils;
|
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 com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.IntStream;
|
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_TIP_DELAY_MS = 200;
|
||||||
private static final long EDUCATION_DIALOG_DELAY_MS = 500;
|
private static final long EDUCATION_DIALOG_DELAY_MS = 500;
|
||||||
private static final float VERTICAL_START_POSITION = 0.3f;
|
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
|
// 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
|
// resolution or landscape on phone. This ratio defines the max percentage of content area that
|
||||||
// the table can display.
|
// the table can display.
|
||||||
private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
|
private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
|
||||||
|
|
||||||
private static final String KEY_WIDGETS_EDUCATION_DIALOG_SEEN =
|
private static final String KEY_WIDGETS_EDUCATION_DIALOG_SEEN =
|
||||||
"launcher.widgets_education_dialog_seen";
|
"launcher.widgets_education_dialog_seen";
|
||||||
|
|
||||||
private final UserManagerState mUserManagerState = new UserManagerState();
|
private final UserManagerState mUserManagerState = new UserManagerState();
|
||||||
|
|
||||||
private final boolean mHasWorkProfile;
|
|
||||||
private final SparseArray<AdapterHolder> mAdapters = new SparseArray();
|
|
||||||
private final UserHandle mCurrentUser = Process.myUserHandle();
|
private final UserHandle mCurrentUser = Process.myUserHandle();
|
||||||
private final Predicate<WidgetsListBaseEntry> mPrimaryWidgetsFilter =
|
private final Predicate<WidgetsListBaseEntry> mPrimaryWidgetsFilter =
|
||||||
entry -> mCurrentUser.equals(entry.mPkgItem.user);
|
entry -> mCurrentUser.equals(entry.mPkgItem.user);
|
||||||
private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
|
private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
|
||||||
entry -> !mCurrentUser.equals(entry.mPkgItem.user)
|
entry -> !mCurrentUser.equals(entry.mPkgItem.user)
|
||||||
&& !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
|
&& !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
|
||||||
|
protected final boolean mHasWorkProfile;
|
||||||
|
protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
|
||||||
@Nullable private ArrowTipView mLatestEducationalTip;
|
@Nullable private ArrowTipView mLatestEducationalTip;
|
||||||
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
|
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
|
||||||
new OnLayoutChangeListener() {
|
new OnLayoutChangeListener() {
|
||||||
@@ -175,52 +160,27 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
@Px private final int mTabsHeight;
|
@Px private final int mTabsHeight;
|
||||||
|
|
||||||
@Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
|
@Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
|
||||||
@Nullable private PersonalWorkPagedView mViewPager;
|
@Nullable private WidgetsRecyclerView mCurrentTouchEventRecyclerView;
|
||||||
|
@Nullable PersonalWorkPagedView mViewPager;
|
||||||
private boolean mIsInSearchMode;
|
private boolean mIsInSearchMode;
|
||||||
private boolean mIsNoWidgetsViewNeeded;
|
private boolean mIsNoWidgetsViewNeeded;
|
||||||
@Px private int mMaxSpanPerRow;
|
@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 DeviceProfile mDeviceProfile;
|
||||||
private final boolean mIsTwoPane;
|
|
||||||
|
|
||||||
private int mOrientation;
|
private int mOrientation;
|
||||||
private @Nullable WidgetsRecyclerView mCurrentTouchEventRecyclerView;
|
|
||||||
|
|
||||||
private RecyclerViewFastScroller mFastScroller;
|
protected TextView mNoWidgetsView;
|
||||||
|
protected StickyHeaderLayout mSearchScrollView;
|
||||||
private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
|
protected WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
|
||||||
@Override
|
protected View mTabBar;
|
||||||
public void getOutline(View view, Outline outline) {
|
protected View mSearchBarContainer;
|
||||||
outline.setRoundRect(
|
protected WidgetsSearchBar mSearchBar;
|
||||||
0,
|
protected TextView mHeaderTitle;
|
||||||
0,
|
protected RecyclerViewFastScroller mFastScroller;
|
||||||
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 WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
|
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile();
|
mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile();
|
||||||
mIsTwoPane = mDeviceProfile.isTablet
|
|
||||||
&& mDeviceProfile.isLandscape
|
|
||||||
&& LARGE_SCREEN_WIDGET_PICKER.get();
|
|
||||||
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
|
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
|
||||||
mOrientation = Launcher.getLauncher(context).getOrientation();
|
mOrientation = Launcher.getLauncher(context).getOrientation();
|
||||||
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
|
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
|
||||||
@@ -243,37 +203,39 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
|
|
||||||
mContent = findViewById(R.id.container);
|
mContent = findViewById(R.id.container);
|
||||||
setContentBackgroundWithParent(getContext().getDrawable(R.drawable.bg_widgets_full_sheet),
|
setContentBackgroundWithParent(getContext().getDrawable(R.drawable.bg_widgets_full_sheet),
|
||||||
mContent);
|
mContent);
|
||||||
|
|
||||||
mContent.setOutlineProvider(mViewOutlineProvider);
|
mContent.setOutlineProvider(mViewOutlineProvider);
|
||||||
mContent.setClipToOutline(true);
|
mContent.setClipToOutline(true);
|
||||||
|
setupSheet();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setupSheet() {
|
||||||
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
|
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) {
|
setupViews();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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);
|
mFastScroller = findViewById(R.id.fast_scroller);
|
||||||
if (mIsTwoPane) {
|
|
||||||
mFastScroller.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
|
mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
|
||||||
|
|
||||||
mAdapters.get(AdapterHolder.PRIMARY).setup(findViewById(R.id.primary_widgets_list_view));
|
mAdapters.get(AdapterHolder.PRIMARY).setup(findViewById(R.id.primary_widgets_list_view));
|
||||||
mAdapters.get(AdapterHolder.SEARCH).setup(findViewById(R.id.search_widgets_list_view));
|
mAdapters.get(AdapterHolder.SEARCH).setup(findViewById(R.id.search_widgets_list_view));
|
||||||
if (mHasWorkProfile) {
|
if (mHasWorkProfile) {
|
||||||
@@ -294,78 +256,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
mViewPager = null;
|
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);
|
mTabBar = mSearchScrollView.findViewById(R.id.tabs);
|
||||||
mSearchBarContainer = mSearchScrollView.findViewById(R.id.search_bar_container);
|
mSearchBarContainer = mSearchScrollView.findViewById(R.id.search_bar_container);
|
||||||
mSearchBar = mSearchScrollView.findViewById(R.id.widgets_search_bar);
|
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(
|
mSearchBar.initialize(
|
||||||
mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
|
mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
|
||||||
|
|
||||||
setUpEducationViewsIfNeeded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDeviceManagementResources() {
|
private void setDeviceManagementResources() {
|
||||||
@@ -380,14 +276,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivePageChanged(int currentActivePage) {
|
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);
|
AdapterHolder currentAdapterHolder = mAdapters.get(currentActivePage);
|
||||||
WidgetsRecyclerView currentRecyclerView =
|
WidgetsRecyclerView currentRecyclerView =
|
||||||
mAdapters.get(currentActivePage).mWidgetsRecyclerView;
|
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.
|
// The first item is always an empty space entry. Look for any more items.
|
||||||
boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
|
boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
|
||||||
|
|
||||||
if (mIsTwoPane) {
|
|
||||||
mRightPane.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
|
adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
|
||||||
|
|
||||||
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
|
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
|
||||||
@@ -468,9 +351,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
mActivityContext.getAppWidgetHolder().addProviderChangeListener(this);
|
mActivityContext.getAppWidgetHolder().addProviderChangeListener(this);
|
||||||
notifyWidgetProvidersChanged();
|
notifyWidgetProvidersChanged();
|
||||||
if (!mIsTwoPane) {
|
onRecommendedWidgetsBound();
|
||||||
onRecommendedWidgetsBound();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -558,14 +439,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
private boolean updateMaxSpansPerRow() {
|
private boolean updateMaxSpansPerRow() {
|
||||||
if (getMeasuredWidth() == 0) return false;
|
if (getMeasuredWidth() == 0) return false;
|
||||||
|
|
||||||
View content = mHasWorkProfile
|
@Px int maxHorizontalSpan = getContentView().getMeasuredWidth()
|
||||||
? mViewPager
|
- (2 * mContentHorizontalMargin);
|
||||||
: mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
|
|
||||||
if (mIsTwoPane && mRightPane != null) {
|
|
||||||
content = mRightPane;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Px int maxHorizontalSpan = content.getMeasuredWidth() - (2 * mContentHorizontalMargin);
|
|
||||||
if (mMaxSpanPerRow != maxHorizontalSpan) {
|
if (mMaxSpanPerRow != maxHorizontalSpan) {
|
||||||
mMaxSpanPerRow = maxHorizontalSpan;
|
mMaxSpanPerRow = maxHorizontalSpan;
|
||||||
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(
|
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(
|
||||||
@@ -582,6 +457,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected View getContentView() {
|
||||||
|
return mHasWorkProfile
|
||||||
|
? mViewPager
|
||||||
|
: mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
int width = r - l;
|
int width = r - l;
|
||||||
@@ -656,19 +537,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
public void onSearchResults(List<WidgetsListBaseEntry> entries) {
|
public void onSearchResults(List<WidgetsListBaseEntry> entries) {
|
||||||
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries);
|
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries);
|
||||||
updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
|
updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
|
||||||
if (mIsTwoPane) {
|
|
||||||
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.selectFirstHeaderEntry();
|
|
||||||
}
|
|
||||||
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
|
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
|
protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
|
||||||
mIsInSearchMode = isInSearchMode;
|
mIsInSearchMode = isInSearchMode;
|
||||||
if (isInSearchMode) {
|
if (isInSearchMode) {
|
||||||
mRecommendedWidgetsTable.setVisibility(GONE);
|
mRecommendedWidgetsTable.setVisibility(GONE);
|
||||||
if (mIsTwoPane) {
|
|
||||||
mSuggestedWidgetsContainer.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
if (mHasWorkProfile) {
|
if (mHasWorkProfile) {
|
||||||
mViewPager.setVisibility(GONE);
|
mViewPager.setVisibility(GONE);
|
||||||
mTabBar.setVisibility(GONE);
|
mTabBar.setVisibility(GONE);
|
||||||
@@ -680,10 +555,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
mNoWidgetsView.setVisibility(GONE);
|
mNoWidgetsView.setVisibility(GONE);
|
||||||
} else {
|
} else {
|
||||||
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
|
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
|
// Visibility of recommended widgets, recycler views and headers are handled in methods
|
||||||
// below.
|
// below.
|
||||||
onRecommendedWidgetsBound();
|
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.PRIMARY).mWidgetsListAdapter.resetExpandedHeader();
|
||||||
mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.resetExpandedHeader();
|
mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.resetExpandedHeader();
|
||||||
}
|
}
|
||||||
@@ -713,14 +584,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
mNoWidgetsView.getText().length(), noWidgetsViewTextBounds);
|
mNoWidgetsView.getText().length(), noWidgetsViewTextBounds);
|
||||||
noWidgetsViewHeight = noWidgetsViewTextBounds.height();
|
noWidgetsViewHeight = noWidgetsViewTextBounds.height();
|
||||||
}
|
}
|
||||||
doMeasure(
|
if (!isTwoPane()) {
|
||||||
makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
|
doMeasure(
|
||||||
MeasureSpec.EXACTLY),
|
makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
|
||||||
makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
|
MeasureSpec.EXACTLY),
|
||||||
MeasureSpec.EXACTLY));
|
makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
|
||||||
float maxTableHeight = mIsTwoPane ? Float.MAX_VALUE : (mContent.getMeasuredHeight()
|
MeasureSpec.EXACTLY));
|
||||||
- mTabsHeight - getHeaderViewHeight()
|
}
|
||||||
- noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
|
float maxTableHeight = getMaxTableHeight(noWidgetsViewHeight);
|
||||||
|
|
||||||
List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
|
List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
|
||||||
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(
|
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(
|
||||||
@@ -732,13 +603,21 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
mRecommendedWidgetsTable.setRecommendedWidgets(
|
mRecommendedWidgetsTable.setRecommendedWidgets(
|
||||||
recommendedWidgetsInTable, maxTableHeight);
|
recommendedWidgetsInTable, maxTableHeight);
|
||||||
} else {
|
} else {
|
||||||
mRecommendedWidgetsTable.setVisibility(GONE);
|
hideRecommendations();
|
||||||
if (mSuggestedWidgetsContainer != null) {
|
|
||||||
mSuggestedWidgetsContainer.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private void open(boolean animate) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
if (getPopupContainer().getInsets().bottom > 0) {
|
if (getPopupContainer().getInsets().bottom > 0) {
|
||||||
@@ -779,37 +658,49 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||||
// Disable swipe down when recycler view is scrolling or scroll view is scrolling
|
|
||||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
mNoIntercept = false;
|
mNoIntercept = shouldScroll(ev);
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (mSearchBar.isSearchBarFocused()
|
if (mSearchBar.isSearchBarFocused()
|
||||||
&& !getPopupContainer().isEventOverView(mSearchBarContainer, ev)) {
|
&& !getPopupContainer().isEventOverView(mSearchBarContainer, ev)) {
|
||||||
mSearchBar.clearSearchBarFocus();
|
mSearchBar.clearSearchBarFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onControllerInterceptTouchEvent(ev);
|
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. */
|
/** Shows the {@link WidgetsFullSheet} on the launcher. */
|
||||||
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
|
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
|
||||||
WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
|
boolean isTwoPane = LARGE_SCREEN_WIDGET_PICKER.get()
|
||||||
.inflate(LARGE_SCREEN_WIDGET_PICKER.get()
|
&& launcher.getDeviceProfile().isTablet
|
||||||
&& launcher.getDeviceProfile().isTablet
|
&& launcher.getDeviceProfile().isLandscape;
|
||||||
&& launcher.getDeviceProfile().isLandscape
|
|
||||||
? R.layout.widgets_full_sheet_large_screen
|
WidgetsFullSheet sheet;
|
||||||
: R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
|
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.attachToContainer();
|
||||||
sheet.mIsOpen = true;
|
sheet.mIsOpen = true;
|
||||||
sheet.open(animate);
|
sheet.open(animate);
|
||||||
@@ -973,7 +864,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
|| Utilities.isRunningInTestHarness();
|
|| Utilities.isRunningInTestHarness();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpEducationViewsIfNeeded() {
|
protected void setUpEducationViewsIfNeeded() {
|
||||||
if (!hasSeenEducationDialog()) {
|
if (!hasSeenEducationDialog()) {
|
||||||
postDelayed(() -> {
|
postDelayed(() -> {
|
||||||
WidgetsEduView eduDialog = showEducationDialog();
|
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. */
|
/** 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 PRIMARY = 0;
|
||||||
static final int WORK = 1;
|
static final int WORK = 1;
|
||||||
static final int SEARCH = 2;
|
static final int SEARCH = 2;
|
||||||
|
|
||||||
private final int mAdapterType;
|
private final int mAdapterType;
|
||||||
private final WidgetsListAdapter mWidgetsListAdapter;
|
final WidgetsListAdapter mWidgetsListAdapter;
|
||||||
private final DefaultItemAnimator mWidgetsListItemAnimator;
|
private final DefaultItemAnimator mWidgetsListItemAnimator;
|
||||||
|
|
||||||
private WidgetsRecyclerView mWidgetsRecyclerView;
|
private WidgetsRecyclerView mWidgetsRecyclerView;
|
||||||
@@ -1006,43 +901,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
AdapterHolder(int adapterType) {
|
AdapterHolder(int adapterType) {
|
||||||
mAdapterType = adapterType;
|
mAdapterType = adapterType;
|
||||||
Context context = getContext();
|
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(
|
mWidgetsListAdapter = new WidgetsListAdapter(
|
||||||
context,
|
context,
|
||||||
LayoutInflater.from(context),
|
LayoutInflater.from(context),
|
||||||
this::getEmptySpaceHeight,
|
this::getEmptySpaceHeight,
|
||||||
/* iconClickListener= */ WidgetsFullSheet.this,
|
/* iconClickListener= */ WidgetsFullSheet.this,
|
||||||
/* iconLongClickListener= */ WidgetsFullSheet.this,
|
/* iconLongClickListener= */ WidgetsFullSheet.this,
|
||||||
mIsTwoPane ? headerChangeListener : null);
|
isTwoPane());
|
||||||
mWidgetsListAdapter.setHasStableIds(true);
|
mWidgetsListAdapter.setHasStableIds(true);
|
||||||
switch (mAdapterType) {
|
switch (mAdapterType) {
|
||||||
case PRIMARY:
|
case PRIMARY:
|
||||||
@@ -1073,7 +939,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
|
mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
|
||||||
mWidgetsRecyclerView.setItemAnimator(mWidgetsListItemAnimator);
|
mWidgetsRecyclerView.setItemAnimator(mWidgetsListItemAnimator);
|
||||||
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
|
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
|
||||||
if (!mIsTwoPane) {
|
if (!isTwoPane()) {
|
||||||
mWidgetsRecyclerView.setEdgeEffectFactory(
|
mWidgetsRecyclerView.setEdgeEffectFactory(
|
||||||
((SpringRelativeLayout) mContent).createEdgeEffectFactory());
|
((SpringRelativeLayout) mContent).createEdgeEffectFactory());
|
||||||
}
|
}
|
||||||
@@ -1086,15 +952,4 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
|||||||
mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(mMaxSpanPerRow);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
|
|||||||
private final SparseArray<ViewHolderBinder> mViewHolderBinders = new SparseArray<>();
|
private final SparseArray<ViewHolderBinder> mViewHolderBinders = new SparseArray<>();
|
||||||
private final WidgetListBaseRowEntryComparator mRowComparator =
|
private final WidgetListBaseRowEntryComparator mRowComparator =
|
||||||
new WidgetListBaseRowEntryComparator();
|
new WidgetListBaseRowEntryComparator();
|
||||||
@Nullable private final WidgetsFullSheet.HeaderChangeListener mHeaderChangeListener;
|
@Nullable private WidgetsTwoPaneSheet.HeaderChangeListener mHeaderChangeListener;
|
||||||
|
|
||||||
private final List<WidgetsListBaseEntry> mAllEntries = new ArrayList<>();
|
private final List<WidgetsListBaseEntry> mAllEntries = new ArrayList<>();
|
||||||
private ArrayList<WidgetsListBaseEntry> mVisibleEntries = new ArrayList<>();
|
private ArrayList<WidgetsListBaseEntry> mVisibleEntries = new ArrayList<>();
|
||||||
@@ -107,8 +107,7 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
|
|||||||
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
|
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
|
||||||
IntSupplier emptySpaceHeightProvider, OnClickListener iconClickListener,
|
IntSupplier emptySpaceHeightProvider, OnClickListener iconClickListener,
|
||||||
OnLongClickListener iconLongClickListener,
|
OnLongClickListener iconLongClickListener,
|
||||||
WidgetsFullSheet.HeaderChangeListener headerChangeListener) {
|
boolean isTwoPane) {
|
||||||
mHeaderChangeListener = headerChangeListener;
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mMaxHorizontalSpan = WidgetSizes.getWidgetSizePx(
|
mMaxHorizontalSpan = WidgetSizes.getWidgetSizePx(
|
||||||
ActivityContext.lookupContext(context).getDeviceProfile(),
|
ActivityContext.lookupContext(context).getDeviceProfile(),
|
||||||
@@ -122,12 +121,17 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
|
|||||||
VIEW_TYPE_WIDGETS_HEADER,
|
VIEW_TYPE_WIDGETS_HEADER,
|
||||||
new WidgetsListHeaderViewHolderBinder(
|
new WidgetsListHeaderViewHolderBinder(
|
||||||
layoutInflater, /* onHeaderClickListener= */ this,
|
layoutInflater, /* onHeaderClickListener= */ this,
|
||||||
headerChangeListener != null));
|
isTwoPane));
|
||||||
mViewHolderBinders.put(
|
mViewHolderBinders.put(
|
||||||
VIEW_TYPE_WIDGETS_SPACE,
|
VIEW_TYPE_WIDGETS_SPACE,
|
||||||
new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
|
new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHeaderChangeListener(WidgetsTwoPaneSheet.HeaderChangeListener
|
||||||
|
headerChangeListener) {
|
||||||
|
mHeaderChangeListener = headerChangeListener;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
|
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||||
mRecyclerView = recyclerView;
|
mRecyclerView = recyclerView;
|
||||||
|
|||||||
@@ -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<WidgetsListBaseEntry> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user