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

Commit 399b5139 authored by Clara Bayarri's avatar Clara Bayarri
Browse files

Floating toolbars: Encapsulate StandaloneActionMode view creation.

This CL defines a new interface to be used by ActionModeWrapper.
This allows each client to inject a different primary ActionMode to
the wrapper and keep view creation code next to ActionMode
creation.
The interface method is only called when the wrapper actually
knows that will be the used type, avoinding unnecessary view
creations.

Things pending after this CL:
- Correct handling of ActionModes created by
callback.onWindowStartingActionMode(). This includes all current usages
in an existing ActionBar, as it is handled by Activity. In the current
state, we do not intercept these ActionModes and hence cannot change the
representation.
- Representing the floating type
- Supporting two ActionModes in parallel in DecorView, one of each type

Change-Id: Ic38e209877c3876161d8dd56902e25b51fbe40b6
parent ed2a54cf
Loading
Loading
Loading
Loading
+81 −66
Original line number Diff line number Diff line
@@ -2694,73 +2694,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
                if (mActionModeView != null) {
                    mActionModeView.killMode();
                }
                ActionModeWrapper wrapperMode =
                        new ActionModeWrapper(mContext, wrappedCallback);
                ActionModeWrapper wrapperMode = new ActionModeWrapper(
                        mContext, wrappedCallback, new StandaloneActionModeProvider());
                if (callback.onCreateActionMode(wrapperMode, wrapperMode.getMenu())) {
                    if (wrapperMode.getType() == ActionMode.TYPE_PRIMARY) {
                        if (mActionModeView == null) {
                            if (isFloating()) {
                                // Use the action bar theme.
                                final TypedValue outValue = new TypedValue();
                                final Theme baseTheme = mContext.getTheme();
                                baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);

                                final Context actionBarContext;
                                if (outValue.resourceId != 0) {
                                    final Theme actionBarTheme = mContext.getResources().newTheme();
                                    actionBarTheme.setTo(baseTheme);
                                    actionBarTheme.applyStyle(outValue.resourceId, true);

                                    actionBarContext = new ContextThemeWrapper(mContext, 0);
                                    actionBarContext.getTheme().setTo(actionBarTheme);
                                } else {
                                    actionBarContext = mContext;
                                }

                                mActionModeView = new ActionBarContextView(actionBarContext);
                                mActionModePopup = new PopupWindow(actionBarContext, null,
                                        R.attr.actionModePopupWindowStyle);
                                mActionModePopup.setWindowLayoutType(
                                        WindowManager.LayoutParams.TYPE_APPLICATION);
                                mActionModePopup.setContentView(mActionModeView);
                                mActionModePopup.setWidth(MATCH_PARENT);

                                actionBarContext.getTheme().resolveAttribute(
                                        R.attr.actionBarSize, outValue, true);
                                final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
                                        actionBarContext.getResources().getDisplayMetrics());
                                mActionModeView.setContentHeight(height);
                                mActionModePopup.setHeight(WRAP_CONTENT);
                                mShowActionModePopup = new Runnable() {
                                    public void run() {
                                        mActionModePopup.showAtLocation(
                                                mActionModeView.getApplicationWindowToken(),
                                                Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
                                    }
                                };
                            } else {
                                ViewStub stub = (ViewStub) findViewById(
                                        R.id.action_mode_bar_stub);
                                if (stub != null) {
                                    mActionModeView = (ActionBarContextView) stub.inflate();
                                }
                            }
                        }
                        if (mActionModeView != null) {
                            wrapperMode.setActionModeView(mActionModeView);
                            wrapperMode.setFocusable(mActionModePopup == null);
                            wrapperMode.lockType();
                            wrapperMode.invalidate();
                            mActionModeView.initForMode(wrapperMode);
                            mActionModeView.setVisibility(View.VISIBLE);
                    mActionMode = wrapperMode;
                            if (mActionModePopup != null) {
                                post(mShowActionModePopup);
                            }
                            mActionModeView.sendAccessibilityEvent(
                                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
                        }
                    }
                    wrapperMode.lockType();
                    mActionMode.invalidate();
                } else {
                    mActionMode = null;
                }
@@ -3258,6 +3197,82 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
            updateColorViewTranslations();
        }

        /**
         * Encapsulates the view creation for {@link StandaloneActionMode}.
         */
        private class StandaloneActionModeProvider
                implements ActionModeWrapper.ActionModeProvider {

            @Override
            public ActionMode createActionMode(android.view.ActionMode.Callback callback,
                    MenuBuilder menuBuilder) {
                if (mActionModeView == null) {
                    if (isFloating()) {
                        // Use the action bar theme.
                        final TypedValue outValue = new TypedValue();
                        final Theme baseTheme = mContext.getTheme();
                        baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);

                        final Context actionBarContext;
                        if (outValue.resourceId != 0) {
                            final Theme actionBarTheme = mContext.getResources().newTheme();
                            actionBarTheme.setTo(baseTheme);
                            actionBarTheme.applyStyle(outValue.resourceId, true);

                            actionBarContext = new ContextThemeWrapper(mContext, 0);
                            actionBarContext.getTheme().setTo(actionBarTheme);
                        } else {
                            actionBarContext = mContext;
                        }

                        mActionModeView = new ActionBarContextView(actionBarContext);
                        mActionModePopup = new PopupWindow(actionBarContext, null,
                                R.attr.actionModePopupWindowStyle);
                        mActionModePopup.setWindowLayoutType(
                                WindowManager.LayoutParams.TYPE_APPLICATION);
                        mActionModePopup.setContentView(mActionModeView);
                        mActionModePopup.setWidth(MATCH_PARENT);

                        actionBarContext.getTheme().resolveAttribute(
                                R.attr.actionBarSize, outValue, true);
                        final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
                                actionBarContext.getResources().getDisplayMetrics());
                        mActionModeView.setContentHeight(height);
                        mActionModePopup.setHeight(WRAP_CONTENT);
                        mShowActionModePopup = new Runnable() {
                            public void run() {
                                mActionModePopup.showAtLocation(
                                        mActionModeView.getApplicationWindowToken(),
                                        Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
                            }
                        };
                    } else {
                        ViewStub stub = (ViewStub) findViewById(
                                R.id.action_mode_bar_stub);
                        if (stub != null) {
                            mActionModeView = (ActionBarContextView) stub.inflate();
                        }
                    }
                }
                if (mActionModeView != null) {
                    ActionMode mode = new StandaloneActionMode(
                            mActionModeView.getContext(), mActionModeView,
                            callback, mActionModePopup == null, menuBuilder);
                    mActionModeView.killMode();
                    mActionModeView.initForMode(mode);
                    mActionModeView.setVisibility(View.VISIBLE);
                    if (mActionModePopup != null) {
                        post(mShowActionModePopup);
                    }
                    mActionModeView.sendAccessibilityEvent(
                            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
                    return mode;
                }
                return null;
            }

        }

        /**
         * Clears out internal reference when the action mode is destroyed.
         */
+22 −17
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.view.MenuItem;
import android.view.View;

import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ActionBarContextView;

/**
 * ActionMode implementation that wraps several actions modes and creates them on the fly depending
@@ -32,6 +31,22 @@ import com.android.internal.widget.ActionBarContextView;
 */
public class ActionModeWrapper extends ActionMode {

    /**
     * Interface to defer the ActionMode creation until the type is chosen.
     */
    public interface ActionModeProvider {
        /**
         * Create the desired ActionMode, that will immediately be used as the current active mode
         * in the decorator.
         *
         * @param callback The {@link ActionMode.Callback} to be used.
         * @param menuBuilder The {@link MenuBuilder} that should be used by the created
         *      {@link ActionMode}. This will already have been populated.
         * @return A new {@link ActionMode} ready to be used that uses menuBuilder as its menu.
         */
        ActionMode createActionMode(ActionMode.Callback callback, MenuBuilder menuBuilder);
    }

    private ActionMode mActionMode;
    private final Context mContext;
    private MenuBuilder mMenu;
@@ -42,15 +57,15 @@ public class ActionModeWrapper extends ActionMode {
    private CharSequence mSubtitle;
    private View mCustomView;
    
    // Fields for StandaloneActionMode
    private ActionBarContextView mActionModeView;
    private boolean mIsFocusable;
    private final ActionModeProvider mActionModeProvider;

    public ActionModeWrapper(Context context, ActionMode.Callback callback) {
    public ActionModeWrapper(
            Context context, ActionMode.Callback callback, ActionModeProvider actionModeProvider) {
        mContext = context;
        mMenu = new MenuBuilder(context).setDefaultShowAsAction(
                MenuItem.SHOW_AS_ACTION_IF_ROOM);
        mCallback = callback;
        mActionModeProvider = actionModeProvider;
    }

    @Override
@@ -107,9 +122,7 @@ public class ActionModeWrapper extends ActionMode {
        switch (getType()) {
            case ActionMode.TYPE_PRIMARY:
            default:
                mActionMode = new StandaloneActionMode(
                        mActionModeView.getContext(),
                        mActionModeView, mCallback, mIsFocusable, mMenu);
                mActionMode = mActionModeProvider.createActionMode(mCallback, mMenu);
                break;
            case ActionMode.TYPE_FLOATING:
                // Not implemented yet.
@@ -189,12 +202,4 @@ public class ActionModeWrapper extends ActionMode {
        return new MenuInflater(mContext);
    }

    public void setActionModeView(ActionBarContextView actionModeView) {
        mActionModeView = actionModeView;
    }

    public void setFocusable(boolean focusable) {
        mIsFocusable = focusable;
    }

}