diff options
author | Tony Wickham <twickham@google.com> | 2015-10-14 15:23:04 -0700 |
---|---|---|
committer | Tony Wickham <twickham@google.com> | 2015-10-15 10:07:06 -0700 |
commit | a0628cc521614835933db74ba5a2536a936629c5 (patch) | |
tree | 9f3b737e5ff18015af6aa8d858f26a76acce707f /src/com/android/launcher3/widget/WidgetHostViewLoader.java | |
parent | fd4264b2b52e294ccb1326784bdf1df2cd7fe14c (diff) | |
download | android_packages_apps_Trebuchet-a0628cc521614835933db74ba5a2536a936629c5.tar.gz android_packages_apps_Trebuchet-a0628cc521614835933db74ba5a2536a936629c5.tar.bz2 android_packages_apps_Trebuchet-a0628cc521614835933db74ba5a2536a936629c5.zip |
Fix "The specified child already has a parent" IllegalStateException.
The problem was due to a race condition between removing a prebound
widget view from the drag layer and adding the same view to the
workspace upon dropping it; if you let go of the widget immediately
after picking it up, the latter happened before the former.
Specifically, the flow was: long-click a widget --> drop --> remove
the view from the drag layer if it's not null (it is, so nothing
happens) --> the view is finally bound/inflated and added to the drag
layer --> add the view to the workspace --> already has a parent.
There are actually 2 problems here: one is that the bind/inflate is
asynchronous, and can therefore happen after dropping the widget view
being inflated, and the other is that the view is added to the
workspace even though the transition has barely started (we usually
ignore drops if the transition is less than half complete). It turns
out that this second problem was also due to a race condition, this
time between dropping a widget or app onto the workspace and calling
LauncherStateTransitionAnimation.dispatchOnLauncherTransitionStart().
If the drop happened before the dispatch, as in the case of the
crash, then the drop was accepted because the transition progress was
still 1.0 from the previous transition.
I fixed the first problem by removing the drag layer widget view
in Launcher where it is potentially used instead of Workspace. And I
fixed the second problem by setting mTransitionProgress to 0 in
Workspace.onLauncherTransitionPrepare().
I also added some debugging logs.
Bug: 23896857
Change-Id: I66944e6d3f23b70dea15f7fb01af0763a1bfcbda
Diffstat (limited to 'src/com/android/launcher3/widget/WidgetHostViewLoader.java')
-rw-r--r-- | src/com/android/launcher3/widget/WidgetHostViewLoader.java | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java index 461aebb6b..5d3af5254 100644 --- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -4,13 +4,13 @@ import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; import android.content.Context; import android.graphics.Rect; -import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.util.Log; import android.view.View; import com.android.launcher3.AppWidgetResizeFrame; -import com.android.launcher3.DragController.DragListener; +import com.android.launcher3.DragController; import com.android.launcher3.DragLayer; import com.android.launcher3.DragSource; import com.android.launcher3.Launcher; @@ -19,7 +19,9 @@ import com.android.launcher3.Utilities; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.util.Thunk; -public class WidgetHostViewLoader implements DragListener { +public class WidgetHostViewLoader implements DragController.DragListener { + private static final String TAG = "WidgetHostViewLoader"; + private static final boolean LOGD = false; /* Runnables to handle inflation and binding. */ @Thunk Runnable mInflateWidgetRunnable = null; @@ -48,6 +50,10 @@ public class WidgetHostViewLoader implements DragListener { @Override public void onDragEnd() { + if (LOGD) { + Log.d(TAG, "Cleaning up in onDragEnd()..."); + } + // Cleanup up preloading state. mLauncher.getDragController().removeDragListener(this); @@ -62,6 +68,9 @@ public class WidgetHostViewLoader implements DragListener { // The widget was inflated and added to the DragLayer -- remove it. if (mInfo.boundWidget != null) { + if (LOGD) { + Log.d(TAG, "...removing widget from drag layer"); + } mLauncher.getDragLayer().removeView(mInfo.boundWidget); mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId()); mInfo.boundWidget = null; @@ -89,6 +98,9 @@ public class WidgetHostViewLoader implements DragListener { @Override public void run() { mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); + if (LOGD) { + Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId); + } if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed( mWidgetLoadingId, pInfo, options)) { @@ -101,6 +113,9 @@ public class WidgetHostViewLoader implements DragListener { mInflateWidgetRunnable = new Runnable() { @Override public void run() { + if (LOGD) { + Log.d(TAG, "Inflating widget, id: " + mWidgetLoadingId); + } if (mWidgetLoadingId == -1) { return; } @@ -120,11 +135,17 @@ public class WidgetHostViewLoader implements DragListener { lp.x = lp.y = 0; lp.customPosition = true; hostView.setLayoutParams(lp); + if (LOGD) { + Log.d(TAG, "Adding host view to drag layer"); + } mLauncher.getDragLayer().addView(hostView); mView.setTag(mInfo); } }; + if (LOGD) { + Log.d(TAG, "About to bind/inflate widget"); + } mHandler.post(mBindWidgetRunnable); return true; } |