• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.intentresolver.grid;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ObjectAnimator;
22 import android.animation.ValueAnimator;
23 import android.view.View;
24 import android.view.View.MeasureSpec;
25 import android.view.ViewGroup;
26 import android.view.animation.AccelerateInterpolator;
27 
28 import androidx.recyclerview.widget.RecyclerView;
29 
30 import com.android.intentresolver.ChooserActivity;
31 
32 import java.util.Arrays;
33 import java.util.List;
34 import java.util.function.Supplier;
35 
36 /** Holder for direct share targets in the {@link ChooserGridAdapter}. */
37 public class DirectShareViewHolder extends ItemGroupViewHolder {
38     private final ViewGroup mParent;
39     private final List<ViewGroup> mRows;
40     private int mCellCountPerRow;
41 
42     private boolean mHideDirectShareExpansion = false;
43     private int mDirectShareMinHeight = 0;
44     private int mDirectShareCurrHeight = 0;
45     private int mDirectShareMaxHeight = 0;
46 
47     private final boolean[] mCellVisibility;
48 
49     private final Supplier<Integer> mDeferredTargetCountSupplier;
50 
DirectShareViewHolder( ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow, int viewType, Supplier<Integer> deferredTargetCountSupplier)51     public DirectShareViewHolder(
52             ViewGroup parent,
53             List<ViewGroup> rows,
54             int cellCountPerRow,
55             int viewType,
56             Supplier<Integer> deferredTargetCountSupplier) {
57         super(rows.size() * cellCountPerRow, parent, viewType);
58 
59         this.mParent = parent;
60         this.mRows = rows;
61         this.mCellCountPerRow = cellCountPerRow;
62         this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
63         Arrays.fill(mCellVisibility, true);
64         this.mDeferredTargetCountSupplier = deferredTargetCountSupplier;
65     }
66 
addView(int index, View v)67     public ViewGroup addView(int index, View v) {
68         ViewGroup row = getRowByIndex(index);
69         row.addView(v);
70         mCells[index] = v;
71 
72         return row;
73     }
74 
getViewGroup()75     public ViewGroup getViewGroup() {
76         return mParent;
77     }
78 
getRowByIndex(int index)79     public ViewGroup getRowByIndex(int index) {
80         return mRows.get(index / mCellCountPerRow);
81     }
82 
getRow(int rowNumber)83     public ViewGroup getRow(int rowNumber) {
84         return mRows.get(rowNumber);
85     }
86 
measure()87     public void measure() {
88         final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
89         getRow(0).measure(spec, spec);
90         getRow(1).measure(spec, spec);
91 
92         mDirectShareMinHeight = getRow(0).getMeasuredHeight();
93         mDirectShareCurrHeight = (mDirectShareCurrHeight > 0)
94                 ? mDirectShareCurrHeight : mDirectShareMinHeight;
95         mDirectShareMaxHeight = 2 * mDirectShareMinHeight;
96     }
97 
getMeasuredRowHeight()98     public int getMeasuredRowHeight() {
99         return mDirectShareCurrHeight;
100     }
101 
getMinRowHeight()102     public int getMinRowHeight() {
103         return mDirectShareMinHeight;
104     }
105 
setViewVisibility(int i, int visibility)106     public void setViewVisibility(int i, int visibility) {
107         final View v = getView(i);
108         if (visibility == View.VISIBLE) {
109             mCellVisibility[i] = true;
110             v.setVisibility(visibility);
111             v.setAlpha(1.0f);
112         } else if (visibility == View.INVISIBLE && mCellVisibility[i]) {
113             mCellVisibility[i] = false;
114 
115             ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f);
116             fadeAnim.setDuration(ChooserGridAdapter.NO_DIRECT_SHARE_ANIM_IN_MILLIS);
117             fadeAnim.setInterpolator(new AccelerateInterpolator(1.0f));
118             fadeAnim.addListener(new AnimatorListenerAdapter() {
119                 public void onAnimationEnd(Animator animation) {
120                     v.setVisibility(View.INVISIBLE);
121                 }
122             });
123             fadeAnim.start();
124         }
125     }
126 
handleScroll(RecyclerView view, int y, int oldy, int maxTargetsPerRow)127     public void handleScroll(RecyclerView view, int y, int oldy, int maxTargetsPerRow) {
128         // only exit early if fully collapsed, otherwise onListRebuilt() with shifting
129         // targets can lock us into an expanded mode
130         boolean notExpanded = mDirectShareCurrHeight == mDirectShareMinHeight;
131         if (notExpanded) {
132             if (mHideDirectShareExpansion) {
133                 return;
134             }
135 
136             // only expand if we have more than maxTargetsPerRow, and delay that decision
137             // until they start to scroll
138             final int validTargets = this.mDeferredTargetCountSupplier.get();
139             if (validTargets <= maxTargetsPerRow) {
140                 mHideDirectShareExpansion = true;
141                 return;
142             }
143         }
144 
145         int yDiff = (int) ((oldy - y) * ChooserActivity.DIRECT_SHARE_EXPANSION_RATE);
146 
147         int prevHeight = mDirectShareCurrHeight;
148         int newHeight = Math.min(prevHeight + yDiff, mDirectShareMaxHeight);
149         newHeight = Math.max(newHeight, mDirectShareMinHeight);
150         yDiff = newHeight - prevHeight;
151 
152         updateDirectShareRowHeight(view, yDiff, newHeight);
153     }
154 
expand(RecyclerView view)155     public void expand(RecyclerView view) {
156         updateDirectShareRowHeight(
157                 view, mDirectShareMaxHeight - mDirectShareCurrHeight, mDirectShareMaxHeight);
158     }
159 
collapse(RecyclerView view)160     public void collapse(RecyclerView view) {
161         updateDirectShareRowHeight(
162                 view, mDirectShareMinHeight - mDirectShareCurrHeight, mDirectShareMinHeight);
163     }
164 
updateDirectShareRowHeight(RecyclerView view, int yDiff, int newHeight)165     private void updateDirectShareRowHeight(RecyclerView view, int yDiff, int newHeight) {
166         if (view == null || view.getChildCount() == 0 || yDiff == 0) {
167             return;
168         }
169 
170         // locate the item to expand, and offset the rows below that one
171         boolean foundExpansion = false;
172         for (int i = 0; i < view.getChildCount(); i++) {
173             View child = view.getChildAt(i);
174 
175             if (foundExpansion) {
176                 child.offsetTopAndBottom(yDiff);
177             } else {
178                 if (child.getTag() != null && child.getTag() instanceof DirectShareViewHolder) {
179                     int widthSpec = MeasureSpec.makeMeasureSpec(child.getWidth(),
180                             MeasureSpec.EXACTLY);
181                     int heightSpec = MeasureSpec.makeMeasureSpec(newHeight,
182                             MeasureSpec.EXACTLY);
183                     child.measure(widthSpec, heightSpec);
184                     child.getLayoutParams().height = child.getMeasuredHeight();
185                     child.layout(child.getLeft(), child.getTop(), child.getRight(),
186                             child.getTop() + child.getMeasuredHeight());
187 
188                     foundExpansion = true;
189                 }
190             }
191         }
192 
193         if (foundExpansion) {
194             mDirectShareCurrHeight = newHeight;
195         }
196     }
197 }
198