| /* |
| * Copyright (C) 2019 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.uioverrides; |
| |
| import static com.android.launcher3.LauncherState.NORMAL; |
| import static com.android.launcher3.LauncherState.OVERVIEW; |
| import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; |
| |
| import android.content.Context; |
| import android.graphics.Rect; |
| import android.view.Gravity; |
| |
| import com.android.launcher3.DeviceProfile; |
| import com.android.launcher3.Launcher; |
| import com.android.launcher3.LauncherState; |
| import com.android.launcher3.LauncherStateManager.StateHandler; |
| import com.android.launcher3.anim.AnimatorPlaybackController; |
| import com.android.launcher3.config.FeatureFlags; |
| import com.android.launcher3.graphics.RotationMode; |
| import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController; |
| import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.NoButtonQuickSwitchTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.OverviewToAllAppsTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController; |
| import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController; |
| import com.android.launcher3.util.TouchController; |
| import com.android.launcher3.util.UiThreadHelper; |
| import com.android.launcher3.util.UiThreadHelper.AsyncCommand; |
| import com.android.quickstep.SysUINavigationMode; |
| import com.android.quickstep.SysUINavigationMode.Mode; |
| import com.android.quickstep.TouchInteractionService; |
| import com.android.quickstep.views.RecentsView; |
| import com.android.systemui.shared.system.WindowManagerWrapper; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * Provides recents-related {@link UiFactory} logic and classes. |
| */ |
| public abstract class RecentsUiFactory { |
| |
| public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false; |
| private static final AsyncCommand SET_SHELF_HEIGHT_CMD = (visible, height) -> |
| WindowManagerWrapper.getInstance().setShelfHeight(visible != 0, height); |
| |
| public static RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) { |
| @Override |
| public void mapRect(int left, int top, int right, int bottom, Rect out) { |
| out.left = top; |
| out.top = right; |
| out.right = bottom; |
| out.bottom = left; |
| } |
| |
| @Override |
| public void mapInsets(Context context, Rect insets, Rect out) { |
| // If there is a display cutout, the top insets in portrait would also include the |
| // cutout, which we will get as the left inset in landscape. Using the max of left and |
| // top allows us to cover both cases (with or without cutout). |
| if (SysUINavigationMode.getMode(context) == NO_BUTTON) { |
| out.top = Math.max(insets.top, insets.left); |
| out.bottom = Math.max(insets.right, insets.bottom); |
| out.left = out.right = 0; |
| } else { |
| out.top = Math.max(insets.top, insets.left); |
| out.bottom = insets.right; |
| out.left = insets.bottom; |
| out.right = 0; |
| } |
| } |
| }; |
| |
| public static RotationMode ROTATION_SEASCAPE = new RotationMode(90) { |
| @Override |
| public void mapRect(int left, int top, int right, int bottom, Rect out) { |
| out.left = bottom; |
| out.top = left; |
| out.right = top; |
| out.bottom = right; |
| } |
| |
| @Override |
| public void mapInsets(Context context, Rect insets, Rect out) { |
| if (SysUINavigationMode.getMode(context) == NO_BUTTON) { |
| out.top = Math.max(insets.top, insets.right); |
| out.bottom = Math.max(insets.left, insets.bottom); |
| out.left = out.right = 0; |
| } else { |
| out.top = Math.max(insets.top, insets.right); |
| out.bottom = insets.left; |
| out.right = insets.bottom; |
| out.left = 0; |
| } |
| } |
| |
| @Override |
| public int toNaturalGravity(int absoluteGravity) { |
| int horizontalGravity = absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK; |
| int verticalGravity = absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK; |
| |
| if (horizontalGravity == Gravity.RIGHT) { |
| horizontalGravity = Gravity.LEFT; |
| } else if (horizontalGravity == Gravity.LEFT) { |
| horizontalGravity = Gravity.RIGHT; |
| } |
| |
| if (verticalGravity == Gravity.TOP) { |
| verticalGravity = Gravity.BOTTOM; |
| } else if (verticalGravity == Gravity.BOTTOM) { |
| verticalGravity = Gravity.TOP; |
| } |
| |
| return ((absoluteGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK) |
| & ~Gravity.VERTICAL_GRAVITY_MASK) |
| | horizontalGravity | verticalGravity; |
| } |
| }; |
| |
| public static RotationMode getRotationMode(DeviceProfile dp) { |
| return !dp.isVerticalBarLayout() ? RotationMode.NORMAL |
| : (dp.isSeascape() ? ROTATION_SEASCAPE : ROTATION_LANDSCAPE); |
| } |
| |
| public static TouchController[] createTouchControllers(Launcher launcher) { |
| Mode mode = SysUINavigationMode.getMode(launcher); |
| |
| ArrayList<TouchController> list = new ArrayList<>(); |
| list.add(launcher.getDragController()); |
| if (mode == NO_BUTTON) { |
| list.add(new NoButtonQuickSwitchTouchController(launcher)); |
| list.add(new NavBarToHomeTouchController(launcher)); |
| list.add(new FlingAndHoldTouchController(launcher)); |
| } else { |
| if (launcher.getDeviceProfile().isVerticalBarLayout()) { |
| list.add(new OverviewToAllAppsTouchController(launcher)); |
| list.add(new LandscapeEdgeSwipeController(launcher)); |
| if (mode.hasGestures) { |
| list.add(new TransposedQuickSwitchTouchController(launcher)); |
| } |
| } else { |
| list.add(new PortraitStatesTouchController(launcher, |
| mode.hasGestures /* allowDragToOverview */)); |
| if (mode.hasGestures) { |
| list.add(new QuickSwitchTouchController(launcher)); |
| } |
| } |
| } |
| |
| if (FeatureFlags.PULL_DOWN_STATUS_BAR |
| && !launcher.getDeviceProfile().isMultiWindowMode) { |
| list.add(new StatusBarTouchController(launcher)); |
| } |
| |
| list.add(new LauncherTaskViewController(launcher)); |
| return list.toArray(new TouchController[list.size()]); |
| } |
| |
| /** |
| * Creates and returns the controller responsible for recents view state transitions. |
| * |
| * @param launcher the launcher activity |
| * @return state handler for recents |
| */ |
| public static StateHandler createRecentsViewStateController(Launcher launcher) { |
| return new RecentsViewStateController(launcher); |
| } |
| |
| /** |
| * Clears the swipe shared state for the current swipe gesture. |
| */ |
| public static void clearSwipeSharedState(boolean finishAnimation) { |
| TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation); |
| } |
| |
| /** |
| * Recents logic that triggers when launcher state changes or launcher activity stops/resumes. |
| * |
| * @param launcher the launcher activity |
| */ |
| public static void onLauncherStateOrResumeChanged(Launcher launcher) { |
| LauncherState state = launcher.getStateManager().getState(); |
| DeviceProfile profile = launcher.getDeviceProfile(); |
| boolean visible = (state == NORMAL || state == OVERVIEW) && launcher.isUserActive() |
| && !profile.isVerticalBarLayout(); |
| UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT_CMD, |
| visible ? 1 : 0, profile.hotseatBarSizePx); |
| |
| if (state == NORMAL) { |
| launcher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(false); |
| } |
| } |
| |
| private static final class LauncherTaskViewController extends |
| TaskViewTouchController<Launcher> { |
| |
| LauncherTaskViewController(Launcher activity) { |
| super(activity); |
| } |
| |
| @Override |
| protected boolean isRecentsInteractive() { |
| return mActivity.isInState(OVERVIEW); |
| } |
| |
| @Override |
| protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) { |
| mActivity.getStateManager().setCurrentUserControlledAnimation(animController); |
| } |
| } |
| } |