Loading quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +9 −7 Original line number Diff line number Diff line Loading @@ -63,7 +63,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.List; import java.util.stream.Stream; /** Loading Loading @@ -245,12 +244,15 @@ public abstract class BaseQuickstepLauncher extends Launcher } @Override protected void collectStateHandlers(List<StateHandler> out) { super.collectStateHandlers(out); out.add(getDepthController()); out.add(new RecentsViewStateController(this)); out.add(new BackButtonAlphaHandler(this)); out.add(getTaskbarStateHandler()); protected StateHandler<LauncherState>[] createStateHandlers() { return new StateHandler[] { getAllAppsController(), getWorkspace(), getDepthController(), new RecentsViewStateController(this), new BackButtonAlphaHandler(this), getTaskbarStateHandler(), }; } public DepthController getDepthController() { Loading quickstep/src/com/android/quickstep/RecentsActivity.java +2 −3 Original line number Diff line number Diff line Loading @@ -71,7 +71,6 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; /** * A recents activity that shows the recently launched tasks as swipable task cards. Loading Loading @@ -318,8 +317,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { } @Override protected void collectStateHandlers(List<StateHandler> out) { out.add(new FallbackRecentsStateController(this)); protected StateHandler<RecentsState>[] createStateHandlers() { return new StateHandler[] { new FallbackRecentsStateController(this) }; } @Override Loading src/com/android/launcher3/Launcher.java +2 −4 Original line number Diff line number Diff line Loading @@ -2761,10 +2761,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche return super.onKeyUp(keyCode, event); } @Override protected void collectStateHandlers(List<StateHandler> out) { out.add(getAllAppsController()); out.add(getWorkspace()); protected StateHandler<LauncherState>[] createStateHandlers() { return new StateHandler[] { getAllAppsController(), getWorkspace() }; } public TouchController[] createTouchControllers() { Loading src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java 0 → 100644 +315 −0 Original line number Diff line number Diff line /* * 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.annotation.TargetApi; 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 com.android.launcher3.Utilities; import com.android.launcher3.util.UiThreadHelper; /** * Handles IME over all apps to be synchronously transitioning along with the passed in * root inset. */ public class AllAppsInsetTransitionController { private static final boolean DEBUG = true; private static final String TAG = "AllAppsInsetTransitionController"; private static final Interpolator LINEAR = new LinearInterpolator(); private WindowInsetsAnimationController mAnimationController; private WindowInsetsAnimationControlListener mCurrentRequest; private Runnable mSearchEduRunnable; private float mAllAppsHeight; private int mDownInsetBottom; private boolean mShownAtDown; private int mHiddenInsetBottom; private int mShownInsetBottom; private float mDown, mCurrent; private View mApps; /** * */ public boolean showSearchEduIfNecessary() { if (mSearchEduRunnable == null) { return false; } mSearchEduRunnable.run(); return true; } public void setSearchEduRunnable(Runnable eduRunnable) { mSearchEduRunnable = eduRunnable; } // Only purpose of these states is to keep track of fast fling transition enum State { RESET, DRAG_START_BOTTOM, DRAG_START_BOTTOM_IME_CANCELLED, FLING_END_TOP, FLING_END_TOP_IME_CANCELLED, DRAG_START_TOP, FLING_END_BOTTOM } private State mState; public AllAppsInsetTransitionController(float allAppsHeight, View appsView) { mAllAppsHeight = allAppsHeight; mApps = appsView; } public void show() { mApps.getWindowInsetsController().show(WindowInsets.Type.ime()); } public void hide() { if (!Utilities.ATLEAST_R) return; WindowInsets insets = mApps.getRootWindowInsets(); if (insets == null) return; boolean imeVisible = insets.isVisible(WindowInsets.Type.ime()); if (DEBUG) { Log.d(TAG, "\nhide imeVisible=" + imeVisible); } if (insets.isVisible(WindowInsets.Type.ime())) { mApps.getWindowInsetsController().hide(WindowInsets.Type.ime()); } } /** * Initializes member variables and requests for the {@link WindowInsetsAnimationController} * object. * * @param progress value between 0..1 */ @TargetApi(Build.VERSION_CODES.R) public void onDragStart(float progress) { if (!Utilities.ATLEAST_R) return; // Until getRootWindowInsets().isVisible(...) method returns correct value, // only support InsetController based IME transition during swipe up and // NOT swipe down if (Float.compare(progress, 0f) == 0) return; setState(true, false, 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()); if (DEBUG) { Log.d(TAG, "\nonDragStart progress=" + progress + " 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 (controller != null) { if (mCurrentRequest == this && !handleFinishOnFling(controller)) { mAnimationController = controller; } else { controller.finish(false /* just don't show */); } } } @Override public void onFinished(WindowInsetsAnimationController controller) { // when screen lock happens, then this method get called if (DEBUG) { Log.d(TAG, "Listener.onFinished ctrl=" + controller + " mAnimationController=" + mAnimationController); } if (mAnimationController != null) { mAnimationController.finish(true); mAnimationController = null; } } @Override public void onCancelled(@Nullable WindowInsetsAnimationController controller) { if (DEBUG) { // Keep the verbose logging to chase down IME not showing up issue. // b/178904132 Log.e(TAG, "Listener.onCancelled ctrl=" + controller + " mAnimationController=" + mAnimationController, new Exception()); } if (mState == State.DRAG_START_BOTTOM) { mState = State.DRAG_START_BOTTOM_IME_CANCELLED; } mAnimationController = null; if (controller != null) { controller.finish(true); } } }); } /** * If IME bounds after touch sequence finishes, call finish. */ private boolean handleFinishOnFling(WindowInsetsAnimationController controller) { if (!Utilities.ATLEAST_R) return false; if (mState == State.FLING_END_TOP) { controller.finish(true); return true; } else if (mState == State.FLING_END_BOTTOM) { controller.finish(false); return true; } return false; } /** * Handles the translation using the progress. * * @param progress value between 0..1 */ @TargetApi(Build.VERSION_CODES.R) public void setProgress(float progress) { if (!Utilities.ATLEAST_R) 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); final int start = mShownAtDown ? mShownInsetBottom : mHiddenInsetBottom; final int end = mShownAtDown ? mHiddenInsetBottom : mShownInsetBottom; inset = Math.max(inset, mHiddenInsetBottom); inset = Math.min(inset, mShownInsetBottom); if (DEBUG && false) { Log.d(TAG, "updateInset mCurrent=" + mCurrent + " mDown=" + mDown + " hidden=" + mHiddenInsetBottom + " shown=" + mShownInsetBottom + " mDownInsets.bottom=" + mDownInsetBottom + " inset=" + inset + " shift= " + shift); } 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 */ @TargetApi(Build.VERSION_CODES.R) public void onAnimationEnd(float progress) { if (DEBUG) { Log.d(TAG, "onAnimationEnd progress=" + progress + " mAnimationController=" + mAnimationController); } if (mState == null) { // only called when launcher restarting. UiThreadHelper.hideKeyboardAsync(mApps.getContext(), mApps.getWindowToken()); } setState(false, true, progress); if (mAnimationController == null) { if (mState == State.FLING_END_TOP_IME_CANCELLED) { mApps.getWindowInsetsController().show(WindowInsets.Type.ime()); } return; } /* handle finish */ if (mState == State.FLING_END_TOP) { mAnimationController.finish(true /* show */); } else { if (Float.compare(progress, 1f) == 0 /* bottom */) { mAnimationController.finish(false /* gone */); } else { mAnimationController.finish(mShownAtDown); } } /* handle finish */ if (DEBUG) { Log.d(TAG, "endTranslation progress=" + progress + " mAnimationController=" + mAnimationController); } mAnimationController = null; mCurrentRequest = null; setState(false, false, progress); } private void setState(boolean start, boolean end, float progress) { State state = State.RESET; if (start && end) { throw new IllegalStateException("drag start and end cannot happen in same call"); } if (start) { if (Float.compare(progress, 1f) == 0) { state = State.DRAG_START_BOTTOM; } else if (Float.compare(progress, 0f) == 0) { state = State.DRAG_START_TOP; } } else if (end) { if (Float.compare(progress, 1f) == 0 && mState == State.DRAG_START_TOP) { state = State.FLING_END_BOTTOM; } else if (Float.compare(progress, 0f) == 0) { if (mState == State.DRAG_START_BOTTOM) { state = State.FLING_END_TOP; } else if (mState == State.DRAG_START_BOTTOM_IME_CANCELLED) { state = State.FLING_END_TOP_IME_CANCELLED; } } } if (DEBUG) { Log.d(TAG, "setState " + mState + " -> " + state); } mState = state; } } src/com/android/launcher3/allapps/AllAppsTransitionController.java +51 −8 Original line number Diff line number Diff line Loading @@ -33,15 +33,18 @@ 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.SharedPreferences; import android.util.FloatProperty; import android.view.View; 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.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; Loading @@ -60,8 +63,8 @@ import com.android.launcher3.views.ScrimView; * If release velocity < THRES1, snap according to either top or bottom depending on whether it's * closer to top or closer to the page indicator. */ public class AllAppsTransitionController implements StateHandler<LauncherState>, OnDeviceProfileChangeListener { public class AllAppsTransitionController implements StateHandler<LauncherState>, OnDeviceProfileChangeListener, SharedPreferences.OnSharedPreferenceChangeListener { public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS = new FloatProperty<AllAppsTransitionController>("allAppsProgress") { Loading @@ -78,6 +81,7 @@ public class AllAppsTransitionController }; private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 0; private static final String PREF_KEY_SHOW_SEARCH_IME = "pref_search_show_ime"; private AllAppsContainerView mAppsView; private ScrimView mScrimView; Loading @@ -95,6 +99,8 @@ public class AllAppsTransitionController private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent private float mScrollRangeDelta = 0; private AllAppsInsetTransitionController mInsetController; private boolean mSearchImeEnabled; public AllAppsTransitionController(Launcher l) { mLauncher = l; Loading @@ -103,12 +109,19 @@ public class AllAppsTransitionController mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout(); mLauncher.addOnDeviceProfileChangeListener(this); onSharedPreferenceChanged(mLauncher.getSharedPrefs(), PREF_KEY_SHOW_SEARCH_IME); mLauncher.getSharedPrefs().registerOnSharedPreferenceChangeListener(this); } public float getShiftRange() { return mShiftRange; } public AllAppsInsetTransitionController getInsetController() { return mInsetController; } @Override public void onDeviceProfileChanged(DeviceProfile dp) { mIsVerticalLayout = dp.isVerticalBarLayout(); Loading @@ -133,7 +146,14 @@ public class AllAppsTransitionController mProgress = progress; mScrimView.setProgress(progress); mAppsView.setTranslationY(progress * mShiftRange); float shiftCurrent = progress * mShiftRange; mAppsView.setTranslationY(shiftCurrent); if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mSearchImeEnabled) { if (mInsetController == null) { setupInsetTransitionController(); } mInsetController.setProgress(progress); } } public float getProgress() { Loading Loading @@ -222,12 +242,17 @@ public class AllAppsTransitionController public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) { mAppsView = appsView; mScrimView = scrimView; if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && Utilities.ATLEAST_R) { if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && BuildCompat.isAtLeastR()) { setupInsetTransitionController(); } } private void setupInsetTransitionController() { mInsetController = new AllAppsInsetTransitionController(mShiftRange, mAppsView); mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } } /** * Updates the total scroll range but does not update the UI. Loading @@ -249,5 +274,23 @@ public class AllAppsTransitionController if (Float.compare(mProgress, 1f) == 0) { mAppsView.reset(false /* animate */); } if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mSearchImeEnabled && BuildCompat.isAtLeastR()) { mInsetController.onAnimationEnd(mProgress); if (Float.compare(mProgress, 0f) == 0) { EditText editText = mAppsView.getSearchUiManager().getEditText(); if (editText != null && !mInsetController.showSearchEduIfNecessary()) { editText.requestFocus(); } } // TODO: should make the controller hide synchronously } } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { if (s.equals(PREF_KEY_SHOW_SEARCH_IME)) { mSearchImeEnabled = sharedPreferences.getBoolean(s, true); } } } Loading
quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +9 −7 Original line number Diff line number Diff line Loading @@ -63,7 +63,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.List; import java.util.stream.Stream; /** Loading Loading @@ -245,12 +244,15 @@ public abstract class BaseQuickstepLauncher extends Launcher } @Override protected void collectStateHandlers(List<StateHandler> out) { super.collectStateHandlers(out); out.add(getDepthController()); out.add(new RecentsViewStateController(this)); out.add(new BackButtonAlphaHandler(this)); out.add(getTaskbarStateHandler()); protected StateHandler<LauncherState>[] createStateHandlers() { return new StateHandler[] { getAllAppsController(), getWorkspace(), getDepthController(), new RecentsViewStateController(this), new BackButtonAlphaHandler(this), getTaskbarStateHandler(), }; } public DepthController getDepthController() { Loading
quickstep/src/com/android/quickstep/RecentsActivity.java +2 −3 Original line number Diff line number Diff line Loading @@ -71,7 +71,6 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; /** * A recents activity that shows the recently launched tasks as swipable task cards. Loading Loading @@ -318,8 +317,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { } @Override protected void collectStateHandlers(List<StateHandler> out) { out.add(new FallbackRecentsStateController(this)); protected StateHandler<RecentsState>[] createStateHandlers() { return new StateHandler[] { new FallbackRecentsStateController(this) }; } @Override Loading
src/com/android/launcher3/Launcher.java +2 −4 Original line number Diff line number Diff line Loading @@ -2761,10 +2761,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche return super.onKeyUp(keyCode, event); } @Override protected void collectStateHandlers(List<StateHandler> out) { out.add(getAllAppsController()); out.add(getWorkspace()); protected StateHandler<LauncherState>[] createStateHandlers() { return new StateHandler[] { getAllAppsController(), getWorkspace() }; } public TouchController[] createTouchControllers() { Loading
src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java 0 → 100644 +315 −0 Original line number Diff line number Diff line /* * 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.annotation.TargetApi; 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 com.android.launcher3.Utilities; import com.android.launcher3.util.UiThreadHelper; /** * Handles IME over all apps to be synchronously transitioning along with the passed in * root inset. */ public class AllAppsInsetTransitionController { private static final boolean DEBUG = true; private static final String TAG = "AllAppsInsetTransitionController"; private static final Interpolator LINEAR = new LinearInterpolator(); private WindowInsetsAnimationController mAnimationController; private WindowInsetsAnimationControlListener mCurrentRequest; private Runnable mSearchEduRunnable; private float mAllAppsHeight; private int mDownInsetBottom; private boolean mShownAtDown; private int mHiddenInsetBottom; private int mShownInsetBottom; private float mDown, mCurrent; private View mApps; /** * */ public boolean showSearchEduIfNecessary() { if (mSearchEduRunnable == null) { return false; } mSearchEduRunnable.run(); return true; } public void setSearchEduRunnable(Runnable eduRunnable) { mSearchEduRunnable = eduRunnable; } // Only purpose of these states is to keep track of fast fling transition enum State { RESET, DRAG_START_BOTTOM, DRAG_START_BOTTOM_IME_CANCELLED, FLING_END_TOP, FLING_END_TOP_IME_CANCELLED, DRAG_START_TOP, FLING_END_BOTTOM } private State mState; public AllAppsInsetTransitionController(float allAppsHeight, View appsView) { mAllAppsHeight = allAppsHeight; mApps = appsView; } public void show() { mApps.getWindowInsetsController().show(WindowInsets.Type.ime()); } public void hide() { if (!Utilities.ATLEAST_R) return; WindowInsets insets = mApps.getRootWindowInsets(); if (insets == null) return; boolean imeVisible = insets.isVisible(WindowInsets.Type.ime()); if (DEBUG) { Log.d(TAG, "\nhide imeVisible=" + imeVisible); } if (insets.isVisible(WindowInsets.Type.ime())) { mApps.getWindowInsetsController().hide(WindowInsets.Type.ime()); } } /** * Initializes member variables and requests for the {@link WindowInsetsAnimationController} * object. * * @param progress value between 0..1 */ @TargetApi(Build.VERSION_CODES.R) public void onDragStart(float progress) { if (!Utilities.ATLEAST_R) return; // Until getRootWindowInsets().isVisible(...) method returns correct value, // only support InsetController based IME transition during swipe up and // NOT swipe down if (Float.compare(progress, 0f) == 0) return; setState(true, false, 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()); if (DEBUG) { Log.d(TAG, "\nonDragStart progress=" + progress + " 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 (controller != null) { if (mCurrentRequest == this && !handleFinishOnFling(controller)) { mAnimationController = controller; } else { controller.finish(false /* just don't show */); } } } @Override public void onFinished(WindowInsetsAnimationController controller) { // when screen lock happens, then this method get called if (DEBUG) { Log.d(TAG, "Listener.onFinished ctrl=" + controller + " mAnimationController=" + mAnimationController); } if (mAnimationController != null) { mAnimationController.finish(true); mAnimationController = null; } } @Override public void onCancelled(@Nullable WindowInsetsAnimationController controller) { if (DEBUG) { // Keep the verbose logging to chase down IME not showing up issue. // b/178904132 Log.e(TAG, "Listener.onCancelled ctrl=" + controller + " mAnimationController=" + mAnimationController, new Exception()); } if (mState == State.DRAG_START_BOTTOM) { mState = State.DRAG_START_BOTTOM_IME_CANCELLED; } mAnimationController = null; if (controller != null) { controller.finish(true); } } }); } /** * If IME bounds after touch sequence finishes, call finish. */ private boolean handleFinishOnFling(WindowInsetsAnimationController controller) { if (!Utilities.ATLEAST_R) return false; if (mState == State.FLING_END_TOP) { controller.finish(true); return true; } else if (mState == State.FLING_END_BOTTOM) { controller.finish(false); return true; } return false; } /** * Handles the translation using the progress. * * @param progress value between 0..1 */ @TargetApi(Build.VERSION_CODES.R) public void setProgress(float progress) { if (!Utilities.ATLEAST_R) 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); final int start = mShownAtDown ? mShownInsetBottom : mHiddenInsetBottom; final int end = mShownAtDown ? mHiddenInsetBottom : mShownInsetBottom; inset = Math.max(inset, mHiddenInsetBottom); inset = Math.min(inset, mShownInsetBottom); if (DEBUG && false) { Log.d(TAG, "updateInset mCurrent=" + mCurrent + " mDown=" + mDown + " hidden=" + mHiddenInsetBottom + " shown=" + mShownInsetBottom + " mDownInsets.bottom=" + mDownInsetBottom + " inset=" + inset + " shift= " + shift); } 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 */ @TargetApi(Build.VERSION_CODES.R) public void onAnimationEnd(float progress) { if (DEBUG) { Log.d(TAG, "onAnimationEnd progress=" + progress + " mAnimationController=" + mAnimationController); } if (mState == null) { // only called when launcher restarting. UiThreadHelper.hideKeyboardAsync(mApps.getContext(), mApps.getWindowToken()); } setState(false, true, progress); if (mAnimationController == null) { if (mState == State.FLING_END_TOP_IME_CANCELLED) { mApps.getWindowInsetsController().show(WindowInsets.Type.ime()); } return; } /* handle finish */ if (mState == State.FLING_END_TOP) { mAnimationController.finish(true /* show */); } else { if (Float.compare(progress, 1f) == 0 /* bottom */) { mAnimationController.finish(false /* gone */); } else { mAnimationController.finish(mShownAtDown); } } /* handle finish */ if (DEBUG) { Log.d(TAG, "endTranslation progress=" + progress + " mAnimationController=" + mAnimationController); } mAnimationController = null; mCurrentRequest = null; setState(false, false, progress); } private void setState(boolean start, boolean end, float progress) { State state = State.RESET; if (start && end) { throw new IllegalStateException("drag start and end cannot happen in same call"); } if (start) { if (Float.compare(progress, 1f) == 0) { state = State.DRAG_START_BOTTOM; } else if (Float.compare(progress, 0f) == 0) { state = State.DRAG_START_TOP; } } else if (end) { if (Float.compare(progress, 1f) == 0 && mState == State.DRAG_START_TOP) { state = State.FLING_END_BOTTOM; } else if (Float.compare(progress, 0f) == 0) { if (mState == State.DRAG_START_BOTTOM) { state = State.FLING_END_TOP; } else if (mState == State.DRAG_START_BOTTOM_IME_CANCELLED) { state = State.FLING_END_TOP_IME_CANCELLED; } } } if (DEBUG) { Log.d(TAG, "setState " + mState + " -> " + state); } mState = state; } }
src/com/android/launcher3/allapps/AllAppsTransitionController.java +51 −8 Original line number Diff line number Diff line Loading @@ -33,15 +33,18 @@ 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.SharedPreferences; import android.util.FloatProperty; import android.view.View; 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.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; Loading @@ -60,8 +63,8 @@ import com.android.launcher3.views.ScrimView; * If release velocity < THRES1, snap according to either top or bottom depending on whether it's * closer to top or closer to the page indicator. */ public class AllAppsTransitionController implements StateHandler<LauncherState>, OnDeviceProfileChangeListener { public class AllAppsTransitionController implements StateHandler<LauncherState>, OnDeviceProfileChangeListener, SharedPreferences.OnSharedPreferenceChangeListener { public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS = new FloatProperty<AllAppsTransitionController>("allAppsProgress") { Loading @@ -78,6 +81,7 @@ public class AllAppsTransitionController }; private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 0; private static final String PREF_KEY_SHOW_SEARCH_IME = "pref_search_show_ime"; private AllAppsContainerView mAppsView; private ScrimView mScrimView; Loading @@ -95,6 +99,8 @@ public class AllAppsTransitionController private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent private float mScrollRangeDelta = 0; private AllAppsInsetTransitionController mInsetController; private boolean mSearchImeEnabled; public AllAppsTransitionController(Launcher l) { mLauncher = l; Loading @@ -103,12 +109,19 @@ public class AllAppsTransitionController mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout(); mLauncher.addOnDeviceProfileChangeListener(this); onSharedPreferenceChanged(mLauncher.getSharedPrefs(), PREF_KEY_SHOW_SEARCH_IME); mLauncher.getSharedPrefs().registerOnSharedPreferenceChangeListener(this); } public float getShiftRange() { return mShiftRange; } public AllAppsInsetTransitionController getInsetController() { return mInsetController; } @Override public void onDeviceProfileChanged(DeviceProfile dp) { mIsVerticalLayout = dp.isVerticalBarLayout(); Loading @@ -133,7 +146,14 @@ public class AllAppsTransitionController mProgress = progress; mScrimView.setProgress(progress); mAppsView.setTranslationY(progress * mShiftRange); float shiftCurrent = progress * mShiftRange; mAppsView.setTranslationY(shiftCurrent); if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mSearchImeEnabled) { if (mInsetController == null) { setupInsetTransitionController(); } mInsetController.setProgress(progress); } } public float getProgress() { Loading Loading @@ -222,12 +242,17 @@ public class AllAppsTransitionController public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) { mAppsView = appsView; mScrimView = scrimView; if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && Utilities.ATLEAST_R) { if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && BuildCompat.isAtLeastR()) { setupInsetTransitionController(); } } private void setupInsetTransitionController() { mInsetController = new AllAppsInsetTransitionController(mShiftRange, mAppsView); mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } } /** * Updates the total scroll range but does not update the UI. Loading @@ -249,5 +274,23 @@ public class AllAppsTransitionController if (Float.compare(mProgress, 1f) == 0) { mAppsView.reset(false /* animate */); } if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mSearchImeEnabled && BuildCompat.isAtLeastR()) { mInsetController.onAnimationEnd(mProgress); if (Float.compare(mProgress, 0f) == 0) { EditText editText = mAppsView.getSearchUiManager().getEditText(); if (editText != null && !mInsetController.showSearchEduIfNecessary()) { editText.requestFocus(); } } // TODO: should make the controller hide synchronously } } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { if (s.equals(PREF_KEY_SHOW_SEARCH_IME)) { mSearchImeEnabled = sharedPreferences.getBoolean(s, true); } } }