blob: 03623d518305ecea7b37f54a6c96c79d81176259 [file] [log] [blame]
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -07001/*
2 * Copyright (C) 2017 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 */
Steven Ng2f5648a2021-02-08 17:18:25 +000016package com.android.launcher3.widget.picker;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070017
Sunny Goyalf3ac7032020-03-13 13:01:33 -070018import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
vadimt9f48a8e2019-12-11 11:52:37 -080019import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
20
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
23import android.animation.PropertyValuesHolder;
24import android.content.Context;
25import android.graphics.Rect;
26import android.util.AttributeSet;
Sunny Goyalde753212018-05-15 13:55:57 -070027import android.util.Pair;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070028import android.view.LayoutInflater;
29import android.view.MotionEvent;
Sunny Goyalde753212018-05-15 13:55:57 -070030import android.view.View;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070031import android.view.animation.AnimationUtils;
Sunny Goyalf3ac7032020-03-13 13:01:33 -070032import android.view.animation.Interpolator;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070033
Tony Wickham9791bd12019-04-05 13:52:35 -070034import androidx.annotation.VisibleForTesting;
35
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070036import com.android.launcher3.Insettable;
37import com.android.launcher3.Launcher;
38import com.android.launcher3.LauncherAppState;
39import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
40import com.android.launcher3.R;
Sunny Goyalf3ac7032020-03-13 13:01:33 -070041import com.android.launcher3.anim.PendingAnimation;
vadimt9f48a8e2019-12-11 11:52:37 -080042import com.android.launcher3.compat.AccessibilityManagerCompat;
Sunny Goyal3661bfa2018-03-01 16:29:15 -080043import com.android.launcher3.views.RecyclerViewFastScroller;
44import com.android.launcher3.views.TopRoundedCornerView;
Steven Ng2f5648a2021-02-08 17:18:25 +000045import com.android.launcher3.widget.BaseWidgetSheet;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070046
47/**
48 * Popup for showing the full list of available widgets
49 */
50public class WidgetsFullSheet extends BaseWidgetSheet
51 implements Insettable, ProviderChangedListener {
52
53 private static final long DEFAULT_OPEN_DURATION = 267;
54 private static final long FADE_IN_DURATION = 150;
55 private static final float VERTICAL_START_POSITION = 0.3f;
56
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070057 private final Rect mInsets = new Rect();
58
59 private final WidgetsListAdapter mAdapter;
60
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070061 private WidgetsRecyclerView mRecyclerView;
62
63 public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
64 super(context, attrs, defStyleAttr);
65 LauncherAppState apps = LauncherAppState.getInstance(context);
66 mAdapter = new WidgetsListAdapter(context,
67 LayoutInflater.from(context), apps.getWidgetCache(), apps.getIconCache(),
68 this, this);
Sunny Goyalde753212018-05-15 13:55:57 -070069
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070070 }
71
72 public WidgetsFullSheet(Context context, AttributeSet attrs) {
73 this(context, attrs, 0);
74 }
75
76 @Override
77 protected void onFinishInflate() {
78 super.onFinishInflate();
79 mContent = findViewById(R.id.container);
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070080
81 mRecyclerView = findViewById(R.id.widgets_list_view);
82 mRecyclerView.setAdapter(mAdapter);
83 mAdapter.setApplyBitmapDeferred(true, mRecyclerView);
84
Sunny Goyal016d7e92018-03-09 11:09:20 -080085 TopRoundedCornerView springLayout = (TopRoundedCornerView) mContent;
86 springLayout.addSpringView(R.id.widgets_list_view);
87 mRecyclerView.setEdgeEffectFactory(springLayout.createEdgeEffectFactory());
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070088 onWidgetsBound();
89 }
90
Sunny Goyal8b37c572020-03-31 12:12:14 -070091 @VisibleForTesting
92 public WidgetsRecyclerView getRecyclerView() {
93 return mRecyclerView;
94 }
95
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070096 @Override
Sunny Goyalde753212018-05-15 13:55:57 -070097 protected Pair<View, String> getAccessibilityTarget() {
98 return Pair.create(mRecyclerView, getContext().getString(
99 mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
100 }
101
102 @Override
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700103 protected void onAttachedToWindow() {
104 super.onAttachedToWindow();
105 mLauncher.getAppWidgetHost().addProviderChangeListener(this);
106 notifyWidgetProvidersChanged();
107 }
108
109 @Override
110 protected void onDetachedFromWindow() {
111 super.onDetachedFromWindow();
112 mLauncher.getAppWidgetHost().removeProviderChangeListener(this);
113 }
114
115 @Override
116 public void setInsets(Rect insets) {
117 mInsets.set(insets);
118
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700119 mRecyclerView.setPadding(
120 mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
121 mRecyclerView.getPaddingRight(), insets.bottom);
122 if (insets.bottom > 0) {
123 setupNavBarColor();
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800124 } else {
125 clearNavBarColor();
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700126 }
Sunny Goyal3661bfa2018-03-01 16:29:15 -0800127
128 ((TopRoundedCornerView) mContent).setNavBarScrimHeight(mInsets.bottom);
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700129 requestLayout();
130 }
131
132 @Override
133 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
134 int widthUsed;
135 if (mInsets.bottom > 0) {
Sunny Goyal786940a2020-06-02 02:31:31 -0700136 widthUsed = mInsets.left + mInsets.right;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700137 } else {
Sunny Goyal07b69292018-01-08 14:19:34 -0800138 Rect padding = mLauncher.getDeviceProfile().workspacePadding;
139 widthUsed = Math.max(padding.left + padding.right,
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700140 2 * (mInsets.left + mInsets.right));
141 }
142
143 int heightUsed = mInsets.top + mLauncher.getDeviceProfile().edgeMarginPx;
144 measureChildWithMargins(mContent, widthMeasureSpec,
145 widthUsed, heightMeasureSpec, heightUsed);
Sunny Goyal6639a5d2018-02-28 15:09:36 -0800146 setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
147 MeasureSpec.getSize(heightMeasureSpec));
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700148 }
149
150 @Override
151 protected void onLayout(boolean changed, int l, int t, int r, int b) {
152 int width = r - l;
153 int height = b - t;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700154
155 // Content is laid out as center bottom aligned
156 int contentWidth = mContent.getMeasuredWidth();
Sunny Goyal786940a2020-06-02 02:31:31 -0700157 int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700158 mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
159 contentLeft + contentWidth, height);
160
161 setTranslationShift(mTranslationShift);
162 }
163
164 @Override
165 public void notifyWidgetProvidersChanged() {
166 mLauncher.refreshAndBindWidgetsForPackageUser(null);
167 }
168
169 @Override
Sunny Goyal202ae0b2019-02-04 16:26:42 -0800170 public void onWidgetsBound() {
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700171 mAdapter.setWidgets(mLauncher.getPopupDataProvider().getAllWidgets());
172 }
173
174 private void open(boolean animate) {
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700175 if (animate) {
Sunny Goyaldb6cdb02018-07-13 11:03:04 -0700176 if (getPopupContainer().getInsets().bottom > 0) {
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700177 mContent.setAlpha(0);
178 setTranslationShift(VERTICAL_START_POSITION);
179 }
180 mOpenCloseAnimator.setValues(
181 PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
182 mOpenCloseAnimator
183 .setDuration(DEFAULT_OPEN_DURATION)
184 .setInterpolator(AnimationUtils.loadInterpolator(
185 getContext(), android.R.interpolator.linear_out_slow_in));
vadimt9915a7c2020-04-08 18:56:52 -0700186 mRecyclerView.setLayoutFrozen(true);
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700187 mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
188 @Override
189 public void onAnimationEnd(Animator animation) {
190 mRecyclerView.setLayoutFrozen(false);
191 mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
192 mOpenCloseAnimator.removeListener(this);
193 }
194 });
Sunny Goyal6639a5d2018-02-28 15:09:36 -0800195 post(() -> {
Sunny Goyal6639a5d2018-02-28 15:09:36 -0800196 mOpenCloseAnimator.start();
197 mContent.animate().alpha(1).setDuration(FADE_IN_DURATION);
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700198 });
199 } else {
200 setTranslationShift(TRANSLATION_SHIFT_OPENED);
201 mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
Sunny Goyalde753212018-05-15 13:55:57 -0700202 post(this::announceAccessibilityChanges);
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700203 }
204 }
205
206 @Override
207 protected void handleClose(boolean animate) {
208 handleClose(animate, DEFAULT_OPEN_DURATION);
209 }
210
211 @Override
212 protected boolean isOfType(int type) {
213 return (type & TYPE_WIDGETS_FULL_SHEET) != 0;
214 }
215
216 @Override
217 public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
218 // Disable swipe down when recycler view is scrolling
219 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
220 mNoIntercept = false;
Sunny Goyal3661bfa2018-03-01 16:29:15 -0800221 RecyclerViewFastScroller scroller = mRecyclerView.getScrollbar();
Steven Ng2f5648a2021-02-08 17:18:25 +0000222 if (scroller.getThumbOffsetY() >= 0
223 && getPopupContainer().isEventOverView(scroller, ev)) {
Sunny Goyal3661bfa2018-03-01 16:29:15 -0800224 mNoIntercept = true;
Sunny Goyaldb6cdb02018-07-13 11:03:04 -0700225 } else if (getPopupContainer().isEventOverView(mContent, ev)) {
226 mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, getPopupContainer());
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700227 }
228 }
229 return super.onControllerInterceptTouchEvent(ev);
230 }
231
Steven Ng2f5648a2021-02-08 17:18:25 +0000232 /** Shows the {@link WidgetsFullSheet} on the launcher. */
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700233 public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
234 WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
235 .inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
Sunny Goyal1642f712018-09-18 11:40:35 -0700236 sheet.attachToContainer();
Sunny Goyalde753212018-05-15 13:55:57 -0700237 sheet.mIsOpen = true;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700238 sheet.open(animate);
239 return sheet;
240 }
Sunny Goyalaeb16432017-10-16 11:46:41 -0700241
Steven Ng2f5648a2021-02-08 17:18:25 +0000242 /** Gets the {@link WidgetsRecyclerView} which shows all widgets in {@link WidgetsFullSheet}. */
Vadim Tryshev2ce6a132018-06-18 19:14:44 -0700243 @VisibleForTesting
244 public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
245 return launcher.findViewById(R.id.widgets_list_view);
246 }
247
Sunny Goyalaeb16432017-10-16 11:46:41 -0700248 @Override
Sunny Goyalf3ac7032020-03-13 13:01:33 -0700249 public void addHintCloseAnim(
250 float distanceToMove, Interpolator interpolator, PendingAnimation target) {
251 target.setFloat(mRecyclerView, VIEW_TRANSLATE_Y, -distanceToMove, interpolator);
252 target.setViewAlpha(mRecyclerView, 0.5f, interpolator);
Tony Wickham9791bd12019-04-05 13:52:35 -0700253 }
vadimt9f48a8e2019-12-11 11:52:37 -0800254
255 @Override
256 protected void onCloseComplete() {
257 super.onCloseComplete();
258 AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
259 }
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700260}