Merge "Add WidgetsAndMore bottom sheet" into ub-launcher3-dorval
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<com.android.launcher3.widget.WidgetsAndMore
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="?android:attr/colorPrimary"
|
||||||
|
android:elevation="@dimen/deep_shortcuts_elevation"
|
||||||
|
android:layout_gravity="bottom">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:gravity="center_horizontal|bottom"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="20sp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:gravity="center_horizontal|top"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@string/long_press_widget_to_add"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widgets_header"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text="@string/widget_button_text"/>
|
||||||
|
|
||||||
|
<include layout="@layout/widgets_scroll_container"
|
||||||
|
android:id="@+id/widgets"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/widget_row_padding"
|
||||||
|
android:layout_marginBottom="@dimen/widget_row_padding"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/shortcuts_header"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text="@string/widgets_bottom_sheet_custom_shortcuts_section_title"/>
|
||||||
|
|
||||||
|
<include layout="@layout/widgets_scroll_container"
|
||||||
|
android:id="@+id/shortcuts"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/widget_row_padding"
|
||||||
|
android:layout_marginBottom="@dimen/widget_row_padding" />
|
||||||
|
|
||||||
|
</com.android.launcher3.widget.WidgetsAndMore>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/widgets_scroll_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/colorPrimaryDark"
|
||||||
|
android:scrollbars="none">
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/widgets_cell_list"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:showDividers="none"/>
|
||||||
|
</HorizontalScrollView>
|
||||||
@@ -203,6 +203,10 @@
|
|||||||
<!-- Title for an app whose download has been started. -->
|
<!-- Title for an app whose download has been started. -->
|
||||||
<string name="app_waiting_download_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> waiting to install</string>
|
<string name="app_waiting_download_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> waiting to install</string>
|
||||||
|
|
||||||
|
<!-- Strings for widgets & more in the popup container/bottom sheet -->
|
||||||
|
<string name="widgets_and_more" translatable="false">Widgets & more</string>
|
||||||
|
<string name="widgets_bottom_sheet_custom_shortcuts_section_title" translatable="false">Custom shortcuts</string>
|
||||||
|
|
||||||
<!-- Strings for accessibility actions -->
|
<!-- Strings for accessibility actions -->
|
||||||
<!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] -->
|
<!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] -->
|
||||||
<string name="action_add_to_workspace">Add to Home screen</string>
|
<string name="action_add_to_workspace">Add to Home screen</string>
|
||||||
|
|||||||
@@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package com.android.launcher3;
|
package com.android.launcher3;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
@@ -32,11 +34,16 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractFloatingView extends LinearLayout {
|
public abstract class AbstractFloatingView extends LinearLayout {
|
||||||
|
|
||||||
@IntDef(flag = true, value = {TYPE_FOLDER, TYPE_POPUP_CONTAINER_WITH_ARROW})
|
@IntDef(flag = true, value = {
|
||||||
|
TYPE_FOLDER,
|
||||||
|
TYPE_POPUP_CONTAINER_WITH_ARROW,
|
||||||
|
TYPE_WIDGETS_AND_MORE
|
||||||
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface FloatingViewType {}
|
public @interface FloatingViewType {}
|
||||||
public static final int TYPE_FOLDER = 1 << 0;
|
public static final int TYPE_FOLDER = 1 << 0;
|
||||||
public static final int TYPE_POPUP_CONTAINER_WITH_ARROW = 1 << 1;
|
public static final int TYPE_POPUP_CONTAINER_WITH_ARROW = 1 << 1;
|
||||||
|
public static final int TYPE_WIDGETS_AND_MORE = 1 << 2;
|
||||||
|
|
||||||
protected boolean mIsOpen;
|
protected boolean mIsOpen;
|
||||||
|
|
||||||
@@ -48,6 +55,15 @@ public abstract class AbstractFloatingView extends LinearLayout {
|
|||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We need to handle touch events to prevent them from falling through to the workspace below.
|
||||||
|
*/
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public final void close(boolean animate) {
|
public final void close(boolean animate) {
|
||||||
animate &= !Utilities.isPowerSaverOn(getContext());
|
animate &= !Utilities.isPowerSaverOn(getContext());
|
||||||
handleClose(animate);
|
handleClose(animate);
|
||||||
@@ -119,7 +135,8 @@ public abstract class AbstractFloatingView extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static AbstractFloatingView getTopOpenView(Launcher launcher) {
|
public static AbstractFloatingView getTopOpenView(Launcher launcher) {
|
||||||
return getOpenView(launcher, TYPE_FOLDER | TYPE_POPUP_CONTAINER_WITH_ARROW);
|
return getOpenView(launcher, TYPE_FOLDER | TYPE_POPUP_CONTAINER_WITH_ARROW
|
||||||
|
| TYPE_WIDGETS_AND_MORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract int getLogContainerType();
|
public abstract int getLogContainerType();
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ import com.android.launcher3.anim.AnimationLayerSet;
|
|||||||
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
||||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||||
import com.android.launcher3.compat.PinItemRequestCompat;
|
import com.android.launcher3.compat.PinItemRequestCompat;
|
||||||
import com.android.launcher3.compat.UserManagerCompat;
|
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.config.ProviderConfig;
|
import com.android.launcher3.config.ProviderConfig;
|
||||||
import com.android.launcher3.dragndrop.DragController;
|
import com.android.launcher3.dragndrop.DragController;
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import com.android.launcher3.logging.LoggerUtils;
|
|||||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
import com.android.launcher3.util.Thunk;
|
import com.android.launcher3.util.Thunk;
|
||||||
import com.android.launcher3.util.TouchController;
|
import com.android.launcher3.util.TouchController;
|
||||||
|
import com.android.launcher3.widget.WidgetsAndMore;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -246,6 +247,12 @@ public class DragLayer extends InsettableFrameLayout {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WidgetsAndMore widgetsAndMore = WidgetsAndMore.getOpen(mLauncher);
|
||||||
|
if (widgetsAndMore != null && widgetsAndMore.onControllerInterceptTouchEvent(ev)) {
|
||||||
|
mActiveController = widgetsAndMore;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPinchListener != null && mPinchListener.onControllerInterceptTouchEvent(ev)) {
|
if (mPinchListener != null && mPinchListener.onControllerInterceptTouchEvent(ev)) {
|
||||||
// Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.)
|
// Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.)
|
||||||
mActiveController = mPinchListener;
|
mActiveController = mPinchListener;
|
||||||
|
|||||||
@@ -388,15 +388,6 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC
|
|||||||
return mFolderIcon;
|
return mFolderIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We need to handle touch events to prevent them from falling through to the workspace below.
|
|
||||||
*/
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
@Override
|
|
||||||
public boolean onTouchEvent(MotionEvent ev) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDragController(DragController dragController) {
|
public void setDragController(DragController dragController) {
|
||||||
mDragController = dragController;
|
mDragController = dragController;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -530,15 +530,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
|
|||||||
> ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
> ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We need to handle touch events to prevent them from falling through to the workspace below.
|
|
||||||
*/
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
@Override
|
|
||||||
public boolean onTouchEvent(MotionEvent ev) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the notification header to reflect the badge info. Since this can be called
|
* Updates the notification header to reflect the badge info. Since this can be called
|
||||||
* for any badge info (not necessarily the one associated with this app), we first
|
* for any badge info (not necessarily the one associated with this app), we first
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
|||||||
private StylusEventHelper mStylusEventHelper;
|
private StylusEventHelper mStylusEventHelper;
|
||||||
|
|
||||||
protected CancellationSignal mActiveRequest;
|
protected CancellationSignal mActiveRequest;
|
||||||
|
private boolean mAnimatePreview = true;
|
||||||
|
|
||||||
protected final BaseActivity mActivity;
|
protected final BaseActivity mActivity;
|
||||||
|
|
||||||
@@ -149,13 +150,21 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
|||||||
return mWidgetImage;
|
return mWidgetImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAnimatePreview(boolean shouldAnimate) {
|
||||||
|
mAnimatePreview = shouldAnimate;
|
||||||
|
}
|
||||||
|
|
||||||
public void applyPreview(Bitmap bitmap) {
|
public void applyPreview(Bitmap bitmap) {
|
||||||
if (bitmap != null) {
|
if (bitmap != null) {
|
||||||
mWidgetImage.setBitmap(bitmap,
|
mWidgetImage.setBitmap(bitmap,
|
||||||
DrawableFactory.get(getContext()).getBadgeForUser(mItem.user, getContext()));
|
DrawableFactory.get(getContext()).getBadgeForUser(mItem.user, getContext()));
|
||||||
mWidgetImage.setAlpha(0f);
|
if (mAnimatePreview) {
|
||||||
ViewPropertyAnimator anim = mWidgetImage.animate();
|
mWidgetImage.setAlpha(0f);
|
||||||
anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
|
ViewPropertyAnimator anim = mWidgetImage.animate();
|
||||||
|
anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
|
||||||
|
} else {
|
||||||
|
mWidgetImage.setAlpha(1f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.launcher3.widget;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.ContextThemeWrapper;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.launcher3.AbstractFloatingView;
|
||||||
|
import com.android.launcher3.DropTarget;
|
||||||
|
import com.android.launcher3.Insettable;
|
||||||
|
import com.android.launcher3.ItemInfo;
|
||||||
|
import com.android.launcher3.Launcher;
|
||||||
|
import com.android.launcher3.LauncherAnimUtils;
|
||||||
|
import com.android.launcher3.LauncherAppState;
|
||||||
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.Utilities;
|
||||||
|
import com.android.launcher3.allapps.VerticalPullDetector;
|
||||||
|
import com.android.launcher3.anim.PropertyListBuilder;
|
||||||
|
import com.android.launcher3.dragndrop.DragController;
|
||||||
|
import com.android.launcher3.dragndrop.DragOptions;
|
||||||
|
import com.android.launcher3.model.WidgetItem;
|
||||||
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
|
import com.android.launcher3.util.TouchController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bottom sheet for the "Widgets & more" long-press option.
|
||||||
|
*/
|
||||||
|
public class WidgetsAndMore extends AbstractFloatingView implements Insettable, TouchController,
|
||||||
|
VerticalPullDetector.Listener, View.OnClickListener, View.OnLongClickListener,
|
||||||
|
DragController.DragListener {
|
||||||
|
|
||||||
|
private int mTranslationYOpen;
|
||||||
|
private int mTranslationYClosed;
|
||||||
|
private float mTranslationYRange;
|
||||||
|
|
||||||
|
private Launcher mLauncher;
|
||||||
|
private ObjectAnimator mOpenCloseAnimator;
|
||||||
|
private Interpolator mFastOutSlowInInterpolator;
|
||||||
|
private VerticalPullDetector.ScrollInterpolator mScrollInterpolator;
|
||||||
|
private Rect mInsets;
|
||||||
|
private boolean mWasNavBarLight;
|
||||||
|
private VerticalPullDetector mVerticalPullDetector;
|
||||||
|
|
||||||
|
public WidgetsAndMore(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WidgetsAndMore(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme), attrs, defStyleAttr);
|
||||||
|
setWillNotDraw(false);
|
||||||
|
mLauncher = Launcher.getLauncher(context);
|
||||||
|
mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
|
||||||
|
mFastOutSlowInInterpolator = new FastOutSlowInInterpolator();
|
||||||
|
mScrollInterpolator = new VerticalPullDetector.ScrollInterpolator();
|
||||||
|
mInsets = new Rect();
|
||||||
|
mVerticalPullDetector = new VerticalPullDetector(context);
|
||||||
|
mVerticalPullDetector.setListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
mTranslationYOpen = 0;
|
||||||
|
mTranslationYClosed = getMeasuredHeight();
|
||||||
|
mTranslationYRange = mTranslationYClosed - mTranslationYOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populateAndShow(ItemInfo itemInfo, List<WidgetItem> widgets) {
|
||||||
|
((TextView) findViewById(R.id.title)).setText(itemInfo.title);
|
||||||
|
|
||||||
|
List<WidgetItem> shortcuts = new ArrayList<>();
|
||||||
|
// Transfer configurable widgets to shortcuts
|
||||||
|
Iterator<WidgetItem> widgetsIter = widgets.iterator();
|
||||||
|
WidgetItem nextWidget;
|
||||||
|
while (widgetsIter.hasNext()) {
|
||||||
|
nextWidget = widgetsIter.next();
|
||||||
|
if (nextWidget.activityInfo != null) {
|
||||||
|
shortcuts.add(nextWidget);
|
||||||
|
widgetsIter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewGroup widgetRow = (ViewGroup) findViewById(R.id.widgets);
|
||||||
|
ViewGroup widgetCells = (ViewGroup) widgetRow.findViewById(R.id.widgets_cell_list);
|
||||||
|
|
||||||
|
ViewGroup shortcutRow = (ViewGroup) findViewById(R.id.shortcuts);
|
||||||
|
ViewGroup shortcutCells = (ViewGroup) shortcutRow.findViewById(R.id.widgets_cell_list);
|
||||||
|
|
||||||
|
for (int i = 0; i < widgets.size(); i++) {
|
||||||
|
addItemCell(widgetCells);
|
||||||
|
if (i < widgets.size() - 1) {
|
||||||
|
addDivider(widgetCells);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < shortcuts.size(); i++) {
|
||||||
|
addItemCell(shortcutCells);
|
||||||
|
if (i < shortcuts.size() - 1) {
|
||||||
|
addDivider(shortcutCells);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind the views in the horizontal tray regions.
|
||||||
|
if (widgetCells.getChildCount() > 0) {
|
||||||
|
for (int i = 0; i < widgets.size(); i++) {
|
||||||
|
WidgetCell widget = (WidgetCell) widgetCells.getChildAt(i*2); // skip dividers
|
||||||
|
widget.applyFromCellItem(widgets.get(i), LauncherAppState.getInstance(mLauncher)
|
||||||
|
.getWidgetCache());
|
||||||
|
widget.ensurePreview();
|
||||||
|
widget.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeView(findViewById(R.id.widgets_header));
|
||||||
|
}
|
||||||
|
if (shortcutCells.getChildCount() > 0) {
|
||||||
|
for (int i = 0; i < shortcuts.size(); i++) {
|
||||||
|
WidgetCell shortcut = (WidgetCell) shortcutCells.getChildAt(i*2); // skip dividers
|
||||||
|
shortcut.applyFromCellItem(shortcuts.get(i), LauncherAppState.getInstance(mLauncher)
|
||||||
|
.getWidgetCache());
|
||||||
|
shortcut.ensurePreview();
|
||||||
|
shortcut.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeView(findViewById(R.id.shortcuts_header));
|
||||||
|
}
|
||||||
|
|
||||||
|
mWasNavBarLight = (mLauncher.getWindow().getDecorView().getSystemUiVisibility()
|
||||||
|
& View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0;
|
||||||
|
mLauncher.getDragLayer().addView(this);
|
||||||
|
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
|
||||||
|
setTranslationY(mTranslationYClosed);
|
||||||
|
mIsOpen = false;
|
||||||
|
open(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDivider(ViewGroup parent) {
|
||||||
|
LayoutInflater.from(getContext()).inflate(R.layout.widget_list_divider, parent, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addItemCell(ViewGroup parent) {
|
||||||
|
WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext()).inflate(
|
||||||
|
R.layout.widget_cell, parent, false);
|
||||||
|
|
||||||
|
widget.setOnClickListener(this);
|
||||||
|
widget.setOnLongClickListener(this);
|
||||||
|
widget.setAnimatePreview(false);
|
||||||
|
|
||||||
|
parent.addView(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
mLauncher.getWidgetsView().handleClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View view) {
|
||||||
|
mLauncher.getDragController().addDragListener(this);
|
||||||
|
return mLauncher.getWidgetsView().handleLongClick(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void open(boolean animate) {
|
||||||
|
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsOpen = true;
|
||||||
|
setLightNavBar(true);
|
||||||
|
if (animate) {
|
||||||
|
mOpenCloseAnimator.setValues(new PropertyListBuilder()
|
||||||
|
.translationY(mTranslationYOpen).build());
|
||||||
|
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
mVerticalPullDetector.finishedScrolling();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mOpenCloseAnimator.setInterpolator(mFastOutSlowInInterpolator);
|
||||||
|
mOpenCloseAnimator.start();
|
||||||
|
} else {
|
||||||
|
setTranslationY(mTranslationYOpen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleClose(boolean animate) {
|
||||||
|
if (!mIsOpen || mOpenCloseAnimator.isRunning()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (animate) {
|
||||||
|
mOpenCloseAnimator.setValues(new PropertyListBuilder()
|
||||||
|
.translationY(mTranslationYClosed).build());
|
||||||
|
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
mIsOpen = false;
|
||||||
|
mVerticalPullDetector.finishedScrolling();
|
||||||
|
((ViewGroup) getParent()).removeView(WidgetsAndMore.this);
|
||||||
|
setLightNavBar(mWasNavBarLight);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mOpenCloseAnimator.setInterpolator(mVerticalPullDetector.isIdleState()
|
||||||
|
? mFastOutSlowInInterpolator : mScrollInterpolator);
|
||||||
|
mOpenCloseAnimator.start();
|
||||||
|
} else {
|
||||||
|
setTranslationY(mTranslationYClosed);
|
||||||
|
setLightNavBar(mWasNavBarLight);
|
||||||
|
mIsOpen = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLightNavBar(boolean lightNavBar) {
|
||||||
|
mLauncher.activateLightSystemBars(lightNavBar, false /* statusBar */, true /* navBar */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isOfType(@FloatingViewType int type) {
|
||||||
|
return (type & TYPE_WIDGETS_AND_MORE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLogContainerType() {
|
||||||
|
return LauncherLogProto.ContainerType.WIDGETS; // TODO: be more specific
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a WidgetsAndMore which is already open or null
|
||||||
|
*/
|
||||||
|
public static WidgetsAndMore getOpen(Launcher launcher) {
|
||||||
|
return getOpenView(launcher, TYPE_WIDGETS_AND_MORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInsets(Rect insets) {
|
||||||
|
// Extend behind left, right, and bottom insets.
|
||||||
|
int leftInset = insets.left - mInsets.left;
|
||||||
|
int rightInset = insets.right - mInsets.right;
|
||||||
|
int bottomInset = insets.bottom - mInsets.bottom;
|
||||||
|
mInsets.set(insets);
|
||||||
|
setPadding(getPaddingLeft() + leftInset, getPaddingTop(),
|
||||||
|
getPaddingRight() + rightInset, getPaddingBottom() + bottomInset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* VerticalPullDetector.Listener */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDragStart(boolean start) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDrag(float displacement, float velocity) {
|
||||||
|
setTranslationY(Utilities.boundToRange(displacement, mTranslationYOpen,
|
||||||
|
mTranslationYClosed));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDragEnd(float velocity, boolean fling) {
|
||||||
|
if ((fling && velocity > 0) || getTranslationY() > (mTranslationYRange) / 2) {
|
||||||
|
mScrollInterpolator.setVelocityAtZero(velocity);
|
||||||
|
mOpenCloseAnimator.setDuration(mVerticalPullDetector.calculateDuration(velocity,
|
||||||
|
(mTranslationYClosed - getTranslationY()) / mTranslationYRange));
|
||||||
|
close(true);
|
||||||
|
} else {
|
||||||
|
mIsOpen = false;
|
||||||
|
mOpenCloseAnimator.setDuration(mVerticalPullDetector.calculateDuration(velocity,
|
||||||
|
(getTranslationY() - mTranslationYOpen) / mTranslationYRange));
|
||||||
|
open(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onControllerTouchEvent(MotionEvent ev) {
|
||||||
|
return mVerticalPullDetector.onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
int directionsToDetectScroll = mVerticalPullDetector.isIdleState() ?
|
||||||
|
VerticalPullDetector.DIRECTION_DOWN : 0;
|
||||||
|
mVerticalPullDetector.setDetectableScrollConditions(
|
||||||
|
directionsToDetectScroll, false);
|
||||||
|
mVerticalPullDetector.onTouchEvent(ev);
|
||||||
|
return mVerticalPullDetector.isDraggingOrSettling();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DragListener */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
|
||||||
|
// A widget or custom shortcut was dragged.
|
||||||
|
close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDragEnd() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,13 +29,10 @@ import com.android.launcher3.BaseContainerView;
|
|||||||
import com.android.launcher3.DeleteDropTarget;
|
import com.android.launcher3.DeleteDropTarget;
|
||||||
import com.android.launcher3.DragSource;
|
import com.android.launcher3.DragSource;
|
||||||
import com.android.launcher3.DropTarget.DragObject;
|
import com.android.launcher3.DropTarget.DragObject;
|
||||||
import com.android.launcher3.IconCache;
|
|
||||||
import com.android.launcher3.ItemInfo;
|
import com.android.launcher3.ItemInfo;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.LauncherAppState;
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.dragndrop.DragController;
|
|
||||||
import com.android.launcher3.dragndrop.DragOptions;
|
import com.android.launcher3.dragndrop.DragOptions;
|
||||||
import com.android.launcher3.folder.Folder;
|
import com.android.launcher3.folder.Folder;
|
||||||
import com.android.launcher3.model.PackageItemInfo;
|
import com.android.launcher3.model.PackageItemInfo;
|
||||||
@@ -55,8 +52,6 @@ public class WidgetsContainerView extends BaseContainerView
|
|||||||
|
|
||||||
/* Global instances that are used inside this container. */
|
/* Global instances that are used inside this container. */
|
||||||
@Thunk Launcher mLauncher;
|
@Thunk Launcher mLauncher;
|
||||||
private DragController mDragController;
|
|
||||||
private IconCache mIconCache;
|
|
||||||
|
|
||||||
/* Recycler view related member variables */
|
/* Recycler view related member variables */
|
||||||
private WidgetsRecyclerView mRecyclerView;
|
private WidgetsRecyclerView mRecyclerView;
|
||||||
@@ -76,9 +71,7 @@ public class WidgetsContainerView extends BaseContainerView
|
|||||||
public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
mLauncher = Launcher.getLauncher(context);
|
mLauncher = Launcher.getLauncher(context);
|
||||||
mDragController = mLauncher.getDragController();
|
|
||||||
mAdapter = new WidgetsListAdapter(this, this, context);
|
mAdapter = new WidgetsListAdapter(this, this, context);
|
||||||
mIconCache = LauncherAppState.getInstance(context).getIconCache();
|
|
||||||
if (LOGD) {
|
if (LOGD) {
|
||||||
Log.d(TAG, "WidgetsContainerView constructor");
|
Log.d(TAG, "WidgetsContainerView constructor");
|
||||||
}
|
}
|
||||||
@@ -116,6 +109,10 @@ public class WidgetsContainerView extends BaseContainerView
|
|||||||
|| mLauncher.getWorkspace().isSwitchingState()
|
|| mLauncher.getWorkspace().isSwitchingState()
|
||||||
|| !(v instanceof WidgetCell)) return;
|
|| !(v instanceof WidgetCell)) return;
|
||||||
|
|
||||||
|
handleClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleClick() {
|
||||||
// Let the user know that they have to long press to add a widget
|
// Let the user know that they have to long press to add a widget
|
||||||
if (mWidgetInstructionToast != null) {
|
if (mWidgetInstructionToast != null) {
|
||||||
mWidgetInstructionToast.cancel();
|
mWidgetInstructionToast.cancel();
|
||||||
@@ -130,14 +127,19 @@ public class WidgetsContainerView extends BaseContainerView
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onLongClick(View v) {
|
public boolean onLongClick(View v) {
|
||||||
|
// When we have exited the widget tray, disregard long clicks
|
||||||
|
if (!mLauncher.isWidgetsViewVisible()) return false;
|
||||||
|
return handleLongClick(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean handleLongClick(View v) {
|
||||||
if (LOGD) {
|
if (LOGD) {
|
||||||
Log.d(TAG, String.format("onLongClick [v=%s]", v));
|
Log.d(TAG, String.format("onLongClick [v=%s]", v));
|
||||||
}
|
}
|
||||||
// Return early if this is not initiated from a touch
|
// Return early if this is not initiated from a touch
|
||||||
if (!v.isInTouchMode()) return false;
|
if (!v.isInTouchMode()) return false;
|
||||||
// When we have exited all apps or are in transition, disregard long clicks
|
// When we are in transition, disregard long clicks
|
||||||
if (!mLauncher.isWidgetsViewVisible() ||
|
if (mLauncher.getWorkspace().isSwitchingState()) return false;
|
||||||
mLauncher.getWorkspace().isSwitchingState()) return false;
|
|
||||||
// Return if global dragging is not enabled
|
// Return if global dragging is not enabled
|
||||||
if (!mLauncher.isDraggingEnabled()) return false;
|
if (!mLauncher.isDraggingEnabled()) return false;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user