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

Commit f0f831e5 authored by Joanne Chung's avatar Joanne Chung
Browse files

Refine FloatingToolbarPopup to allow multiple implementations

This change refined the FloatingToolbarPopup to allow the local and
system implementation. Use the flag to control which implementation
will be used. Use the local implementation as default, we will switch
the system version when it is done and stable.

Bug: 190030331
Bug: 205822301
Test: manual. The toolbar still work after refinement
Test: atest TextViewActivityTest
Test: atest TextViewIntegrationTest
Ignore-AOSP-First: new feature for T.

Change-Id: I191cb02fc4857855f5b63bdab21c014fa0879a0c
parent 6e398eb8
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.provider.DeviceConfig;

import java.util.Objects;

@@ -40,6 +41,11 @@ public final class SelectionToolbarManager {
     */
    public static final String LOG_TAG = "SelectionToolbar";

    /**
     * Whether system selection toolbar is enabled.
     */
    private static final String REMOTE_SELECTION_TOOLBAR_ENABLED =
            "remote_selection_toolbar_enabled";

    @NonNull
    private final Context mContext;
@@ -86,4 +92,21 @@ public final class SelectionToolbarManager {
            throw e.rethrowFromSystemServer();
        }
    }

    private boolean isRemoteSelectionToolbarEnabled() {
        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SELECTION_TOOLBAR,
                REMOTE_SELECTION_TOOLBAR_ENABLED, false);
    }

    /**
     * Returns {@code true} if remote render selection toolbar enabled, otherwise
     * returns {@code false}.
     */
    public static boolean isRemoteSelectionToolbarEnabled(Context context) {
        SelectionToolbarManager manager = context.getSystemService(SelectionToolbarManager.class);
        if (manager != null) {
            return manager.isRemoteSelectionToolbarEnabled();
        }
        return false;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ import com.android.internal.view.menu.MenuHelper;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.BackgroundFallback;
import com.android.internal.widget.DecorCaptionView;
import com.android.internal.widget.FloatingToolbar;
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;

import java.util.List;
import java.util.function.Consumer;
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ import android.widget.PopupWindow;

import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.FloatingToolbar;
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;

import java.util.Arrays;
import java.util.Objects;
+5 −25
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

package com.android.internal.widget;
package com.android.internal.widget.floatingtoolbar;

import android.annotation.Nullable;
import android.graphics.Rect;
@@ -50,14 +50,10 @@ public final class FloatingToolbar {
    private final FloatingToolbarPopup mPopup;

    private final Rect mContentRect = new Rect();
    private final Rect mPreviousContentRect = new Rect();

    private Menu mMenu;
    private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;

    private int mSuggestedWidth;
    private boolean mWidthChanged = true;

    private final OnLayoutChangeListener mOrientationChangeHandler = new OnLayoutChangeListener() {

        private final Rect mNewRect = new Rect();
@@ -71,7 +67,7 @@ public final class FloatingToolbar {
            mNewRect.set(newLeft, newRight, newTop, newBottom);
            mOldRect.set(oldLeft, oldRight, oldTop, oldBottom);
            if (mPopup.isShowing() && !mNewRect.equals(mOldRect)) {
                mWidthChanged = true;
                mPopup.setWidthChanged(true);
                updateLayout();
            }
        }
@@ -114,7 +110,7 @@ public final class FloatingToolbar {
        // TODO(b/65172902): Pass context in constructor when DecorView (and other callers)
        // supports multi-display.
        mWindow = Objects.requireNonNull(window);
        mPopup = new FloatingToolbarPopup(window.getContext(), window.getDecorView());
        mPopup = FloatingToolbarPopup.createInstance(window.getContext(), window.getDecorView());
    }

    /**
@@ -159,11 +155,7 @@ public final class FloatingToolbar {
     * toolbar.
     */
    public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
        // Check if there's been a substantial width spec change.
        int difference = Math.abs(suggestedWidth - mSuggestedWidth);
        mWidthChanged = difference > (mSuggestedWidth * 0.2);

        mSuggestedWidth = suggestedWidth;
        mPopup.setSuggestedWidth(suggestedWidth);
        return this;
    }

@@ -232,19 +224,7 @@ public final class FloatingToolbar {
    private void doShow() {
        List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
        menuItems.sort(mMenuItemComparator);
        if (mPopup.isLayoutRequired(menuItems) || mWidthChanged) {
            mPopup.dismiss();
            mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
        } else {
            mPopup.updateMenuItems(menuItems, mMenuItemClickListener);
        }
        if (!mPopup.isShowing()) {
            mPopup.show(mContentRect);
        } else if (!mPreviousContentRect.equals(mContentRect)) {
            mPopup.updateCoordinates(mContentRect);
        }
        mWidthChanged = false;
        mPreviousContentRect.set(mContentRect);
        mPopup.show(menuItems, mMenuItemClickListener, mContentRect);
    }

    /**
+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.internal.widget.floatingtoolbar;

import android.content.Context;
import android.graphics.Rect;
import android.view.MenuItem;
import android.view.View;
import android.view.selectiontoolbar.SelectionToolbarManager;
import android.widget.PopupWindow;

import java.util.List;

/**
 * A popup window used by the {@link FloatingToolbar} to render menu items.
 *
 */
public interface FloatingToolbarPopup {

    /**
     * Sets the suggested dp width of this floating toolbar.
     * The actual width will be about this size but there are no guarantees that it will be exactly
     * the suggested width.
     */
    void setSuggestedWidth(int suggestedWidth);

    /**
     * Sets if the floating toolbar width changed.
     */
    void setWidthChanged(boolean widthChanged);

    /**
     * Shows this popup at the specified coordinates.
     * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
     */
    void show(List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener,
            Rect contentRect);

    /**
     * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
     */
    void dismiss();

    /**
     * Hides this popup. This is a no-op if this popup is not showing.
     * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
     */
    void hide();

    /**
     * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
     */
    boolean isShowing();

    /**
     * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
     */
    boolean isHidden();

    /**
     * Makes this toolbar "outside touchable" and sets the onDismissListener.
     *
     * @param outsideTouchable if true, the popup will be made "outside touchable" and
     *      "non focusable". The reverse will happen if false.
     * @param onDismiss
     *
     * @return true if the "outsideTouchable" setting was modified. Otherwise returns false
     *
     * @see PopupWindow#setOutsideTouchable(boolean)
     * @see PopupWindow#setFocusable(boolean)
     * @see PopupWindow.OnDismissListener
     */
    boolean setOutsideTouchable(boolean outsideTouchable, PopupWindow.OnDismissListener onDismiss);

    /**
     * Returns {@link RemoteFloatingToolbarPopup} implementation if the system selection toolbar
     * enabled, otherwise returns {@link LocalFloatingToolbarPopup} implementation.
     */
    static FloatingToolbarPopup createInstance(Context context, View parent) {
        boolean enabled = SelectionToolbarManager.isRemoteSelectionToolbarEnabled(context);
        return enabled
                ? new RemoteFloatingToolbarPopup(context, parent)
                : new LocalFloatingToolbarPopup(context, parent);
    }

}
Loading