Merge "Only draw double shadows of BubbleTextView if both shadow color's alpha value is non-zero." into ub-launcher3-dorval-polish
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 2bbd76d..e6f98a4 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -63,8 +63,8 @@
<com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
android:id="@+id/page_indicator"
android:theme="@style/HomeScreenElementTheme"
- android:layout_width="@dimen/dynamic_grid_page_indicator_size"
- android:layout_height="@dimen/dynamic_grid_page_indicator_size"
+ android:layout_width="@dimen/dynamic_grid_min_page_indicator_size"
+ android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
android:layout_gravity="bottom|left"/>
<include layout="@layout/widgets_view"
diff --git a/res/layout/horizontal_divider.xml b/res/layout/horizontal_divider.xml
deleted file mode 100644
index 167f8f5..0000000
--- a/res/layout/horizontal_divider.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<View xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/popup_item_divider_height"
- android:background="?attr/popupColorTertiary" />
\ No newline at end of file
diff --git a/res/layout/page_indicator.xml b/res/layout/page_indicator.xml
index 14ff2bd..92f52d6 100644
--- a/res/layout/page_indicator.xml
+++ b/res/layout/page_indicator.xml
@@ -18,11 +18,11 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/HomeScreenElementTheme"
android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_page_indicator_size">
+ android:layout_height="@dimen/dynamic_grid_min_page_indicator_size">
<ImageView
android:id="@+id/all_apps_handle"
android:layout_width="48dp"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
android:layout_gravity="top|center"
android:scaleType="centerInside"/>
</com.android.launcher3.pageindicators.PageIndicatorLineCaret>
diff --git a/res/layout/popup_container.xml b/res/layout/popup_container.xml
index e9cfe24..67db4a5 100644
--- a/res/layout/popup_container.xml
+++ b/res/layout/popup_container.xml
@@ -19,8 +19,8 @@
android:id="@+id/deep_shortcuts_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
android:clipToPadding="false"
android:clipChildren="false"
android:elevation="@dimen/deep_shortcuts_elevation"
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 0db0e61..1d36f75 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -26,7 +26,7 @@
<!-- Dynamic grid -->
<dimen name="dynamic_grid_overview_bar_item_width">120dp</dimen>
- <dimen name="dynamic_grid_page_indicator_size">24dp</dimen>
+ <dimen name="dynamic_grid_min_page_indicator_size">24dp</dimen>
<dimen name="folder_preview_padding">5dp</dimen>
<!-- Hotseat -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 980b714..21abd3c 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -17,7 +17,7 @@
<resources>
<!-- Dynamic Grid -->
<dimen name="dynamic_grid_edge_margin">16dp</dimen>
- <dimen name="dynamic_grid_page_indicator_size">32dp</dimen>
+ <dimen name="dynamic_grid_min_page_indicator_size">32dp</dimen>
<dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
<dimen name="dynamic_grid_page_indicator_gutter_width">50dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index eef6510..7520be2 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -80,7 +80,7 @@
public final int workspaceSpringLoadedBottomSpace;
// Page indicator
- private final int pageIndicatorSizePx;
+ private int pageIndicatorSizePx;
private final int pageIndicatorLandGutterPx;
private final int pageIndicatorLandWorkspaceOffsetPx;
@@ -172,7 +172,8 @@
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
desiredWorkspaceLeftRightMarginPx = edgeMarginPx;
- pageIndicatorSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_size);
+ pageIndicatorSizePx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_min_page_indicator_size);
pageIndicatorLandGutterPx = res.getDimensionPixelSize(
R.dimen.dynamic_grid_page_indicator_gutter_width);
pageIndicatorLandWorkspaceOffsetPx =
@@ -228,8 +229,23 @@
availableHeightPx = maxSize.y;
}
- // Calculate the remaining vars
+ // Calculate all of the remaining variables.
updateAvailableDimensions(dm, res);
+
+ // Now that we have all of the variables calculated, we can tune certain sizes.
+ if (!isVerticalBarLayout()) {
+ // We increase the page indicator size when there is extra space.
+ // ie. For a display with a large aspect ratio, we can keep the icons on the workspace
+ // in portrait mode closer together by increasing the page indicator size.
+ int newPageIndicatorSizePx = getCellSize().y - iconSizePx - iconTextSizePx
+ - iconDrawablePaddingOriginalPx;
+ if (newPageIndicatorSizePx > pageIndicatorSizePx) {
+ pageIndicatorSizePx = newPageIndicatorSizePx;
+ // Recalculate the available dimensions using the new page indicator size.
+ updateAvailableDimensions(dm, res);
+ }
+ }
+
computeAllAppsButtonSize(context);
// This is done last, after iconSizePx is calculated above.
@@ -484,8 +500,8 @@
return new Rect(mInsets.left,
mInsets.top + dropTargetBarSizePx + edgeMarginPx,
mInsets.left + availableWidthPx,
- mInsets.top + availableHeightPx - hotseatBarHeightPx - pageIndicatorSizePx -
- edgeMarginPx);
+ mInsets.top + availableHeightPx - hotseatBarHeightPx
+ - pageIndicatorSizePx - edgeMarginPx);
}
}
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a23a674..3bcd7af 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -68,7 +68,7 @@
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
// Empty class name is used for storing package default entry.
- private static final String EMPTY_CLASS_NAME = ".";
+ public static final String EMPTY_CLASS_NAME = ".";
private static final boolean DEBUG = false;
private static final boolean DEBUG_IGNORE_CACHE = false;
@@ -120,7 +120,8 @@
}
private Drawable getFullResDefaultActivityIcon() {
- return getFullResIcon(Resources.getSystem(), android.R.drawable.sym_def_app_icon);
+ return getFullResIcon(Resources.getSystem(), Utilities.isAtLeastO() ?
+ android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon);
}
private Drawable getFullResIcon(Resources resources, int iconId) {
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 11c5309..c5be096 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -137,7 +137,18 @@
}
public ComponentName getTargetComponent() {
- return getIntent() == null ? null : getIntent().getComponent();
+ Intent intent = getIntent();
+ if (intent == null) {
+ return null;
+ }
+ ComponentName cn = intent.getComponent();
+ if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT && cn == null) {
+ // Legacy shortcuts may not have a componentName but just a packageName. In that case
+ // create a dummy componentName instead of adding additional check everywhere.
+ String pkg = intent.getPackage();
+ return pkg == null ? null : new ComponentName(pkg, IconCache.EMPTY_CLASS_NAME);
+ }
+ return cn;
}
public void writeToValues(ContentWriter writer) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 4fb0b86..ccef4f2 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -410,22 +410,19 @@
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- if (mScrollState == RecyclerView.SCROLL_STATE_DRAGGING
- || (dx == 0 && dy == 0)) {
+ if (mScrollState == RecyclerView.SCROLL_STATE_DRAGGING || (dx == 0 && dy == 0)) {
if (mSpringAnimationHandler.isRunning()){
mSpringAnimationHandler.skipToEnd();
}
return;
}
- int first = mLayoutManager.findFirstVisibleItemPosition();
- int last = mLayoutManager.findLastVisibleItemPosition();
-
- // We only show the spring animation when at the top or bottom, so we wait until the
- // first or last row is visible to ensure that all animations run in sync.
- boolean scrollUp = dy < 0;
- if ((first == 0 && scrollUp) || (last == mAdapter.getItemCount() - 1 && dy > 0)) {
- mSpringAnimationHandler.animateToFinalPosition(0, scrollUp ? 1 : -1);
+ // We only start the spring animation when we fling and hit the top/bottom, to ensure
+ // that all of the animations start at the same time.
+ if (dy < 0 && !mAppsRecyclerView.canScrollVertically(-1)) {
+ mSpringAnimationHandler.animateToFinalPosition(0, 1);
+ } else if (dy > 0 && !mAppsRecyclerView.canScrollVertically(1)) {
+ mSpringAnimationHandler.animateToFinalPosition(0, -1);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index ff8de88..fb785fb 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -96,8 +96,7 @@
mOverScrollHelper = new OverScrollHelper();
mPullDetector = new VerticalPullDetector(getContext());
mPullDetector.setListener(mOverScrollHelper);
- mPullDetector.setDetectableScrollConditions(VerticalPullDetector.DIRECTION_UP
- | VerticalPullDetector.DIRECTION_DOWN, true);
+ mPullDetector.setDetectableScrollConditions(VerticalPullDetector.DIRECTION_BOTH, true);
}
public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) {
@@ -487,28 +486,53 @@
private boolean mIsInOverScroll;
+ // We use this value to calculate the actual amount the user has overscrolled.
+ private float mFirstDisplacement = 0;
+
+ private boolean mAlreadyScrollingUp;
+ private int mFirstScrollYOnScrollUp;
+
@Override
public void onDragStart(boolean start) {
}
@Override
public boolean onDrag(float displacement, float velocity) {
- // We are in overscroll iff we are trying to drag further down when we're already at
- // the bottom of All Apps.
- mIsInOverScroll = !canScrollVertically(1) && displacement < 0
- && !mScrollbar.isDraggingThumb();
+ boolean isScrollingUp = displacement > 0;
+ if (isScrollingUp) {
+ if (!mAlreadyScrollingUp) {
+ mFirstScrollYOnScrollUp = getCurrentScrollY();
+ mAlreadyScrollingUp = true;
+ }
+ } else {
+ mAlreadyScrollingUp = false;
+ }
+
+ // Only enter overscroll if the user is interacting with the RecyclerView directly
+ // and if one of the following criteria are met:
+ // - User scrolls down when they're already at the bottom.
+ // - User starts scrolling up, hits the top, and continues scrolling up.
+ mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
+ ((!canScrollVertically(1) && displacement < 0) ||
+ (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));
if (mIsInOverScroll) {
- displacement = getDampedOverScroll(displacement);
- setContentTranslationY(displacement);
+ if (Float.compare(mFirstDisplacement, 0) == 0) {
+ // Because users can scroll before entering overscroll, we need to
+ // subtract the amount where the user was not in overscroll.
+ mFirstDisplacement = displacement;
+ }
+ float overscrollY = displacement - mFirstDisplacement;
+ setContentTranslationY(getDampedOverScroll(overscrollY));
}
+
return mIsInOverScroll;
}
@Override
public void onDragEnd(float velocity, boolean fling) {
float y = getContentTranslationY();
- if (mIsInOverScroll && Float.compare(y, 0) != 0) {
+ if (Float.compare(y, 0) != 0) {
if (FeatureFlags.LAUNCHER3_PHYSICS) {
// We calculate our own velocity to give the springs the desired effect.
velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
@@ -523,6 +547,9 @@
.start();
}
mIsInOverScroll = false;
+ mFirstDisplacement = 0;
+ mFirstScrollYOnScrollUp = 0;
+ mAlreadyScrollingUp = false;
}
public boolean isInOverScroll() {
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index eb6a6d5..61490ee 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -306,6 +306,7 @@
// It is the callers responsibility to save and restore the canvas layers.
void clipCanvasHardware(Canvas canvas) {
mPaint.setColor(Color.BLACK);
+ mPaint.setStyle(Paint.Style.FILL);
mPaint.setXfermode(mClipPorterDuffXfermode);
float radius = getScaledRadius();
@@ -336,6 +337,7 @@
}
mDrawingDelegate = null;
+ isClipping = true;
invalidate();
}
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index b83c9b9..2455eab 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -206,7 +206,10 @@
@Override
public void onAnimationEnd(Animator animation) {
((ViewGroup) getParent()).findViewById(R.id.divider).setVisibility(GONE);
- ((ViewGroup) getParent()).removeView(NotificationFooterLayout.this);
+ // Keep view around because gutter is aligned to it, but remove height to
+ // both hide the view and keep calculations correct for last dismissal.
+ getLayoutParams().height = 0;
+ requestLayout();
}
});
collapseFooter.start();
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index 0cd5a4c..11f6aa0 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -17,6 +17,8 @@
package com.android.launcher3.notification;
import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.app.Notification;
import android.content.Context;
import android.graphics.Rect;
@@ -28,7 +30,9 @@
import android.widget.TextView;
import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertyResetListener;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
@@ -89,6 +93,8 @@
}
public Animator animateHeightRemoval(int heightToRemove, boolean shouldRemoveFromTop) {
+ AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+
Rect startRect = new Rect(mPillRect);
Rect endRect = new Rect(mPillRect);
if (shouldRemoveFromTop) {
@@ -96,8 +102,18 @@
} else {
endRect.bottom -= heightToRemove;
}
- return new RoundedRectRevealOutlineProvider(getBackgroundRadius(), getBackgroundRadius(),
- startRect, endRect, mRoundedCorners).createRevealAnimator(this, false);
+ anim.play(new RoundedRectRevealOutlineProvider(getBackgroundRadius(), getBackgroundRadius(),
+ startRect, endRect, mRoundedCorners).createRevealAnimator(this, false));
+
+ View bottomGutter = findViewById(R.id.gutter_bottom);
+ if (bottomGutter != null && bottomGutter.getVisibility() == VISIBLE) {
+ Animator translateGutter = ObjectAnimator.ofFloat(bottomGutter, TRANSLATION_Y,
+ -heightToRemove);
+ translateGutter.addListener(new PropertyResetListener<>(TRANSLATION_Y, 0f));
+ anim.play(translateGutter);
+ }
+
+ return anim;
}
public void updateHeader(int notificationCount, @Nullable IconPalette palette) {
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index c6ae0d2..3de9bad 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -44,7 +44,6 @@
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
@@ -118,6 +117,7 @@
private boolean mIsLeftAligned;
protected boolean mIsAboveIcon;
private View mArrow;
+ private int mGravity;
protected Animator mOpenCloseAnimator;
private boolean mDeferContainerRemoval;
@@ -490,9 +490,10 @@
}
y -= insets.top;
- if (y < dragLayer.getTop() || y + height > dragLayer.getBottom()) {
+ mGravity = 0;
+ if (y + height > dragLayer.getBottom() - insets.bottom) {
// The container is opening off the screen, so just center it in the drag layer instead.
- ((FrameLayout.LayoutParams) getLayoutParams()).gravity = Gravity.CENTER_VERTICAL;
+ mGravity = Gravity.CENTER_VERTICAL;
// Put the container next to the icon, preferring the right side in ltr (left in rtl).
int rightSide = leftAlignedX + iconWidth - insets.left;
int leftSide = rightAlignedX - iconWidth - insets.left;
@@ -518,14 +519,17 @@
if (x < dragLayer.getLeft() || x + width > dragLayer.getRight()) {
// If we are still off screen, center horizontally too.
- ((FrameLayout.LayoutParams) getLayoutParams()).gravity |= Gravity.CENTER_HORIZONTAL;
+ mGravity |= Gravity.CENTER_HORIZONTAL;
}
- int gravity = ((FrameLayout.LayoutParams) getLayoutParams()).gravity;
- if (!Gravity.isHorizontal(gravity)) {
+ if (Gravity.isHorizontal(mGravity)) {
+ setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
+ } else {
setX(x);
}
- if (!Gravity.isVertical(gravity)) {
+ if (Gravity.isVertical(mGravity)) {
+ setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);
+ } else {
setY(y);
}
}
@@ -555,7 +559,7 @@
}
View arrowView = new View(getContext());
- if (Gravity.isVertical(((FrameLayout.LayoutParams) getLayoutParams()).gravity)) {
+ if (Gravity.isVertical(mGravity)) {
// This is only true if there wasn't room for the container next to the icon,
// so we centered it instead. In that case we don't want to show the arrow.
arrowView.setVisibility(INVISIBLE);
diff --git a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
index f6fffe0..b4fa04e 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
@@ -24,7 +24,6 @@
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
@@ -145,18 +144,8 @@
if (mSystemShortcutIcons == null) {
mSystemShortcutIcons = (LinearLayout) mLauncher.getLayoutInflater().inflate(
R.layout.system_shortcut_icons, mContent, false);
-
- View divider = LayoutInflater.from(getContext()).inflate(
- R.layout.horizontal_divider, this, false);
-
boolean iconsAreBelowShortcuts = mShortcutsLayout.getChildCount() > 0;
- if (iconsAreBelowShortcuts) {
- mContent.addView(divider);
- mContent.addView(mSystemShortcutIcons);
- } else {
- mContent.addView(divider, 0);
- mContent.addView(mSystemShortcutIcons, 0);
- }
+ mContent.addView(mSystemShortcutIcons, iconsAreBelowShortcuts ? -1 : 0);
}
mSystemShortcutIcons.addView(shortcutView, index);
} else {