Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7030216f authored by Jeremy Sim's avatar Jeremy Sim
Browse files

Refactor/clean up Overview Actions buttons

Since the number of Overview actions is growing, this patch factors out the button hiding logic so it's not all handled in OverviewActionsView.

Also, since splitscreen can now be carried out on Taskbar targets, the split button is no longer ever disabled (only hidden), so removed unused code for that.

Bug: 274835596
Test: Manual
Flag: NA
Change-Id: Icacdee6d0e6071ccb400dfc25a84572e7e9ce772
parent f0732e73
Loading
Loading
Loading
Loading
+3 −8
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@
            android:layout_height="1dp"
            android:layout_weight="1" />

        <Button
        <com.android.quickstep.views.ScreenshotActionButton
            android:id="@+id/action_screenshot"
            style="@style/OverviewActionButton"
            android:layout_width="wrap_content"
@@ -40,17 +40,12 @@
            android:text="@string/action_screenshot"
            android:theme="@style/ThemeControlHighlightWorkspaceColor" />

        <Space
            android:id="@+id/action_split_space"
            android:layout_width="@dimen/overview_actions_button_spacing"
            android:layout_height="1dp"
            android:visibility="gone" />

        <Button
        <com.android.quickstep.views.SplitActionButton
            android:id="@+id/action_split"
            style="@style/OverviewActionButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/overview_actions_button_spacing"
            android:text="@string/action_split"
            android:theme="@style/ThemeControlHighlightWorkspaceColor"
            android:visibility="gone" />
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.quickstep.views

import android.content.Context
import android.util.AttributeSet
import android.widget.Button

/**
 * A button on the Overview Actions Bar. Custom logic for hiding/showing each button type is handled
 * in the respective subclass.
 */
open class ActionButton : Button {
    private var mHiddenFlags = 0

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr)

    /**
     * Updates the proper flags to indicate whether the button should be hidden.
     *
     * @param flag The flag to update.
     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
     */
    protected fun updateHiddenFlags(flag: Int, enable: Boolean) {
        if (enable) {
            mHiddenFlags = mHiddenFlags or flag
        } else {
            mHiddenFlags = mHiddenFlags and flag.inv()
        }
        val shouldBeVisible = mHiddenFlags == 0
        this.visibility = if (shouldBeVisible) VISIBLE else GONE
    }

    /** Show/hide the button when the focused task is a single/pair. */
    open fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
        // overridden in subclass, or else don't do anything
    }

    /** Show/hide the button depending on if the device is a tablet. */
    open fun updateForTablet(isTablet: Boolean) {
        // overridden in subclass, or else don't do anything
    }
}
+22 −53
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;

import androidx.annotation.IntDef;
@@ -41,6 +40,8 @@ import com.android.quickstep.util.LayoutUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;

/**
 * View for showing action buttons in Overview
@@ -89,14 +90,11 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
    private static final int INDEX_SCROLL_ALPHA = 5;
    private static final int NUM_ALPHAS = 6;

    public @interface SplitButtonHiddenFlags { }
    public static final int FLAG_IS_NOT_TABLET = 1 << 0;

    public @interface SplitButtonDisabledFlags { }
    public static final int FLAG_SINGLE_TASK = 1 << 0;

    private MultiValueAlpha mMultiValueAlpha;
    private Button mSplitButton;

    private List<ActionButton> mActionButtons = new ArrayList<>();
    private ScreenshotActionButton mScreenshotButton;
    private SplitActionButton mSplitButton;

    @ActionsHiddenFlags
    private int mHiddenFlags;
@@ -104,12 +102,6 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
    @ActionsDisabledFlags
    protected int mDisabledFlags;

    @SplitButtonHiddenFlags
    private int mSplitButtonHiddenFlags;

    @SplitButtonDisabledFlags
    private int mSplitButtonDisabledFlags;

    @Nullable
    protected T mCallbacks;

@@ -135,9 +127,12 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
        mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
        mMultiValueAlpha.setUpdateVisibility(true);

        findViewById(R.id.action_screenshot).setOnClickListener(this);
        mScreenshotButton = findViewById(R.id.action_screenshot);
        mScreenshotButton.setOnClickListener(this);
        mActionButtons.add(mScreenshotButton);
        mSplitButton = findViewById(R.id.action_split);
        mSplitButton.setOnClickListener(this);
        mActionButtons.add(mSplitButton);
    }

    /**
@@ -201,40 +196,28 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
        }
        boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
        LayoutUtils.setViewEnabled(this, isEnabled);
        updateSplitButtonEnabledState();
    }

    /**
     * Updates the proper flags to indicate whether the "Split screen" button should be hidden.
     *
     * @param flag   The flag to update.
     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
     * Updates flags to hide and show actions buttons when a grouped task (split screen) is focused.
     * @param isGroupedTask True if the focused task is a grouped task.
     */
    public void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag, boolean enable) {
        if (enable) {
            mSplitButtonHiddenFlags |= flag;
        } else {
            mSplitButtonHiddenFlags &= ~flag;
    public void updateForGroupedTask(boolean isGroupedTask) {
        for (ActionButton button : mActionButtons) {
            // Update flags to show/hide buttons.
            button.updateForMultipleTasks(isGroupedTask);
        }
        if (mSplitButton == null) return;
        boolean shouldBeVisible = mSplitButtonHiddenFlags == 0;
        mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
        findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE);
    }

    /**
     * Updates the proper flags to indicate whether the "Split screen" button should be disabled.
     *
     * @param flag   The flag to update.
     * @param enable Whether to enable the disable flag: True will cause view to be disabled.
     * Updates flags to hide and show actions buttons depending on if the device is a tablet.
     * @param isTablet True if the current device is a tablet.
     */
    public void updateSplitButtonDisabledFlags(@SplitButtonDisabledFlags int flag, boolean enable) {
        if (enable) {
            mSplitButtonDisabledFlags |= flag;
        } else {
            mSplitButtonDisabledFlags &= ~flag;
    public void updateForTablet(boolean isTablet) {
        for (ActionButton button : mActionButtons) {
            // Update flags to show/hide buttons.
            button.updateForTablet(isTablet);
        }
        updateSplitButtonEnabledState();
    }

    public MultiProperty getContentAlpha() {
@@ -312,18 +295,4 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
                (dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical),
                0, 0, 0);
    }

    /**
     * Enables/disables the "Split" button based on the status of mSplitButtonDisabledFlags and
     * mDisabledFlags.
     */
    private void updateSplitButtonEnabledState() {
        if (mSplitButton == null) {
            return;
        }
        boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
        boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled;
        mSplitButton.setEnabled(shouldBeEnabled);
    }

}
+14 −12
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.Surface.ROTATION_0;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;

import static com.android.app.animation.Interpolators.ACCELERATE;
import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
@@ -34,6 +33,7 @@ import static com.android.app.animation.Interpolators.clampToProgress;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
@@ -42,7 +42,6 @@ import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_ACTIONS_SPLIT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
@@ -57,8 +56,6 @@ import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
@@ -3927,18 +3924,23 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
    }

    /**
     * Hides all overview actions if current page is for split apps, shows otherwise
     * If actions are showing, we only show split option if
     * Hides all overview actions if user is halfway through split selection, shows otherwise.
     * We only show split option if:
     * * Focused view is a single app
     * * Device is large screen
     * * There are at least 2 tasks to invoke split
     */
    private void updateCurrentTaskActionsVisibility() {
        boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
        boolean isGroupedTask = getCurrentPageTaskView() != null
                && getCurrentPageTaskView().containsMultipleTasks();
        // Update flags to see if entire actions bar should be hidden.
        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isGroupedTask);
        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
        mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
                !mActivity.getDeviceProfile().isTablet);
        mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
        // Update flags to see if actions bar should show buttons for a single task or a pair of
        // tasks.
        mActionsView.updateForGroupedTask(isGroupedTask);
        // Update flags to see if split button should be hidden.
        mActionsView.updateForTablet(mActivity.getDeviceProfile().isTablet);

        if (isDesktopModeSupported()) {
            boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
            mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.quickstep.views

import android.content.Context
import android.util.AttributeSet

/** A button on the Overview Actions Bar for screenshotting the focused app. */
class ScreenshotActionButton : ActionButton {
    companion object {
        const val FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 shl 0
    }

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr)

    /** Show/hide the button when the focused task is a single/pair. */
    override fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
        // Hidden for multiple tasks
        updateHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, hasMultipleTasks)
    }
}
Loading