1 /*
2  * Copyright (C) 2021 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 package com.android.launcher3.widget.picker;
17 
18 import static android.view.View.MeasureSpec.EXACTLY;
19 import static android.view.View.MeasureSpec.makeMeasureSpec;
20 
21 import android.content.Context;
22 import android.view.View;
23 import android.view.ViewGroup;
24 
25 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
26 
27 import com.android.launcher3.recyclerview.ViewHolderBinder;
28 import com.android.launcher3.widget.model.WidgetListSpaceEntry;
29 
30 import java.util.List;
31 import java.util.function.IntSupplier;
32 
33 /**
34  * {@link ViewHolderBinder} for binding the top empty space
35  */
36 public class WidgetsSpaceViewHolderBinder
37         implements ViewHolderBinder<WidgetListSpaceEntry, ViewHolder> {
38 
39     private final IntSupplier mEmptySpaceHeightProvider;
40 
WidgetsSpaceViewHolderBinder(IntSupplier emptySpaceHeightProvider)41     public WidgetsSpaceViewHolderBinder(IntSupplier emptySpaceHeightProvider) {
42         mEmptySpaceHeightProvider = emptySpaceHeightProvider;
43     }
44 
45     @Override
newViewHolder(ViewGroup parent)46     public ViewHolder newViewHolder(ViewGroup parent) {
47         return new ViewHolder(new EmptySpaceView(parent.getContext())) { };
48     }
49 
50     @Override
bindViewHolder(ViewHolder holder, WidgetListSpaceEntry data, @ListPosition int position, List<Object> payloads)51     public void bindViewHolder(ViewHolder holder, WidgetListSpaceEntry data,
52             @ListPosition int position, List<Object> payloads) {
53         ((EmptySpaceView) holder.itemView).setFixedHeight(mEmptySpaceHeightProvider.getAsInt());
54     }
55 
56     /**
57      * Empty view which allows listening for 'Y' changes
58      */
59     public static class EmptySpaceView extends View {
60 
61         private Runnable mOnYChangeCallback;
62         private int mHeight = 0;
63 
EmptySpaceView(Context context)64         private EmptySpaceView(Context context) {
65             super(context);
66             animate().setUpdateListener(v -> notifyYChanged());
67         }
68 
69         /**
70          * Sets the height for the empty view
71          * @return true if the height changed, false otherwise
72          */
setFixedHeight(int height)73         public boolean setFixedHeight(int height) {
74             if (mHeight != height) {
75                 mHeight = height;
76                 requestLayout();
77                 return true;
78             }
79             return false;
80         }
81 
82         @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)83         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
84             super.onMeasure(widthMeasureSpec, makeMeasureSpec(mHeight, EXACTLY));
85         }
86 
setOnYChangeCallback(Runnable callback)87         public void setOnYChangeCallback(Runnable callback) {
88             mOnYChangeCallback = callback;
89         }
90 
91         @Override
onLayout(boolean changed, int left, int top, int right, int bottom)92         protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
93             super.onLayout(changed, left, top, right, bottom);
94             notifyYChanged();
95         }
96 
97         @Override
offsetTopAndBottom(int offset)98         public void offsetTopAndBottom(int offset) {
99             super.offsetTopAndBottom(offset);
100             notifyYChanged();
101         }
102 
103         @Override
setTranslationY(float translationY)104         public void setTranslationY(float translationY) {
105             super.setTranslationY(translationY);
106             notifyYChanged();
107         }
108 
notifyYChanged()109         private void notifyYChanged() {
110             if (mOnYChangeCallback != null) {
111                 mOnYChangeCallback.run();
112             }
113         }
114     }
115 }
116