Merge "Use the right layout for inflating Action Bar." into lmp-dev

automerge: 84a89ed

* commit '84a89ed0f56d4c35cde5a1451a22a6edb59db06a':
  Use the right layout for inflating Action Bar.
This commit is contained in:
Deepanshu Gupta
2014-11-04 00:49:43 +00:00
committed by android-build-merger
6 changed files with 597 additions and 185 deletions

View File

@ -1745,6 +1745,17 @@ public class Toolbar extends ViewGroup {
mMenuBuilderCallback = mcb; mMenuBuilderCallback = mcb;
} }
/**
* Accessor to enable LayoutLib to get ActionMenuPresenter directly.
*/
ActionMenuPresenter getOuterActionMenuPresenter() {
return mOuterActionMenuPresenter;
}
Context getPopupContext() {
return mPopupContext;
}
/** /**
* Interface responsible for receiving menu item click events if the items themselves * Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners. * do not have individual item click listeners.

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2014 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 android.view;
import android.view.ActionMode.Callback;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
/**
* An empty implementation of {@link Window.Callback} that always returns null/false.
*/
public class WindowCallback implements Window.Callback {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
return false;
}
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
return false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return false;
}
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
return false;
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
return false;
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
return false;
}
@Override
public View onCreatePanelView(int featureId) {
return null;
}
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
return false;
}
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
return false;
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
return false;
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
return false;
}
@Override
public void onWindowAttributesChanged(LayoutParams attrs) {
}
@Override
public void onContentChanged() {
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
}
@Override
public void onAttachedToWindow() {
}
@Override
public void onDetachedFromWindow() {
}
@Override
public void onPanelClosed(int featureId, Menu menu) {
}
@Override
public boolean onSearchRequested() {
return false;
}
@Override
public ActionMode onWindowStartingActionMode(Callback callback) {
return null;
}
@Override
public void onActionModeStarted(ActionMode mode) {
}
@Override
public void onActionModeFinished(ActionMode mode) {
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 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 android.widget;
import android.content.Context;
/**
* To access non public members of classes in {@link Toolbar}
*/
public class Toolbar_Accessor {
public static ActionMenuPresenter getActionMenuPresenter(Toolbar toolbar) {
return toolbar.getOuterActionMenuPresenter();
}
public static Context getPopupContext(Toolbar toolbar) {
return toolbar.getPopupContext();
}
}

View File

@ -18,36 +18,24 @@ package com.android.layoutlib.bridge.bars;
import com.android.annotations.NonNull; import com.android.annotations.NonNull;
import com.android.annotations.Nullable; import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.ActionBarCallback;
import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams; import com.android.ide.common.rendering.api.SessionParams;
import com.android.internal.R; import com.android.internal.R;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl; import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.widget.ActionBarAccessor;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarView;
import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.ResourceHelper; import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.ResourceType;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.FragmentTransaction;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View; import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ActionMenuPresenter;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListAdapter; import android.widget.ListAdapter;
@ -56,180 +44,80 @@ import android.widget.RelativeLayout;
import java.util.ArrayList; import java.util.ArrayList;
/** public class ActionBarLayout {
* A layout representing the action bar.
*/ private static final String LAYOUT_ATTR_NAME = "windowActionBarFullscreenDecorLayout";
public class ActionBarLayout extends LinearLayout {
// The Action Bar
@NonNull private CustomActionBarWrapper mActionBar;
// Store another reference to the context so that we don't have to cast it repeatedly. // Store another reference to the context so that we don't have to cast it repeatedly.
@NonNull private final BridgeContext mBridgeContext; @NonNull private final BridgeContext mBridgeContext;
@NonNull private final Context mThemedContext;
@NonNull private final ActionBar mActionBar; @NonNull private FrameLayout mContentRoot;
// Data for Action Bar.
@Nullable private final String mIcon;
@Nullable private final String mTitle;
@Nullable private final String mSubTitle;
private final boolean mSplit;
private final boolean mShowHomeAsUp;
private final int mNavMode;
// Helper fields.
@NonNull private final MenuBuilder mMenuBuilder;
private final int mPopupMaxWidth;
@NonNull private final RenderResources res;
@Nullable private final ActionBarView mActionBarView;
@Nullable private FrameLayout mContentRoot;
@NonNull private final ActionBarCallback mCallback;
// A fake parent for measuring views. // A fake parent for measuring views.
@Nullable private ViewGroup mMeasureParent; @Nullable private ViewGroup mMeasureParent;
public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params) { /**
* Inflate the action bar and attach it to {@code parentView}
*/
public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params,
@NonNull ViewGroup parentView) {
super(context);
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL);
// Inflate action bar layout.
LayoutInflater.from(context).inflate(R.layout.screen_action_bar, this,
true /*attachToRoot*/);
mActionBar = new WindowDecorActionBar(this);
// Set contexts.
mBridgeContext = context; mBridgeContext = context;
mThemedContext = mActionBar.getThemedContext();
// Set data for action bar. ResourceValue layoutName = context.getRenderResources()
mCallback = params.getProjectCallback().getActionBarCallback(); .findItemInTheme(LAYOUT_ATTR_NAME, true);
mIcon = params.getAppIcon(); if (layoutName != null) {
mTitle = params.getAppLabel(); // We may need to resolve the reference obtained.
// Split Action Bar when the screen size is narrow and the application requests split action layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
// bar when narrow. layoutName.isFramework());
mSplit = context.getResources().getBoolean(R.bool.split_action_bar_is_narrow) &&
mCallback.getSplitActionBarWhenNarrow();
mNavMode = mCallback.getNavigationMode();
// TODO: Support Navigation Drawer Indicator.
mShowHomeAsUp = mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP;
mSubTitle = mCallback.getSubTitle();
// Set helper fields.
mMenuBuilder = new MenuBuilder(mThemedContext);
res = mBridgeContext.getRenderResources();
mPopupMaxWidth = Math.max(mBridgeContext.getMetrics().widthPixels / 2,
mThemedContext.getResources().getDimensionPixelSize(
R.dimen.config_prefDialogWidth));
mActionBarView = (ActionBarView) findViewById(R.id.action_bar);
mContentRoot = (FrameLayout) findViewById(android.R.id.content);
setupActionBar();
} }
int layoutId = 0;
/** String error = null;
* Sets up the action bar by filling the appropriate data. if (layoutName == null) {
*/ error = "Unable to find action bar layout (" + LAYOUT_ATTR_NAME
private void setupActionBar() { + ") in the current theme.";
// Add title and sub title.
ResourceValue titleValue = res.findResValue(mTitle, false /*isFramework*/);
if (titleValue != null && titleValue.getValue() != null) {
mActionBar.setTitle(titleValue.getValue());
} else { } else {
mActionBar.setTitle(mTitle); layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
layoutName.getName(), 0);
if (layoutId == 0) {
error = String.format("Unable to resolve attribute \"%s\" of type \"%s\"",
layoutName.getName(), layoutName.getResourceType());
} }
if (mSubTitle != null) {
mActionBar.setSubtitle(mSubTitle);
} }
if (layoutId == 0) {
throw new RuntimeException(error);
}
// Inflate action bar layout.
View decorContent = LayoutInflater.from(context).inflate(layoutId, parentView, true);
// Add show home as up icon. mActionBar = CustomActionBarWrapper.getActionBarWrapper(context, params, decorContent);
if (mShowHomeAsUp) {
mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
}
// Set the navigation mode. FrameLayout contentRoot = (FrameLayout) parentView.findViewById(android.R.id.content);
mActionBar.setNavigationMode(mNavMode);
if (mNavMode == ActionBar.NAVIGATION_MODE_TABS) {
setupTabs(3);
}
if (mActionBarView != null) { // If something went wrong and we were not able to initialize the content root,
// If the action bar style doesn't specify an icon, set the icon obtained from the session // just add a frame layout inside this and return.
// params. if (contentRoot == null) {
if (!mActionBarView.hasIcon() && mIcon != null) { contentRoot = new FrameLayout(context);
Drawable iconDrawable = getDrawable(mIcon, false /*isFramework*/); contentRoot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
if (iconDrawable != null) { LayoutParams.MATCH_PARENT));
mActionBar.setIcon(iconDrawable); parentView.addView(contentRoot);
mContentRoot = contentRoot;
} else {
mContentRoot = contentRoot;
mActionBar.setupActionBar();
mActionBar.inflateMenus();
} }
} }
// Set action bar to be split, if needed.
ActionBarContainer splitView = (ActionBarContainer) findViewById(R.id.split_action_bar);
mActionBarView.setSplitView(splitView);
mActionBarView.setSplitToolbar(mSplit);
inflateMenus();
}
}
/**
* Gets the menus to add to the action bar from the callback, resolves them, inflates them and
* adds them to the action bar.
*/
private void inflateMenus() {
if (mActionBarView == null) {
return;
}
final MenuInflater inflater = new MenuInflater(mThemedContext);
for (String name : mCallback.getMenuIdNames()) {
if (mBridgeContext.getRenderResources().getProjectResource(ResourceType.MENU, name)
!= null) {
int id = mBridgeContext.getProjectResourceValue(ResourceType.MENU, name, -1);
if (id > -1) {
inflater.inflate(id, mMenuBuilder);
}
}
}
mActionBarView.setMenu(mMenuBuilder, null /*callback*/);
}
// TODO: Use an adapter, like List View to set up tabs.
private void setupTabs(int num) {
for (int i = 1; i <= num; i++) {
Tab tab = mActionBar.newTab().setText("Tab" + i).setTabListener(new TabListener() {
@Override
public void onTabUnselected(Tab t, FragmentTransaction ft) {
// pass
}
@Override
public void onTabSelected(Tab t, FragmentTransaction ft) {
// pass
}
@Override
public void onTabReselected(Tab t, FragmentTransaction ft) {
// pass
}
});
mActionBar.addTab(tab);
}
}
@Nullable
private Drawable getDrawable(@NonNull String name, boolean isFramework) {
ResourceValue value = res.findResValue(name, isFramework);
value = res.resolveResValue(value);
if (value != null) {
return ResourceHelper.getDrawable(value, mBridgeContext);
}
return null;
}
/** /**
* Creates a Popup and adds it to the content frame. It also adds another {@link FrameLayout} to * Creates a Popup and adds it to the content frame. It also adds another {@link FrameLayout} to
* the content frame which shall serve as the new content root. * the content frame which shall serve as the new content root.
*/ */
public void createMenuPopup() { public void createMenuPopup() {
assert mContentRoot != null && findViewById(android.R.id.content) == mContentRoot assert mContentRoot.getId() == android.R.id.content
: "Action Bar Menus have already been created."; : "Action Bar Menus have already been created.";
if (!isOverflowPopupNeeded()) { if (!isOverflowPopupNeeded()) {
@ -237,7 +125,7 @@ public class ActionBarLayout extends LinearLayout {
} }
// Create a layout to hold the menus and the user's content. // Create a layout to hold the menus and the user's content.
RelativeLayout layout = new RelativeLayout(mThemedContext); RelativeLayout layout = new RelativeLayout(mActionBar.getPopupContext());
layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT)); LayoutParams.MATCH_PARENT));
mContentRoot.addView(layout); mContentRoot.addView(layout);
@ -259,13 +147,14 @@ public class ActionBarLayout extends LinearLayout {
@NonNull @NonNull
private View createMenuView() { private View createMenuView() {
DisplayMetrics metrics = mBridgeContext.getMetrics(); DisplayMetrics metrics = mBridgeContext.getMetrics();
OverflowMenuAdapter adapter = new OverflowMenuAdapter(mMenuBuilder, mThemedContext); MenuBuilder menu = mActionBar.getMenuBuilder();
OverflowMenuAdapter adapter = new OverflowMenuAdapter(menu, mActionBar.getPopupContext());
LinearLayout layout = new LinearLayout(mThemedContext); LinearLayout layout = new LinearLayout(mActionBar.getPopupContext());
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
measureContentWidth(adapter), LayoutParams.WRAP_CONTENT); measureContentWidth(adapter), LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END);
if (mSplit) { if (mActionBar.isSplit()) {
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
// TODO: Find correct value instead of hardcoded 10dp. // TODO: Find correct value instead of hardcoded 10dp.
layoutParams.bottomMargin = getPixelValue("-10dp", metrics); layoutParams.bottomMargin = getPixelValue("-10dp", metrics);
@ -273,7 +162,7 @@ public class ActionBarLayout extends LinearLayout {
layoutParams.topMargin = getPixelValue("-10dp", metrics); layoutParams.topMargin = getPixelValue("-10dp", metrics);
} }
layout.setLayoutParams(layoutParams); layout.setLayoutParams(layoutParams);
final TypedArray a = mThemedContext.obtainStyledAttributes(null, final TypedArray a = mActionBar.getPopupContext().obtainStyledAttributes(null,
R.styleable.PopupWindow, R.attr.popupMenuStyle, 0); R.styleable.PopupWindow, R.attr.popupMenuStyle, 0);
layout.setBackground(a.getDrawable(R.styleable.PopupWindow_popupBackground)); layout.setBackground(a.getDrawable(R.styleable.PopupWindow_popupBackground));
layout.setDividerDrawable(a.getDrawable(R.attr.actionBarDivider)); layout.setDividerDrawable(a.getDrawable(R.attr.actionBarDivider));
@ -282,20 +171,25 @@ public class ActionBarLayout extends LinearLayout {
layout.setDividerPadding(getPixelValue("12dp", metrics)); layout.setDividerPadding(getPixelValue("12dp", metrics));
layout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); layout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
ListView listView = new ListView(mThemedContext, null, R.attr.dropDownListViewStyle); ListView listView = new ListView(mActionBar.getPopupContext(), null,
R.attr.dropDownListViewStyle);
listView.setAdapter(adapter); listView.setAdapter(adapter);
layout.addView(listView); layout.addView(listView);
return layout; return layout;
} }
private boolean isOverflowPopupNeeded() { private boolean isOverflowPopupNeeded() {
boolean needed = mCallback.isOverflowPopupNeeded(); boolean needed = mActionBar.isOverflowPopupNeeded();
if (!needed) { if (!needed) {
return false; return false;
} }
// Copied from android.widget.ActionMenuPresenter.updateMenuView() // Copied from android.widget.ActionMenuPresenter.updateMenuView()
ArrayList<MenuItemImpl> menus = mMenuBuilder.getNonActionItems(); ArrayList<MenuItemImpl> menus = mActionBar.getMenuBuilder().getNonActionItems();
if (ActionBarAccessor.getActionMenuPresenter(mActionBarView).isOverflowReserved() && ActionMenuPresenter presenter = mActionBar.getActionMenuPresenter();
if (presenter == null) {
throw new RuntimeException("Failed to create a Presenter for Action Bar Menus.");
}
if (presenter.isOverflowReserved() &&
menus != null) { menus != null) {
final int count = menus.size(); final int count = menus.size();
if (count == 1) { if (count == 1) {
@ -307,7 +201,7 @@ public class ActionBarLayout extends LinearLayout {
return needed; return needed;
} }
@Nullable @NonNull
public FrameLayout getContentRoot() { public FrameLayout getContentRoot() {
return mContentRoot; return mContentRoot;
} }
@ -319,6 +213,7 @@ public class ActionBarLayout extends LinearLayout {
View itemView = null; View itemView = null;
int itemType = 0; int itemType = 0;
Context context = mActionBar.getPopupContext();
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final int count = adapter.getCount(); final int count = adapter.getCount();
@ -330,15 +225,17 @@ public class ActionBarLayout extends LinearLayout {
} }
if (mMeasureParent == null) { if (mMeasureParent == null) {
mMeasureParent = new FrameLayout(mThemedContext); mMeasureParent = new FrameLayout(context);
} }
itemView = adapter.getView(i, itemView, mMeasureParent); itemView = adapter.getView(i, itemView, mMeasureParent);
itemView.measure(widthMeasureSpec, heightMeasureSpec); itemView.measure(widthMeasureSpec, heightMeasureSpec);
final int itemWidth = itemView.getMeasuredWidth(); final int itemWidth = itemView.getMeasuredWidth();
if (itemWidth >= mPopupMaxWidth) { int popupMaxWidth = Math.max(mBridgeContext.getMetrics().widthPixels / 2,
return mPopupMaxWidth; context.getResources().getDimensionPixelSize(R.dimen.config_prefDialogWidth));
if (itemWidth >= popupMaxWidth) {
return popupMaxWidth;
} else if (itemWidth > maxWidth) { } else if (itemWidth > maxWidth) {
maxWidth = itemWidth; maxWidth = itemWidth;
} }

View File

@ -0,0 +1,344 @@
/*
* Copyright (C) 2014 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.layoutlib.bridge.bars;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.ActionBarCallback;
import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams;
import com.android.internal.R;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ActionBarAccessor;
import com.android.internal.widget.ActionBarView;
import com.android.internal.widget.DecorToolbar;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.ResourceType;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowCallback;
import android.widget.ActionMenuPresenter;
import android.widget.Toolbar;
import android.widget.Toolbar_Accessor;
/**
* A common API to access {@link ToolbarActionBar} and {@link WindowDecorActionBar}.
*/
public abstract class CustomActionBarWrapper {
@NonNull protected ActionBar mActionBar;
@NonNull protected SessionParams mParams;
@NonNull protected ActionBarCallback mCallback;
@NonNull protected BridgeContext mContext;
/**
* Returns a wrapper around different implementations of the Action Bar to provide a common API.
*
* @param decorContent the top level view returned by inflating
* ?attr/windowActionBarFullscreenDecorLayout
*/
@NonNull
public static CustomActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
@NonNull SessionParams params, @NonNull View decorContent) {
View view = decorContent.findViewById(R.id.action_bar);
if (view instanceof Toolbar) {
return new ToolbarWrapper(context, params, ((Toolbar) view)
);
} else if (view instanceof ActionBarView) {
return new WindowActionBarWrapper(context, params, decorContent, ((ActionBarView) view)
);
} else {
throw new IllegalStateException("Can't make an action bar out of " +
view.getClass().getSimpleName());
}
}
CustomActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
@NonNull ActionBar actionBar) {
mActionBar = actionBar;
mParams = params;
mCallback = params.getProjectCallback().getActionBarCallback();
mContext = context;
}
protected void setupActionBar() {
// Do the things that are common to all implementations.
RenderResources res = mContext.getRenderResources();
String title = mParams.getAppLabel();
ResourceValue titleValue = res.findResValue(title, false);
if (titleValue != null && titleValue.getValue() != null) {
mActionBar.setTitle(titleValue.getValue());
} else {
mActionBar.setTitle(title);
}
String subTitle = mCallback.getSubTitle();
if (subTitle != null) {
mActionBar.setSubtitle(subTitle);
}
// Add show home as up icon.
if (mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP) {
mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
}
}
protected boolean isSplit() {
return getDecorToolbar().isSplit();
}
protected boolean isOverflowPopupNeeded() {
return mCallback.isOverflowPopupNeeded();
}
/**
* Gets the menus to add to the action bar from the callback, resolves them, inflates them and
* adds them to the action bar.
*/
protected void inflateMenus() {
MenuInflater inflater = new MenuInflater(getActionMenuContext());
MenuBuilder menuBuilder = getMenuBuilder();
for (String name : mCallback.getMenuIdNames()) {
if (mContext.getRenderResources().getProjectResource(ResourceType.MENU, name)
!= null) {
int id = mContext.getProjectResourceValue(ResourceType.MENU, name, -1);
if (id > -1) {
inflater.inflate(id, menuBuilder);
}
}
}
}
/**
* The context used for the ActionBar and the menus in the ActionBarView.
*/
@NonNull
protected Context getActionMenuContext() {
return mActionBar.getThemedContext();
}
/**
* The context used to inflate the popup menu.
*/
@NonNull
abstract Context getPopupContext();
/**
* The Menu in which to inflate the user's menus.
*/
@NonNull
abstract MenuBuilder getMenuBuilder();
@Nullable
abstract ActionMenuPresenter getActionMenuPresenter();
/**
* Framework's wrapper over two ActionBar implementations.
*/
@NonNull
abstract DecorToolbar getDecorToolbar();
// ---- The implementations ----
/**
* Material theme uses {@link Toolbar} as the action bar. This wrapper provides access to
* Toolbar using a common API.
*/
private static class ToolbarWrapper extends CustomActionBarWrapper {
@NonNull
private final Toolbar mToolbar; // This is the view.
ToolbarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
@NonNull Toolbar toolbar) {
super(context, params, new ToolbarActionBar(toolbar, "", new WindowCallback())
);
mToolbar = toolbar;
}
@Override
protected void inflateMenus() {
super.inflateMenus();
// Inflating the menus doesn't initialize the ActionMenuPresenter. Setting a fake menu
// and then setting it back does the trick.
MenuBuilder menu = getMenuBuilder();
DecorToolbar decorToolbar = getDecorToolbar();
decorToolbar.setMenu(new MenuBuilder(getActionMenuContext()), null);
decorToolbar.setMenu(menu, null);
}
@NonNull
@Override
Context getPopupContext() {
return Toolbar_Accessor.getPopupContext(mToolbar);
}
@NonNull
@Override
MenuBuilder getMenuBuilder() {
return (MenuBuilder) mToolbar.getMenu();
}
@Nullable
@Override
ActionMenuPresenter getActionMenuPresenter() {
return Toolbar_Accessor.getActionMenuPresenter(mToolbar);
}
@NonNull
@Override
DecorToolbar getDecorToolbar() {
return mToolbar.getWrapper();
}
}
/**
* Holo theme uses {@link WindowDecorActionBar} as the action bar. This wrapper provides
* access to it using a common API.
*/
private static class WindowActionBarWrapper extends CustomActionBarWrapper{
@NonNull
private final WindowDecorActionBar mActionBar;
private final ActionBarView mActionBarView;
private MenuBuilder mMenuBuilder;
public WindowActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
@NonNull View decorContentRoot, @NonNull ActionBarView actionBarView) {
super(context, params, new WindowDecorActionBar(decorContentRoot)
);
mActionBarView = actionBarView;
mActionBar = ((WindowDecorActionBar) super.mActionBar);
}
@Override
protected void setupActionBar() {
super.setupActionBar();
// Set the navigation mode.
int navMode = mCallback.getNavigationMode();
mActionBar.setNavigationMode(navMode);
//noinspection deprecation
if (navMode == ActionBar.NAVIGATION_MODE_TABS) {
setupTabs(3);
}
String icon = mParams.getAppIcon();
// If the action bar style doesn't specify an icon, set the icon obtained from the
// session params.
if (!mActionBar.hasIcon() && icon != null) {
Drawable iconDrawable = getDrawable(icon, false);
if (iconDrawable != null) {
mActionBar.setIcon(iconDrawable);
}
}
// Set action bar to be split, if needed.
ViewGroup splitView = (ViewGroup) mActionBarView.findViewById(R.id.split_action_bar);
if (splitView != null) {
mActionBarView.setSplitView(splitView);
Resources res = mContext.getResources();
boolean split = res.getBoolean(R.bool.split_action_bar_is_narrow)
&& mCallback.getSplitActionBarWhenNarrow();
mActionBarView.setSplitToolbar(split);
}
}
@Override
protected void inflateMenus() {
super.inflateMenus();
// The super implementation doesn't set the menu on the view. Set it here.
mActionBarView.setMenu(getMenuBuilder(), null);
}
@NonNull
@Override
Context getPopupContext() {
return getActionMenuContext();
}
@NonNull
@Override
MenuBuilder getMenuBuilder() {
if (mMenuBuilder == null) {
mMenuBuilder = new MenuBuilder(getActionMenuContext());
}
return mMenuBuilder;
}
@Nullable
@Override
ActionMenuPresenter getActionMenuPresenter() {
return ActionBarAccessor.getActionMenuPresenter(mActionBarView);
}
@NonNull
@Override
ActionBarView getDecorToolbar() {
return mActionBarView;
}
// TODO: Use an adapter, like List View to set up tabs.
@SuppressWarnings("deprecation") // For Tab
private void setupTabs(int num) {
for (int i = 1; i <= num; i++) {
Tab tab = mActionBar.newTab().setText("Tab" + i).setTabListener(new TabListener() {
@Override
public void onTabUnselected(Tab t, FragmentTransaction ft) {
// pass
}
@Override
public void onTabSelected(Tab t, FragmentTransaction ft) {
// pass
}
@Override
public void onTabReselected(Tab t, FragmentTransaction ft) {
// pass
}
});
mActionBar.addTab(tab);
}
}
@Nullable
private Drawable getDrawable(@NonNull String name, boolean isFramework) {
RenderResources res = mContext.getRenderResources();
ResourceValue value = res.findResValue(name, isFramework);
value = res.resolveResValue(value);
if (value != null) {
return ResourceHelper.getDrawable(value, mContext);
}
return null;
}
}
}

View File

@ -353,8 +353,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// if the theme says no title/action bar, then the size will be 0 // if the theme says no title/action bar, then the size will be 0
if (mActionBarSize > 0) { if (mActionBarSize > 0) {
ActionBarLayout actionBar = createActionBar(context, params); ActionBarLayout actionBar = createActionBar(context, params, backgroundLayout);
backgroundLayout.addView(actionBar);
actionBar.createMenuPopup(); actionBar.createMenuPopup();
mContentRoot = actionBar.getContentRoot(); mContentRoot = actionBar.getContentRoot();
} else if (mTitleBarSize > 0) { } else if (mTitleBarSize > 0) {
@ -1624,11 +1623,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
/** /**
* Creates the action bar. Also queries the project callback for missing information. * Creates the action bar. Also queries the project callback for missing information.
*/ */
private ActionBarLayout createActionBar(BridgeContext context, SessionParams params) { private ActionBarLayout createActionBar(BridgeContext context, SessionParams params,
ActionBarLayout actionBar = new ActionBarLayout(context, params); ViewGroup parentView) {
actionBar.setLayoutParams(new LinearLayout.LayoutParams( return new ActionBarLayout(context, params, parentView);
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
return actionBar;
} }
public BufferedImage getImage() { public BufferedImage getImage() {