1 /* 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 */ 16 17 package com.android.launcher3.widget; 18 19 import static com.android.launcher3.Utilities.ATLEAST_R; 20 21 import android.annotation.SuppressLint; 22 import android.content.Context; 23 import android.graphics.Insets; 24 import android.graphics.Rect; 25 import android.util.AttributeSet; 26 import android.view.MotionEvent; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.view.ViewParent; 30 import android.view.WindowInsets; 31 import android.widget.ScrollView; 32 33 import com.android.launcher3.DeviceProfile; 34 import com.android.launcher3.R; 35 import com.android.launcher3.dragndrop.AddItemActivity; 36 import com.android.launcher3.views.AbstractSlideInView; 37 38 /** 39 * Bottom sheet for the pin widget. 40 */ 41 public class AddItemWidgetsBottomSheet extends AbstractSlideInView<AddItemActivity> implements 42 View.OnApplyWindowInsetsListener { 43 44 private static final int DEFAULT_CLOSE_DURATION = 200; 45 46 private final Rect mInsets; 47 private ScrollView mWidgetPreviewScrollView; 48 49 private int mContentHorizontalMarginInPx; 50 AddItemWidgetsBottomSheet(Context context, AttributeSet attrs)51 public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs) { 52 this(context, attrs, 0); 53 } 54 AddItemWidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr)55 public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) { 56 super(context, attrs, defStyleAttr); 57 mInsets = new Rect(); 58 mContentHorizontalMarginInPx = getResources().getDimensionPixelSize( 59 R.dimen.widget_list_horizontal_margin); 60 } 61 62 /** 63 * Attaches to activity container and animates open the bottom sheet. 64 */ show()65 public void show() { 66 ViewParent parent = getParent(); 67 if (parent instanceof ViewGroup) { 68 ((ViewGroup) parent).removeView(this); 69 } 70 attachToContainer(); 71 setOnApplyWindowInsetsListener(this); 72 animateOpen(); 73 } 74 75 @Override onControllerInterceptTouchEvent(MotionEvent ev)76 public boolean onControllerInterceptTouchEvent(MotionEvent ev) { 77 if (ev.getAction() == MotionEvent.ACTION_DOWN) { 78 mNoIntercept = false; 79 // Suppress drag to dismiss gesture if the scroll view is being scrolled. 80 if (getPopupContainer().isEventOverView(mWidgetPreviewScrollView, ev) 81 && mWidgetPreviewScrollView.getScrollY() > 0) { 82 mNoIntercept = true; 83 } 84 } 85 return super.onControllerInterceptTouchEvent(ev); 86 } 87 88 @Override onLayout(boolean changed, int l, int t, int r, int b)89 protected void onLayout(boolean changed, int l, int t, int r, int b) { 90 int width = r - l; 91 int height = b - t; 92 93 // Lay out content as center bottom aligned. 94 int contentWidth = mContent.getMeasuredWidth(); 95 int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left; 96 mContent.layout(contentLeft, height - mContent.getMeasuredHeight(), 97 contentLeft + contentWidth, height); 98 99 setTranslationShift(mTranslationShift); 100 } 101 102 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)103 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 104 DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); 105 int widthUsed; 106 if (deviceProfile.isTablet) { 107 int margin = deviceProfile.allAppsLeftRightMargin; 108 widthUsed = Math.max(2 * margin, 2 * (mInsets.left + mInsets.right)); 109 } else if (mInsets.bottom > 0) { 110 widthUsed = mInsets.left + mInsets.right; 111 } else { 112 Rect padding = deviceProfile.workspacePadding; 113 widthUsed = Math.max(padding.left + padding.right, 114 2 * (mInsets.left + mInsets.right)); 115 } 116 117 measureChildWithMargins(mContent, widthMeasureSpec, 118 widthUsed, heightMeasureSpec, deviceProfile.bottomSheetTopPadding); 119 setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), 120 MeasureSpec.getSize(heightMeasureSpec)); 121 } 122 123 @Override onFinishInflate()124 protected void onFinishInflate() { 125 super.onFinishInflate(); 126 mContent = findViewById(R.id.add_item_bottom_sheet_content); 127 mWidgetPreviewScrollView = findViewById(R.id.widget_preview_scroll_view); 128 } 129 animateOpen()130 private void animateOpen() { 131 if (mIsOpen || mOpenCloseAnimation.getAnimationPlayer().isRunning()) { 132 return; 133 } 134 mIsOpen = true; 135 setUpDefaultOpenAnimation().start(); 136 } 137 138 @Override handleClose(boolean animate)139 protected void handleClose(boolean animate) { 140 handleClose(animate, DEFAULT_CLOSE_DURATION); 141 } 142 143 @Override isOfType(@loatingViewType int type)144 protected boolean isOfType(@FloatingViewType int type) { 145 return (type & TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP) != 0; 146 } 147 148 @Override getScrimColor(Context context)149 protected int getScrimColor(Context context) { 150 return context.getResources().getColor(R.color.widgets_picker_scrim); 151 } 152 153 @SuppressLint("NewApi") // Already added API check. 154 @Override onApplyWindowInsets(View view, WindowInsets windowInsets)155 public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) { 156 if (ATLEAST_R) { 157 Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars()); 158 mInsets.set(insets.left, insets.top, insets.right, insets.bottom); 159 } else { 160 mInsets.set(windowInsets.getSystemWindowInsetLeft(), 161 windowInsets.getSystemWindowInsetTop(), 162 windowInsets.getSystemWindowInsetRight(), 163 windowInsets.getSystemWindowInsetBottom()); 164 } 165 mContent.setPadding(mContent.getPaddingStart(), 166 mContent.getPaddingTop(), mContent.getPaddingEnd(), mInsets.bottom); 167 168 int contentHorizontalMarginInPx = getResources().getDimensionPixelSize( 169 R.dimen.widget_list_horizontal_margin); 170 if (contentHorizontalMarginInPx != mContentHorizontalMarginInPx) { 171 setContentHorizontalMargin(findViewById(R.id.widget_appName), 172 contentHorizontalMarginInPx); 173 setContentHorizontalMargin(findViewById(R.id.widget_drag_instruction), 174 contentHorizontalMarginInPx); 175 setContentHorizontalMargin(findViewById(R.id.widget_cell), contentHorizontalMarginInPx); 176 setContentHorizontalMargin(findViewById(R.id.actions_container), 177 contentHorizontalMarginInPx); 178 mContentHorizontalMarginInPx = contentHorizontalMarginInPx; 179 } 180 return windowInsets; 181 } 182 setContentHorizontalMargin(View view, int contentHorizontalMargin)183 private static void setContentHorizontalMargin(View view, int contentHorizontalMargin) { 184 ViewGroup.MarginLayoutParams layoutParams = 185 ((ViewGroup.MarginLayoutParams) view.getLayoutParams()); 186 layoutParams.setMarginStart(contentHorizontalMargin); 187 layoutParams.setMarginEnd(contentHorizontalMargin); 188 } 189 } 190