blob: 48f8afecdcc68df1279feb60858f6196603604be [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 */
16package com.android.launcher3.widget;
17
18import android.animation.Animator;
19import android.animation.AnimatorListenerAdapter;
20import android.animation.PropertyValuesHolder;
21import android.content.Context;
22import android.graphics.Rect;
23import android.util.AttributeSet;
24import android.view.LayoutInflater;
25import android.view.MotionEvent;
26import android.view.View;
27import android.view.animation.AnimationUtils;
28
29import com.android.launcher3.Insettable;
30import com.android.launcher3.Launcher;
31import com.android.launcher3.LauncherAppState;
32import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
33import com.android.launcher3.R;
34
35/**
36 * Popup for showing the full list of available widgets
37 */
38public class WidgetsFullSheet extends BaseWidgetSheet
39 implements Insettable, ProviderChangedListener {
40
41 private static final long DEFAULT_OPEN_DURATION = 267;
42 private static final long FADE_IN_DURATION = 150;
43 private static final float VERTICAL_START_POSITION = 0.3f;
44
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070045 private final Rect mInsets = new Rect();
46
47 private final WidgetsListAdapter mAdapter;
48
49 private View mNavBarScrim;
50 private WidgetsRecyclerView mRecyclerView;
51
52 public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
53 super(context, attrs, defStyleAttr);
54 LauncherAppState apps = LauncherAppState.getInstance(context);
55 mAdapter = new WidgetsListAdapter(context,
56 LayoutInflater.from(context), apps.getWidgetCache(), apps.getIconCache(),
57 this, this);
58 }
59
60 public WidgetsFullSheet(Context context, AttributeSet attrs) {
61 this(context, attrs, 0);
62 }
63
64 @Override
65 protected void onFinishInflate() {
66 super.onFinishInflate();
67 mContent = findViewById(R.id.container);
68 mNavBarScrim = findViewById(R.id.nav_bar_bg);
69
70 mRecyclerView = findViewById(R.id.widgets_list_view);
71 mRecyclerView.setAdapter(mAdapter);
72 mAdapter.setApplyBitmapDeferred(true, mRecyclerView);
73
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -070074 onWidgetsBound();
75 }
76
77 @Override
78 protected void onAttachedToWindow() {
79 super.onAttachedToWindow();
80 mLauncher.getAppWidgetHost().addProviderChangeListener(this);
81 notifyWidgetProvidersChanged();
82 }
83
84 @Override
85 protected void onDetachedFromWindow() {
86 super.onDetachedFromWindow();
87 mLauncher.getAppWidgetHost().removeProviderChangeListener(this);
88 }
89
90 @Override
91 public void setInsets(Rect insets) {
92 mInsets.set(insets);
93
94 mNavBarScrim.getLayoutParams().height = insets.bottom;
95 mRecyclerView.setPadding(
96 mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
97 mRecyclerView.getPaddingRight(), insets.bottom);
98 if (insets.bottom > 0) {
99 setupNavBarColor();
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800100 } else {
101 clearNavBarColor();
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700102 }
103 requestLayout();
104 }
105
106 @Override
107 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
108 int widthUsed;
109 if (mInsets.bottom > 0) {
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700110 widthUsed = 0;
111 } else {
Sunny Goyal07b69292018-01-08 14:19:34 -0800112 Rect padding = mLauncher.getDeviceProfile().workspacePadding;
113 widthUsed = Math.max(padding.left + padding.right,
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700114 2 * (mInsets.left + mInsets.right));
115 }
116
117 int heightUsed = mInsets.top + mLauncher.getDeviceProfile().edgeMarginPx;
118 measureChildWithMargins(mContent, widthMeasureSpec,
119 widthUsed, heightMeasureSpec, heightUsed);
Sunny Goyal6639a5d2018-02-28 15:09:36 -0800120 setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
121 MeasureSpec.getSize(heightMeasureSpec));
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700122 }
123
124 @Override
125 protected void onLayout(boolean changed, int l, int t, int r, int b) {
126 int width = r - l;
127 int height = b - t;
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700128
129 // Content is laid out as center bottom aligned
130 int contentWidth = mContent.getMeasuredWidth();
131 int contentLeft = (width - contentWidth) / 2;
132 mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
133 contentLeft + contentWidth, height);
134
135 setTranslationShift(mTranslationShift);
136 }
137
138 @Override
139 public void notifyWidgetProvidersChanged() {
140 mLauncher.refreshAndBindWidgetsForPackageUser(null);
141 }
142
143 @Override
144 protected void onWidgetsBound() {
145 mAdapter.setWidgets(mLauncher.getPopupDataProvider().getAllWidgets());
146 }
147
148 private void open(boolean animate) {
149 if (mIsOpen) {
150 return;
151 }
152 mIsOpen = true;
153 if (animate) {
154 if (mLauncher.getDragLayer().getInsets().bottom > 0) {
155 mContent.setAlpha(0);
156 setTranslationShift(VERTICAL_START_POSITION);
157 }
158 mOpenCloseAnimator.setValues(
159 PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
160 mOpenCloseAnimator
161 .setDuration(DEFAULT_OPEN_DURATION)
162 .setInterpolator(AnimationUtils.loadInterpolator(
163 getContext(), android.R.interpolator.linear_out_slow_in));
164 mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
165 @Override
166 public void onAnimationEnd(Animator animation) {
167 mRecyclerView.setLayoutFrozen(false);
168 mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
169 mOpenCloseAnimator.removeListener(this);
170 }
171 });
Sunny Goyal6639a5d2018-02-28 15:09:36 -0800172 post(() -> {
173 mRecyclerView.setLayoutFrozen(true);
174 mOpenCloseAnimator.start();
175 mContent.animate().alpha(1).setDuration(FADE_IN_DURATION);
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700176 });
177 } else {
178 setTranslationShift(TRANSLATION_SHIFT_OPENED);
179 mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
180 }
181 }
182
183 @Override
184 protected void handleClose(boolean animate) {
185 handleClose(animate, DEFAULT_OPEN_DURATION);
186 }
187
188 @Override
189 protected boolean isOfType(int type) {
190 return (type & TYPE_WIDGETS_FULL_SHEET) != 0;
191 }
192
193 @Override
194 public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
195 // Disable swipe down when recycler view is scrolling
196 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
197 mNoIntercept = false;
198 if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
199 mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, mLauncher.getDragLayer());
200 }
201 }
202 return super.onControllerInterceptTouchEvent(ev);
203 }
204
205 public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
206 WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
207 .inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
208 launcher.getDragLayer().addView(sheet);
209 sheet.open(animate);
210 return sheet;
211 }
Sunny Goyalaeb16432017-10-16 11:46:41 -0700212
213 @Override
214 protected int getElementsRowCount() {
215 return mAdapter.getItemCount();
216 }
Sunny Goyalf1fbc3f2017-10-10 15:21:15 -0700217}