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/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 5492bbb..62e76d8 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -33,6 +33,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.media.midi.MidiManager.OnDeviceOpenedListener;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -43,6 +44,7 @@
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.InsettableFrameLayout.LayoutParams;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.anim.Interpolators;
@@ -61,7 +63,8 @@
  */
 @TargetApi(Build.VERSION_CODES.O)
 @SuppressWarnings("unused")
-public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManager {
+public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManager
+        implements OnDeviceProfileChangeListener {
 
     private static final String TAG = "LauncherTransition";
     private static final int REFRESH_RATE_MS = 16;
@@ -78,7 +81,7 @@
 
     private final DragLayer mDragLayer;
     private final Launcher mLauncher;
-    private final DeviceProfile mDeviceProfile;
+    private DeviceProfile mDeviceProfile;
 
     private final float mContentTransY;
     private final float mWorkspaceTransY;
@@ -99,9 +102,15 @@
         mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
         mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
 
+        mLauncher.addOnDeviceProfileChangeListener(this);
         registerRemoteAnimations();
     }
 
+    @Override
+    public void onDeviceProfileChanged(DeviceProfile dp) {
+        mDeviceProfile = dp;
+    }
+
     private void setCurrentAnimator(Animator animator) {
         if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.cancel();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
index fa09f23..e39430d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
@@ -27,6 +27,7 @@
 import android.view.MotionEvent;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.anim.SpringAnimationHandler;
 import com.android.launcher3.dragndrop.DragLayer;
@@ -36,13 +37,20 @@
 /**
  * Extension of {@link VerticalSwipeController} to go from NORMAL to OVERVIEW.
  */
-public class EdgeSwipeController extends VerticalSwipeController {
+public class EdgeSwipeController extends VerticalSwipeController implements
+        OnDeviceProfileChangeListener {
 
     private static final Rect sTempRect = new Rect();
 
     public EdgeSwipeController(Launcher l) {
         super(l, NORMAL, OVERVIEW, l.getDeviceProfile().isVerticalBarLayout()
                 ? HORIZONTAL : VERTICAL);
+        l.addOnDeviceProfileChangeListener(this);
+    }
+
+    @Override
+    public void onDeviceProfileChanged(DeviceProfile dp) {
+        mDetector.updateDirection(dp.isVerticalBarLayout() ? HORIZONTAL : VERTICAL);
     }
 
     @Override
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;