Merge "Tying accessibility drag lifecycle to that of dragController" into ub-launcher3-burnaby
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 81d595a..76ad8c1 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.util.Log;
 
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index b40ace3..dc0bccc 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -146,7 +146,6 @@
     private long mLastBackupRestoreTime;
     private boolean mBackupDataWasUpdated;
 
-    private LauncherAppState mLauncherAppState;
     private IconCache mIconCache;
     private DeviceProfieData mDeviceProfileData;
 
@@ -205,7 +204,11 @@
             return;
         }
 
-        lazyInitAppState(true /* noCreate */);
+        if (mDeviceProfileData == null) {
+            LauncherAppState app = LauncherAppState.getInstance();
+            mDeviceProfileData = initDeviceProfileData(app.getInvariantDeviceProfile());
+            mIconCache = app.getIconCache();
+        }
 
         Log.v(TAG, "lastBackupTime = " + in.t);
         mKeys.clear();
@@ -240,7 +243,7 @@
                 // Check if any metadata has changed
                 mBackupDataWasUpdated = (in.profile == null)
                         || !Arrays.equals(DeviceProfieData.toByteArray(in.profile),
-                            DeviceProfieData.toByteArray(getDeviceProfieData()))
+                            DeviceProfieData.toByteArray(mDeviceProfileData))
                         || (in.backupVersion != BACKUP_VERSION)
                         || (in.appVersion != getAppVersion());
             }
@@ -268,8 +271,7 @@
      * to this device.
      */
     private boolean isBackupCompatible(Journal oldState) {
-        DeviceProfieData currentProfile = getDeviceProfieData();
-
+        DeviceProfieData currentProfile = mDeviceProfileData;
         DeviceProfieData oldProfile = oldState.profile;
 
         if (oldProfile == null || oldProfile.desktopCols == 0) {
@@ -302,7 +304,14 @@
         if (!restoreSuccessful) {
             return;
         }
-        lazyInitAppState(false /* noCreate */);
+
+        if (mDeviceProfileData == null) {
+            // This call does not happen on a looper thread. So LauncherAppState
+            // can't be created . Instead initialize required dependencies directly.
+            InvariantDeviceProfile profile = new InvariantDeviceProfile(mContext);
+            mDeviceProfileData = initDeviceProfileData(profile);
+            mIconCache = new IconCache(mContext, profile);
+        }
 
         int dataSize = data.size();
         if (mBuffer.length < dataSize) {
@@ -379,7 +388,7 @@
         journal.key = mKeys.toArray(new BackupProtos.Key[mKeys.size()]);
         journal.appVersion = getAppVersion();
         journal.backupVersion = BACKUP_VERSION;
-        journal.profile = getDeviceProfieData();
+        journal.profile = mDeviceProfileData;
         return journal;
     }
 
@@ -392,31 +401,6 @@
         }
     }
 
-    /**
-     * @return the current device profile information.
-     */
-    private DeviceProfieData getDeviceProfieData() {
-        return mDeviceProfileData;
-    }
-
-    private void lazyInitAppState(boolean noCreate) {
-        if (mLauncherAppState != null) {
-            return;
-        }
-
-        if (noCreate) {
-            mLauncherAppState = LauncherAppState.getInstanceNoCreate();
-        } else {
-            LauncherAppState.setApplicationContext(mContext);
-            mLauncherAppState = LauncherAppState.getInstance();
-        }
-
-        mIconCache = mLauncherAppState.getIconCache();
-        InvariantDeviceProfile profile = mLauncherAppState.getInvariantDeviceProfile();
-
-        mDeviceProfileData = initDeviceProfileData(profile);
-    }
-
     private DeviceProfieData initDeviceProfileData(InvariantDeviceProfile profile) {
         DeviceProfieData data = new DeviceProfieData();
         data.desktopRows = profile.numRows;
@@ -631,7 +615,6 @@
     private void backupWidgets(BackupDataOutput data) throws IOException {
         // persist static widget info that hasn't been persisted yet
         final ContentResolver cr = mContext.getContentResolver();
-        final WidgetPreviewLoader previewLoader = mLauncherAppState.getWidgetCache();
         final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
         int backupWidgetCount = 0;
 
@@ -644,7 +627,6 @@
             while(cursor.moveToNext()) {
                 final long id = cursor.getLong(ID_INDEX);
                 final String providerName = cursor.getString(APPWIDGET_PROVIDER_INDEX);
-                final int spanX = cursor.getInt(SPANX_INDEX);
                 final ComponentName provider = ComponentName.unflattenFromString(providerName);
                 Key key = null;
                 String backupKey = null;
@@ -664,9 +646,7 @@
                     if (backupWidgetCount < MAX_WIDGETS_PER_PASS) {
                         if (DEBUG) Log.d(TAG, "saving widget " + backupKey);
                         UserHandleCompat user = UserHandleCompat.myUserHandle();
-                        writeRowToBackup(key,
-                                packWidget(dpi, previewLoader, mIconCache, provider, user),
-                                data);
+                        writeRowToBackup(key, packWidget(dpi, provider, user), data);
                         mKeys.add(key);
                         backupWidgetCount ++;
                     } else {
@@ -895,7 +875,7 @@
                 UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle);
         values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber);
 
-        DeviceProfieData currentProfile = getDeviceProfieData();
+        DeviceProfieData currentProfile = mDeviceProfileData;
 
         if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
             if (!TextUtils.isEmpty(favorite.appWidgetProvider)) {
@@ -972,8 +952,7 @@
     }
 
     /** Serialize a widget for persistence, including a checksum wrapper. */
-    private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache,
-            ComponentName provider, UserHandleCompat user) {
+    private Widget packWidget(int dpi, ComponentName provider, UserHandleCompat user) {
         final LauncherAppWidgetProviderInfo info =
                 LauncherModel.getProviderInfo(mContext, provider, user);
         Widget widget = new Widget();
@@ -982,7 +961,7 @@
         widget.configure = info.configure != null;
         if (info.icon != 0) {
             widget.icon = new Resource();
-            Drawable fullResIcon = iconCache.getFullResIcon(provider.getPackageName(), info.icon);
+            Drawable fullResIcon = mIconCache.getFullResIcon(provider.getPackageName(), info.icon);
             Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext);
             widget.icon.data = Utilities.flattenBitmap(icon);
             widget.icon.dpi = dpi;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 10b8648..a132e91 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -45,6 +45,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.TransactionTooLargeException;
 import android.provider.BaseColumns;
 import android.text.TextUtils;
 import android.util.Log;
@@ -3284,27 +3285,51 @@
 
     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,
             boolean refresh) {
-        synchronized (sBgLock) {
-            if (sBgWidgetProviders == null || refresh) {
-                sBgWidgetProviders = new HashMap<>();
-                AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);
-                LauncherAppWidgetProviderInfo info;
+        ArrayList<LauncherAppWidgetProviderInfo> results =
+                new ArrayList<LauncherAppWidgetProviderInfo>();
+        try {
+            synchronized (sBgLock) {
+                if (sBgWidgetProviders == null || refresh) {
+                    HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders
+                            = new HashMap<>();
+                    AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);
+                    LauncherAppWidgetProviderInfo info;
 
-                List<AppWidgetProviderInfo> widgets = wm.getAllProviders();
-                for (AppWidgetProviderInfo pInfo : widgets) {
-                    info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);
-                    UserHandleCompat user = wm.getUser(info);
-                    sBgWidgetProviders.put(new ComponentKey(info.provider, user), info);
-                }
+                    List<AppWidgetProviderInfo> widgets = wm.getAllProviders();
+                    for (AppWidgetProviderInfo pInfo : widgets) {
+                        info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);
+                        UserHandleCompat user = wm.getUser(info);
+                        tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);
+                    }
 
-                Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();
-                for (CustomAppWidget widget : customWidgets) {
-                    info = new LauncherAppWidgetProviderInfo(context, widget);
-                    UserHandleCompat user = wm.getUser(info);
-                    sBgWidgetProviders.put(new ComponentKey(info.provider, user), info);
+                    Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();
+                    for (CustomAppWidget widget : customWidgets) {
+                        info = new LauncherAppWidgetProviderInfo(context, widget);
+                        UserHandleCompat user = wm.getUser(info);
+                        tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);
+                    }
+                    // Replace the global list at the very end, so that if there is an exception,
+                    // previously loaded provider list is used.
+                    sBgWidgetProviders = tmpWidgetProviders;
                 }
+                results.addAll(sBgWidgetProviders.values());
+                return results;
             }
-            return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());
+        } catch (Exception e) {
+            if (e.getCause() instanceof TransactionTooLargeException) {
+                // the returned value may be incomplete and will not be refreshed until the next
+                // time Launcher starts.
+                // TODO: after figuring out a repro step, introduce a dirty bit to check when
+                // onResume is called to refresh the widget provider list.
+                synchronized (sBgLock) {
+                    if (sBgWidgetProviders != null) {
+                        results.addAll(sBgWidgetProviders.values());
+                    }
+                    return results;
+                }
+            } else {
+                throw e;
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 18832c6..4a85b44 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -567,6 +567,13 @@
     public void scrollTo(int x, int y) {
         // In free scroll mode, we clamp the scrollX
         if (mFreeScroll) {
+            // If the scroller is trying to move to a location beyond the maximum allowed
+            // in the free scroll mode, we make sure to end the scroll operation.
+            if (!mScroller.isFinished() &&
+                    (x > mFreeScrollMaxScrollX || x < mFreeScrollMinScrollX)) {
+                forceFinishScroller();
+            }
+
             x = Math.min(x, mFreeScrollMaxScrollX);
             x = Math.max(x, mFreeScrollMinScrollX);
         }
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 4aa3323..9d265f8 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -25,7 +25,6 @@
 
 import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.PackageItemInfo;
 
@@ -37,7 +36,6 @@
     private static final String TAG = "WidgetsRecyclerView";
     private WidgetsModel mWidgets;
     private Rect mBackgroundPadding = new Rect();
-    private PackageItemInfo mLastPackageItemInfo;
 
     public WidgetsRecyclerView(Context context) {
         this(context, null);
@@ -48,9 +46,15 @@
     }
 
     public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        // API 21 and below only support 3 parameter ctor.
         super(context, attrs, defStyleAttr);
     }
 
+    public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        this(context, attrs, defStyleAttr);
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();