am 4ccc4bd5: Action bar rendering in layoutlib [DO NOT MERGE]

* commit '4ccc4bd54f85d86818f61d728c6361d2003ddd8e':
  Action bar rendering in layoutlib [DO NOT MERGE]
This commit is contained in:
Deepanshu Gupta
2014-04-16 18:33:00 +00:00
committed by Android Git Automerger
12 changed files with 457 additions and 162 deletions

View File

@@ -161,9 +161,11 @@ public class ShareActionProvider extends ActionProvider {
@Override
public View onCreateActionView() {
// Create the view and set its data model.
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
activityChooserView.setActivityChooserModel(dataModel);
if (!activityChooserView.isInEditMode()) {
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
activityChooserView.setActivityChooserModel(dataModel);
}
// Lookup and set the expand action icon.
TypedValue outTypedValue = new TypedValue();

View File

@@ -174,6 +174,15 @@ public class ActionBarImpl extends ActionBar {
init(dialog.getWindow().getDecorView());
}
/**
* Only for edit mode.
* @hide
*/
public ActionBarImpl(View layout) {
assert layout.isInEditMode();
init(layout);
}
private void init(View decor) {
mContext = decor.getContext();
mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
@@ -559,8 +568,8 @@ public class ActionBarImpl extends ActionBar {
return;
}
final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
.disallowAddToBackStack();
final FragmentTransaction trans = mActionView.isInEditMode() ? null :
mActivity.getFragmentManager().beginTransaction().disallowAddToBackStack();
if (mSelectedTab == tab) {
if (mSelectedTab != null) {
@@ -578,7 +587,7 @@ public class ActionBarImpl extends ActionBar {
}
}
if (!trans.isEmpty()) {
if (trans != null && !trans.isEmpty()) {
trans.commit();
}
}

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<include layout="@android:layout/action_bar_home" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<include layout="@android:layout/screen_action_bar" />
</merge>

View File

@@ -215,7 +215,8 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
Capability.ADAPTER_BINDING,
Capability.EXTENDED_VIEWINFO,
Capability.FIXED_SCALABLE_NINE_PATCH,
Capability.RTL);
Capability.RTL,
Capability.ACTION_BAR);
BridgeAssetManager.initSystem();

View File

@@ -63,6 +63,11 @@ public class BridgeRenderSession extends RenderSession {
return mSession.getViewInfos();
}
@Override
public List<ViewInfo> getSystemRootViews() {
return mSession.getSystemViewInfos();
}
@Override
public Map<String, String> getDefaultProperties(Object viewObject) {
return mSession.getDefaultProperties(viewObject);

View File

@@ -604,7 +604,8 @@ public final class BridgeContext extends Context {
}
if (value != null) {
if (value.getFirst() == ResourceType.STYLE) {
if ((value.getFirst() == ResourceType.STYLE)
|| (value.getFirst() == ResourceType.ATTR)) {
// look for the style in the current theme, and its parent:
ResourceValue item = mRenderResources.findItemInTheme(value.getSecond(),
isFrameworkRes);

View File

@@ -0,0 +1,190 @@
/*
* 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.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.app.ActionBarImpl;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarView;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.FragmentTransaction;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
public class ActionBarLayout extends LinearLayout {
// Store another reference to the context so that we don't have to cast it repeatedly.
@SuppressWarnings("hiding")
private final BridgeContext mContext;
private final ActionBar mActionBar;
private final String mIcon;
private final String mTitle;
private final String mSubTitle;
private final boolean mSplit;
private final boolean mShowHomeAsUp;
private final List<Integer> mMenuIds;
private final MenuBuilder mMenuBuilder;
private final int mNavMode;
public ActionBarLayout(BridgeContext context, SessionParams params)
throws XmlPullParserException {
super(context);
mIcon = params.getAppIcon();
mTitle = params.getAppLabel();
mContext = context;
mMenuIds = new ArrayList<Integer>();
ActionBarCallback callback = params.getProjectCallback().getActionBarCallback();
mSplit = callback.getSplitActionBarWhenNarrow() &
context.getResources().getBoolean(
com.android.internal.R.bool.split_action_bar_is_narrow);
mNavMode = callback.getNavigationMode();
// TODO: Support Navigation Drawer Indicator.
mShowHomeAsUp = callback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP;
mSubTitle = callback.getSubTitle();
fillMenuIds(callback.getMenuIdNames());
mMenuBuilder = new MenuBuilder(mContext);
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
XmlPullParser parser = ParserFactory.create(
getClass().getResourceAsStream("/bars/action_bar.xml"), "action_bar.xml");
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
parser, context, false /*platformFile*/);
try {
inflater.inflate(bridgeParser, this, true /*attachToRoot*/);
} finally {
bridgeParser.ensurePopped();
}
mActionBar = new ActionBarImpl(this);
setUpActionBar();
}
private void fillMenuIds(List<String> menuIdNames) {
for (String name : menuIdNames) {
int id = mContext.getProjectResourceValue(ResourceType.MENU, name, -1);
if (id > -1) {
mMenuIds.add(id);
}
}
}
private void setUpActionBar() {
RenderResources res = mContext.getRenderResources();
Drawable iconDrawable = getDrawable(res, mIcon, false /*isFramework*/);
if (iconDrawable != null) {
mActionBar.setIcon(iconDrawable);
}
ResourceValue titleValue = res.findResValue(mTitle, false /*isFramework*/);
if (titleValue != null && titleValue.getValue() != null) {
mActionBar.setTitle(titleValue.getValue());
} else {
mActionBar.setTitle(mTitle);
}
if (mSubTitle != null) {
mActionBar.setSubtitle(mSubTitle);
}
ActionBarView actionBarView = (ActionBarView) findViewById(
Bridge.getResourceId(ResourceType.ID, "action_bar"));
actionBarView.setSplitView((ActionBarContainer) findViewById(
Bridge.getResourceId(ResourceType.ID, "split_action_bar")));
actionBarView.setSplitActionBar(mSplit);
if (mShowHomeAsUp) {
mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
}
setUpActionMenus();
mActionBar.setNavigationMode(mNavMode);
if (mNavMode == ActionBar.NAVIGATION_MODE_TABS) {
setUpTabs(3);
}
}
private void setUpActionMenus() {
if (mMenuIds == null) {
return;
}
ActionBarView actionBarView = (ActionBarView) findViewById(Bridge.getResourceId(
ResourceType.ID, "action_bar"));
final MenuInflater inflater = new MenuInflater(mActionBar.getThemedContext());
for (int id : mMenuIds) {
inflater.inflate(id, mMenuBuilder);
}
actionBarView.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);
}
}
private Drawable getDrawable(RenderResources res, String name, boolean isFramework) {
ResourceValue value = res.findResValue(name, isFramework);
value = res.resolveResValue(value);
if (value != null) {
return ResourceHelper.getDrawable(value, mContext);
}
return null;
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (C) 2011 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.resources.Density;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.widget.LinearLayout;
import android.widget.TextView;
public class FakeActionBar extends CustomBar {
private TextView mTextView;
public FakeActionBar(Context context, Density density, String label, String icon)
throws XmlPullParserException {
super(context, density, LinearLayout.HORIZONTAL, "/bars/action_bar.xml", "action_bar.xml");
// Cannot access the inside items through id because no R.id values have been
// created for them.
// We do know the order though.
loadIconById(android.R.id.home, icon);
mTextView = setText(1, label);
setStyle("actionBarStyle");
}
@Override
protected TextView getStyleableTextView() {
return mTextView;
}
}

View File

@@ -43,12 +43,13 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.bars.FakeActionBar;
import com.android.layoutlib.bridge.bars.ActionBarLayout;
import com.android.layoutlib.bridge.bars.NavigationBar;
import com.android.layoutlib.bridge.bars.StatusBar;
import com.android.layoutlib.bridge.bars.TitleBar;
import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
import com.android.resources.Density;
import com.android.resources.ResourceType;
import com.android.resources.ScreenOrientation;
import com.android.util.Pair;
@@ -134,6 +135,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// information being returned through the API
private BufferedImage mImage;
private List<ViewInfo> mViewInfoList;
private List<ViewInfo> mSystemViewInfoList;
private static final class PostInflateException extends Exception {
private static final long serialVersionUID = 1L;
@@ -225,14 +227,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
HardwareConfig hardwareConfig = params.getHardwareConfig();
BridgeContext context = getContext();
boolean isRtl = Bridge.isLocaleRtl(params.getLocale());
int direction = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
int layoutDirection = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
// the view group that receives the window background.
ViewGroup backgroundView = null;
if (mWindowIsFloating || params.isForceNoDecor()) {
backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
mViewRoot.setLayoutDirection(direction);
mViewRoot.setLayoutDirection(layoutDirection);
} else {
if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
/*
@@ -254,18 +256,13 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
the bottom
*/
LinearLayout topLayout = new LinearLayout(context);
topLayout.setLayoutDirection(direction);
topLayout.setLayoutDirection(layoutDirection);
mViewRoot = topLayout;
topLayout.setOrientation(LinearLayout.HORIZONTAL);
try {
NavigationBar navigationBar = new NavigationBar(context,
hardwareConfig.getDensity(), LinearLayout.VERTICAL, isRtl,
params.isRtlSupported());
navigationBar.setLayoutParams(
new LinearLayout.LayoutParams(
mNavigationBarSize,
LayoutParams.MATCH_PARENT));
NavigationBar navigationBar = createNavigationBar(context,
hardwareConfig.getDensity(), isRtl, params.isRtlSupported());
topLayout.addView(navigationBar);
} catch (XmlPullParserException e) {
@@ -293,14 +290,15 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
LinearLayout topLayout = new LinearLayout(context);
topLayout.setOrientation(LinearLayout.VERTICAL);
topLayout.setLayoutDirection(direction);
topLayout.setLayoutDirection(layoutDirection);
// if we don't already have a view root this is it
if (mViewRoot == null) {
mViewRoot = topLayout;
} else {
int topLayoutWidth =
params.getHardwareConfig().getScreenWidth() - mNavigationBarSize;
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
layoutParams.weight = 1;
topLayoutWidth, LayoutParams.MATCH_PARENT);
topLayout.setLayoutParams(layoutParams);
// this is the case of soft buttons + vertical bar.
@@ -319,12 +317,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
if (mStatusBarSize > 0) {
// system bar
try {
StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity(),
direction, params.isRtlSupported());
systemBar.setLayoutParams(
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, mStatusBarSize));
topLayout.addView(systemBar);
StatusBar statusBar = createStatusBar(context, hardwareConfig.getDensity(),
layoutDirection, params.isRtlSupported());
topLayout.addView(statusBar);
} catch (XmlPullParserException e) {
}
@@ -343,23 +338,16 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// if the theme says no title/action bar, then the size will be 0
if (mActionBarSize > 0) {
try {
FakeActionBar actionBar = new FakeActionBar(context,
hardwareConfig.getDensity(),
params.getAppLabel(), params.getAppIcon());
actionBar.setLayoutParams(
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, mActionBarSize));
ActionBarLayout actionBar = createActionBar(context, params);
backgroundLayout.addView(actionBar);
mContentRoot = (FrameLayout) actionBar.findViewById(android.R.id.content);
} catch (XmlPullParserException e) {
}
} else if (mTitleBarSize > 0) {
try {
TitleBar titleBar = new TitleBar(context,
TitleBar titleBar = createTitleBar(context,
hardwareConfig.getDensity(), params.getAppLabel());
titleBar.setLayoutParams(
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, mTitleBarSize));
backgroundLayout.addView(titleBar);
} catch (XmlPullParserException e) {
@@ -367,23 +355,21 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
// content frame
mContentRoot = new FrameLayout(context);
layoutParams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, 0);
layoutParams.weight = 1;
mContentRoot.setLayoutParams(layoutParams);
backgroundLayout.addView(mContentRoot);
if (mContentRoot == null) {
mContentRoot = new FrameLayout(context);
layoutParams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, 0);
layoutParams.weight = 1;
mContentRoot.setLayoutParams(layoutParams);
backgroundLayout.addView(mContentRoot);
}
if (mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
mNavigationBarSize > 0) {
// system bar
try {
NavigationBar navigationBar = new NavigationBar(context,
hardwareConfig.getDensity(), LinearLayout.HORIZONTAL, isRtl,
params.isRtlSupported());
navigationBar.setLayoutParams(
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, mNavigationBarSize));
NavigationBar navigationBar = createNavigationBar(context,
hardwareConfig.getDensity(), isRtl, params.isRtlSupported());
topLayout.addView(navigationBar);
} catch (XmlPullParserException e) {
@@ -584,7 +570,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
mViewRoot.draw(mCanvas);
}
mViewInfoList = startVisitingViews(mViewRoot, 0, params.getExtendedViewInfoMode());
mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(), false);
// success!
return SUCCESS.createResult();
@@ -1369,50 +1355,126 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
}
private List<ViewInfo> startVisitingViews(View view, int offset, boolean setExtendedInfo) {
if (view == null) {
return null;
}
// adjust the offset to this view.
offset += view.getTop();
if (view == mContentRoot) {
return visitAllChildren(mContentRoot, offset, setExtendedInfo);
}
// otherwise, look for mContentRoot in the children
if (view instanceof ViewGroup) {
ViewGroup group = ((ViewGroup) view);
for (int i = 0; i < group.getChildCount(); i++) {
List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset,
setExtendedInfo);
if (list != null) {
return list;
}
}
}
return null;
}
/**
* Visits a View and its children and generate a {@link ViewInfo} containing the
* Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
* bounds of all the views.
*
* @param view the root View
* @param offset an offset for the view bounds.
* @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
* @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
* content frame.
*
* @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
*/
private ViewInfo visit(View view, int offset, boolean setExtendedInfo) {
private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
boolean isContentFrame) {
ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
if (view instanceof ViewGroup) {
ViewGroup group = ((ViewGroup) view);
result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
setExtendedInfo, isContentFrame));
}
return result;
}
/**
* Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
* containing the bounds of all the views. It also initializes the {@link mViewInfoList} with
* the children of the {@code mContentRoot}.
*
* @param viewGroup the root View
* @param offset an offset from the top for the content view frame.
* @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
* @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
* content frame. {@code false} if the {@code ViewInfo} to be created is
* part of the system decor.
*/
private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
boolean setExtendedInfo, boolean isContentFrame) {
if (viewGroup == null) {
return null;
}
if (!isContentFrame) {
offset += viewGroup.getTop();
}
int childCount = viewGroup.getChildCount();
if (viewGroup == mContentRoot) {
List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
for (int i = 0; i < childCount; i++) {
ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
setExtendedInfo);
childrenWithoutOffset.add(childViewInfo[0]);
childrenWithOffset.add(childViewInfo[1]);
}
mViewInfoList = childrenWithOffset;
return childrenWithoutOffset;
} else {
List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
for (int i = 0; i < childCount; i++) {
children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
isContentFrame));
}
return children;
}
}
/**
* Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
* bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
* one with the {@code offset} and other without the {@code offset}. The offset is needed to
* get the right bounds if the {@code ViewInfo} hierarchy is accessed from
* {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
* offset is not needed.
*
* @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
* index 1 is with the offset.
*/
private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
ViewInfo[] result = new ViewInfo[2];
if (view == null) {
return result;
}
result[0] = createViewInfo(view, 0, setExtendedInfo, true);
result[1] = createViewInfo(view, offset, setExtendedInfo, true);
if (view instanceof ViewGroup) {
List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
result[0].setChildren(children);
result[1].setChildren(children);
}
return result;
}
/**
* Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
* of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
* set.
* @param offset an offset for the view bounds. Used only if view is part of the content frame.
*/
private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
boolean isContentFrame) {
if (view == null) {
return null;
}
ViewInfo result = new ViewInfo(view.getClass().getName(),
getContext().getViewKey(view),
view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
view, view.getLayoutParams());
ViewInfo result;
if (isContentFrame) {
result = new ViewInfo(view.getClass().getName(),
getContext().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),
view.getLeft(), view.getTop(), view.getRight(),
view.getBottom(), view, view.getLayoutParams());
}
if (setExtendedInfo) {
MarginLayoutParams marginParams = null;
@@ -1427,39 +1489,67 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
marginParams != null ? marginParams.bottomMargin : 0);
}
if (view instanceof ViewGroup) {
ViewGroup group = ((ViewGroup) view);
result.setChildren(visitAllChildren(group, 0 /*offset*/, setExtendedInfo));
}
return result;
}
/**
* Visits all the children of a given ViewGroup generate a list of {@link ViewInfo}
* containing the bounds of all the views.
* @param view the root View
* @param offset an offset for the view bounds.
* @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
*/
private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
boolean setExtendedInfo) {
if (viewGroup == null) {
return null;
}
List<ViewInfo> children = new ArrayList<ViewInfo>();
for (int i = 0; i < viewGroup.getChildCount(); i++) {
children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo));
}
return children;
}
private void invalidateRenderingSize() {
mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
}
/**
* Creates the status bar with wifi and battery icons.
*/
private StatusBar createStatusBar(BridgeContext context, Density density, int direction,
boolean isRtlSupported) throws XmlPullParserException {
StatusBar statusBar = new StatusBar(context, density,
direction, isRtlSupported);
statusBar.setLayoutParams(
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, mStatusBarSize));
return statusBar;
}
/**
* Creates the navigation bar with back, home and recent buttons.
*
* @param isRtl true if the current locale is right-to-left
* @param isRtlSupported true is the project manifest declares that the application
* is RTL aware.
*/
private NavigationBar createNavigationBar(BridgeContext context, Density density,
boolean isRtl, boolean isRtlSupported) throws XmlPullParserException {
NavigationBar navigationBar = new NavigationBar(context,
density, mNavigationBarOrientation, isRtl,
isRtlSupported);
if (mNavigationBarOrientation == LinearLayout.VERTICAL) {
navigationBar.setLayoutParams(new LinearLayout.LayoutParams(mNavigationBarSize,
LayoutParams.MATCH_PARENT));
} else {
navigationBar.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
mNavigationBarSize));
}
return navigationBar;
}
private TitleBar createTitleBar(BridgeContext context, Density density, String title)
throws XmlPullParserException {
TitleBar titleBar = new TitleBar(context, density, title);
titleBar.setLayoutParams(
new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, mTitleBarSize));
return titleBar;
}
/**
* Creates the action bar. Also queries the project callback for missing information.
*/
private ActionBarLayout createActionBar(BridgeContext context, SessionParams params)
throws XmlPullParserException {
ActionBarLayout actionBar = new ActionBarLayout(context, params);
actionBar.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
return actionBar;
}
public BufferedImage getImage() {
return mImage;
}
@@ -1472,6 +1562,10 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
return mViewInfoList;
}
public List<ViewInfo> getSystemViewInfos() {
return mSystemViewInfoList;
}
public Map<String, String> getDefaultProperties(Object viewObject) {
return getContext().getDefaultPropMap(viewObject);
}

View File

@@ -165,6 +165,9 @@ public final class ResourceHelper {
* @param context the current context
*/
public static Drawable getDrawable(ResourceValue value, BridgeContext context) {
if (value == null) {
return null;
}
String stringValue = value.getValue();
if (RenderResources.REFERENCE_NULL.equals(stringValue)) {
return null;

View File

@@ -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.layoutlib.bridge.impl;
import com.android.ide.common.rendering.api.ViewInfo;
public class SystemViewInfo extends ViewInfo {
public SystemViewInfo(String name, Object cookie, int left, int top,
int right, int bottom) {
super(name, cookie, left, top, right, bottom);
}
public SystemViewInfo(String name, Object cookie, int left, int top,
int right, int bottom, Object viewObject, Object layoutParamsObject) {
super(name, cookie, left, top, right, bottom, viewObject,
layoutParamsObject);
}
@Override
public boolean isSystemView() {
return true;
}
}

View File

@@ -116,6 +116,7 @@ public class Main {
"com.android.i18n.phonenumbers.*", // for TextView with autolink attribute
"android.app.DatePickerDialog", // b.android.com/28318
"android.app.TimePickerDialog", // b.android.com/61515
"com.android.internal.view.menu.ActionMenu",
},
excludeClasses,
new String[] {