am 77048379: Add view cookies for action bar menus. [DO NOT MERGE]
* commit '7704837947455909f295b088a3d15a20e107dbd7': Add view cookies for action bar menus. [DO NOT MERGE]
This commit is contained in:
@@ -161,6 +161,7 @@ public class MenuInflater {
|
||||
} else if (tagName.equals(XML_MENU)) {
|
||||
// A menu start tag denotes a submenu for an item
|
||||
SubMenu subMenu = menuState.addSubMenuItem();
|
||||
registerMenu(subMenu, attrs);
|
||||
|
||||
// Parse the submenu into returned SubMenu
|
||||
parseMenu(parser, attrs, subMenu);
|
||||
@@ -183,9 +184,9 @@ public class MenuInflater {
|
||||
if (!menuState.hasAddedItem()) {
|
||||
if (menuState.itemActionProvider != null &&
|
||||
menuState.itemActionProvider.hasSubMenu()) {
|
||||
menuState.addSubMenuItem();
|
||||
registerMenu(menuState.addSubMenuItem(), attrs);
|
||||
} else {
|
||||
menuState.addItem();
|
||||
registerMenu(menuState.addItem(), attrs);
|
||||
}
|
||||
}
|
||||
} else if (tagName.equals(XML_MENU)) {
|
||||
@@ -200,7 +201,30 @@ public class MenuInflater {
|
||||
eventType = parser.next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The method is a hook for layoutlib to do its magic.
|
||||
* Nothing is needed outside of LayoutLib. However, it should not be deleted because it
|
||||
* appears to do nothing.
|
||||
*/
|
||||
private void registerMenu(@SuppressWarnings("unused") MenuItem item,
|
||||
@SuppressWarnings("unused") AttributeSet set) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The method is a hook for layoutlib to do its magic.
|
||||
* Nothing is needed outside of LayoutLib. However, it should not be deleted because it
|
||||
* appears to do nothing.
|
||||
*/
|
||||
private void registerMenu(@SuppressWarnings("unused") SubMenu subMenu,
|
||||
@SuppressWarnings("unused") AttributeSet set) {
|
||||
}
|
||||
|
||||
// Needed by layoutlib.
|
||||
/*package*/ Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
private static class InflatedOnMenuItemClickListener
|
||||
implements MenuItem.OnMenuItemClickListener {
|
||||
private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
|
||||
@@ -446,9 +470,11 @@ public class MenuInflater {
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem() {
|
||||
public MenuItem addItem() {
|
||||
itemAdded = true;
|
||||
setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));
|
||||
MenuItem item = menu.add(groupId, itemId, itemCategoryOrder, itemTitle);
|
||||
setItem(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenuItem() {
|
||||
|
||||
@@ -386,8 +386,8 @@ public class MenuBuilder implements Menu {
|
||||
private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
|
||||
final int ordering = getOrdering(categoryOrder);
|
||||
|
||||
final MenuItemImpl item = new MenuItemImpl(this, group, id, categoryOrder,
|
||||
ordering, title, mDefaultShowAsAction);
|
||||
final MenuItemImpl item = createNewMenuItem(group, id, categoryOrder, ordering, title,
|
||||
mDefaultShowAsAction);
|
||||
|
||||
if (mCurrentMenuInfo != null) {
|
||||
// Pass along the current menu info
|
||||
@@ -399,7 +399,14 @@ public class MenuBuilder implements Menu {
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
// Layoutlib overrides this method to return its custom implementation of MenuItemImpl
|
||||
private MenuItemImpl createNewMenuItem(int group, int id, int categoryOrder, int ordering,
|
||||
CharSequence title, int defaultShowAsAction) {
|
||||
return new MenuItemImpl(this, group, id, categoryOrder, ordering, title,
|
||||
defaultShowAsAction);
|
||||
}
|
||||
|
||||
public MenuItem add(CharSequence title) {
|
||||
return addInternal(0, 0, 0, title);
|
||||
}
|
||||
|
||||
@@ -32,10 +32,6 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.InflateException;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -154,6 +150,9 @@ public final class BridgeInflater extends LayoutInflater {
|
||||
@Override
|
||||
public View inflate(int resource, ViewGroup root) {
|
||||
Context context = getContext();
|
||||
if (context instanceof ContextThemeWrapper) {
|
||||
context = ((ContextThemeWrapper) context).getBaseContext();
|
||||
}
|
||||
if (context instanceof BridgeContext) {
|
||||
BridgeContext bridgeContext = (BridgeContext)context;
|
||||
|
||||
@@ -216,43 +215,16 @@ public final class BridgeInflater extends LayoutInflater {
|
||||
}
|
||||
|
||||
private void setupViewInContext(View view, AttributeSet attrs) {
|
||||
if (getContext() instanceof BridgeContext) {
|
||||
BridgeContext bc = (BridgeContext) getContext();
|
||||
if (attrs instanceof BridgeXmlBlockParser) {
|
||||
BridgeXmlBlockParser parser = (BridgeXmlBlockParser) attrs;
|
||||
|
||||
// get the view key
|
||||
Object viewKey = parser.getViewCookie();
|
||||
|
||||
if (viewKey == null) {
|
||||
int currentDepth = parser.getDepth();
|
||||
|
||||
// test whether we are in an included file or in a adapter binding view.
|
||||
BridgeXmlBlockParser previousParser = bc.getPreviousParser();
|
||||
if (previousParser != null) {
|
||||
// looks like we inside an embedded layout.
|
||||
// only apply the cookie of the calling node (<include>) if we are at the
|
||||
// top level of the embedded layout. If there is a merge tag, then
|
||||
// skip it and look for the 2nd level
|
||||
int testDepth = mIsInMerge ? 2 : 1;
|
||||
if (currentDepth == testDepth) {
|
||||
viewKey = previousParser.getViewCookie();
|
||||
// if we are in a merge, wrap the cookie in a MergeCookie.
|
||||
if (viewKey != null && mIsInMerge) {
|
||||
viewKey = new MergeCookie(viewKey);
|
||||
}
|
||||
}
|
||||
} else if (mResourceReference != null && currentDepth == 1) {
|
||||
// else if there's a resource reference, this means we are in an adapter
|
||||
// binding case. Set the resource ref as the view cookie only for the top
|
||||
// level view.
|
||||
viewKey = mResourceReference;
|
||||
}
|
||||
}
|
||||
|
||||
if (viewKey != null) {
|
||||
bc.addViewKey(view, viewKey);
|
||||
}
|
||||
Context context = getContext();
|
||||
if (context instanceof ContextThemeWrapper) {
|
||||
context = ((ContextThemeWrapper) context).getBaseContext();
|
||||
}
|
||||
if (context instanceof BridgeContext) {
|
||||
BridgeContext bc = (BridgeContext) context;
|
||||
// get the view key
|
||||
Object viewKey = getViewKeyFromParser(attrs, bc, mResourceReference, mIsInMerge);
|
||||
if (viewKey != null) {
|
||||
bc.addViewKey(view, viewKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,4 +241,44 @@ public final class BridgeInflater extends LayoutInflater {
|
||||
public LayoutInflater cloneInContext(Context newContext) {
|
||||
return new BridgeInflater(this, newContext);
|
||||
}
|
||||
|
||||
/*package*/ static Object getViewKeyFromParser(AttributeSet attrs, BridgeContext bc,
|
||||
ResourceReference resourceReference, boolean isInMerge) {
|
||||
|
||||
if (!(attrs instanceof BridgeXmlBlockParser)) {
|
||||
return null;
|
||||
}
|
||||
BridgeXmlBlockParser parser = ((BridgeXmlBlockParser) attrs);
|
||||
|
||||
// get the view key
|
||||
Object viewKey = parser.getViewCookie();
|
||||
|
||||
if (viewKey == null) {
|
||||
int currentDepth = parser.getDepth();
|
||||
|
||||
// test whether we are in an included file or in a adapter binding view.
|
||||
BridgeXmlBlockParser previousParser = bc.getPreviousParser();
|
||||
if (previousParser != null) {
|
||||
// looks like we are inside an embedded layout.
|
||||
// only apply the cookie of the calling node (<include>) if we are at the
|
||||
// top level of the embedded layout. If there is a merge tag, then
|
||||
// skip it and look for the 2nd level
|
||||
int testDepth = isInMerge ? 2 : 1;
|
||||
if (currentDepth == testDepth) {
|
||||
viewKey = previousParser.getViewCookie();
|
||||
// if we are in a merge, wrap the cookie in a MergeCookie.
|
||||
if (viewKey != null && isInMerge) {
|
||||
viewKey = new MergeCookie(viewKey);
|
||||
}
|
||||
}
|
||||
} else if (resourceReference != null && currentDepth == 1) {
|
||||
// else if there's a resource reference, this means we are in an adapter
|
||||
// binding case. Set the resource ref as the view cookie only for the top
|
||||
// level view.
|
||||
viewKey = resourceReference;
|
||||
}
|
||||
}
|
||||
|
||||
return viewKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.content.Context;
|
||||
import com.android.ide.common.rendering.api.LayoutLog;
|
||||
import com.android.ide.common.rendering.api.ViewInfo;
|
||||
import com.android.internal.view.menu.BridgeMenuItemImpl;
|
||||
import com.android.internal.view.menu.MenuView;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
||||
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
||||
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* Delegate used to provide new implementation of a select few methods of {@link MenuInflater}
|
||||
* <p/>
|
||||
* Through the layoutlib_create tool, the original methods of MenuInflater have been
|
||||
* replaced by calls to methods of the same name in this delegate class.
|
||||
* <p/>
|
||||
* The main purpose of the class is to get the view key from the menu xml parser and add it to
|
||||
* the menu item. The view key is used by the IDE to match the individual view elements to the
|
||||
* corresponding xml tag in the menu/layout file.
|
||||
* <p/>
|
||||
* For Menus, the views may be reused and the {@link MenuItem} is a better object to hold the
|
||||
* view key than the {@link MenuView.ItemView}. At the time of computation of the rest of {@link
|
||||
* ViewInfo}, we check the corresponding view key in the menu item for the view and add it
|
||||
*/
|
||||
public class MenuInflater_Delegate {
|
||||
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static void registerMenu(MenuInflater thisInflater, MenuItem menuItem,
|
||||
AttributeSet attrs) {
|
||||
if (menuItem instanceof BridgeMenuItemImpl) {
|
||||
Context context = thisInflater.getContext();
|
||||
if (context instanceof ContextThemeWrapper) {
|
||||
context = ((ContextThemeWrapper) context).getBaseContext();
|
||||
}
|
||||
if (context instanceof BridgeContext) {
|
||||
Object viewKey = BridgeInflater.getViewKeyFromParser(
|
||||
attrs, ((BridgeContext) context), null, false);
|
||||
((BridgeMenuItemImpl) menuItem).setViewCookie(viewKey);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// This means that Bridge did not take over the instantiation of some object properly.
|
||||
// This is most likely a bug in the LayoutLib code.
|
||||
Bridge.getLog().warning(LayoutLog.TAG_BROKEN,
|
||||
"Action Bar Menu rendering may be incorrect.", null);
|
||||
|
||||
}
|
||||
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static void registerMenu(MenuInflater thisInflater, SubMenu subMenu,
|
||||
AttributeSet parser) {
|
||||
registerMenu(thisInflater, subMenu.getItem(), parser);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.internal.view.menu;
|
||||
|
||||
/**
|
||||
* An extension of the {@link MenuItemImpl} to store the view cookie also.
|
||||
*/
|
||||
public class BridgeMenuItemImpl extends MenuItemImpl {
|
||||
|
||||
/**
|
||||
* An object returned by the IDE that helps mapping each View to the corresponding XML tag in
|
||||
* the layout. For Menus, we store this cookie here and attach it to the corresponding view
|
||||
* at the time of rendering.
|
||||
*/
|
||||
private Object viewCookie;
|
||||
|
||||
/**
|
||||
* Instantiates this menu item.
|
||||
*/
|
||||
BridgeMenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
|
||||
CharSequence title, int showAsAction) {
|
||||
super(menu, group, id, categoryOrder, ordering, title, showAsAction);
|
||||
}
|
||||
|
||||
|
||||
public Object getViewCookie() {
|
||||
return viewCookie;
|
||||
}
|
||||
|
||||
public void setViewCookie(Object viewCookie) {
|
||||
this.viewCookie = viewCookie;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.internal.view.menu;
|
||||
|
||||
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
||||
|
||||
/**
|
||||
* Delegate used to provide new implementation of a select few methods of {@link MenuBuilder}
|
||||
* <p/>
|
||||
* Through the layoutlib_create tool, the original methods of {@code MenuBuilder} have been
|
||||
* replaced by calls to methods of the same name in this delegate class.
|
||||
*/
|
||||
public class MenuBuilder_Delegate {
|
||||
/**
|
||||
* The method overrides the instantiation of the {@link MenuItemImpl} with an instance of
|
||||
* {@link BridgeMenuItemImpl} so that view cookies may be stored.
|
||||
*/
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static MenuItemImpl createNewMenuItem(MenuBuilder thisMenu, int group, int id,
|
||||
int categoryOrder, int ordering, CharSequence title, int defaultShowAsAction) {
|
||||
return new BridgeMenuItemImpl(thisMenu, group, id, categoryOrder, ordering, title,
|
||||
defaultShowAsAction);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import com.android.ide.common.rendering.api.HardwareConfig;
|
||||
import com.android.ide.common.rendering.api.IAnimationListener;
|
||||
import com.android.ide.common.rendering.api.ILayoutPullParser;
|
||||
import com.android.ide.common.rendering.api.IProjectCallback;
|
||||
import com.android.ide.common.rendering.api.RenderParams;
|
||||
import com.android.ide.common.rendering.api.RenderResources;
|
||||
import com.android.ide.common.rendering.api.RenderSession;
|
||||
import com.android.ide.common.rendering.api.ResourceReference;
|
||||
@@ -39,6 +38,12 @@ import com.android.ide.common.rendering.api.SessionParams;
|
||||
import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
|
||||
import com.android.ide.common.rendering.api.ViewInfo;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.internal.view.menu.ActionMenuItemView;
|
||||
import com.android.internal.view.menu.BridgeMenuItemImpl;
|
||||
import com.android.internal.view.menu.IconMenuItemView;
|
||||
import com.android.internal.view.menu.ListMenuItemView;
|
||||
import com.android.internal.view.menu.MenuItemImpl;
|
||||
import com.android.internal.view.menu.MenuView;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
|
||||
@@ -574,7 +579,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
mViewRoot.draw(mCanvas);
|
||||
}
|
||||
|
||||
mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(), false);
|
||||
mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
|
||||
false);
|
||||
|
||||
// success!
|
||||
return SUCCESS.createResult();
|
||||
@@ -1469,13 +1475,13 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
ViewInfo result;
|
||||
if (isContentFrame) {
|
||||
result = new ViewInfo(view.getClass().getName(),
|
||||
getContext().getViewKey(view),
|
||||
getViewKey(view),
|
||||
view.getLeft(), view.getTop() + offset, view.getRight(),
|
||||
view.getBottom() + offset, view, view.getLayoutParams());
|
||||
|
||||
} else {
|
||||
result = new SystemViewInfo(view.getClass().getName(),
|
||||
getContext().getViewKey(view),
|
||||
getViewKey(view),
|
||||
view.getLeft(), view.getTop(), view.getRight(),
|
||||
view.getBottom(), view, view.getLayoutParams());
|
||||
}
|
||||
@@ -1496,6 +1502,32 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cookie for menu items are stored in menu item and not in the map from View stored in
|
||||
* BridgeContext.
|
||||
*/
|
||||
private Object getViewKey(View view) {
|
||||
BridgeContext context = getContext();
|
||||
if (!(view instanceof MenuView.ItemView)) {
|
||||
return context.getViewKey(view);
|
||||
}
|
||||
MenuItemImpl menuItem;
|
||||
if (view instanceof ActionMenuItemView) {
|
||||
menuItem = ((ActionMenuItemView) view).getItemData();
|
||||
} else if (view instanceof ListMenuItemView) {
|
||||
menuItem = ((ListMenuItemView) view).getItemData();
|
||||
} else if (view instanceof IconMenuItemView) {
|
||||
menuItem = ((IconMenuItemView) view).getItemData();
|
||||
} else {
|
||||
menuItem = null;
|
||||
}
|
||||
if (menuItem instanceof BridgeMenuItemImpl) {
|
||||
return ((BridgeMenuItemImpl) menuItem).getViewCookie();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void invalidateRenderingSize() {
|
||||
mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
|
||||
}
|
||||
|
||||
@@ -142,6 +142,8 @@ public final class CreateInfo implements ICreateInfo {
|
||||
"android.view.ViewRootImpl#isInTouchMode",
|
||||
"android.view.WindowManagerGlobal#getWindowManagerService",
|
||||
"android.view.inputmethod.InputMethodManager#getInstance",
|
||||
"android.view.MenuInflater#registerMenu",
|
||||
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
|
||||
"com.android.internal.util.XmlUtils#convertValueToInt",
|
||||
"com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user