Merge "Salt packageNameHash with unique user identifier Bug: 62676166" 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/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/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 4b71ba0..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;
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/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/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index c0b5fe1..c8203f7 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -23,6 +23,7 @@
 import android.graphics.Region;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
+import android.widget.TextView;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
@@ -50,13 +51,12 @@
 
     @Override
     public void onDraw(Canvas canvas) {
-        // If text is transparent, don't draw any shadow
-        int alpha = Color.alpha(getCurrentTextColor());
-        if (alpha == 0) {
-            getPaint().clearShadowLayer();
+        // If text is transparent or shadow alpha is 0, don't draw any shadow
+        if (mShadowInfo.skipDoubleShadow(this)) {
             super.onDraw(canvas);
             return;
         }
+        int alpha = Color.alpha(getCurrentTextColor());
 
         // We enhance the shadow by drawing the shadow twice
         getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0,
@@ -97,5 +97,25 @@
             keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
             a.recycle();
         }
+
+        public boolean skipDoubleShadow(TextView textView) {
+            int textAlpha = Color.alpha(textView.getCurrentTextColor());
+            int keyShadowAlpha = Color.alpha(keyShadowColor);
+            int ambientShadowAlpha = Color.alpha(ambientShadowColor);
+            if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
+                textView.getPaint().clearShadowLayer();
+                return true;
+            } else if (ambientShadowAlpha > 0) {
+                textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
+                        ColorUtils.setAlphaComponent(ambientShadowColor, textAlpha));
+                return true;
+            } else if (keyShadowAlpha > 0) {
+                textView.getPaint().setShadowLayer(keyShadowBlur, 0.0f, keyShadowOffset,
+                        ColorUtils.setAlphaComponent(keyShadowColor, textAlpha));
+                return true;
+            } else {
+                return false;
+            }
+        }
     }
 }