Adding WidgetAddFlowHandler to handle widget addition and configuration.

This will allow us to override the implementation and provide custom
logic for widget addition.

Bug: 33584624
Change-Id: I310bf39e301c7e1c8de4f62456594535e2fe5bbc
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 9245f18..8d8a70c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -123,6 +123,7 @@
 import com.android.launcher3.util.ViewOnDrawExecutor;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetAddFlowHandler;
 import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetsContainerView;
 
@@ -683,8 +684,9 @@
                     // Since the view was just bound, also launch the configure activity if needed
                     LauncherAppWidgetProviderInfo provider = mAppWidgetManager
                             .getLauncherAppWidgetInfo(widgetId);
-                    if (provider != null && provider.configure != null) {
-                        startRestoredWidgetReconfigActivity(provider, widgetInfo);
+                    if (provider != null) {
+                        new WidgetAddFlowHandler(provider)
+                                .startConfigActivity(this, widgetInfo, REQUEST_RECONFIGURE_APPWIDGET);
                     }
                 }
                 break;
@@ -731,7 +733,7 @@
             } else if (resultCode == RESULT_OK) {
                 addAppWidgetImpl(
                         appWidgetId, requestArgs, null,
-                        requestArgs.getWidgetProvider(this),
+                        requestArgs.getWidgetHandler(),
                         ON_ACTIVITY_RESULT_ANIMATION_DELAY);
             }
             return;
@@ -890,7 +892,7 @@
         if (resultCode == RESULT_OK) {
             animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
             final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
-                    requestArgs.getWidgetProvider(this));
+                    requestArgs.getWidgetHandler().getProviderInfo(this));
             boundWidget = layout;
             onCompleteRunnable = new Runnable() {
                 @Override
@@ -1983,7 +1985,7 @@
         }
     }
 
-    private void setWaitingForResult(PendingRequestArgs args) {
+    public void setWaitingForResult(PendingRequestArgs args) {
         boolean isLocked = isWorkspaceLocked();
         mPendingRequestArgs = args;
         if (isLocked != isWorkspaceLocked()) {
@@ -1998,24 +2000,18 @@
     }
 
     void addAppWidgetFromDropImpl(int appWidgetId, ItemInfo info, AppWidgetHostView boundWidget,
-            LauncherAppWidgetProviderInfo appWidgetInfo) {
+            WidgetAddFlowHandler addFlowHandler) {
         if (LOGD) {
             Log.d(TAG, "Adding widget from drop");
         }
-        addAppWidgetImpl(appWidgetId, info, boundWidget, appWidgetInfo, 0);
+        addAppWidgetImpl(appWidgetId, info, boundWidget, addFlowHandler, 0);
     }
 
     void addAppWidgetImpl(int appWidgetId, ItemInfo info,
-            AppWidgetHostView boundWidget, LauncherAppWidgetProviderInfo appWidgetInfo,
-            int delay) {
-        if (appWidgetInfo.configure != null) {
-            setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, appWidgetInfo, info));
+            AppWidgetHostView boundWidget, WidgetAddFlowHandler addFlowHandler, int delay) {
+        if (!addFlowHandler.startConfigActivity(this, appWidgetId, info, REQUEST_CREATE_APPWIDGET)) {
+            // If the configuration flow was not started, add the widget
 
-            // Launch over to configure widget, if needed
-            mAppWidgetManager.startConfigActivity(appWidgetInfo, appWidgetId, this,
-                    mAppWidgetHost, REQUEST_CREATE_APPWIDGET);
-        } else {
-            // Otherwise just add it
             Runnable onComplete = new Runnable() {
                 @Override
                 public void run() {
@@ -2024,7 +2020,7 @@
                             null);
                 }
             };
-            completeAddAppWidget(appWidgetId, info, boundWidget, appWidgetInfo);
+            completeAddAppWidget(appWidgetId, info, boundWidget, addFlowHandler.getProviderInfo(this));
             mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete, delay, false);
         }
     }
@@ -2076,6 +2072,7 @@
     private void addAppWidgetFromDrop(PendingAddWidgetInfo info) {
         AppWidgetHostView hostView = info.boundWidget;
         int appWidgetId;
+        WidgetAddFlowHandler addFlowHandler = info.getHander();
         if (hostView != null) {
             // In the case where we've prebound the widget, we remove it from the DragLayer
             if (LOGD) {
@@ -2084,7 +2081,7 @@
             getDragLayer().removeView(hostView);
 
             appWidgetId = hostView.getAppWidgetId();
-            addAppWidgetFromDropImpl(appWidgetId, info, hostView, info.info);
+            addAppWidgetFromDropImpl(appWidgetId, info, hostView, addFlowHandler);
 
             // Clear the boundWidget so that it doesn't get destroyed.
             info.boundWidget = null;
@@ -2097,17 +2094,9 @@
             boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
                     appWidgetId, info.info, options);
             if (success) {
-                addAppWidgetFromDropImpl(appWidgetId, info, null, info.info);
+                addAppWidgetFromDropImpl(appWidgetId, info, null, addFlowHandler);
             } else {
-                setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, info.info, info));
-                Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
-                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
-                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
-                        info.info.getUser());
-                // TODO: we need to make sure that this accounts for the options bundle.
-                // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
-                startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
+                addFlowHandler.startBindFlow(this, appWidgetId, info, REQUEST_BIND_APPWIDGET);
             }
         }
     }
@@ -2323,30 +2312,22 @@
 
         final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
         if (v.isReadyForClickSetup()) {
+            LauncherAppWidgetProviderInfo appWidgetInfo =
+                    mAppWidgetManager.findProvider(info.providerName, info.user);
+            if (appWidgetInfo == null) {
+                return;
+            }
+            WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo);
+
             if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
                 if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
                     // This should not happen, as we make sure that an Id is allocated during bind.
                     return;
                 }
-                LauncherAppWidgetProviderInfo appWidgetInfo =
-                        mAppWidgetManager.findProvider(info.providerName, info.user);
-                if (appWidgetInfo != null) {
-                    setWaitingForResult(PendingRequestArgs
-                            .forWidgetInfo(info.appWidgetId, appWidgetInfo, info));
-
-                    Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
-                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, info.appWidgetId);
-                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, appWidgetInfo.provider);
-                    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
-                            appWidgetInfo.getUser());
-                    startActivityForResult(intent, REQUEST_BIND_PENDING_APPWIDGET);
-                }
+                addFlowHandler.startBindFlow(this, info.appWidgetId, info,
+                        REQUEST_BIND_PENDING_APPWIDGET);
             } else {
-                LauncherAppWidgetProviderInfo appWidgetInfo =
-                        mAppWidgetManager.getLauncherAppWidgetInfo(info.appWidgetId);
-                if (appWidgetInfo != null) {
-                    startRestoredWidgetReconfigActivity(appWidgetInfo, info);
-                }
+                addFlowHandler.startConfigActivity(this, info, REQUEST_RECONFIGURE_APPWIDGET);
             }
         } else {
             final String packageName = info.providerName.getPackageName();
@@ -2354,13 +2335,6 @@
         }
     }
 
-    private void startRestoredWidgetReconfigActivity(
-            LauncherAppWidgetProviderInfo provider, LauncherAppWidgetInfo info) {
-        setWaitingForResult(PendingRequestArgs.forWidgetInfo(info.appWidgetId, provider, info));
-        mAppWidgetManager.startConfigActivity(provider,
-                info.appWidgetId, this, mAppWidgetHost, REQUEST_RECONFIGURE_APPWIDGET);
-    }
-
     /**
      * Event handler for the "grid" button that appears on the home screen, which
      * enters all apps mode.
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index b68a64b..285a93c 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -76,7 +76,7 @@
      * Identifier for this widget when talking with
      * {@link android.appwidget.AppWidgetManager} for updates.
      */
-    int appWidgetId = NO_ID;
+    public int appWidgetId = NO_ID;
 
     public ComponentName providerName;
 
diff --git a/src/com/android/launcher3/util/PendingRequestArgs.java b/src/com/android/launcher3/util/PendingRequestArgs.java
index 9452fbd..538e1df 100644
--- a/src/com/android/launcher3/util/PendingRequestArgs.java
+++ b/src/com/android/launcher3/util/PendingRequestArgs.java
@@ -15,15 +15,13 @@
  */
 package com.android.launcher3.util;
 
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import com.android.launcher3.ItemInfo;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.WidgetAddFlowHandler;
 
 /**
  * Utility class to store information regarding a pending request made by launcher. This information
@@ -58,12 +56,7 @@
 
         mArg1 = parcel.readInt();
         mObjectType = parcel.readInt();
-        if (parcel.readInt() != 0) {
-            mObject = (mObjectType == TYPE_INTENT ? Intent.CREATOR : AppWidgetProviderInfo.CREATOR)
-                    .createFromParcel(parcel);
-        } else {
-            mObject = null;
-        }
+        mObject = parcel.readParcelable(null);
     }
 
     @Override
@@ -79,18 +72,11 @@
 
         dest.writeInt(mArg1);
         dest.writeInt(mObjectType);
-        if (mObject != null) {
-            dest.writeInt(1);
-            mObject.writeToParcel(dest, flags);
-        } else {
-            dest.writeInt(0);
-        }
+        dest.writeParcelable(mObject, flags);
     }
 
-    public LauncherAppWidgetProviderInfo getWidgetProvider(Context context) {
-        return mObjectType == TYPE_APP_WIDGET ?
-                LauncherAppWidgetProviderInfo.fromProviderInfo(
-                        context, (AppWidgetProviderInfo) mObject) : null;
+    public WidgetAddFlowHandler getWidgetHandler() {
+        return mObjectType == TYPE_APP_WIDGET ? (WidgetAddFlowHandler) mObject : null;
     }
 
     public int getWidgetId() {
@@ -106,8 +92,9 @@
     }
 
     public static PendingRequestArgs forWidgetInfo(
-            int appWidgetId, AppWidgetProviderInfo widgetInfo, ItemInfo info) {
-        PendingRequestArgs args = new PendingRequestArgs(appWidgetId, TYPE_APP_WIDGET, widgetInfo);
+            int appWidgetId, WidgetAddFlowHandler widgetHandler, ItemInfo info) {
+        PendingRequestArgs args =
+                new PendingRequestArgs(appWidgetId, TYPE_APP_WIDGET, widgetHandler);
         args.copyFrom(info);
         return args;
     }
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index 7968684..23e2f92 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -51,4 +51,8 @@
         minSpanX = i.minSpanX;
         minSpanY = i.minSpanY;
     }
+
+    public WidgetAddFlowHandler getHander() {
+        return new WidgetAddFlowHandler(info);
+    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
new file mode 100644
index 0000000..f44e56c
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
@@ -0,0 +1,108 @@
+/*
+ * 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.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.util.PendingRequestArgs;
+
+/**
+ * Utility class to handle app widget add flow.
+ */
+public class WidgetAddFlowHandler implements Parcelable {
+
+    private final AppWidgetProviderInfo mProviderInfo;
+
+    public WidgetAddFlowHandler(AppWidgetProviderInfo providerInfo) {
+        mProviderInfo = providerInfo;
+    }
+
+    private WidgetAddFlowHandler(Parcel parcel) {
+        mProviderInfo = AppWidgetProviderInfo.CREATOR.createFromParcel(parcel);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int i) {
+        mProviderInfo.writeToParcel(parcel, i);
+    }
+
+    public void startBindFlow(Launcher launcher, int appWidgetId, ItemInfo info, int requestCode) {
+        launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
+
+        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
+        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mProviderInfo.provider);
+        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
+                mProviderInfo.getProfile());
+        // TODO: we need to make sure that this accounts for the options bundle.
+        // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
+        launcher.startActivityForResult(intent, requestCode);
+    }
+
+    /**
+     * @see #startConfigActivity(Launcher, int, ItemInfo, int)
+     */
+    public boolean startConfigActivity(Launcher launcher, LauncherAppWidgetInfo info,
+            int requestCode) {
+        return startConfigActivity(launcher, info.appWidgetId, info, requestCode);
+    }
+
+    /**
+     * Starts the widget configuration flow if needed.
+     * @return true if the configuration flow was started, false otherwise.
+     */
+    public boolean startConfigActivity(Launcher launcher, int appWidgetId, ItemInfo info,
+            int requestCode) {
+        if (mProviderInfo.configure == null) {
+            return false;
+        }
+        launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info));
+
+        AppWidgetManagerCompat.getInstance(launcher).startConfigActivity(
+                mProviderInfo, appWidgetId, launcher, launcher.getAppWidgetHost(), requestCode);
+        return true;
+    }
+
+    public LauncherAppWidgetProviderInfo getProviderInfo(Context context) {
+        return LauncherAppWidgetProviderInfo.fromProviderInfo(context, mProviderInfo);
+    }
+
+    public static final Parcelable.Creator<WidgetAddFlowHandler> CREATOR =
+            new Parcelable.Creator<WidgetAddFlowHandler>() {
+                public WidgetAddFlowHandler createFromParcel(Parcel source) {
+                    return new WidgetAddFlowHandler(source);
+                }
+
+                public WidgetAddFlowHandler[] newArray(int size) {
+                    return new WidgetAddFlowHandler[size];
+                }
+            };
+}