From 43b15371f9f1da7d97fe0500eb1536d981097e31 Mon Sep 17 00:00:00 2001 From: Deepanshu Gupta Date: Thu, 12 Dec 2013 12:16:24 -0800 Subject: Action bar rendering in layoutlib [DO NOT MERGE] This also makes a couple of changes to the framework: 1. ShareActionProvider - Use edit mode to execute activity chooser code. 2. ActionBarImpl - add a new constructor for use by layoutlib. This also relies on some changes to the plugin to pass the correct params. Change-Id: Ia30fef816afd91ec1e439734d56b59b1323bfee2 (cherry-picked from fe38489f6734fefd0a216e9cfe12f8f978ff371f) --- .../layoutlib/bridge/resources/bars/action_bar.xml | 7 +- .../src/com/android/layoutlib/bridge/Bridge.java | 3 +- .../layoutlib/bridge/BridgeRenderSession.java | 5 + .../layoutlib/bridge/android/BridgeContext.java | 3 +- .../layoutlib/bridge/bars/ActionBarLayout.java | 190 ++++++++++++++ .../layoutlib/bridge/bars/FakeActionBar.java | 48 ---- .../layoutlib/bridge/impl/RenderSessionImpl.java | 276 ++++++++++++++------- .../layoutlib/bridge/impl/ResourceHelper.java | 3 + .../layoutlib/bridge/impl/SystemViewInfo.java | 38 +++ .../com/android/tools/layoutlib/create/Main.java | 1 + 10 files changed, 428 insertions(+), 146 deletions(-) create mode 100644 tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java delete mode 100644 tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java create mode 100644 tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java (limited to 'tools') diff --git a/tools/layoutlib/bridge/resources/bars/action_bar.xml b/tools/layoutlib/bridge/resources/bars/action_bar.xml index 7adc5af..dcfb979 100644 --- a/tools/layoutlib/bridge/resources/bars/action_bar.xml +++ b/tools/layoutlib/bridge/resources/bars/action_bar.xml @@ -1,7 +1,6 @@ - - + + + diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index bf8658e..430b773 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -211,7 +211,8 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { Capability.ANIMATED_VIEW_MANIPULATION, Capability.ADAPTER_BINDING, Capability.EXTENDED_VIEWINFO, - Capability.FIXED_SCALABLE_NINE_PATCH); + Capability.FIXED_SCALABLE_NINE_PATCH, + Capability.ACTION_BAR); BridgeAssetManager.initSystem(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java index f9f4b3a..e0f87fd 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java @@ -64,6 +64,11 @@ public class BridgeRenderSession extends RenderSession { } @Override + public List getSystemRootViews() { + return mSession.getSystemViewInfos(); + } + + @Override public Map getDefaultProperties(Object viewObject) { return mSession.getDefaultProperties(viewObject); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index c64b4d1..78ae102 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -607,7 +607,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); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java new file mode 100644 index 0000000..86471f5 --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java @@ -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 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(); + + 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 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; + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java deleted file mode 100644 index 226649d..0000000 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java +++ /dev/null @@ -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; - } -} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index f8f348c..28c5f65 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -43,14 +43,15 @@ 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.ActionBarLayout; import com.android.layoutlib.bridge.bars.CustomBar; -import com.android.layoutlib.bridge.bars.FakeActionBar; import com.android.layoutlib.bridge.bars.NavigationBar; import com.android.layoutlib.bridge.bars.StatusBar; import com.android.layoutlib.bridge.bars.TabletSystemBar; 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.resources.ScreenSize; @@ -133,6 +134,7 @@ public class RenderSessionImpl extends RenderAction { // information being returned through the API private BufferedImage mImage; private List mViewInfoList; + private List mSystemViewInfoList; private static final class PostInflateException extends Exception { private static final long serialVersionUID = 1L; @@ -217,7 +219,6 @@ public class RenderSessionImpl extends RenderAction { HardwareConfig hardwareConfig = params.getHardwareConfig(); BridgeContext context = getContext(); - // the view group that receives the window background. ViewGroup backgroundView = null; @@ -248,12 +249,8 @@ public class RenderSessionImpl extends RenderAction { topLayout.setOrientation(LinearLayout.HORIZONTAL); try { - NavigationBar navigationBar = new NavigationBar(context, - hardwareConfig.getDensity(), LinearLayout.VERTICAL); - navigationBar.setLayoutParams( - new LinearLayout.LayoutParams( - mNavigationBarSize, - LayoutParams.MATCH_PARENT)); + CustomBar navigationBar = createNavigationBar(context, + hardwareConfig.getDensity(), hardwareConfig.getScreenSize()); topLayout.addView(navigationBar); } catch (XmlPullParserException e) { @@ -285,9 +282,10 @@ public class RenderSessionImpl extends RenderAction { 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. @@ -298,11 +296,9 @@ public class RenderSessionImpl extends RenderAction { if (mStatusBarSize > 0) { // system bar try { - StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity()); - systemBar.setLayoutParams( - new LinearLayout.LayoutParams( - LayoutParams.MATCH_PARENT, mStatusBarSize)); - topLayout.addView(systemBar); + StatusBar statusBar = createStatusBar(context, + hardwareConfig.getDensity()); + topLayout.addView(statusBar); } catch (XmlPullParserException e) { } @@ -321,23 +317,16 @@ public class RenderSessionImpl extends RenderAction { // 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) { @@ -345,29 +334,21 @@ public class RenderSessionImpl extends RenderAction { } // 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 { - CustomBar navigationBar; - if (hardwareConfig.getScreenSize() == ScreenSize.XLARGE) { - navigationBar = new TabletSystemBar(context, - hardwareConfig.getDensity()); - } else { - navigationBar = new NavigationBar(context, - hardwareConfig.getDensity(), LinearLayout.HORIZONTAL); - } - - navigationBar.setLayoutParams( - new LinearLayout.LayoutParams( - LayoutParams.MATCH_PARENT, mNavigationBarSize)); + CustomBar navigationBar = createNavigationBar(context, + hardwareConfig.getDensity(), hardwareConfig.getScreenSize()); topLayout.addView(navigationBar); } catch (XmlPullParserException e) { @@ -568,7 +549,7 @@ public class RenderSessionImpl extends RenderAction { mViewRoot.draw(mCanvas); } - mViewInfoList = startVisitingViews(mViewRoot, 0, params.getExtendedViewInfoMode()); + mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(), false); // success! return SUCCESS.createResult(); @@ -1357,50 +1338,126 @@ public class RenderSessionImpl extends RenderAction { } } - private List startVisitingViews(View view, int offset, boolean setExtendedInfo) { - if (view == null) { - return null; - } + /** + * 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, + boolean isContentFrame) { + ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame); - // adjust the offset to this view. - offset += view.getTop(); + if (view instanceof ViewGroup) { + ViewGroup group = ((ViewGroup) view); + result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset, + setExtendedInfo, isContentFrame)); + } + return result; + } - if (view == mContentRoot) { - return visitAllChildren(mContentRoot, offset, setExtendedInfo); + /** + * 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 visitAllChildren(ViewGroup viewGroup, int offset, + boolean setExtendedInfo, boolean isContentFrame) { + if (viewGroup == null) { + return null; } - // otherwise, look for mContentRoot in the children - if (view instanceof ViewGroup) { - ViewGroup group = ((ViewGroup) view); + if (!isContentFrame) { + offset += viewGroup.getTop(); + } - for (int i = 0; i < group.getChildCount(); i++) { - List list = startVisitingViews(group.getChildAt(i), offset, + int childCount = viewGroup.getChildCount(); + if (viewGroup == mContentRoot) { + List childrenWithoutOffset = new ArrayList(childCount); + List childrenWithOffset = new ArrayList(childCount); + for (int i = 0; i < childCount; i++) { + ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset, setExtendedInfo); - if (list != null) { - return list; - } + childrenWithoutOffset.add(childViewInfo[0]); + childrenWithOffset.add(childViewInfo[1]); + } + mViewInfoList = childrenWithOffset; + return childrenWithoutOffset; + } else { + List children = new ArrayList(childCount); + for (int i = 0; i < childCount; i++) { + children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo, + isContentFrame)); } + return children; } + } - return null; + /** + * 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 children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true); + result[0].setChildren(children); + result[1].setChildren(children); + } + return result; } /** - * Visits a 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. + * 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 visit(View view, int offset, boolean setExtendedInfo) { + 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; @@ -1415,37 +1472,68 @@ public class RenderSessionImpl extends RenderAction { marginParams != null ? marginParams.bottomMargin : 0); } - if (view instanceof ViewGroup) { - ViewGroup group = ((ViewGroup) view); - result.setChildren(visitAllChildren(group, 0 /*offset*/, setExtendedInfo)); - } - return result; } + private void invalidateRenderingSize() { + mMeasuredScreenWidth = mMeasuredScreenHeight = -1; + } + /** - * 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. + * Creates the status bar with wifi and battery icons. */ - private List visitAllChildren(ViewGroup viewGroup, int offset, - boolean setExtendedInfo) { - if (viewGroup == null) { - return null; - } + private StatusBar createStatusBar(BridgeContext context, Density density) + throws XmlPullParserException { + StatusBar statusBar = new StatusBar(context, density); + statusBar.setLayoutParams( + new LinearLayout.LayoutParams( + LayoutParams.MATCH_PARENT, mStatusBarSize)); + return statusBar; + } - List children = new ArrayList(); - for (int i = 0; i < viewGroup.getChildCount(); i++) { - children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo)); + /** + * 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 CustomBar createNavigationBar(BridgeContext context, Density density, ScreenSize size) + throws XmlPullParserException { + CustomBar navigationBar; + if (size == ScreenSize.XLARGE) { + navigationBar = new TabletSystemBar(context, density); + } else { + navigationBar = new NavigationBar(context, density, + mNavigationBarOrientation); + } + if (mNavigationBarOrientation == LinearLayout.VERTICAL) { + navigationBar.setLayoutParams(new LinearLayout.LayoutParams(mNavigationBarSize, + LayoutParams.MATCH_PARENT)); + } else { + navigationBar.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, + mNavigationBarSize)); } - return children; + 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; + } - private void invalidateRenderingSize() { - mMeasuredScreenWidth = mMeasuredScreenHeight = -1; + /** + * 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() { @@ -1460,6 +1548,10 @@ public class RenderSessionImpl extends RenderAction { return mViewInfoList; } + public List getSystemViewInfos() { + return mSystemViewInfoList; + } + public Map getDefaultProperties(Object viewObject) { return getContext().getDefaultPropMap(viewObject); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java index 6dcb693..adb0937 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java @@ -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; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java new file mode 100644 index 0000000..5c267df --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java @@ -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; + } +} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java index 26b96ae..0dd43c1 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java @@ -96,6 +96,7 @@ public class Main { "android.pim.*", // for datepicker "android.os.*", // for android.os.Handler "android.database.ContentObserver", // for Digital clock + "com.android.internal.view.menu.ActionMenu", }, excludeClasses); aa.analyze(); -- cgit v1.1