Merge "Floating toolbars: Encapsulate StandaloneActionMode view creation."

This commit is contained in:
Clara Bayarri
2015-02-23 17:49:43 +00:00
committed by Android (Google) Code Review
2 changed files with 103 additions and 83 deletions

View File

@@ -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);
}
}
mActionMode = wrapperMode;
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.
*/

View File

@@ -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;
@@ -41,16 +56,16 @@ public class ActionModeWrapper extends ActionMode {
private CharSequence mTitle;
private CharSequence mSubtitle;
private View mCustomView;
private final ActionModeProvider mActionModeProvider;
// Fields for StandaloneActionMode
private ActionBarContextView mActionModeView;
private boolean mIsFocusable;
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;
}
}