Moving widget reinflation to push model

Instead of checking every widget, a widget which needs reinflation
would post a callback on launcher avoiding unnecessary loops in onResume

Bug: 67305604
Change-Id: I53e08d6f4795f7b716a9debca5c0c68dd25a7afe
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 9d31492..7688b9d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -908,14 +908,6 @@
             mWaitingForResume.setStayPressed(false);
         }
 
-        // It is possible that widgets can receive updates while launcher is not in the foreground.
-        // Consequently, the widgets will be inflated in the orientation of the foreground activity
-        // (framework issue). On resuming, we ensure that any widgets are inflated for the current
-        // orientation.
-        if (!isWorkspaceLoading()) {
-            getWorkspace().reinflateWidgetsIfNecessary();
-        }
-
         updateInteraction(Workspace.State.NORMAL, mWorkspace.getState());
         mWorkspace.onResume();
 
@@ -3257,7 +3249,10 @@
             info.pendingItemInfo = null;
         }
 
-        mWorkspace.reinflateWidgetsIfNecessary();
+        if (((PendingAppWidgetHostView) view).isReinflateIfNeeded()) {
+            view.reinflate();
+        }
+
         getModelWriter().updateItemInDatabase(info);
         return info;
     }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 819f23f..70440fa 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -122,7 +122,6 @@
                     context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             inflater.inflate(appWidget.initialLayout, lahv);
             lahv.setAppWidget(0, appWidget);
-            lahv.updateLastInflationOrientation();
             return lahv;
         } else {
             try {
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 7fe1308..6f953e5 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -19,6 +19,7 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Handler;
@@ -58,10 +59,14 @@
 
     private final CheckLongPressHelper mLongPressHelper;
     private final StylusEventHelper mStylusEventHelper;
-    private final Context mContext;
+    private final Launcher mLauncher;
+
+    private static final int DONT_REINFLATE = 0;
+    private static final int REINFLATE_ON_RESUME = 1;
+    private static final int REINFLATE_ON_CONFIG_CHANGE = 2;
 
     @ViewDebug.ExportedProperty(category = "launcher")
-    private int mPreviousOrientation;
+    private int mReinflateStatus;
 
     private float mSlop;
 
@@ -85,11 +90,11 @@
 
     public LauncherAppWidgetHostView(Context context) {
         super(context);
-        mContext = context;
+        mLauncher = Launcher.getLauncher(context);
         mLongPressHelper = new CheckLongPressHelper(this, this);
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
         mInflater = LayoutInflater.from(context);
-        setAccessibilityDelegate(Launcher.getLauncher(context).getAccessibilityDelegate());
+        setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
         setBackgroundResource(R.drawable.widget_internal_focus_bg);
 
         if (Utilities.ATLEAST_OREO) {
@@ -112,18 +117,28 @@
         return mInflater.inflate(R.layout.appwidget_error, this, false);
     }
 
-    public void updateLastInflationOrientation() {
-        mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
-    }
-
     @Override
     public void updateAppWidget(RemoteViews remoteViews) {
-        // Store the orientation in which the widget was inflated
-        updateLastInflationOrientation();
         super.updateAppWidget(remoteViews);
 
         // The provider info or the views might have changed.
         checkIfAutoAdvance();
+
+        // It is possible that widgets can receive updates while launcher is not in the foreground.
+        // Consequently, the widgets will be inflated for the orientation of the foreground activity
+        // (framework issue). On resuming, we ensure that any widgets are inflated for the current
+        // orientation.
+        if (mReinflateStatus == DONT_REINFLATE && !isSameOrientation()) {
+            mReinflateStatus = REINFLATE_ON_RESUME;
+            if (!mLauncher.waitUntilResume(new ReInflateRunnable())) {
+                mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE;
+            }
+        }
+    }
+
+    private boolean isSameOrientation() {
+        return mLauncher.getResources().getConfiguration().orientation ==
+                mLauncher.getOrientation();
     }
 
     private boolean checkScrollableRecursively(ViewGroup viewGroup) {
@@ -142,14 +157,6 @@
         return false;
     }
 
-    public boolean isReinflateRequired(int orientation) {
-        // Re-inflate is required if the orientation has changed since last inflated.
-        if (mPreviousOrientation != orientation) {
-           return true;
-       }
-       return false;
-    }
-
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         // Just in case the previous long press hasn't been cleared, we make sure to start fresh
         // on touch down.
@@ -473,4 +480,45 @@
     public PointF getTranslationForCentering() {
         return mTranslationForCentering;
     }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        if (mReinflateStatus == REINFLATE_ON_CONFIG_CHANGE) {
+            // We are finally in the same orientation
+            reinflateIfNecessary();
+        }
+    }
+
+    private void reinflateIfNecessary() {
+        if (!isSameOrientation()) {
+            // We cannot reinflate yet, wait until next config change
+            mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE;
+            return;
+        }
+
+        mReinflateStatus = DONT_REINFLATE;
+        if (isAttachedToWindow()) {
+            LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+            reinflate();
+        }
+    }
+
+    public void reinflate() {
+        LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+        // Remove and rebind the current widget (which was inflated in the wrong
+        // orientation), but don't delete it from the database
+        mLauncher.removeItem(this, info, false  /* deleteFromDb */);
+        mLauncher.bindAppWidget(info);
+    }
+
+    private class ReInflateRunnable implements Runnable {
+        @Override
+        public void run() {
+            if (mReinflateStatus == REINFLATE_ON_RESUME) {
+                reinflateIfNecessary();
+            }
+        }
+    }
 }
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index c2d5501..b86d413 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -110,9 +110,7 @@
         mClickListener = l;
     }
 
-    @Override
-    public boolean isReinflateRequired(int orientation) {
-        // Re inflate is required any time the widget restore status changes
+    public boolean isReinflateIfNeeded() {
         return mStartState != mInfo.restoreStatus;
     }
 
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index b80bdc0..7297ee1 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1043,30 +1043,6 @@
         return super.onInterceptTouchEvent(ev);
     }
 
-    protected void reinflateWidgetsIfNecessary() {
-        final int clCount = getChildCount();
-        for (int i = 0; i < clCount; i++) {
-            CellLayout cl = (CellLayout) getChildAt(i);
-            ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();
-            final int itemCount = swc.getChildCount();
-            for (int j = 0; j < itemCount; j++) {
-                View v = swc.getChildAt(j);
-
-                if (v instanceof LauncherAppWidgetHostView
-                        && v.getTag() instanceof LauncherAppWidgetInfo) {
-                    LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
-                    LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) v;
-                    if (lahv.isReinflateRequired(mLauncher.getOrientation())) {
-                        // Remove and rebind the current widget (which was inflated in the wrong
-                        // orientation), but don't delete it from the database
-                        mLauncher.removeItem(lahv, info, false  /* deleteFromDb */);
-                        mLauncher.bindAppWidget(info);
-                    }
-                }
-            }
-        }
-    }
-
     @Override
     protected void determineScrollingStart(MotionEvent ev) {
         if (!isFinishedSwitchingState()) return;