From d25dabb466554fb15cd5bbe712318fb39197f96c Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Sat, 18 Jul 2020 08:32:23 -0700 Subject: [PATCH] Add InsetTransitionController to device search Also removed plugin support as if both the feature flag and the plugin is turned on, there are object/resource contention Bug: 161594550 Change-Id: I2cb98e83c46c7e47db96b90fa8d7cb9620643221 --- src/com/android/launcher3/Launcher.java | 1 - .../AllAppsInsetTransitionController.java | 186 ++++++++++++++++++ .../allapps/AllAppsTransitionController.java | 111 +++++------ .../AbstractStateChangeTouchController.java | 9 +- .../launcher3/util/SystemUiController.java | 3 +- 5 files changed, 239 insertions(+), 71 deletions(-) create mode 100644 src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index f3cc164aa9..e49c4559f0 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1550,7 +1550,6 @@ public class Launcher extends StatefulActivity implements Launche mOverlayManager.onActivityDestroyed(this); mAppTransitionManager.unregisterRemoteAnimations(); mUserChangedCallbackCloseable.close(); - mAllAppsController.onActivityDestroyed(); } public LauncherAccessibilityDelegate getAccessibilityDelegate() { diff --git a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java new file mode 100644 index 0000000000..5af9113ae8 --- /dev/null +++ b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2020 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.allapps; + +import android.graphics.Insets; +import android.os.Build; +import android.util.Log; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowInsetsAnimationControlListener; +import android.view.WindowInsetsAnimationController; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.os.BuildCompat; + +/** + * Handles IME over all apps to be synchronously transitioning along with the passed in + * root inset. + */ +public class AllAppsInsetTransitionController { + + private static final boolean DEBUG = false; + private static final String TAG = "AllAppsInsetTransitionController"; + private static final Interpolator LINEAR = new LinearInterpolator(); + + private WindowInsetsAnimationController mAnimationController; + private WindowInsetsAnimationControlListener mCurrentRequest; + + private float mAllAppsHeight; + + private int mDownInsetBottom; + private boolean mShownAtDown; + + private int mHiddenInsetBottom; + private int mShownInsetBottom; + + private float mDown, mCurrent; + private View mApps; + + public AllAppsInsetTransitionController(float allAppsHeight, View appsView) { + mAllAppsHeight = allAppsHeight; + mApps = appsView; + } + + /** + * Initializes member variables and requests for the {@link WindowInsetsAnimationController} + * object. + * + * @param progress value between 0..1 + */ + @RequiresApi(api = Build.VERSION_CODES.R) + public void onDragStart(float progress) { + if (!BuildCompat.isAtLeastR()) return; + onAnimationEnd(progress); + + mDown = progress * mAllAppsHeight; + + // Below two values are sometimes incorrect. Possibly a platform bug + mDownInsetBottom = mApps.getRootWindowInsets().getInsets(WindowInsets.Type.ime()).bottom; + mShownAtDown = mApps.getRootWindowInsets().isVisible(WindowInsets.Type.ime()); + + // override this value based on what it should actually be. + mShownAtDown = Float.compare(progress, 1f) == 0 ? false : true; + mDownInsetBottom = mShownAtDown ? mShownInsetBottom : mHiddenInsetBottom; + if (DEBUG) { + Log.d(TAG, "\nonDragStart mDownInsets=" + mDownInsetBottom + + " mShownAtDown =" + mShownAtDown); + } + + mApps.getWindowInsetsController().controlWindowInsetsAnimation( + WindowInsets.Type.ime(), -1 /* no predetermined duration */, LINEAR, null, + mCurrentRequest = new WindowInsetsAnimationControlListener() { + + @Override + public void onReady(WindowInsetsAnimationController controller, int types) { + if (DEBUG) { + Log.d(TAG, "Listener.onReady " + (mCurrentRequest == this)); + } + if (mCurrentRequest == this) { + mAnimationController = controller; + } else { + controller.finish(mShownAtDown); + } + } + + @Override + public void onFinished(WindowInsetsAnimationController controller) { + // when screen lock happens, then this method get called + mAnimationController.finish(false); + mAnimationController = null; + if (DEBUG) { + Log.d(TAG, "Listener.onFinished ctrl=" + controller); + } + } + + @Override + public void onCancelled(@Nullable WindowInsetsAnimationController controller) { + mAnimationController = null; + if (controller != null) { + controller.finish(mShownAtDown); + } + if (DEBUG) { + Log.d(TAG, "Listener.onCancelled ctrl=" + controller); + } + } + }); + } + + /** + * Handles the translation using the progress. + * + * @param progress value between 0..1 + */ + @RequiresApi(api = 30) + public void setProgress(float progress) { + if (!BuildCompat.isAtLeastR()) return; + // progress that equals to 0 or 1 is error prone. Do not use them. + // Instead use onDragStart and onAnimationEnd + if (mAnimationController == null || progress <= 0f || progress >= 1f) return; + + mCurrent = progress * mAllAppsHeight; + mHiddenInsetBottom = mAnimationController.getHiddenStateInsets().bottom; // 0 + mShownInsetBottom = mAnimationController.getShownStateInsets().bottom; // 1155 + + int shift = mShownAtDown ? 0 : (int) (mAllAppsHeight - mShownInsetBottom); + + int inset = (int) (mDownInsetBottom + (mDown - mCurrent) - shift); + + if (DEBUG) { + Log.d(TAG, "updateInset mCurrent=" + mCurrent + " mDown=" + + mDown + " hidden=" + mHiddenInsetBottom + + " shown=" + mShownInsetBottom + + " mDownInsets.bottom=" + mDownInsetBottom + " inset:" + inset + + " shift: " + shift); + } + final int start = mShownAtDown ? mShownInsetBottom : mHiddenInsetBottom; + final int end = mShownAtDown ? mHiddenInsetBottom : mShownInsetBottom; + inset = Math.max(inset, mHiddenInsetBottom); + inset = Math.min(inset, mShownInsetBottom); + Log.d(TAG, "updateInset inset:" + inset); + + mAnimationController.setInsetsAndAlpha( + Insets.of(0, 0, 0, inset), + 1f, (inset - start) / (float) (end - start)); + } + + /** + * Report to the animation controller that we no longer plan to translate anymore. + * + * @param progress value between 0..1 + */ + @RequiresApi(api = 30) + public void onAnimationEnd(float progress) { + if (DEBUG) { + Log.d(TAG, "endTranslation progress=" + progress + + " mAnimationController=" + mAnimationController); + } + + if (mAnimationController == null) return; + + if (Float.compare(progress, 1f) == 0 /* bottom */) { + mAnimationController.finish(false /* gone */); + } + if (Float.compare(progress, 0f) == 0 /* top */) { + mAnimationController.finish(true /* show */); + } + mAnimationController = null; + mCurrentRequest = null; + } +} diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index a9b030e056..5b00631659 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2015 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.allapps; import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT; @@ -14,31 +29,28 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FA import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; +import static com.android.launcher3.util.SystemUiController.UI_STATE_ALLAPPS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.content.Context; import android.util.FloatProperty; import android.view.View; -import android.view.ViewGroup; import android.view.animation.Interpolator; -import android.widget.EditText; + +import androidx.core.os.BuildCompat; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; -import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.views.ScrimView; -import com.android.systemui.plugins.AllAppsSearchPlugin; -import com.android.systemui.plugins.PluginListener; /** * Handles AllApps view transition. @@ -51,7 +63,7 @@ import com.android.systemui.plugins.PluginListener; * closer to top or closer to the page indicator. */ public class AllAppsTransitionController implements StateHandler, - OnDeviceProfileChangeListener, PluginListener { + OnDeviceProfileChangeListener { public static final FloatProperty ALL_APPS_PROGRESS = new FloatProperty("allAppsProgress") { @@ -85,10 +97,7 @@ public class AllAppsTransitionController implements StateHandler, private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent private float mScrollRangeDelta = 0; - - // plugin related variables - private AllAppsSearchPlugin mPlugin; - private View mPluginContent; + private AllAppsInsetTransitionController mInsetController; public AllAppsTransitionController(Launcher l) { mLauncher = l; @@ -103,6 +112,10 @@ public class AllAppsTransitionController implements StateHandler, return mShiftRange; } + public AllAppsInsetTransitionController getInsetController() { + return mInsetController; + } + @Override public void onDeviceProfileChanged(DeviceProfile dp) { mIsVerticalLayout = dp.isVerticalBarLayout(); @@ -130,8 +143,8 @@ public class AllAppsTransitionController implements StateHandler, float shiftCurrent = progress * mShiftRange; mAppsView.setTranslationY(shiftCurrent); - if (mPlugin != null) { - mPlugin.setProgress(progress); + if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { + mInsetController.setProgress(progress); } } @@ -201,16 +214,12 @@ public class AllAppsTransitionController implements StateHandler, Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR); Interpolator headerFade = config.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade); - if (mPlugin == null) { - setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade); - setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade); - mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, - hasAllAppsContent, setter, headerFade, allAppsFade); - } else { - setter.setViewAlpha(mPluginContent, hasAllAppsContent ? 1 : 0, allAppsFade); - setter.setViewAlpha(mAppsView.getContentView(), 0, allAppsFade); - setter.setViewAlpha(mAppsView.getScrollBar(), 0, allAppsFade); - } + + setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade); + setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade); + mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, + hasAllAppsContent, setter, headerFade, allAppsFade); + mAppsView.getSearchUiManager().setContentVisibility(visibleElements, setter, allAppsFade); setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA, @@ -228,8 +237,12 @@ public class AllAppsTransitionController implements StateHandler, public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) { mAppsView = appsView; mScrimView = scrimView; - PluginManagerWrapper.INSTANCE.get(mLauncher) - .addPluginListener(this, AllAppsSearchPlugin.class, false); + if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && BuildCompat.isAtLeastR()) { + mInsetController = new AllAppsInsetTransitionController(mShiftRange, mAppsView); + mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS, + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); + } } /** @@ -252,47 +265,11 @@ public class AllAppsTransitionController implements StateHandler, if (Float.compare(mProgress, 1f) == 0) { mAppsView.reset(false /* animate */); } - updatePluginAnimationEnd(); - } - - @Override - public void onPluginConnected(AllAppsSearchPlugin plugin, Context context) { - mPlugin = plugin; - mPluginContent = mLauncher.getLayoutInflater().inflate( - R.layout.all_apps_content_layout, mAppsView, false); - mAppsView.addView(mPluginContent); - mPluginContent.setAlpha(0f); - mPlugin.setup((ViewGroup) mPluginContent, mLauncher, mShiftRange); - } - - @Override - public void onPluginDisconnected(AllAppsSearchPlugin plugin) { - mPlugin = null; - mAppsView.removeView(mPluginContent); - } - - public void onActivityDestroyed() { - PluginManagerWrapper.INSTANCE.get(mLauncher).removePluginListener(this); - } - - /** Used for the plugin to signal when drag starts happens - * @param toAllApps*/ - public void onDragStart(boolean toAllApps) { - if (mPlugin == null) return; - - if (toAllApps) { - EditText editText = mAppsView.getSearchUiManager().setTextSearchEnabled(true); - mPlugin.setEditText(editText); - } - mPlugin.onDragStart(toAllApps ? 1f : 0f); - } - - private void updatePluginAnimationEnd() { - if (mPlugin == null) return; - mPlugin.onAnimationEnd(mProgress); - if (Float.compare(mProgress, 1f) == 0) { - mAppsView.getSearchUiManager().setTextSearchEnabled(false); - mPlugin.setEditText(null); + if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && BuildCompat.isAtLeastR()) { + mInsetController.onAnimationEnd(mProgress); + if (Float.compare(mProgress, 1f) == 0) { + mAppsView.getSearchUiManager().setTextSearchEnabled(true).requestFocus(); + } } } } diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 3c78b08960..66dbf6a73d 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -37,6 +37,8 @@ import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; +import androidx.core.os.BuildCompat; + import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherState; @@ -44,6 +46,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.states.StateAnimationConfig; @@ -265,8 +268,10 @@ public abstract class AbstractStateChangeTouchController mCanBlockFling = mFromState == NORMAL; mFlingBlockCheck.unblockFling(); // Must be called after all the animation controllers have been paused - if (mToState == ALL_APPS || mToState == NORMAL) { - mLauncher.getAllAppsController().onDragStart(mToState == ALL_APPS); + if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && BuildCompat.isAtLeastR() + && (mToState == ALL_APPS || mToState == NORMAL)) { + mLauncher.getAllAppsController().getInsetController().onDragStart( + mToState == ALL_APPS ? 0 : 1); } } diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java index 275c0246e2..3e48006f62 100644 --- a/src/com/android/launcher3/util/SystemUiController.java +++ b/src/com/android/launcher3/util/SystemUiController.java @@ -33,6 +33,7 @@ public class SystemUiController { public static final int UI_STATE_SCRIM_VIEW = 1; public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2; public static final int UI_STATE_OVERVIEW = 3; + public static final int UI_STATE_ALLAPPS = 4; public static final int FLAG_LIGHT_NAV = 1 << 0; public static final int FLAG_DARK_NAV = 1 << 1; @@ -40,7 +41,7 @@ public class SystemUiController { public static final int FLAG_DARK_STATUS = 1 << 3; private final Window mWindow; - private final int[] mStates = new int[4]; + private final int[] mStates = new int[5]; public SystemUiController(Window window) { mWindow = window;