Use drawable states for list positions instead of swapping drawables
Replacing drawables interrupts touch feedback of ripples. Implementing custom state lists allows altering the corner radius without cutting off ripples and also means we reduce unnecessary object creation. Fix: 190467676 Test: locally Change-Id: I10eec042aae57d278f8254327d42df945767c7ac
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<TableLayout
|
||||
<com.android.launcher3.widget.picker.WidgetsListTableView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/widgets_table"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -137,7 +137,6 @@
|
||||
|
||||
<dimen name="widget_list_top_bottom_corner_radius">28dp</dimen>
|
||||
<dimen name="widget_list_content_corner_radius">4dp</dimen>
|
||||
<dimen name="widget_list_content_joined_corner_radius">0dp</dimen>
|
||||
|
||||
<dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
|
||||
<dimen name="widget_list_entry_bottom_margin">2dp</dimen>
|
||||
|
||||
+4
-1
@@ -107,7 +107,10 @@ public final class WidgetsListHeaderViewHolderBinderTest {
|
||||
/* iconClickListener= */ view -> {},
|
||||
/* iconLongClickListener= */ view -> false);
|
||||
mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
|
||||
LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
|
||||
LayoutInflater.from(mTestActivity),
|
||||
mOnHeaderClickListener,
|
||||
new WidgetsListDrawableFactory(mTestActivity),
|
||||
widgetsListAdapter);
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
+4
-1
@@ -107,7 +107,10 @@ public final class WidgetsListSearchHeaderViewHolderBinderTest {
|
||||
/* iconClickListener= */ view -> {},
|
||||
/* iconLongClickListener= */ view -> false);
|
||||
mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
|
||||
LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
|
||||
LayoutInflater.from(mTestActivity),
|
||||
mOnHeaderClickListener,
|
||||
new WidgetsListDrawableFactory(mTestActivity),
|
||||
widgetsListAdapter);
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
+1
@@ -118,6 +118,7 @@ public final class WidgetsListTableViewHolderBinderTest {
|
||||
mOnIconClickListener,
|
||||
mOnLongClickListener,
|
||||
mWidgetPreviewLoader,
|
||||
new WidgetsListDrawableFactory(mTestActivity),
|
||||
widgetsListAdapter);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,18 +103,25 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC
|
||||
OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mDiffReporter = new WidgetsDiffReporter(iconCache, this);
|
||||
WidgetsListDrawableFactory listDrawableFactory = new WidgetsListDrawableFactory(context);
|
||||
mWidgetsListTableViewHolderBinder = new WidgetsListTableViewHolderBinder(context,
|
||||
layoutInflater, iconClickListener, iconLongClickListener,
|
||||
widgetPreviewLoader, /* listAdapter= */ this);
|
||||
widgetPreviewLoader, listDrawableFactory, /* listAdapter= */ this);
|
||||
mViewHolderBinders.put(VIEW_TYPE_WIDGETS_LIST, mWidgetsListTableViewHolderBinder);
|
||||
mViewHolderBinders.put(
|
||||
VIEW_TYPE_WIDGETS_HEADER,
|
||||
new WidgetsListHeaderViewHolderBinder(
|
||||
layoutInflater, /* onHeaderClickListener= */this, /* listAdapter= */ this));
|
||||
layoutInflater,
|
||||
/* onHeaderClickListener= */ this,
|
||||
listDrawableFactory,
|
||||
/* listAdapter= */ this));
|
||||
mViewHolderBinders.put(
|
||||
VIEW_TYPE_WIDGETS_SEARCH_HEADER,
|
||||
new WidgetsListSearchHeaderViewHolderBinder(
|
||||
layoutInflater, /*onHeaderClickListener=*/ this, /* listAdapter= */ this));
|
||||
layoutInflater,
|
||||
/* onHeaderClickListener= */ this,
|
||||
listDrawableFactory,
|
||||
/* listAdapter= */ this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.widget.picker;
|
||||
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.FIRST;
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.FIRST_EXPANDED;
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.LAST;
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE;
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE_EXPANDED;
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.SINGLE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.graphics.drawable.StateListDrawable;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
/** Factory for creating drawables to use as background for list elements. */
|
||||
final class WidgetsListDrawableFactory {
|
||||
|
||||
private final float mTopBottomCornerRadius;
|
||||
private final float mMiddleCornerRadius;
|
||||
private final ColorStateList mSurfaceColor;
|
||||
private final ColorStateList mRippleColor;
|
||||
|
||||
WidgetsListDrawableFactory(Context context) {
|
||||
Resources res = context.getResources();
|
||||
mTopBottomCornerRadius = res.getDimension(R.dimen.widget_list_top_bottom_corner_radius);
|
||||
mMiddleCornerRadius = res.getDimension(R.dimen.widget_list_content_corner_radius);
|
||||
mSurfaceColor = context.getColorStateList(R.color.surface);
|
||||
mRippleColor = ColorStateList.valueOf(
|
||||
Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a drawable for widget header list items. This drawable supports all positions
|
||||
* in {@link WidgetsListDrawableState}.
|
||||
*/
|
||||
Drawable createHeaderBackgroundDrawable() {
|
||||
StateListDrawable stateList = new StateListDrawable();
|
||||
stateList.addState(
|
||||
SINGLE.mStateSet,
|
||||
createRoundedRectDrawable(mTopBottomCornerRadius, mTopBottomCornerRadius));
|
||||
stateList.addState(
|
||||
FIRST_EXPANDED.mStateSet,
|
||||
createRoundedRectDrawable(mTopBottomCornerRadius, 0));
|
||||
stateList.addState(
|
||||
FIRST.mStateSet,
|
||||
createRoundedRectDrawable(mTopBottomCornerRadius, mMiddleCornerRadius));
|
||||
stateList.addState(
|
||||
MIDDLE_EXPANDED.mStateSet,
|
||||
createRoundedRectDrawable(mMiddleCornerRadius, 0));
|
||||
stateList.addState(
|
||||
MIDDLE.mStateSet,
|
||||
createRoundedRectDrawable(mMiddleCornerRadius, mMiddleCornerRadius));
|
||||
stateList.addState(
|
||||
LAST.mStateSet,
|
||||
createRoundedRectDrawable(mMiddleCornerRadius, mTopBottomCornerRadius));
|
||||
return new RippleDrawable(mRippleColor, /* content= */ stateList, /* mask= */ stateList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a drawable for widget content list items. This state list supports the middle and
|
||||
* last states.
|
||||
*/
|
||||
Drawable createContentBackgroundDrawable() {
|
||||
StateListDrawable stateList = new StateListDrawable();
|
||||
stateList.addState(
|
||||
MIDDLE.mStateSet,
|
||||
createRoundedRectDrawable(0, mMiddleCornerRadius));
|
||||
stateList.addState(
|
||||
LAST.mStateSet,
|
||||
createRoundedRectDrawable(0, mTopBottomCornerRadius));
|
||||
return new RippleDrawable(mRippleColor, /* content= */ stateList, /* mask= */ stateList);
|
||||
}
|
||||
|
||||
/** Creates a rounded-rect drawable with the specified radii. */
|
||||
private Drawable createRoundedRectDrawable(float topRadius, float bottomRadius) {
|
||||
GradientDrawable backgroundMask = new GradientDrawable();
|
||||
backgroundMask.setColor(mSurfaceColor);
|
||||
backgroundMask.setShape(GradientDrawable.RECTANGLE);
|
||||
backgroundMask.setCornerRadii(
|
||||
new float[]{
|
||||
topRadius,
|
||||
topRadius,
|
||||
topRadius,
|
||||
topRadius,
|
||||
bottomRadius,
|
||||
bottomRadius,
|
||||
bottomRadius,
|
||||
bottomRadius
|
||||
});
|
||||
return backgroundMask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.widget.picker;
|
||||
|
||||
/**
|
||||
* Different possible list position states for an item in the widgets list to have. Note that only
|
||||
* headers use the expanded state.
|
||||
*/
|
||||
enum WidgetsListDrawableState {
|
||||
FIRST(new int[]{android.R.attr.state_first}),
|
||||
FIRST_EXPANDED(new int[]{android.R.attr.state_first, android.R.attr.state_expanded}),
|
||||
MIDDLE(new int[]{android.R.attr.state_middle}),
|
||||
MIDDLE_EXPANDED(new int[]{android.R.attr.state_middle, android.R.attr.state_expanded}),
|
||||
LAST(new int[]{android.R.attr.state_last}),
|
||||
SINGLE(new int[]{android.R.attr.state_single});
|
||||
|
||||
final int[] mStateSet;
|
||||
|
||||
WidgetsListDrawableState(int[] stateSet) {
|
||||
mStateSet = stateSet;
|
||||
}
|
||||
|
||||
static WidgetsListDrawableState obtain(boolean isFirst, boolean isLast, boolean isExpanded) {
|
||||
if (isFirst && isLast) return SINGLE;
|
||||
if (isFirst && isExpanded) return FIRST_EXPANDED;
|
||||
if (isFirst) return FIRST;
|
||||
if (isLast) return LAST;
|
||||
if (isExpanded) return MIDDLE_EXPANDED;
|
||||
return MIDDLE;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.widget.picker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
/** Helper class for creating drawables to use as background for list elements. */
|
||||
final class WidgetsListDrawables {
|
||||
|
||||
private WidgetsListDrawables() {}
|
||||
|
||||
/** Creates a list background drawable with the specified radii. */
|
||||
static Drawable createListBackgroundDrawable(
|
||||
Context context,
|
||||
float topRadius,
|
||||
float bottomRadius) {
|
||||
GradientDrawable backgroundMask = new GradientDrawable();
|
||||
backgroundMask.setColor(context.getColorStateList(R.color.surface));
|
||||
backgroundMask.setShape(GradientDrawable.RECTANGLE);
|
||||
|
||||
backgroundMask.setCornerRadii(
|
||||
new float[]{
|
||||
topRadius,
|
||||
topRadius,
|
||||
topRadius,
|
||||
topRadius,
|
||||
bottomRadius,
|
||||
bottomRadius,
|
||||
bottomRadius,
|
||||
bottomRadius
|
||||
});
|
||||
|
||||
return new RippleDrawable(
|
||||
/* color= */ ColorStateList.valueOf(
|
||||
Themes.getAttrColor(context, android.R.attr.colorControlHighlight)),
|
||||
/* content= */ backgroundMask,
|
||||
/* mask= */ backgroundMask);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -60,9 +60,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
|
||||
@Nullable private Drawable mIconDrawable;
|
||||
private final int mIconSize;
|
||||
private final int mBottomMarginSize;
|
||||
private final float mTopBottomCornerRadius;
|
||||
private final float mMiddleCornerRadius;
|
||||
private final float mJoinedCornerRadius;
|
||||
|
||||
private ImageView mAppIcon;
|
||||
private TextView mTitle;
|
||||
@@ -70,6 +67,7 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
|
||||
|
||||
private CheckBox mExpandToggle;
|
||||
private boolean mIsExpanded = false;
|
||||
@Nullable private WidgetsListDrawableState mListDrawableState;
|
||||
|
||||
public WidgetsListHeader(Context context) {
|
||||
this(context, /* attrs= */ null);
|
||||
@@ -90,12 +88,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
|
||||
grid.iconSizePx);
|
||||
mBottomMarginSize =
|
||||
getResources().getDimensionPixelSize(R.dimen.widget_list_entry_bottom_margin);
|
||||
mTopBottomCornerRadius =
|
||||
getResources().getDimension(R.dimen.widget_list_top_bottom_corner_radius);
|
||||
mMiddleCornerRadius =
|
||||
getResources().getDimension(R.dimen.widget_list_content_corner_radius);
|
||||
mJoinedCornerRadius =
|
||||
getResources().getDimension(R.dimen.widget_list_content_joined_corner_radius);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,6 +155,14 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */
|
||||
@UiThread
|
||||
public void setListDrawableState(WidgetsListDrawableState state) {
|
||||
if (state == mListDrawableState) return;
|
||||
this.mListDrawableState = state;
|
||||
refreshDrawableState();
|
||||
}
|
||||
|
||||
/** Apply app icon, labels and tag using a generic {@link WidgetsListHeaderEntry}. */
|
||||
@UiThread
|
||||
public void applyFromItemInfoWithIcon(WidgetsListHeaderEntry entry) {
|
||||
@@ -263,20 +263,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
|
||||
verifyHighRes();
|
||||
}
|
||||
|
||||
/** Updates the list to have a background drawable with the appropriate corner radii. */
|
||||
@UiThread
|
||||
public void updateListBackground(boolean isFirst, boolean isLast, boolean isExpanded) {
|
||||
float topRadius = isFirst ? mTopBottomCornerRadius : mMiddleCornerRadius;
|
||||
float bottomRadius = isLast
|
||||
? mTopBottomCornerRadius
|
||||
: isExpanded
|
||||
? mJoinedCornerRadius
|
||||
: mMiddleCornerRadius;
|
||||
setBackground(
|
||||
WidgetsListDrawables.createListBackgroundDrawable(
|
||||
getContext(), topRadius, bottomRadius));
|
||||
}
|
||||
|
||||
private void setTitles(WidgetsListSearchHeaderEntry entry) {
|
||||
mTitle.setText(entry.mPkgItem.title);
|
||||
|
||||
@@ -300,6 +286,17 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] onCreateDrawableState(int extraSpace) {
|
||||
if (mListDrawableState == null) return super.onCreateDrawableState(extraSpace);
|
||||
// Augment the state set from the super implementation with the custom states from
|
||||
// mListDrawableState.
|
||||
int[] drawableState =
|
||||
super.onCreateDrawableState(extraSpace + mListDrawableState.mStateSet.length);
|
||||
mergeDrawableStates(drawableState, mListDrawableState.mStateSet);
|
||||
return drawableState;
|
||||
}
|
||||
|
||||
/** Verifies that the current icon is high-res otherwise posts a request to load the icon. */
|
||||
public void verifyHighRes() {
|
||||
if (mIconLoadRequest != null) {
|
||||
|
||||
@@ -30,13 +30,16 @@ public final class WidgetsListHeaderViewHolderBinder implements
|
||||
ViewHolderBinder<WidgetsListHeaderEntry, WidgetsListHeaderHolder> {
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final OnHeaderClickListener mOnHeaderClickListener;
|
||||
private final WidgetsListDrawableFactory mListDrawableFactory;
|
||||
private final WidgetsListAdapter mWidgetsListAdapter;
|
||||
|
||||
public WidgetsListHeaderViewHolderBinder(LayoutInflater layoutInflater,
|
||||
OnHeaderClickListener onHeaderClickListener,
|
||||
WidgetsListDrawableFactory listDrawableFactory,
|
||||
WidgetsListAdapter listAdapter) {
|
||||
mLayoutInflater = layoutInflater;
|
||||
mOnHeaderClickListener = onHeaderClickListener;
|
||||
mListDrawableFactory = listDrawableFactory;
|
||||
mWidgetsListAdapter = listAdapter;
|
||||
}
|
||||
|
||||
@@ -44,7 +47,7 @@ public final class WidgetsListHeaderViewHolderBinder implements
|
||||
public WidgetsListHeaderHolder newViewHolder(ViewGroup parent) {
|
||||
WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
|
||||
R.layout.widgets_list_row_header, parent, false);
|
||||
|
||||
header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
|
||||
return new WidgetsListHeaderHolder(header);
|
||||
}
|
||||
|
||||
@@ -52,12 +55,13 @@ public final class WidgetsListHeaderViewHolderBinder implements
|
||||
public void bindViewHolder(WidgetsListHeaderHolder viewHolder, WidgetsListHeaderEntry data,
|
||||
int position) {
|
||||
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
|
||||
widgetsListHeader.updateListBackground(
|
||||
/* isFirst= */ position == 0,
|
||||
/* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
|
||||
/* isExpanded= */ data.isWidgetListShown());
|
||||
widgetsListHeader.applyFromItemInfoWithIcon(data);
|
||||
widgetsListHeader.setExpanded(data.isWidgetListShown());
|
||||
widgetsListHeader.setListDrawableState(
|
||||
WidgetsListDrawableState.obtain(
|
||||
/* isFirst= */ position == 0,
|
||||
/* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
|
||||
/* isExpanded= */ data.isWidgetListShown()));
|
||||
widgetsListHeader.setOnExpandChangeListener(isExpanded ->
|
||||
mOnHeaderClickListener.onHeaderClicked(
|
||||
isExpanded,
|
||||
|
||||
+9
-5
@@ -31,13 +31,16 @@ public final class WidgetsListSearchHeaderViewHolderBinder implements
|
||||
ViewHolderBinder<WidgetsListSearchHeaderEntry, WidgetsListSearchHeaderHolder> {
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final OnHeaderClickListener mOnHeaderClickListener;
|
||||
private final WidgetsListDrawableFactory mListDrawableFactory;
|
||||
private final WidgetsListAdapter mWidgetsListAdapter;
|
||||
|
||||
public WidgetsListSearchHeaderViewHolderBinder(LayoutInflater layoutInflater,
|
||||
OnHeaderClickListener onHeaderClickListener,
|
||||
WidgetsListDrawableFactory listDrawableFactory,
|
||||
WidgetsListAdapter listAdapter) {
|
||||
mLayoutInflater = layoutInflater;
|
||||
mOnHeaderClickListener = onHeaderClickListener;
|
||||
mListDrawableFactory = listDrawableFactory;
|
||||
mWidgetsListAdapter = listAdapter;
|
||||
}
|
||||
|
||||
@@ -45,7 +48,7 @@ public final class WidgetsListSearchHeaderViewHolderBinder implements
|
||||
public WidgetsListSearchHeaderHolder newViewHolder(ViewGroup parent) {
|
||||
WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
|
||||
R.layout.widgets_list_row_header, parent, false);
|
||||
|
||||
header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
|
||||
return new WidgetsListSearchHeaderHolder(header);
|
||||
}
|
||||
|
||||
@@ -53,12 +56,13 @@ public final class WidgetsListSearchHeaderViewHolderBinder implements
|
||||
public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
|
||||
WidgetsListSearchHeaderEntry data, int position) {
|
||||
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
|
||||
widgetsListHeader.updateListBackground(
|
||||
/* isFirst= */ position == 0,
|
||||
/* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
|
||||
/* isExpanded= */ data.isWidgetListShown());
|
||||
widgetsListHeader.applyFromItemInfoWithIcon(data);
|
||||
widgetsListHeader.setExpanded(data.isWidgetListShown());
|
||||
widgetsListHeader.setListDrawableState(
|
||||
WidgetsListDrawableState.obtain(
|
||||
/* isFirst= */ position == 0,
|
||||
/* isLast= */ position == mWidgetsListAdapter.getItemCount() - 1,
|
||||
/* isExpanded= */ data.isWidgetListShown()));
|
||||
widgetsListHeader.setOnExpandChangeListener(isExpanded ->
|
||||
mOnHeaderClickListener.onHeaderClicked(isExpanded,
|
||||
new PackageUserKey(data.mPkgItem.packageName, data.mPkgItem.user)));
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.widget.picker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TableLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
/**
|
||||
* Extension of {@link TableLayout} to support the drawable states used by
|
||||
* {@link WidgetsListDrawableState}.
|
||||
*/
|
||||
public class WidgetsListTableView extends TableLayout {
|
||||
|
||||
@Nullable private WidgetsListDrawableState mListDrawableState;
|
||||
|
||||
public WidgetsListTableView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public WidgetsListTableView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
/** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */
|
||||
@UiThread
|
||||
public void setListDrawableState(WidgetsListDrawableState state) {
|
||||
if (state == mListDrawableState) return;
|
||||
mListDrawableState = state;
|
||||
refreshDrawableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] onCreateDrawableState(int extraSpace) {
|
||||
if (mListDrawableState == null) return super.onCreateDrawableState(extraSpace);
|
||||
// Augment the state set from the super implementation with the custom states from
|
||||
// mListDrawableState.
|
||||
int[] drawableState =
|
||||
super.onCreateDrawableState(extraSpace + mListDrawableState.mStateSet.length);
|
||||
mergeDrawableStates(drawableState, mListDrawableState.mStateSet);
|
||||
return drawableState;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.android.launcher3.widget.picker;
|
||||
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.LAST;
|
||||
import static com.android.launcher3.widget.picker.WidgetsListDrawableState.MIDDLE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -51,10 +53,8 @@ public final class WidgetsListTableViewHolderBinder
|
||||
private final OnClickListener mIconClickListener;
|
||||
private final OnLongClickListener mIconLongClickListener;
|
||||
private final WidgetPreviewLoader mWidgetPreviewLoader;
|
||||
private final WidgetsListDrawableFactory mListDrawableFactory;
|
||||
private final WidgetsListAdapter mWidgetsListAdapter;
|
||||
private final float mTopBottomCornerRadius;
|
||||
private final float mMiddleCornerRadius;
|
||||
private final float mJoinedCornerRadius;
|
||||
private boolean mApplyBitmapDeferred = false;
|
||||
|
||||
public WidgetsListTableViewHolderBinder(
|
||||
@@ -63,19 +63,14 @@ public final class WidgetsListTableViewHolderBinder
|
||||
OnClickListener iconClickListener,
|
||||
OnLongClickListener iconLongClickListener,
|
||||
WidgetPreviewLoader widgetPreviewLoader,
|
||||
WidgetsListDrawableFactory listDrawableFactory,
|
||||
WidgetsListAdapter listAdapter) {
|
||||
mLayoutInflater = layoutInflater;
|
||||
mIconClickListener = iconClickListener;
|
||||
mIconLongClickListener = iconLongClickListener;
|
||||
mWidgetPreviewLoader = widgetPreviewLoader;
|
||||
mListDrawableFactory = listDrawableFactory;
|
||||
mWidgetsListAdapter = listAdapter;
|
||||
Resources resources = context.getResources();
|
||||
mTopBottomCornerRadius =
|
||||
resources.getDimension(R.dimen.widget_list_top_bottom_corner_radius);
|
||||
mMiddleCornerRadius =
|
||||
resources.getDimension(R.dimen.widget_list_content_corner_radius);
|
||||
mJoinedCornerRadius =
|
||||
resources.getDimension(R.dimen.widget_list_content_joined_corner_radius);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,28 +92,25 @@ public final class WidgetsListTableViewHolderBinder
|
||||
Log.v(TAG, "\nonCreateViewHolder");
|
||||
}
|
||||
|
||||
ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
|
||||
R.layout.widgets_table_container, parent, false);
|
||||
return new WidgetsRowViewHolder(container);
|
||||
WidgetsRowViewHolder viewHolder =
|
||||
new WidgetsRowViewHolder(mLayoutInflater.inflate(
|
||||
R.layout.widgets_table_container, parent, false));
|
||||
viewHolder.mTableContainer.setBackgroundDrawable(
|
||||
mListDrawableFactory.createContentBackgroundDrawable());
|
||||
return viewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindViewHolder(WidgetsRowViewHolder holder, WidgetsListContentEntry entry,
|
||||
int position) {
|
||||
TableLayout table = holder.mTableContainer;
|
||||
WidgetsListTableView table = holder.mTableContainer;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format("onBindViewHolder [widget#=%d, table.getChildCount=%d]",
|
||||
entry.mWidgets.size(), table.getChildCount()));
|
||||
}
|
||||
|
||||
// The content is always joined to an expanded header above.
|
||||
float topRadius = mJoinedCornerRadius;
|
||||
float bottomRadius = position == mWidgetsListAdapter.getItemCount() - 1
|
||||
? mTopBottomCornerRadius
|
||||
: mMiddleCornerRadius;
|
||||
table.setBackgroundDrawable(
|
||||
WidgetsListDrawables.createListBackgroundDrawable(
|
||||
holder.itemView.getContext(), topRadius, bottomRadius));
|
||||
table.setListDrawableState(
|
||||
position == mWidgetsListAdapter.getItemCount() - 1 ? LAST : MIDDLE);
|
||||
|
||||
List<ArrayList<WidgetItem>> widgetItemsTable =
|
||||
WidgetsTableUtils.groupWidgetItemsIntoTable(entry.mWidgets, mMaxSpansPerRow);
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package com.android.launcher3.widget.picker;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TableLayout;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
@@ -25,9 +24,9 @@ import com.android.launcher3.R;
|
||||
/** A {@link ViewHolder} for showing widgets of an app in the full widget picker. */
|
||||
public final class WidgetsRowViewHolder extends ViewHolder {
|
||||
|
||||
public final TableLayout mTableContainer;
|
||||
public final WidgetsListTableView mTableContainer;
|
||||
|
||||
public WidgetsRowViewHolder(ViewGroup v) {
|
||||
public WidgetsRowViewHolder(View v) {
|
||||
super(v);
|
||||
|
||||
mTableContainer = v.findViewById(R.id.widgets_table);
|
||||
|
||||
Reference in New Issue
Block a user