Merge "Scaling down the icon before applying the user badge   > This also saves memory only create one new bitmap while loading instead of two" into ub-launcher3-burnaby-polish
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index c95d558..ede6c71 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -51,11 +51,6 @@
      */
     boolean usingLowResIcon;
 
-    /**
-     * The time at which the app was first installed.
-     */
-    long firstInstallTime;
-
     public ComponentName componentName;
 
     static final int DOWNLOADED_FLAG = 1;
@@ -84,7 +79,6 @@
         this.container = ItemInfo.NO_ID;
 
         flags = initFlags(info);
-        firstInstallTime = info.getFirstInstallTime();
         iconCache.getTitleAndIcon(this, info, true /* useLowResIcon */);
         intent = makeLaunchIntent(context, info, user);
         this.user = user;
@@ -109,7 +103,6 @@
         title = Utilities.trim(info.title);
         intent = new Intent(info.intent);
         flags = info.flags;
-        firstInstallTime = info.firstInstallTime;
         iconBitmap = info.iconBitmap;
     }
 
@@ -129,7 +122,6 @@
         Log.d(tag, label + " size=" + list.size());
         for (AppInfo info: list) {
             Log.d(tag, "   title=\"" + info.title + "\" iconBitmap=" + info.iconBitmap 
-                    + " firstInstallTime=" + info.firstInstallTime
                     + " componentName=" + info.componentName.getPackageName());
         }
     }
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index e983eb1..0d183db 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -17,7 +17,6 @@
 package com.android.launcher3;
 
 import android.annotation.TargetApi;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.graphics.Point;
 import android.util.DisplayMetrics;
@@ -84,9 +83,6 @@
     DeviceProfile landscapeProfile;
     DeviceProfile portraitProfile;
 
-    // On Marshmallow the status bar is no longer opaque, when drawn on the right.
-    public boolean isRightInsetOpaque;
-
     InvariantDeviceProfile() {
     }
 
@@ -170,9 +166,6 @@
                 largeSide, smallSide, true /* isLandscape */);
         portraitProfile = new DeviceProfile(context, this, smallestSize, largestSize,
                 smallSide, largeSide, false /* isLandscape */);
-
-        isRightInsetOpaque = !Utilities.ATLEAST_MARSHMALLOW ||
-                context.getSystemService(ActivityManager.class).isLowRamDevice();
     }
 
     ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 34c2943..c49d43f 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -244,4 +244,27 @@
         }
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
     }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        super.requestChildFocus(child, focused);
+        dispatchChildFocus(focused != null);
+    }
+
+    @Override
+    public void clearChildFocus(View child) {
+        super.clearChildFocus(child);
+        dispatchChildFocus(false);
+    }
+
+    @Override
+    public boolean dispatchUnhandledMove(View focused, int direction) {
+        return mChildrenFocused;
+    }
+
+    private void dispatchChildFocus(boolean focused) {
+        if (getOnFocusChangeListener() != null) {
+            getOnFocusChangeListener().onFocusChange(this, focused || isFocused());
+        }
+    }
 }
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 1c6ca87..71ccd85 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -1,17 +1,22 @@
 package com.android.launcher3;
 
+import android.annotation.TargetApi;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.View;
 
 public class LauncherRootView extends InsettableFrameLayout {
 
     private final Paint mOpaquePaint;
     private boolean mDrawRightInsetBar;
 
+    private View mAlignedView;
+
     public LauncherRootView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -21,10 +26,32 @@
     }
 
     @Override
+    protected void onFinishInflate() {
+        if (getChildCount() > 0) {
+            // LauncherRootView contains only one child, which should be aligned
+            // based on the horizontal insets.
+            mAlignedView = getChildAt(0);
+        }
+        super.onFinishInflate();
+    }
+
+    @TargetApi(23)
+    @Override
     protected boolean fitSystemWindows(Rect insets) {
-        setInsets(insets);
-        mDrawRightInsetBar = mInsets.right > 0 && LauncherAppState
-                .getInstance().getInvariantDeviceProfile().isRightInsetOpaque;
+        mDrawRightInsetBar = insets.right > 0 &&
+                (!Utilities.ATLEAST_MARSHMALLOW ||
+                getContext().getSystemService(ActivityManager.class).isLowRamDevice());
+        setInsets(mDrawRightInsetBar ? new Rect(0, insets.top, 0, insets.bottom) : insets);
+
+        if (mAlignedView != null) {
+            // Apply margins on aligned view to handle left/right insets.
+            MarginLayoutParams lp = (MarginLayoutParams) mAlignedView.getLayoutParams();
+            if (lp.leftMargin != insets.left || lp.rightMargin != insets.right) {
+                lp.leftMargin = insets.left;
+                lp.rightMargin = insets.right;
+                mAlignedView.setLayoutParams(lp);
+            }
+        }
 
         return true; // I'll take it from here
     }
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 3391d06..83b12a9 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -641,11 +641,11 @@
                     }
                     animation.play(reveal);
                 }
-
-                dispatchOnLauncherTransitionPrepare(fromView, animated, true);
-                dispatchOnLauncherTransitionPrepare(toView, animated, true);
             }
 
+            dispatchOnLauncherTransitionPrepare(fromView, animated, true);
+            dispatchOnLauncherTransitionPrepare(toView, animated, true);
+
             animation.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 9258360..b6d3cc4 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -202,9 +202,6 @@
     protected final Rect mInsets = new Rect();
     protected final boolean mIsRtl;
 
-    // When set to true, full screen content and overscroll effect is shited inside by right inset.
-    protected boolean mIgnoreRightInset;
-
     // Edge effect
     private final LauncherEdgeEffect mEdgeGlowLeft = new LauncherEdgeEffect();
     private final LauncherEdgeEffect mEdgeGlowRight = new LauncherEdgeEffect();
@@ -822,8 +819,7 @@
                     childWidthMode = MeasureSpec.EXACTLY;
                     childHeightMode = MeasureSpec.EXACTLY;
 
-                    childWidth = getViewportWidth() - mInsets.left
-                            - (mIgnoreRightInset ? mInsets.right : 0);
+                    childWidth = getViewportWidth() - mInsets.left - mInsets.right;
                     childHeight = getViewportHeight();
                 }
                 if (referenceChildWidth == 0) {
@@ -1182,9 +1178,8 @@
 
                 getEdgeVerticalPostion(sTmpIntPoint);
 
-                int width = mIgnoreRightInset ? (display.width() - mInsets.right) : display.width();
-                canvas.translate(sTmpIntPoint[0] - display.top, -width);
-                mEdgeGlowRight.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], width);
+                canvas.translate(sTmpIntPoint[0] - display.top, -display.width());
+                mEdgeGlowRight.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width());
                 if (mEdgeGlowRight.draw(canvas)) {
                     postInvalidateOnAnimation();
                 }
@@ -1225,7 +1220,17 @@
 
     @Override
     public boolean dispatchUnhandledMove(View focused, int direction) {
-        // XXX-RTL: This will be fixed in a future CL
+        if (super.dispatchUnhandledMove(focused, direction)) {
+            return true;
+        }
+
+        if (mIsRtl) {
+            if (direction == View.FOCUS_LEFT) {
+                direction = View.FOCUS_RIGHT;
+            } else if (direction == View.FOCUS_RIGHT) {
+                direction = View.FOCUS_LEFT;
+            }
+        }
         if (direction == View.FOCUS_LEFT) {
             if (getCurrentPage() > 0) {
                 snapToPage(getCurrentPage() - 1);
@@ -1237,7 +1242,7 @@
                 return true;
             }
         }
-        return super.dispatchUnhandledMove(focused, direction);
+        return false;
     }
 
     @Override
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 5766cf2..6bdcb4b 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -52,7 +52,7 @@
     public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
 
     /**
-     * The icon is being installed. If {@link FLAG_RESTORED_ICON} or {@link FLAG_AUTOINTALL_ICON}
+     * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINTALL_ICON}
      * is set, then the icon is either being installed or is in a broken state.
      */
     public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
@@ -126,19 +126,14 @@
     private int mInstallProgress;
 
     /**
-     * Refer {@link AppInfo#firstInstallTime}.
-     */
-    public long firstInstallTime;
-
-    /**
-     * TODO move this to {@link status}
+     * TODO move this to {@link #status}
      */
     int flags = 0;
 
     /**
      * If this shortcut is a placeholder, then intent will be a market intent for the package, and
      * this will hold the original intent from the database.  Otherwise, null.
-     * Refer {@link #FLAG_RESTORE_PENDING}, {@link #FLAG_INSTALL_PENDING}
+     * Refer {@link #FLAG_RESTORED_ICON}, {@link #FLAG_AUTOINTALL_ICON}
      */
     Intent promisedIntent;
 
@@ -172,7 +167,6 @@
         mIcon = info.mIcon; // TODO: should make a copy here.  maybe we don't need this ctor at all
         customIcon = info.customIcon;
         flags = info.flags;
-        firstInstallTime = info.firstInstallTime;
         user = info.user;
         status = info.status;
     }
@@ -184,7 +178,6 @@
         intent = new Intent(info.intent);
         customIcon = false;
         flags = info.flags;
-        firstInstallTime = info.firstInstallTime;
     }
 
     public void setIcon(Bitmap b) {
@@ -293,7 +286,6 @@
         shortcut.intent = AppInfo.makeLaunchIntent(context, info, info.getUser());
         shortcut.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
         shortcut.flags = AppInfo.initFlags(info);
-        shortcut.firstInstallTime = info.getFirstInstallTime();
         return shortcut;
     }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f046fbd..5073902 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -455,7 +455,6 @@
         setWallpaperDimension();
 
         setEdgeGlowColor(getResources().getColor(R.color.workspace_edge_effect_color));
-        mIgnoreRightInset = app.getInvariantDeviceProfile().isRightInsetOpaque;
     }
 
     private void setupLayoutTransition() {
@@ -1544,6 +1543,13 @@
     }
 
     @Override
+    protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
+        if (!isSwitchingState()) {
+            super.determineScrollingStart(ev, touchSlopScale);
+        }
+    }
+
+    @Override
     public void announceForAccessibility(CharSequence text) {
         // Don't announce if apps is on top of us.
         if (!mLauncher.isAppsViewVisible()) {
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index 849b05c..fb9bbb2 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -42,6 +42,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -85,6 +86,7 @@
 
     private ArrayList<ShortcutInfo> mHomescreenApps;
     private ArrayList<ShortcutInfo> mWorkFolderApps;
+    private HashMap<ShortcutInfo, Long> mShortcutToInstallTimeMap;
 
     private ManagedProfileHeuristic(Context context, UserHandleCompat user) {
         mContext = context;
@@ -100,32 +102,29 @@
                 Context.MODE_PRIVATE);
     }
 
+    private void initVars() {
+        mHomescreenApps = new ArrayList<>();
+        mWorkFolderApps = new ArrayList<>();
+        mShortcutToInstallTimeMap = new HashMap<>();
+    }
+
     /**
      * Checks the list of user apps and adds icons for newly installed apps on the homescreen or
      * workfolder.
      */
     public void processUserApps(List<LauncherActivityInfoCompat> apps) {
-        mHomescreenApps = new ArrayList<>();
-        mWorkFolderApps = new ArrayList<>();
+        initVars();
 
         HashSet<String> packageSet = new HashSet<>();
         final boolean userAppsExisted = getUserApps(packageSet);
 
         boolean newPackageAdded = false;
-
         for (LauncherActivityInfoCompat info : apps) {
             String packageName = info.getComponentName().getPackageName();
             if (!packageSet.contains(packageName)) {
                 packageSet.add(packageName);
                 newPackageAdded = true;
-
-                try {
-                    PackageInfo pkgInfo = mContext.getPackageManager()
-                            .getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
-                    markForAddition(info, pkgInfo.firstInstallTime);
-                } catch (NameNotFoundException e) {
-                    Log.e(TAG, "Unknown package " + packageName, e);
-                }
+                markForAddition(info, info.getFirstInstallTime());
             }
         }
 
@@ -142,7 +141,22 @@
         ArrayList<ShortcutInfo> targetList =
                 (installTime <= mUserCreationTime + AUTO_ADD_TO_FOLDER_DURATION) ?
                         mWorkFolderApps : mHomescreenApps;
-        targetList.add(ShortcutInfo.fromActivityInfo(info, mContext));
+        ShortcutInfo si = ShortcutInfo.fromActivityInfo(info, mContext);
+        mShortcutToInstallTimeMap.put(si, installTime);
+        targetList.add(si);
+    }
+
+    private void sortList(ArrayList<ShortcutInfo> infos) {
+        Collections.sort(infos, new Comparator<ShortcutInfo>() {
+
+            @Override
+            public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
+                Long lhsTime = mShortcutToInstallTimeMap.get(lhs);
+                Long rhsTime = mShortcutToInstallTimeMap.get(rhs);
+                return Utilities.longCompare(lhsTime == null ? 0 : lhsTime,
+                        rhsTime == null ? 0 : rhsTime);
+            }
+        });
     }
 
     /**
@@ -152,13 +166,7 @@
         if (mWorkFolderApps.isEmpty()) {
             return;
         }
-        Collections.sort(mWorkFolderApps, new Comparator<ShortcutInfo>() {
-
-            @Override
-            public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
-                return Utilities.longCompare(lhs.firstInstallTime, rhs.firstInstallTime);
-            }
-        });
+        sortList(mWorkFolderApps);
 
         // Try to get a work folder.
         String folderIdKey = USER_FOLDER_ID_PREFIX + mUserSerial;
@@ -222,6 +230,7 @@
         finalizeWorkFolder();
 
         if (addHomeScreenShortcuts && !mHomescreenApps.isEmpty()) {
+            sortList(mHomescreenApps);
             mModel.addAndBindAddedWorkspaceItems(mContext, mHomescreenApps);
         }
     }
@@ -230,9 +239,7 @@
      * Updates the list of installed apps and adds any new icons on homescreen or work folder.
      */
     public void processPackageAdd(String[] packages) {
-        mHomescreenApps = new ArrayList<>();
-        mWorkFolderApps = new ArrayList<>();
-
+        initVars();
         HashSet<String> packageSet = new HashSet<>();
         final boolean userAppsExisted = getUserApps(packageSet);