summaryrefslogtreecommitdiff
path: root/java/src/com
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2022-11-28 22:33:51 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-11-28 22:33:51 +0000
commit7d10435590e2230d283758871ae6aae15a22da6e (patch)
treedd26bf4d9c4acdc341d977cdde5145fcde997f1b /java/src/com
parent0919a83ee94b469eba0a72ee6e79fddb1e7dc7f7 (diff)
parent83128998e50f5bce173638b4b25c5722f8267932 (diff)
Merge "Extract ChooserActivity inner ViewHolder classes" into tm-qpr-dev
Diffstat (limited to 'java/src/com')
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java354
-rw-r--r--java/src/com/android/intentresolver/grid/DirectShareViewHolder.java199
-rw-r--r--java/src/com/android/intentresolver/grid/FooterViewHolder.java28
-rw-r--r--java/src/com/android/intentresolver/grid/ItemGroupViewHolder.java76
-rw-r--r--java/src/com/android/intentresolver/grid/ItemViewHolder.java63
-rw-r--r--java/src/com/android/intentresolver/grid/SingleRowViewHolder.java73
-rw-r--r--java/src/com/android/intentresolver/grid/ViewHolderBase.java35
7 files changed, 514 insertions, 314 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 776d34a9..11044a1d 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -26,8 +26,6 @@ import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_S
import static com.android.internal.util.LatencyTracker.ACTION_LOAD_SHARE_SHEET;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -93,7 +91,6 @@ import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
-import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
@@ -114,6 +111,12 @@ import com.android.intentresolver.ResolverListAdapter.ViewHolder;
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.MultiDisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
+import com.android.intentresolver.grid.DirectShareViewHolder;
+import com.android.intentresolver.grid.FooterViewHolder;
+import com.android.intentresolver.grid.ItemGroupViewHolder;
+import com.android.intentresolver.grid.ItemViewHolder;
+import com.android.intentresolver.grid.SingleRowViewHolder;
+import com.android.intentresolver.grid.ViewHolderBase;
import com.android.intentresolver.model.AbstractResolverComparator;
import com.android.intentresolver.model.AppPredictionServiceResolverComparator;
import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
@@ -136,7 +139,6 @@ import java.lang.annotation.RetentionPolicy;
import java.net.URISyntaxException;
import java.text.Collator;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -232,9 +234,9 @@ public class ChooserActivity extends ResolverActivity implements
* The transition time between placeholders for direct share to a message
* indicating that non are available.
*/
- private static final int NO_DIRECT_SHARE_ANIM_IN_MILLIS = 200;
+ public static final int NO_DIRECT_SHARE_ANIM_IN_MILLIS = 200;
- private static final float DIRECT_SHARE_EXPANSION_RATE = 0.78f;
+ public static final float DIRECT_SHARE_EXPANSION_RATE = 0.78f;
private static final int DEFAULT_SALT_EXPIRATION_DAYS = 7;
private final int mMaxHashSaltDays = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
@@ -2210,60 +2212,6 @@ public class ChooserActivity extends ResolverActivity implements
return mContentView;
}
- abstract static class ViewHolderBase extends RecyclerView.ViewHolder {
- private int mViewType;
-
- ViewHolderBase(View itemView, int viewType) {
- super(itemView);
- this.mViewType = viewType;
- }
-
- int getViewType() {
- return mViewType;
- }
- }
-
- /**
- * Used to bind types of individual item including
- * {@link ChooserGridAdapter#VIEW_TYPE_NORMAL},
- * {@link ChooserGridAdapter#VIEW_TYPE_CONTENT_PREVIEW},
- * {@link ChooserGridAdapter#VIEW_TYPE_PROFILE},
- * and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}.
- */
- final class ItemViewHolder extends ViewHolderBase {
- ResolverListAdapter.ViewHolder mWrappedViewHolder;
- int mListPosition = ChooserListAdapter.NO_POSITION;
-
- ItemViewHolder(View itemView, boolean isClickable, int viewType) {
- super(itemView, viewType);
- mWrappedViewHolder = new ResolverListAdapter.ViewHolder(itemView);
- if (isClickable) {
- itemView.setOnClickListener(v -> startSelected(mListPosition,
- false/* always */, true/* filterd */));
-
- itemView.setOnLongClickListener(v -> {
- final TargetInfo ti = mChooserMultiProfilePagerAdapter.getActiveListAdapter()
- .targetInfoForPosition(mListPosition, /* filtered */ true);
-
- // This should always be the case for ItemViewHolder, check for validity
- if (ti.isDisplayResolveInfo()) {
- showTargetDetails(ti);
- }
- return true;
- });
- }
- }
- }
-
- /**
- * Add a footer to the list, to support scrolling behavior below the navbar.
- */
- static final class FooterViewHolder extends ViewHolderBase {
- FooterViewHolder(View itemView, int viewType) {
- super(itemView, viewType);
- }
- }
-
/**
* Intentionally override the {@link ResolverActivity} implementation as we only need that
* implementation for the intent resolver case.
@@ -2503,15 +2451,41 @@ public class ChooserActivity extends ResolverActivity implements
case VIEW_TYPE_CONTENT_PREVIEW:
return new ItemViewHolder(
createContentPreviewView(parent, mPreviewCoordinator),
- false,
- viewType);
+ viewType,
+ null,
+ null);
case VIEW_TYPE_PROFILE:
- return new ItemViewHolder(createProfileView(parent), false, viewType);
+ return new ItemViewHolder(
+ createProfileView(parent),
+ viewType,
+ null,
+ null);
case VIEW_TYPE_AZ_LABEL:
- return new ItemViewHolder(createAzLabelView(parent), false, viewType);
+ return new ItemViewHolder(
+ createAzLabelView(parent),
+ viewType,
+ null,
+ null);
case VIEW_TYPE_NORMAL:
return new ItemViewHolder(
- mChooserListAdapter.createView(parent), true, viewType);
+ mChooserListAdapter.createView(parent),
+ viewType,
+ selectedPosition -> startSelected(
+ selectedPosition,
+ /* always= */ false,
+ /* filtered= */ true),
+ selectedPosition -> {
+ final TargetInfo longPressedTargetInfo =
+ mChooserMultiProfilePagerAdapter
+ .getActiveListAdapter()
+ .targetInfoForPosition(
+ selectedPosition, /* filtered= */ true);
+ // ItemViewHolder contents should always be "display resolve info"
+ // targets, but check just to make sure.
+ if (longPressedTargetInfo.isDisplayResolveInfo()) {
+ showTargetDetails(longPressedTargetInfo);
+ }
+ });
case VIEW_TYPE_DIRECT_SHARE:
case VIEW_TYPE_CALLER_AND_RANK:
return createItemGroupViewHolder(viewType, parent);
@@ -2704,7 +2678,7 @@ public class ChooserActivity extends ResolverActivity implements
void bindItemViewHolder(int position, ItemViewHolder holder) {
View v = holder.itemView;
int listPosition = getListPosition(position);
- holder.mListPosition = listPosition;
+ holder.setListPosition(listPosition);
mChooserListAdapter.bindView(listPosition, v);
}
@@ -2821,254 +2795,6 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- /**
- * Used to bind types for group of items including:
- * {@link ChooserGridAdapter#VIEW_TYPE_DIRECT_SHARE},
- * and {@link ChooserGridAdapter#VIEW_TYPE_CALLER_AND_RANK}.
- */
- abstract static class ItemGroupViewHolder extends ViewHolderBase {
- protected int mMeasuredRowHeight;
- private int[] mItemIndices;
- protected final View[] mCells;
- private final int mColumnCount;
-
- ItemGroupViewHolder(int cellCount, View itemView, int viewType) {
- super(itemView, viewType);
- this.mCells = new View[cellCount];
- this.mItemIndices = new int[cellCount];
- this.mColumnCount = cellCount;
- }
-
- abstract ViewGroup addView(int index, View v);
-
- abstract ViewGroup getViewGroup();
-
- abstract ViewGroup getRowByIndex(int index);
-
- abstract ViewGroup getRow(int rowNumber);
-
- abstract void setViewVisibility(int i, int visibility);
-
- public int getColumnCount() {
- return mColumnCount;
- }
-
- public void measure() {
- final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- getViewGroup().measure(spec, spec);
- mMeasuredRowHeight = getViewGroup().getMeasuredHeight();
- }
-
- public int getMeasuredRowHeight() {
- return mMeasuredRowHeight;
- }
-
- public void setItemIndex(int itemIndex, int listIndex) {
- mItemIndices[itemIndex] = listIndex;
- }
-
- public int getItemIndex(int itemIndex) {
- return mItemIndices[itemIndex];
- }
-
- public View getView(int index) {
- return mCells[index];
- }
- }
-
- static class SingleRowViewHolder extends ItemGroupViewHolder {
- private final ViewGroup mRow;
-
- SingleRowViewHolder(ViewGroup row, int cellCount, int viewType) {
- super(cellCount, row, viewType);
-
- this.mRow = row;
- }
-
- public ViewGroup getViewGroup() {
- return mRow;
- }
-
- public ViewGroup getRowByIndex(int index) {
- return mRow;
- }
-
- public ViewGroup getRow(int rowNumber) {
- if (rowNumber == 0) return mRow;
- return null;
- }
-
- public ViewGroup addView(int index, View v) {
- mRow.addView(v);
- mCells[index] = v;
-
- return mRow;
- }
-
- public void setViewVisibility(int i, int visibility) {
- getView(i).setVisibility(visibility);
- }
- }
-
- static class DirectShareViewHolder extends ItemGroupViewHolder {
- private final ViewGroup mParent;
- private final List<ViewGroup> mRows;
- private int mCellCountPerRow;
-
- private boolean mHideDirectShareExpansion = false;
- private int mDirectShareMinHeight = 0;
- private int mDirectShareCurrHeight = 0;
- private int mDirectShareMaxHeight = 0;
-
- private final boolean[] mCellVisibility;
-
- private final Supplier<ChooserListAdapter> mListAdapterSupplier;
-
- DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow,
- int viewType, Supplier<ChooserListAdapter> listAdapterSupplier) {
- super(rows.size() * cellCountPerRow, parent, viewType);
-
- this.mParent = parent;
- this.mRows = rows;
- this.mCellCountPerRow = cellCountPerRow;
- this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
- Arrays.fill(mCellVisibility, true);
- this.mListAdapterSupplier = listAdapterSupplier;
- }
-
- public ViewGroup addView(int index, View v) {
- ViewGroup row = getRowByIndex(index);
- row.addView(v);
- mCells[index] = v;
-
- return row;
- }
-
- public ViewGroup getViewGroup() {
- return mParent;
- }
-
- public ViewGroup getRowByIndex(int index) {
- return mRows.get(index / mCellCountPerRow);
- }
-
- public ViewGroup getRow(int rowNumber) {
- return mRows.get(rowNumber);
- }
-
- public void measure() {
- final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- getRow(0).measure(spec, spec);
- getRow(1).measure(spec, spec);
-
- mDirectShareMinHeight = getRow(0).getMeasuredHeight();
- mDirectShareCurrHeight = mDirectShareCurrHeight > 0
- ? mDirectShareCurrHeight : mDirectShareMinHeight;
- mDirectShareMaxHeight = 2 * mDirectShareMinHeight;
- }
-
- public int getMeasuredRowHeight() {
- return mDirectShareCurrHeight;
- }
-
- public int getMinRowHeight() {
- return mDirectShareMinHeight;
- }
-
- public void setViewVisibility(int i, int visibility) {
- final View v = getView(i);
- if (visibility == View.VISIBLE) {
- mCellVisibility[i] = true;
- v.setVisibility(visibility);
- v.setAlpha(1.0f);
- } else if (visibility == View.INVISIBLE && mCellVisibility[i]) {
- mCellVisibility[i] = false;
-
- ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f);
- fadeAnim.setDuration(NO_DIRECT_SHARE_ANIM_IN_MILLIS);
- fadeAnim.setInterpolator(new AccelerateInterpolator(1.0f));
- fadeAnim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- v.setVisibility(View.INVISIBLE);
- }
- });
- fadeAnim.start();
- }
- }
-
- public void handleScroll(RecyclerView view, int y, int oldy, int maxTargetsPerRow) {
- // only exit early if fully collapsed, otherwise onListRebuilt() with shifting
- // targets can lock us into an expanded mode
- boolean notExpanded = mDirectShareCurrHeight == mDirectShareMinHeight;
- if (notExpanded) {
- if (mHideDirectShareExpansion) {
- return;
- }
-
- // only expand if we have more than maxTargetsPerRow, and delay that decision
- // until they start to scroll
- ChooserListAdapter adapter = mListAdapterSupplier.get();
- int validTargets = adapter.getSelectableServiceTargetCount();
- if (validTargets <= maxTargetsPerRow) {
- mHideDirectShareExpansion = true;
- return;
- }
- }
-
- int yDiff = (int) ((oldy - y) * DIRECT_SHARE_EXPANSION_RATE);
-
- int prevHeight = mDirectShareCurrHeight;
- int newHeight = Math.min(prevHeight + yDiff, mDirectShareMaxHeight);
- newHeight = Math.max(newHeight, mDirectShareMinHeight);
- yDiff = newHeight - prevHeight;
-
- updateDirectShareRowHeight(view, yDiff, newHeight);
- }
-
- void expand(RecyclerView view) {
- updateDirectShareRowHeight(view, mDirectShareMaxHeight - mDirectShareCurrHeight,
- mDirectShareMaxHeight);
- }
-
- void collapse(RecyclerView view) {
- updateDirectShareRowHeight(view, mDirectShareMinHeight - mDirectShareCurrHeight,
- mDirectShareMinHeight);
- }
-
- private void updateDirectShareRowHeight(RecyclerView view, int yDiff, int newHeight) {
- if (view == null || view.getChildCount() == 0 || yDiff == 0) {
- return;
- }
-
- // locate the item to expand, and offset the rows below that one
- boolean foundExpansion = false;
- for (int i = 0; i < view.getChildCount(); i++) {
- View child = view.getChildAt(i);
-
- if (foundExpansion) {
- child.offsetTopAndBottom(yDiff);
- } else {
- if (child.getTag() != null && child.getTag() instanceof DirectShareViewHolder) {
- int widthSpec = MeasureSpec.makeMeasureSpec(child.getWidth(),
- MeasureSpec.EXACTLY);
- int heightSpec = MeasureSpec.makeMeasureSpec(newHeight,
- MeasureSpec.EXACTLY);
- child.measure(widthSpec, heightSpec);
- child.getLayoutParams().height = child.getMeasuredHeight();
- child.layout(child.getLeft(), child.getTop(), child.getRight(),
- child.getTop() + child.getMeasuredHeight());
-
- foundExpansion = true;
- }
- }
- }
-
- if (foundExpansion) {
- mDirectShareCurrHeight = newHeight;
- }
- }
- }
-
static class ChooserTargetRankingInfo {
public final List<AppTarget> scores;
public final UserHandle userHandle;
diff --git a/java/src/com/android/intentresolver/grid/DirectShareViewHolder.java b/java/src/com/android/intentresolver/grid/DirectShareViewHolder.java
new file mode 100644
index 00000000..95c61e3a
--- /dev/null
+++ b/java/src/com/android/intentresolver/grid/DirectShareViewHolder.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2022 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.intentresolver.grid;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.intentresolver.ChooserActivity;
+import com.android.intentresolver.ChooserListAdapter;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Supplier;
+
+/** Holder for direct share targets in the {@link ChooserGridAdapter}. */
+public class DirectShareViewHolder extends ItemGroupViewHolder {
+ private final ViewGroup mParent;
+ private final List<ViewGroup> mRows;
+ private int mCellCountPerRow;
+
+ private boolean mHideDirectShareExpansion = false;
+ private int mDirectShareMinHeight = 0;
+ private int mDirectShareCurrHeight = 0;
+ private int mDirectShareMaxHeight = 0;
+
+ private final boolean[] mCellVisibility;
+
+ private final Supplier<ChooserListAdapter> mListAdapterSupplier;
+
+ public DirectShareViewHolder(
+ ViewGroup parent,
+ List<ViewGroup> rows,
+ int cellCountPerRow,
+ int viewType,
+ Supplier<ChooserListAdapter> listAdapterSupplier) {
+ super(rows.size() * cellCountPerRow, parent, viewType);
+
+ this.mParent = parent;
+ this.mRows = rows;
+ this.mCellCountPerRow = cellCountPerRow;
+ this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
+ Arrays.fill(mCellVisibility, true);
+ this.mListAdapterSupplier = listAdapterSupplier;
+ }
+
+ public ViewGroup addView(int index, View v) {
+ ViewGroup row = getRowByIndex(index);
+ row.addView(v);
+ mCells[index] = v;
+
+ return row;
+ }
+
+ public ViewGroup getViewGroup() {
+ return mParent;
+ }
+
+ public ViewGroup getRowByIndex(int index) {
+ return mRows.get(index / mCellCountPerRow);
+ }
+
+ public ViewGroup getRow(int rowNumber) {
+ return mRows.get(rowNumber);
+ }
+
+ public void measure() {
+ final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ getRow(0).measure(spec, spec);
+ getRow(1).measure(spec, spec);
+
+ mDirectShareMinHeight = getRow(0).getMeasuredHeight();
+ mDirectShareCurrHeight = (mDirectShareCurrHeight > 0)
+ ? mDirectShareCurrHeight : mDirectShareMinHeight;
+ mDirectShareMaxHeight = 2 * mDirectShareMinHeight;
+ }
+
+ public int getMeasuredRowHeight() {
+ return mDirectShareCurrHeight;
+ }
+
+ public int getMinRowHeight() {
+ return mDirectShareMinHeight;
+ }
+
+ public void setViewVisibility(int i, int visibility) {
+ final View v = getView(i);
+ if (visibility == View.VISIBLE) {
+ mCellVisibility[i] = true;
+ v.setVisibility(visibility);
+ v.setAlpha(1.0f);
+ } else if (visibility == View.INVISIBLE && mCellVisibility[i]) {
+ mCellVisibility[i] = false;
+
+ ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f);
+ fadeAnim.setDuration(ChooserActivity.NO_DIRECT_SHARE_ANIM_IN_MILLIS);
+ fadeAnim.setInterpolator(new AccelerateInterpolator(1.0f));
+ fadeAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ v.setVisibility(View.INVISIBLE);
+ }
+ });
+ fadeAnim.start();
+ }
+ }
+
+ public void handleScroll(RecyclerView view, int y, int oldy, int maxTargetsPerRow) {
+ // only exit early if fully collapsed, otherwise onListRebuilt() with shifting
+ // targets can lock us into an expanded mode
+ boolean notExpanded = mDirectShareCurrHeight == mDirectShareMinHeight;
+ if (notExpanded) {
+ if (mHideDirectShareExpansion) {
+ return;
+ }
+
+ // only expand if we have more than maxTargetsPerRow, and delay that decision
+ // until they start to scroll
+ ChooserListAdapter adapter = mListAdapterSupplier.get();
+ int validTargets = adapter.getSelectableServiceTargetCount();
+ if (validTargets <= maxTargetsPerRow) {
+ mHideDirectShareExpansion = true;
+ return;
+ }
+ }
+
+ int yDiff = (int) ((oldy - y) * ChooserActivity.DIRECT_SHARE_EXPANSION_RATE);
+
+ int prevHeight = mDirectShareCurrHeight;
+ int newHeight = Math.min(prevHeight + yDiff, mDirectShareMaxHeight);
+ newHeight = Math.max(newHeight, mDirectShareMinHeight);
+ yDiff = newHeight - prevHeight;
+
+ updateDirectShareRowHeight(view, yDiff, newHeight);
+ }
+
+ public void expand(RecyclerView view) {
+ updateDirectShareRowHeight(
+ view, mDirectShareMaxHeight - mDirectShareCurrHeight, mDirectShareMaxHeight);
+ }
+
+ public void collapse(RecyclerView view) {
+ updateDirectShareRowHeight(
+ view, mDirectShareMinHeight - mDirectShareCurrHeight, mDirectShareMinHeight);
+ }
+
+ private void updateDirectShareRowHeight(RecyclerView view, int yDiff, int newHeight) {
+ if (view == null || view.getChildCount() == 0 || yDiff == 0) {
+ return;
+ }
+
+ // locate the item to expand, and offset the rows below that one
+ boolean foundExpansion = false;
+ for (int i = 0; i < view.getChildCount(); i++) {
+ View child = view.getChildAt(i);
+
+ if (foundExpansion) {
+ child.offsetTopAndBottom(yDiff);
+ } else {
+ if (child.getTag() != null && child.getTag() instanceof DirectShareViewHolder) {
+ int widthSpec = MeasureSpec.makeMeasureSpec(child.getWidth(),
+ MeasureSpec.EXACTLY);
+ int heightSpec = MeasureSpec.makeMeasureSpec(newHeight,
+ MeasureSpec.EXACTLY);
+ child.measure(widthSpec, heightSpec);
+ child.getLayoutParams().height = child.getMeasuredHeight();
+ child.layout(child.getLeft(), child.getTop(), child.getRight(),
+ child.getTop() + child.getMeasuredHeight());
+
+ foundExpansion = true;
+ }
+ }
+ }
+
+ if (foundExpansion) {
+ mDirectShareCurrHeight = newHeight;
+ }
+ }
+}
diff --git a/java/src/com/android/intentresolver/grid/FooterViewHolder.java b/java/src/com/android/intentresolver/grid/FooterViewHolder.java
new file mode 100644
index 00000000..0c94e3ed
--- /dev/null
+++ b/java/src/com/android/intentresolver/grid/FooterViewHolder.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 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.intentresolver.grid;
+
+import android.view.View;
+
+/**
+ * A footer on the list, to support scrolling behavior below the navbar.
+ */
+public final class FooterViewHolder extends ViewHolderBase {
+ public FooterViewHolder(View itemView, int viewType) {
+ super(itemView, viewType);
+ }
+}
diff --git a/java/src/com/android/intentresolver/grid/ItemGroupViewHolder.java b/java/src/com/android/intentresolver/grid/ItemGroupViewHolder.java
new file mode 100644
index 00000000..5470506b
--- /dev/null
+++ b/java/src/com/android/intentresolver/grid/ItemGroupViewHolder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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.intentresolver.grid;
+
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+
+/**
+ * Used to bind types for group of items including:
+ * {@link ChooserGridAdapter#VIEW_TYPE_DIRECT_SHARE},
+ * and {@link ChooserGridAdapter#VIEW_TYPE_CALLER_AND_RANK}.
+ */
+public abstract class ItemGroupViewHolder extends ViewHolderBase {
+ protected int mMeasuredRowHeight;
+ private int[] mItemIndices;
+ protected final View[] mCells;
+ private final int mColumnCount;
+
+ public ItemGroupViewHolder(int cellCount, View itemView, int viewType) {
+ super(itemView, viewType);
+ this.mCells = new View[cellCount];
+ this.mItemIndices = new int[cellCount];
+ this.mColumnCount = cellCount;
+ }
+
+ public abstract ViewGroup addView(int index, View v);
+
+ public abstract ViewGroup getViewGroup();
+
+ public abstract ViewGroup getRowByIndex(int index);
+
+ public abstract ViewGroup getRow(int rowNumber);
+
+ public abstract void setViewVisibility(int i, int visibility);
+
+ public int getColumnCount() {
+ return mColumnCount;
+ }
+
+ public void measure() {
+ final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ getViewGroup().measure(spec, spec);
+ mMeasuredRowHeight = getViewGroup().getMeasuredHeight();
+ }
+
+ public int getMeasuredRowHeight() {
+ return mMeasuredRowHeight;
+ }
+
+ public void setItemIndex(int itemIndex, int listIndex) {
+ mItemIndices[itemIndex] = listIndex;
+ }
+
+ public int getItemIndex(int itemIndex) {
+ return mItemIndices[itemIndex];
+ }
+
+ public View getView(int index) {
+ return mCells[index];
+ }
+}
diff --git a/java/src/com/android/intentresolver/grid/ItemViewHolder.java b/java/src/com/android/intentresolver/grid/ItemViewHolder.java
new file mode 100644
index 00000000..2ec56b1b
--- /dev/null
+++ b/java/src/com/android/intentresolver/grid/ItemViewHolder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 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.intentresolver.grid;
+
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.intentresolver.ChooserListAdapter;
+import com.android.intentresolver.ResolverListAdapter;
+
+import java.util.function.Consumer;
+
+/**
+ * Used to bind types of individual item including
+ * {@link ChooserGridAdapter#VIEW_TYPE_NORMAL},
+ * {@link ChooserGridAdapter#VIEW_TYPE_CONTENT_PREVIEW},
+ * {@link ChooserGridAdapter#VIEW_TYPE_PROFILE},
+ * and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}.
+ */
+public final class ItemViewHolder extends ViewHolderBase {
+ private final ResolverListAdapter.ViewHolder mWrappedViewHolder;
+
+ private int mListPosition = ChooserListAdapter.NO_POSITION;
+
+ public ItemViewHolder(
+ View itemView,
+ int viewType,
+ @Nullable Consumer<Integer> onClick,
+ @Nullable Consumer<Integer> onLongClick) {
+ super(itemView, viewType);
+ mWrappedViewHolder = new ResolverListAdapter.ViewHolder(itemView);
+
+ if (onClick != null) {
+ itemView.setOnClickListener(v -> onClick.accept(mListPosition));
+ }
+
+ if (onLongClick != null) {
+ itemView.setOnLongClickListener(v -> {
+ onLongClick.accept(mListPosition);
+ return true;
+ });
+ }
+ }
+
+ public void setListPosition(int listPosition) {
+ mListPosition = listPosition;
+ }
+}
diff --git a/java/src/com/android/intentresolver/grid/SingleRowViewHolder.java b/java/src/com/android/intentresolver/grid/SingleRowViewHolder.java
new file mode 100644
index 00000000..a72da7aa
--- /dev/null
+++ b/java/src/com/android/intentresolver/grid/SingleRowViewHolder.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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.intentresolver.grid;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+/** Holder for a group of items displayed in a single row of the {@link ChooserGridAdapter}. */
+public final class SingleRowViewHolder extends ItemGroupViewHolder {
+ private final ViewGroup mRow;
+
+ public SingleRowViewHolder(ViewGroup row, int cellCount, int viewType) {
+ super(cellCount, row, viewType);
+
+ this.mRow = row;
+ }
+
+ /** Get the group of all views in this holder. */
+ public ViewGroup getViewGroup() {
+ return mRow;
+ }
+
+ /**
+ * Get the group of views for the row containing the specified cell index.
+ * TODO: unclear if that's what this `index` meant. It doesn't matter for our "single row"
+ * holders, and it doesn't look like this is an override from some other interface; maybe we can
+ * just remove?
+ */
+ public ViewGroup getRowByIndex(int index) {
+ return mRow;
+ }
+
+ /** Get the group of views for the specified {@code rowNumber}, if any. */
+ public ViewGroup getRow(int rowNumber) {
+ if (rowNumber == 0) {
+ return mRow;
+ }
+ return null;
+ }
+
+ /**
+ * @param index the index of the cell to add the view into.
+ * @param v the view to add into the cell.
+ */
+ public ViewGroup addView(int index, View v) {
+ mRow.addView(v);
+ mCells[index] = v;
+
+ return mRow;
+ }
+
+ /**
+ * @param i the index of the cell containing the view to modify.
+ * @param visibility the new visibility to set on the view with the specified index.
+ */
+ public void setViewVisibility(int i, int visibility) {
+ getView(i).setVisibility(visibility);
+ }
+}
diff --git a/java/src/com/android/intentresolver/grid/ViewHolderBase.java b/java/src/com/android/intentresolver/grid/ViewHolderBase.java
new file mode 100644
index 00000000..78e9104a
--- /dev/null
+++ b/java/src/com/android/intentresolver/grid/ViewHolderBase.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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.intentresolver.grid;
+
+import android.view.View;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+/** Base class for all {@link RecyclerView.ViewHolder} types in the {@link ChooserGridAdapter}. */
+public abstract class ViewHolderBase extends RecyclerView.ViewHolder {
+ private int mViewType;
+
+ ViewHolderBase(View itemView, int viewType) {
+ super(itemView);
+ this.mViewType = viewType;
+ }
+
+ public int getViewType() {
+ return mViewType;
+ }
+}