Handling configuration changes

> Adding a listener for device profile changes
> Updating various controllers instead of recreating them
> Clearing all-apps icon

Bug: 71709920
Change-Id: Ief7db199eb7494ebd8fb433198f333cd2e8e661d
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index a54c21c..4a0f52d 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -22,11 +22,16 @@
 import android.content.Intent;
 import android.view.View.AccessibilityDelegate;
 
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.util.SystemUiController;
 
+import java.util.ArrayList;
+
 public abstract class BaseActivity extends Activity {
 
+    private final ArrayList<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
+
     protected DeviceProfile mDeviceProfile;
     protected UserEventDispatcher mUserEventDispatcher;
     protected SystemUiController mSystemUiController;
@@ -87,4 +92,15 @@
     public boolean isStarted() {
         return mStarted;
     }
+
+    public void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+        mDPChangeListeners.add(listener);
+    }
+
+    protected void dispatchDeviceProfileChanged() {
+        int count = mDPChangeListeners.size();
+        for (int i = 0; i < count; i++) {
+            mDPChangeListeners.get(i).onDeviceProfileChanged(mDeviceProfile);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 5789755..2227bfd 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -518,4 +518,18 @@
         context.orientation = orientation;
         return c.createConfigurationContext(context);
     }
+
+    /**
+     * Callback when a component changes the DeviceProfile associated with it, as a result of
+     * configuration change
+     */
+    public interface OnDeviceProfileChangeListener {
+
+        /**
+         * Called when the device profile is reassigned. Note that for layout and measurements, it
+         * is sufficient to listen for inset changes. Use this callback when you need to perform
+         * a one time operation.
+         */
+        void onDeviceProfileChanged(DeviceProfile dp);
+    }
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8ef1da9..7595793 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -413,16 +413,7 @@
         if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
             mUserEventDispatcher = null;
             initDeviceProfile(mDeviceProfile.inv);
-
-            // Re create transition manager as it may rely on the device profile.
-            // TODO: Remove any dynamic states from this class.
-            mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
-
-            // TODO: Link these to the callbacks
-            mAllAppsController.onDeviceProfileChanged(mDeviceProfile);
-            mDragLayer.setup(this, mDragController);
-
-            // TODO: Clear all-apps recycler view pools
+            dispatchDeviceProfileChanged();
 
             getRootView().dispatchInsets();
             getStateManager().reapplyState();
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index e2c0d10..b5c9af2 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -32,13 +32,16 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.widget.RelativeLayout;
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
 import com.android.launcher3.ClickShadowView;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.DropTarget.DragObject;
@@ -67,7 +70,7 @@
  * The all apps view container.
  */
 public class AllAppsContainerView extends RelativeLayout implements DragSource,
-        View.OnLongClickListener, Insettable, BubbleTextView.BubbleTextShadowHandler {
+        OnLongClickListener, Insettable, BubbleTextShadowHandler, OnDeviceProfileChangeListener {
 
     private final Launcher mLauncher;
     private final AdapterHolder[] mAH;
@@ -103,6 +106,7 @@
         super(context, attrs, defStyleAttr);
 
         mLauncher = Launcher.getLauncher(context);
+        mLauncher.addOnDeviceProfileChangeListener(this);
 
         mSearchQueryBuilder = new SpannableStringBuilder();
 
@@ -140,6 +144,18 @@
     }
 
     @Override
+    public void onDeviceProfileChanged(DeviceProfile dp) {
+        for (AdapterHolder holder : mAH) {
+            if (holder.recyclerView != null) {
+                // Remove all views and clear the pool, while keeping the data same. After this
+                // call, all the viewHolders will be recreated.
+                holder.recyclerView.swapAdapter(holder.recyclerView.getAdapter(), true);
+                holder.recyclerView.getRecycledViewPool().clear();
+            }
+        }
+    }
+
+    @Override
     public void setPressedIcon(BubbleTextView icon, Bitmap background) {
         mTouchFeedbackView.setPressedIcon(icon, background);
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4292f65..c859347 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -12,17 +12,19 @@
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
+import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.AllAppsScrim;
 
@@ -37,7 +39,7 @@
  * closer to top or closer to the page indicator.
  */
 public class AllAppsTransitionController
-        implements SearchUiManager.OnScrollRangeChangeListener, LauncherStateManager.StateHandler {
+        implements OnScrollRangeChangeListener, StateHandler, OnDeviceProfileChangeListener {
 
     public static final Property<AllAppsTransitionController, Float> ALL_APPS_PROGRESS =
             new Property<AllAppsTransitionController, Float>(Float.class, "allAppsProgress") {
@@ -82,7 +84,8 @@
         mProgress = 1f;
 
         mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
-        onDeviceProfileChanged(mLauncher.getDeviceProfile());
+        mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout();
+        mLauncher.addOnDeviceProfileChangeListener(this);
     }
 
     public float getShiftRange() {
@@ -95,8 +98,16 @@
         mAppsView.setVisibility(View.VISIBLE);
     }
 
-    public void onDeviceProfileChanged(DeviceProfile profile) {
-        mIsVerticalLayout = profile.isVerticalBarLayout();
+    @Override
+    public void onDeviceProfileChanged(DeviceProfile dp) {
+        mIsVerticalLayout = dp.isVerticalBarLayout();
+
+        if (mIsVerticalLayout) {
+            mAppsView.setAlpha(1);
+            mLauncher.getHotseat().setTranslationY(0);
+            mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
+        }
     }
 
     /**
@@ -135,11 +146,6 @@
             } else {
                 mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
             }
-        } else {
-            mAppsView.setAlpha(1);
-            mLauncher.getHotseat().setTranslationY(0);
-            mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
-            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
         }
     }
 
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index df34885..4b36ad9 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -150,7 +150,7 @@
 
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
-    private final Direction mDir;
+    private Direction mDir;
 
     private final float mTouchSlop;
 
@@ -185,6 +185,10 @@
         mDir = dir;
     }
 
+    public void updateDirection(Direction dir) {
+        mDir = dir;
+    }
+
     public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
         mScrollConditions = scrollDirectionFlags;
         mIgnoreSlopWhenSettling = ignoreSlop;
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
index 29477e3..735fb2f 100644
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ b/src/com/android/launcher3/util/VerticalSwipeController.java
@@ -55,7 +55,7 @@
     private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
 
     protected final Launcher mLauncher;
-    private final SwipeDetector mDetector;
+    protected final SwipeDetector mDetector;
     private final LauncherState mBaseState;
     private final LauncherState mTargetState;