am 49fcfdd4: Merge changes I9c294329,Ie4db5d28 into mnc-dev
* commit '49fcfdd4ba6b9e19139b0650542d573cf493dc5b': LayoutLib: translucent sys ui bars Move the layout code out of RenderSessionImpl.
This commit is contained in:
@@ -594,9 +594,13 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
||||
|
||||
/**
|
||||
* Returns the integer id of a framework resource, from a given resource type and resource name.
|
||||
* <p/>
|
||||
* If no resource is found, it creates a dynamic id for the resource.
|
||||
*
|
||||
* @param type the type of the resource
|
||||
* @param name the name of the resource.
|
||||
* @return an {@link Integer} containing the resource id, or null if no resource were found.
|
||||
*
|
||||
* @return an {@link Integer} containing the resource id.
|
||||
*/
|
||||
@NonNull
|
||||
public static Integer getResourceId(ResourceType type, String name) {
|
||||
|
||||
@@ -31,7 +31,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -51,9 +50,8 @@ public class AppCompatActionBar extends BridgeActionBar {
|
||||
/**
|
||||
* Inflate the action bar and attach it to {@code parentView}
|
||||
*/
|
||||
public AppCompatActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
|
||||
@NonNull ViewGroup parentView) {
|
||||
super(context, params, parentView);
|
||||
public AppCompatActionBar(@NonNull BridgeContext context, @NonNull SessionParams params) {
|
||||
super(context, params);
|
||||
int contentRootId = context.getProjectResourceValue(ResourceType.ID,
|
||||
"action_bar_activity_content", 0);
|
||||
View contentView = getDecorContent().findViewById(contentRootId);
|
||||
@@ -64,7 +62,9 @@ public class AppCompatActionBar extends BridgeActionBar {
|
||||
// Something went wrong. Create a new FrameLayout in the enclosing layout.
|
||||
FrameLayout contentRoot = new FrameLayout(context);
|
||||
setMatchParent(contentRoot);
|
||||
mEnclosingLayout.addView(contentRoot);
|
||||
if (mEnclosingLayout != null) {
|
||||
mEnclosingLayout.addView(contentRoot);
|
||||
}
|
||||
setContentRoot(contentRoot);
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.ide.common.rendering.api.SessionParams;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -39,7 +40,7 @@ public abstract class BridgeActionBar {
|
||||
@NonNull protected final BridgeContext mBridgeContext;
|
||||
@NonNull protected final SessionParams mParams;
|
||||
// A Layout that contains the inflated action bar. The menu popup is added to this layout.
|
||||
@NonNull protected final ViewGroup mEnclosingLayout;
|
||||
@Nullable protected final ViewGroup mEnclosingLayout;
|
||||
|
||||
private final View mDecorContent;
|
||||
private final ActionBarCallback mCallback;
|
||||
@@ -47,8 +48,7 @@ public abstract class BridgeActionBar {
|
||||
@SuppressWarnings("NullableProblems") // Should be initialized by subclasses.
|
||||
@NonNull private FrameLayout mContentRoot;
|
||||
|
||||
public BridgeActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
|
||||
@NonNull ViewGroup parentView) {
|
||||
public BridgeActionBar(@NonNull BridgeContext context, @NonNull SessionParams params) {
|
||||
mBridgeContext = context;
|
||||
mParams = params;
|
||||
mCallback = params.getLayoutlibCallback().getActionBarCallback();
|
||||
@@ -75,14 +75,13 @@ public abstract class BridgeActionBar {
|
||||
// added.
|
||||
mEnclosingLayout = new RelativeLayout(mBridgeContext);
|
||||
setMatchParent(mEnclosingLayout);
|
||||
parentView.addView(mEnclosingLayout);
|
||||
} else {
|
||||
mEnclosingLayout = parentView;
|
||||
mEnclosingLayout = null;
|
||||
}
|
||||
|
||||
// Inflate action bar layout.
|
||||
mDecorContent = getInflater(context).inflate(layoutId, mEnclosingLayout, true);
|
||||
|
||||
mDecorContent =
|
||||
getInflater(context).inflate(layoutId, mEnclosingLayout, mEnclosingLayout != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,6 +152,13 @@ public abstract class BridgeActionBar {
|
||||
|
||||
public abstract void createMenuPopup();
|
||||
|
||||
/**
|
||||
* The root view that represents the action bar and possibly the content included in it.
|
||||
*/
|
||||
public View getRootView() {
|
||||
return mEnclosingLayout == null ? mDecorContent : mEnclosingLayout;
|
||||
}
|
||||
|
||||
public ActionBarCallback getCallBack() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap_Delegate;
|
||||
@@ -68,7 +67,7 @@ abstract class CustomBar extends LinearLayout {
|
||||
protected abstract TextView getStyleableTextView();
|
||||
|
||||
protected CustomBar(BridgeContext context, int orientation, String layoutPath,
|
||||
String name, int simulatedPlatformVersion) throws XmlPullParserException {
|
||||
String name, int simulatedPlatformVersion) {
|
||||
super(context);
|
||||
mSimulatedPlatformVersion = simulatedPlatformVersion;
|
||||
setOrientation(orientation);
|
||||
@@ -78,14 +77,18 @@ abstract class CustomBar extends LinearLayout {
|
||||
setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
}
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE);
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
|
||||
XmlPullParser parser = ParserFactory.create(getClass().getResourceAsStream(layoutPath),
|
||||
name);
|
||||
XmlPullParser parser;
|
||||
try {
|
||||
parser = ParserFactory.create(getClass().getResourceAsStream(layoutPath), name);
|
||||
} catch (XmlPullParserException e) {
|
||||
// Should not happen as the resource is bundled with the jar, and ParserFactory should
|
||||
// have been initialized.
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
|
||||
parser, (BridgeContext) context, false /*platformFile*/);
|
||||
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(parser, context, false);
|
||||
|
||||
try {
|
||||
inflater.inflate(bridgeParser, this, true);
|
||||
@@ -154,7 +157,7 @@ abstract class CustomBar extends LinearLayout {
|
||||
|
||||
protected void setStyle(String themeEntryName) {
|
||||
|
||||
BridgeContext bridgeContext = (BridgeContext) mContext;
|
||||
BridgeContext bridgeContext = getContext();
|
||||
RenderResources res = bridgeContext.getRenderResources();
|
||||
|
||||
ResourceValue value = res.findItemInTheme(themeEntryName, true /*isFrameworkAttr*/);
|
||||
@@ -214,27 +217,47 @@ abstract class CustomBar extends LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BridgeContext getContext() {
|
||||
return (BridgeContext) mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a theme attribute name, get the color referenced by it. The theme attribute may be
|
||||
* used in a layout like "?attr/foo".
|
||||
* Find the background color for this bar from the theme attributes. Only relevant to StatusBar
|
||||
* and NavigationBar.
|
||||
* <p/>
|
||||
* Returns 0 if not found.
|
||||
*
|
||||
* @param colorAttrName the attribute name for the background color
|
||||
* @param translucentAttrName the attribute name for the translucency property of the bar.
|
||||
*
|
||||
* @throws NumberFormatException if color resolved to an invalid string.
|
||||
*/
|
||||
protected int getThemeAttrColor(@NonNull String attrName, boolean isFramework) {
|
||||
protected int getBarColor(@NonNull String colorAttrName, @NonNull String translucentAttrName) {
|
||||
if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) {
|
||||
return 0;
|
||||
}
|
||||
assert mContext instanceof BridgeContext;
|
||||
BridgeContext context = ((BridgeContext) mContext);
|
||||
RenderResources renderResources = context.getRenderResources();
|
||||
// From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
|
||||
ResourceValue resource = renderResources.findItemInTheme(attrName, isFramework);
|
||||
if (resource != null) {
|
||||
// Form @color/bar to the #AARRGGBB
|
||||
resource = renderResources.resolveResValue(resource);
|
||||
RenderResources renderResources = getContext().getRenderResources();
|
||||
// First check if the bar is translucent.
|
||||
boolean translucent = ResourceHelper.getBooleanThemeValue(renderResources,
|
||||
translucentAttrName, true, false);
|
||||
if (translucent) {
|
||||
// Keep in sync with R.color.system_bar_background_semi_transparent from system ui.
|
||||
return 0x66000000; // 40% black.
|
||||
}
|
||||
boolean transparent = ResourceHelper.getBooleanThemeValue(renderResources,
|
||||
"windowDrawsSystemBarBackgrounds", true, false);
|
||||
if (transparent) {
|
||||
return getColor(renderResources, colorAttrName);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int getColor(RenderResources renderResources, String attr) {
|
||||
// From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
|
||||
ResourceValue resource = renderResources.findItemInTheme(attr, true);
|
||||
// Form @color/bar to the #AARRGGBB
|
||||
resource = renderResources.resolveResValue(resource);
|
||||
if (resource != null && ResourceType.COLOR.equals(resource.getResourceType())) {
|
||||
return ResourceHelper.getColor(resource.getValue());
|
||||
}
|
||||
@@ -242,8 +265,7 @@ abstract class CustomBar extends LinearLayout {
|
||||
}
|
||||
|
||||
private ResourceValue getResourceValue(String reference) {
|
||||
BridgeContext bridgeContext = (BridgeContext) mContext;
|
||||
RenderResources res = bridgeContext.getRenderResources();
|
||||
RenderResources res = getContext().getRenderResources();
|
||||
|
||||
// find the resource
|
||||
ResourceValue value = res.findResValue(reference, false);
|
||||
|
||||
@@ -60,23 +60,24 @@ public class FrameworkActionBar extends BridgeActionBar {
|
||||
/**
|
||||
* Inflate the action bar and attach it to {@code parentView}
|
||||
*/
|
||||
public FrameworkActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
|
||||
@NonNull ViewGroup parentView) {
|
||||
super(context, params, parentView);
|
||||
public FrameworkActionBar(@NonNull BridgeContext context, @NonNull SessionParams params) {
|
||||
super(context, params);
|
||||
|
||||
View decorContent = getDecorContent();
|
||||
|
||||
mActionBar = FrameworkActionBarWrapper.getActionBarWrapper(context, getCallBack(),
|
||||
decorContent);
|
||||
|
||||
FrameLayout contentRoot = (FrameLayout) mEnclosingLayout.findViewById(android.R.id.content);
|
||||
FrameLayout contentRoot = (FrameLayout) decorContent.findViewById(android.R.id.content);
|
||||
|
||||
// If something went wrong and we were not able to initialize the content root,
|
||||
// just add a frame layout inside this and return.
|
||||
if (contentRoot == null) {
|
||||
contentRoot = new FrameLayout(context);
|
||||
setMatchParent(contentRoot);
|
||||
mEnclosingLayout.addView(contentRoot);
|
||||
if (mEnclosingLayout != null) {
|
||||
mEnclosingLayout.addView(contentRoot);
|
||||
}
|
||||
setContentRoot(contentRoot);
|
||||
} else {
|
||||
setContentRoot(contentRoot);
|
||||
@@ -162,6 +163,7 @@ public class FrameworkActionBar extends BridgeActionBar {
|
||||
listView.setDivider(a.getDrawable(R.attr.actionBarDivider));
|
||||
a.recycle();
|
||||
listView.setElevation(mActionBar.getMenuPopupElevation());
|
||||
assert mEnclosingLayout != null : "Unable to find view to attach ActionMenuPopup.";
|
||||
mEnclosingLayout.addView(listView);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ public abstract class FrameworkActionBarWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
FrameworkActionBarWrapper(@NonNull BridgeContext context, ActionBarCallback callback,
|
||||
FrameworkActionBarWrapper(@NonNull BridgeContext context, @NonNull ActionBarCallback callback,
|
||||
@NonNull ActionBar actionBar) {
|
||||
mActionBar = actionBar;
|
||||
mCallback = callback;
|
||||
|
||||
@@ -19,8 +19,6 @@ package com.android.layoutlib.bridge.bars;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.resources.Density;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.util.AttributeSet;
|
||||
@@ -33,6 +31,8 @@ public class NavigationBar extends CustomBar {
|
||||
|
||||
/** Navigation bar background color attribute name. */
|
||||
private static final String ATTR_COLOR = "navigationBarColor";
|
||||
/** Attribute for translucency property. */
|
||||
public static final String ATTR_TRANSLUCENT = "windowTranslucentNavigation";
|
||||
// These correspond to @dimen/navigation_side_padding in the system ui code.
|
||||
private static final int PADDING_WIDTH_DEFAULT = 36;
|
||||
private static final int PADDING_WIDTH_SW360 = 40;
|
||||
@@ -49,8 +49,8 @@ public class NavigationBar extends CustomBar {
|
||||
* Constructor to be used when creating the {@link NavigationBar} as a regular control.
|
||||
* This is currently used by the theme editor.
|
||||
*/
|
||||
public NavigationBar(Context context, AttributeSet attrs)
|
||||
throws XmlPullParserException {
|
||||
@SuppressWarnings("unused")
|
||||
public NavigationBar(Context context, AttributeSet attrs) {
|
||||
this((BridgeContext) context,
|
||||
Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
|
||||
LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
|
||||
@@ -61,11 +61,11 @@ public class NavigationBar extends CustomBar {
|
||||
}
|
||||
|
||||
public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
|
||||
boolean rtlEnabled, int simulatedPlatformVersion) throws XmlPullParserException {
|
||||
boolean rtlEnabled, int simulatedPlatformVersion) {
|
||||
super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
|
||||
"navigation_bar.xml", simulatedPlatformVersion);
|
||||
|
||||
int color = getThemeAttrColor(ATTR_COLOR, true);
|
||||
int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
|
||||
setBackgroundColor(color == 0 ? 0xFF000000 : color);
|
||||
|
||||
// Cannot access the inside items through id because no R.id values have been
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.android.resources.Density;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
@@ -42,22 +43,26 @@ public class StatusBar extends CustomBar {
|
||||
private final int mSimulatedPlatformVersion;
|
||||
/** Status bar background color attribute name. */
|
||||
private static final String ATTR_COLOR = "statusBarColor";
|
||||
/** Attribute for translucency property. */
|
||||
public static final String ATTR_TRANSLUCENT = "windowTranslucentStatus";
|
||||
|
||||
/**
|
||||
* Constructor to be used when creating the {@link StatusBar} as a regular control. This
|
||||
* is currently used by the theme editor.
|
||||
*/
|
||||
public StatusBar(Context context, AttributeSet attrs) throws XmlPullParserException {
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
public StatusBar(Context context, AttributeSet attrs) {
|
||||
this((BridgeContext) context,
|
||||
Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
|
||||
LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
|
||||
((BridgeContext) context).getConfiguration().getLayoutDirection() ==
|
||||
View.LAYOUT_DIRECTION_RTL,
|
||||
(context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
|
||||
context.getApplicationInfo().targetSdkVersion);
|
||||
}
|
||||
|
||||
public StatusBar(BridgeContext context, Density density, int direction, boolean RtlEnabled,
|
||||
int simulatedPlatformVersion) throws XmlPullParserException {
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
public StatusBar(BridgeContext context, Density density, boolean isRtl, boolean rtlEnabled,
|
||||
int simulatedPlatformVersion) {
|
||||
// FIXME: if direction is RTL but it's not enabled in application manifest, mirror this bar.
|
||||
super(context, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml",
|
||||
simulatedPlatformVersion);
|
||||
@@ -66,7 +71,7 @@ public class StatusBar extends CustomBar {
|
||||
// FIXME: use FILL_H?
|
||||
setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
|
||||
|
||||
int color = getThemeAttrColor(ATTR_COLOR, true);
|
||||
int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
|
||||
setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
|
||||
|
||||
// Cannot access the inside items through id because no R.id values have been
|
||||
|
||||
@@ -27,8 +27,7 @@ public class TitleBar extends CustomBar {
|
||||
|
||||
private TextView mTextView;
|
||||
|
||||
public TitleBar(BridgeContext context, String label, int simulatedPlatformVersion)
|
||||
throws XmlPullParserException {
|
||||
public TitleBar(BridgeContext context, String label, int simulatedPlatformVersion) {
|
||||
super(context, LinearLayout.HORIZONTAL, "/bars/title_bar.xml", "title_bar.xml",
|
||||
simulatedPlatformVersion);
|
||||
|
||||
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.HardwareConfig;
|
||||
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.ide.common.rendering.api.StyleResourceValue;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
|
||||
import com.android.layoutlib.bridge.bars.BridgeActionBar;
|
||||
import com.android.layoutlib.bridge.bars.Config;
|
||||
import com.android.layoutlib.bridge.bars.FrameworkActionBar;
|
||||
import com.android.layoutlib.bridge.bars.NavigationBar;
|
||||
import com.android.layoutlib.bridge.bars.StatusBar;
|
||||
import com.android.layoutlib.bridge.bars.TitleBar;
|
||||
import com.android.resources.Density;
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.resources.ScreenOrientation;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
|
||||
/**
|
||||
* The Layout used to create the system decor.
|
||||
*
|
||||
* The layout inflated will contain a content frame where the user's layout can be inflated.
|
||||
* <pre>
|
||||
* +-------------------------------------------------+---+
|
||||
* | Status bar | N |
|
||||
* +-------------------------------------------------+ a |
|
||||
* | Title/Action bar (optional) | v |
|
||||
* +-------------------------------------------------+ |
|
||||
* | Content, vertical extending | b |
|
||||
* | | a |
|
||||
* | | r |
|
||||
* +-------------------------------------------------+---+
|
||||
* </pre>
|
||||
* or
|
||||
* <pre>
|
||||
* +-------------------------------------+
|
||||
* | Status bar |
|
||||
* +-------------------------------------+
|
||||
* | Title/Action bar (optional) |
|
||||
* +-------------------------------------+
|
||||
* | Content, vertical extending |
|
||||
* | |
|
||||
* | |
|
||||
* +-------------------------------------+
|
||||
* | Nav bar |
|
||||
* +-------------------------------------+
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
class Layout extends RelativeLayout {
|
||||
|
||||
// Theme attributes used for configuring appearance of the system decor.
|
||||
private static final String ATTR_WINDOW_FLOATING = "windowIsFloating";
|
||||
private static final String ATTR_WINDOW_BACKGROUND = "windowBackground";
|
||||
private static final String ATTR_WINDOW_FULL_SCREEN = "windowFullScreen";
|
||||
private static final String ATTR_NAV_BAR_HEIGHT = "navigation_bar_height";
|
||||
private static final String ATTR_NAV_BAR_WIDTH = "navigation_bar_width";
|
||||
private static final String ATTR_STATUS_BAR_HEIGHT = "status_bar_height";
|
||||
private static final String ATTR_WINDOW_ACTION_BAR = "windowActionBar";
|
||||
private static final String ATTR_ACTION_BAR_SIZE = "actionBarSize";
|
||||
private static final String ATTR_WINDOW_NO_TITLE = "windowNoTitle";
|
||||
private static final String ATTR_WINDOW_TITLE_SIZE = "windowTitleSize";
|
||||
private static final String ATTR_WINDOW_TRANSLUCENT_STATUS = StatusBar.ATTR_TRANSLUCENT;
|
||||
private static final String ATTR_WINDOW_TRANSLUCENT_NAV = NavigationBar.ATTR_TRANSLUCENT;
|
||||
private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat";
|
||||
|
||||
// Default sizes
|
||||
private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
|
||||
private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
|
||||
private static final int DEFAULT_NAV_BAR_SIZE = 48;
|
||||
|
||||
// Ids assigned to components created. This is so that we can refer to other components in
|
||||
// layout params.
|
||||
private static final String ID_NAV_BAR = "navBar";
|
||||
private static final String ID_STATUS_BAR = "statusBar";
|
||||
private static final String ID_TITLE_BAR = "titleBar";
|
||||
// Prefix used with the above ids in order to make them unique in framework namespace.
|
||||
private static final String ID_PREFIX = "android_layoutlib_";
|
||||
|
||||
/**
|
||||
* Temporarily store the builder so that it doesn't have to be passed to all methods used
|
||||
* during inflation.
|
||||
*/
|
||||
private Builder mBuilder;
|
||||
|
||||
/**
|
||||
* This holds user's layout.
|
||||
*/
|
||||
private FrameLayout mContentRoot;
|
||||
|
||||
public Layout(@NonNull Builder builder) {
|
||||
super(builder.mContext);
|
||||
mBuilder = builder;
|
||||
if (builder.mWindowBackground != null) {
|
||||
Drawable d = ResourceHelper.getDrawable(builder.mWindowBackground, builder.mContext);
|
||||
setBackground(d);
|
||||
}
|
||||
|
||||
int simulatedPlatformVersion = getParams().getSimulatedPlatformVersion();
|
||||
HardwareConfig hwConfig = getParams().getHardwareConfig();
|
||||
Density density = hwConfig.getDensity();
|
||||
boolean isRtl = Bridge.isLocaleRtl(getParams().getLocale());
|
||||
|
||||
NavigationBar navBar = null;
|
||||
if (mBuilder.hasNavBar()) {
|
||||
navBar = createNavBar(getContext(), density, isRtl, getParams().isRtlSupported(),
|
||||
simulatedPlatformVersion);
|
||||
}
|
||||
|
||||
StatusBar statusBar = null;
|
||||
if (builder.mStatusBarSize > 0) {
|
||||
statusBar = createStatusBar(getContext(), density, isRtl, getParams().isRtlSupported(),
|
||||
simulatedPlatformVersion);
|
||||
}
|
||||
|
||||
View actionBar = null;
|
||||
TitleBar titleBar = null;
|
||||
if (builder.mActionBarSize > 0) {
|
||||
BridgeActionBar bar = createActionBar(getContext(), getParams());
|
||||
mContentRoot = bar.getContentRoot();
|
||||
actionBar = bar.getRootView();
|
||||
} else if (mBuilder.mTitleBarSize > 0) {
|
||||
titleBar = createTitleBar(getContext(), getParams().getAppLabel(),
|
||||
simulatedPlatformVersion);
|
||||
}
|
||||
|
||||
addViews(titleBar, mContentRoot == null ? (mContentRoot = createContentFrame()) : actionBar,
|
||||
statusBar, navBar);
|
||||
// Done with the builder. Don't hold a reference to it.
|
||||
mBuilder = null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private FrameLayout createContentFrame() {
|
||||
FrameLayout contentRoot = new FrameLayout(getContext());
|
||||
LayoutParams params = createLayoutParams(MATCH_PARENT, MATCH_PARENT);
|
||||
int rule = mBuilder.isNavBarVertical() ? START_OF : ABOVE;
|
||||
if (mBuilder.solidBars()) {
|
||||
params.addRule(rule, getId(ID_NAV_BAR));
|
||||
}
|
||||
int below = -1;
|
||||
if (mBuilder.mActionBarSize <= 0 && mBuilder.mTitleBarSize > 0) {
|
||||
below = getId(ID_TITLE_BAR);
|
||||
} else if (mBuilder.solidBars()) {
|
||||
below = getId(ID_STATUS_BAR);
|
||||
}
|
||||
if (below != -1) {
|
||||
params.addRule(BELOW, below);
|
||||
}
|
||||
contentRoot.setLayoutParams(params);
|
||||
return contentRoot;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private LayoutParams createLayoutParams(int width, int height) {
|
||||
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||
if (width > 0) {
|
||||
width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics);
|
||||
}
|
||||
if (height > 0) {
|
||||
height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics);
|
||||
}
|
||||
return new LayoutParams(width, height);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public FrameLayout getContentRoot() {
|
||||
return mContentRoot;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private SessionParams getParams() {
|
||||
return mBuilder.mParams;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BridgeContext getContext(){
|
||||
return (BridgeContext) super.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isRtl whether the current locale is an RTL locale.
|
||||
* @param isRtlSupported whether the applications supports RTL (i.e. has supportsRtl=true
|
||||
* in the manifest and targetSdkVersion >= 17.
|
||||
*/
|
||||
@NonNull
|
||||
private StatusBar createStatusBar(BridgeContext context, Density density, boolean isRtl,
|
||||
boolean isRtlSupported, int simulatedPlatformVersion) {
|
||||
StatusBar statusBar =
|
||||
new StatusBar(context, density, isRtl, isRtlSupported, simulatedPlatformVersion);
|
||||
LayoutParams params = createLayoutParams(MATCH_PARENT, mBuilder.mStatusBarSize);
|
||||
if (mBuilder.isNavBarVertical()) {
|
||||
params.addRule(START_OF, getId(ID_NAV_BAR));
|
||||
}
|
||||
statusBar.setLayoutParams(params);
|
||||
statusBar.setId(getId(ID_STATUS_BAR));
|
||||
return statusBar;
|
||||
}
|
||||
|
||||
private BridgeActionBar createActionBar(@NonNull BridgeContext context,
|
||||
@NonNull SessionParams params) {
|
||||
BridgeActionBar actionBar;
|
||||
if (mBuilder.isThemeAppCompat()) {
|
||||
actionBar = new AppCompatActionBar(context, params);
|
||||
} else {
|
||||
actionBar = new FrameworkActionBar(context, params);
|
||||
}
|
||||
LayoutParams layoutParams = createLayoutParams(MATCH_PARENT, MATCH_PARENT);
|
||||
int rule = mBuilder.isNavBarVertical() ? START_OF : ABOVE;
|
||||
if (mBuilder.solidBars()) {
|
||||
layoutParams.addRule(rule, getId(ID_NAV_BAR));
|
||||
}
|
||||
if (mBuilder.solidBars()) {
|
||||
layoutParams.addRule(BELOW, getId(ID_STATUS_BAR));
|
||||
}
|
||||
actionBar.getRootView().setLayoutParams(layoutParams);
|
||||
actionBar.createMenuPopup();
|
||||
return actionBar;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TitleBar createTitleBar(BridgeContext context, String title,
|
||||
int simulatedPlatformVersion) {
|
||||
TitleBar titleBar = new TitleBar(context, title, simulatedPlatformVersion);
|
||||
LayoutParams params = createLayoutParams(MATCH_PARENT, mBuilder.mTitleBarSize);
|
||||
if (mBuilder.solidBars()) {
|
||||
params.addRule(BELOW, getId(ID_STATUS_BAR));
|
||||
}
|
||||
if (mBuilder.isNavBarVertical() && mBuilder.solidBars()) {
|
||||
params.addRule(START_OF, getId(ID_NAV_BAR));
|
||||
}
|
||||
titleBar.setLayoutParams(params);
|
||||
titleBar.setId(getId(ID_TITLE_BAR));
|
||||
return titleBar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isRtl whether the current locale is an RTL locale.
|
||||
* @param isRtlSupported whether the applications supports RTL (i.e. has supportsRtl=true
|
||||
* in the manifest and targetSdkVersion >= 17.
|
||||
*/
|
||||
@NonNull
|
||||
private NavigationBar createNavBar(BridgeContext context, Density density, boolean isRtl,
|
||||
boolean isRtlSupported, int simulatedPlatformVersion) {
|
||||
int orientation = mBuilder.mNavBarOrientation;
|
||||
int size = mBuilder.mNavBarSize;
|
||||
NavigationBar navBar = new NavigationBar(context, density, orientation, isRtl,
|
||||
isRtlSupported, simulatedPlatformVersion);
|
||||
boolean isVertical = mBuilder.isNavBarVertical();
|
||||
int w = isVertical ? size : MATCH_PARENT;
|
||||
int h = isVertical ? MATCH_PARENT : size;
|
||||
LayoutParams params = createLayoutParams(w, h);
|
||||
params.addRule(isVertical ? ALIGN_PARENT_END : ALIGN_PARENT_BOTTOM);
|
||||
navBar.setLayoutParams(params);
|
||||
navBar.setId(getId(ID_NAV_BAR));
|
||||
return navBar;
|
||||
}
|
||||
|
||||
private void addViews(@NonNull View... views) {
|
||||
for (View view : views) {
|
||||
if (view != null) {
|
||||
addView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getId(String name) {
|
||||
return Bridge.getResourceId(ResourceType.ID, ID_PREFIX + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class to help initialize the Layout.
|
||||
*/
|
||||
static class Builder {
|
||||
@NonNull
|
||||
private final SessionParams mParams;
|
||||
@NonNull
|
||||
private final BridgeContext mContext;
|
||||
private final RenderResources mResources;
|
||||
|
||||
private final boolean mWindowIsFloating;
|
||||
private ResourceValue mWindowBackground;
|
||||
private int mStatusBarSize;
|
||||
private int mNavBarSize;
|
||||
private int mNavBarOrientation;
|
||||
private int mActionBarSize;
|
||||
private int mTitleBarSize;
|
||||
private boolean mTranslucentStatus;
|
||||
private boolean mTranslucentNav;
|
||||
|
||||
private Boolean mIsThemeAppCompat;
|
||||
|
||||
public Builder(@NonNull SessionParams params, @NonNull BridgeContext context) {
|
||||
mParams = params;
|
||||
mContext = context;
|
||||
mResources = mParams.getResources();
|
||||
mWindowIsFloating = ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_FLOATING, true, true);
|
||||
|
||||
findBackground();
|
||||
findStatusBar();
|
||||
findActionBar();
|
||||
findNavBar();
|
||||
}
|
||||
|
||||
public boolean isNavBarVertical() {
|
||||
return mNavBarOrientation == VERTICAL;
|
||||
}
|
||||
|
||||
private void findBackground() {
|
||||
if (!mParams.isBgColorOverridden()) {
|
||||
mWindowBackground = mResources.findItemInTheme(ATTR_WINDOW_BACKGROUND, true);
|
||||
mWindowBackground = mResources.resolveResValue(mWindowBackground);
|
||||
}
|
||||
}
|
||||
|
||||
private void findStatusBar() {
|
||||
boolean windowFullScreen =
|
||||
ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_FULL_SCREEN, true, false);
|
||||
if (!windowFullScreen && !mWindowIsFloating) {
|
||||
mStatusBarSize =
|
||||
getDimension(ATTR_STATUS_BAR_HEIGHT, true, DEFAULT_STATUS_BAR_HEIGHT);
|
||||
mTranslucentStatus = ResourceHelper.getBooleanThemeValue(mResources,
|
||||
ATTR_WINDOW_TRANSLUCENT_STATUS, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void findActionBar() {
|
||||
if (mWindowIsFloating) {
|
||||
return;
|
||||
}
|
||||
// Check if an actionbar is needed
|
||||
boolean windowActionBar = ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_ACTION_BAR,
|
||||
!isThemeAppCompat(), true);
|
||||
if (windowActionBar) {
|
||||
mActionBarSize = getDimension(ATTR_ACTION_BAR_SIZE, true, DEFAULT_TITLE_BAR_HEIGHT);
|
||||
} else {
|
||||
// Maybe the gingerbread era title bar is needed
|
||||
boolean windowNoTitle =
|
||||
ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_NO_TITLE, true, false);
|
||||
if (!windowNoTitle) {
|
||||
mTitleBarSize =
|
||||
getDimension(ATTR_WINDOW_TITLE_SIZE, true, DEFAULT_TITLE_BAR_HEIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findNavBar() {
|
||||
if (hasSoftwareButtons() && !mWindowIsFloating) {
|
||||
|
||||
// get orientation
|
||||
HardwareConfig hwConfig = mParams.getHardwareConfig();
|
||||
boolean barOnBottom = true;
|
||||
|
||||
if (hwConfig.getOrientation() == ScreenOrientation.LANDSCAPE) {
|
||||
int shortSize = hwConfig.getScreenHeight();
|
||||
int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT /
|
||||
hwConfig.getDensity().getDpiValue();
|
||||
|
||||
// 0-599dp: "phone" UI with bar on the side
|
||||
// 600+dp: "tablet" UI with bar on the bottom
|
||||
barOnBottom = shortSizeDp >= 600;
|
||||
}
|
||||
|
||||
mNavBarOrientation = barOnBottom ? LinearLayout.HORIZONTAL : VERTICAL;
|
||||
mNavBarSize = getDimension(barOnBottom ? ATTR_NAV_BAR_HEIGHT : ATTR_NAV_BAR_WIDTH,
|
||||
true, DEFAULT_NAV_BAR_SIZE);
|
||||
mTranslucentNav = ResourceHelper.getBooleanThemeValue(mResources,
|
||||
ATTR_WINDOW_TRANSLUCENT_NAV, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private int getDimension(String attr, boolean isFramework, int defaultValue) {
|
||||
ResourceValue value = mResources.findItemInTheme(attr, isFramework);
|
||||
value = mResources.resolveResValue(value);
|
||||
if (value != null) {
|
||||
TypedValue typedValue = ResourceHelper.getValue(attr, value.getValue(), true);
|
||||
if (typedValue != null) {
|
||||
return (int) typedValue.getDimension(mContext.getMetrics());
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private boolean hasSoftwareButtons() {
|
||||
return mParams.getHardwareConfig().hasSoftwareButtons();
|
||||
}
|
||||
|
||||
private boolean isThemeAppCompat() {
|
||||
// If a cached value exists, return it.
|
||||
if (mIsThemeAppCompat != null) {
|
||||
return mIsThemeAppCompat;
|
||||
}
|
||||
// Ideally, we should check if the corresponding activity extends
|
||||
// android.support.v7.app.ActionBarActivity, and not care about the theme name at all.
|
||||
StyleResourceValue defaultTheme = mResources.getDefaultTheme();
|
||||
// We can't simply check for parent using resources.themeIsParentOf() since the
|
||||
// inheritance structure isn't really what one would expect. The first common parent
|
||||
// between Theme.AppCompat.Light and Theme.AppCompat is Theme.Material (for v21).
|
||||
boolean isThemeAppCompat = false;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (defaultTheme == null) {
|
||||
break;
|
||||
}
|
||||
// for loop ensures that we don't run into cyclic theme inheritance.
|
||||
if (defaultTheme.getName().startsWith(PREFIX_THEME_APPCOMPAT)) {
|
||||
isThemeAppCompat = true;
|
||||
break;
|
||||
}
|
||||
defaultTheme = mResources.getParent(defaultTheme);
|
||||
}
|
||||
mIsThemeAppCompat = isThemeAppCompat;
|
||||
return isThemeAppCompat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if both status bar and nav bar are solid (content doesn't overlap with these
|
||||
* bars).
|
||||
*/
|
||||
private boolean solidBars() {
|
||||
return hasNavBar() && !mTranslucentNav && !mTranslucentStatus && mStatusBarSize > 0;
|
||||
}
|
||||
|
||||
private boolean hasNavBar() {
|
||||
return Config.showOnScreenNavBar(mParams.getSimulatedPlatformVersion()) &&
|
||||
hasSoftwareButtons() && mNavBarSize > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,8 @@ import com.android.ide.common.rendering.api.Result;
|
||||
import com.android.ide.common.rendering.api.Result.Status;
|
||||
import com.android.ide.common.rendering.api.SessionParams;
|
||||
import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
|
||||
import com.android.ide.common.rendering.api.StyleResourceValue;
|
||||
import com.android.ide.common.rendering.api.ViewInfo;
|
||||
import com.android.ide.common.rendering.api.ViewType;
|
||||
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;
|
||||
@@ -45,22 +43,11 @@ import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
|
||||
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
||||
import com.android.layoutlib.bridge.android.RenderParamsFlags;
|
||||
import com.android.layoutlib.bridge.android.support.DesignLibUtil;
|
||||
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
|
||||
import com.android.layoutlib.bridge.bars.BridgeActionBar;
|
||||
import com.android.layoutlib.bridge.bars.Config;
|
||||
import com.android.layoutlib.bridge.bars.FrameworkActionBar;
|
||||
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;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.animation.AnimationThread;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorInflater;
|
||||
@@ -72,10 +59,7 @@ import android.app.Fragment_Delegate;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap_Delegate;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.Preference_Delegate;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.AttachInfo_Accessor;
|
||||
import android.view.BridgeInflater;
|
||||
import android.view.IWindowManager;
|
||||
@@ -126,33 +110,22 @@ import static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
|
||||
*/
|
||||
public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
|
||||
private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
|
||||
private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
|
||||
|
||||
// scene state
|
||||
private RenderSession mScene;
|
||||
private BridgeXmlBlockParser mBlockParser;
|
||||
private BridgeInflater mInflater;
|
||||
private ResourceValue mWindowBackground;
|
||||
private ViewGroup mViewRoot;
|
||||
private FrameLayout mContentRoot;
|
||||
private Canvas mCanvas;
|
||||
private int mMeasuredScreenWidth = -1;
|
||||
private int mMeasuredScreenHeight = -1;
|
||||
private boolean mIsAlphaChannelImage;
|
||||
private boolean mWindowIsFloating;
|
||||
private Boolean mIsThemeAppCompat;
|
||||
|
||||
private int mStatusBarSize;
|
||||
private int mNavigationBarSize;
|
||||
private int mNavigationBarOrientation = LinearLayout.HORIZONTAL;
|
||||
private int mTitleBarSize;
|
||||
private int mActionBarSize;
|
||||
|
||||
// information being returned through the API
|
||||
private BufferedImage mImage;
|
||||
private List<ViewInfo> mViewInfoList;
|
||||
private List<ViewInfo> mSystemViewInfoList;
|
||||
private Layout.Builder mLayoutBuilder;
|
||||
|
||||
private static final class PostInflateException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -196,34 +169,24 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
SessionParams params = getParams();
|
||||
BridgeContext context = getContext();
|
||||
|
||||
|
||||
RenderResources resources = getParams().getResources();
|
||||
DisplayMetrics metrics = getContext().getMetrics();
|
||||
|
||||
// use default of true in case it's not found to use alpha by default
|
||||
mIsAlphaChannelImage = getBooleanThemeValue(resources, "windowIsFloating", true, true);
|
||||
// FIXME: Find out why both variables are taking the same value.
|
||||
mWindowIsFloating = getBooleanThemeValue(resources, "windowIsFloating", true, true);
|
||||
mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(),
|
||||
"windowIsFloating", true, true);
|
||||
|
||||
findBackground(resources);
|
||||
findStatusBar(resources, metrics);
|
||||
findActionBar(resources, metrics);
|
||||
findNavigationBar(resources, metrics);
|
||||
mLayoutBuilder = new Layout.Builder(params, context);
|
||||
|
||||
// FIXME: find those out, and possibly add them to the render params
|
||||
boolean hasNavigationBar = true;
|
||||
//noinspection ConstantConditions
|
||||
IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
|
||||
metrics, Surface.ROTATION_0,
|
||||
hasNavigationBar);
|
||||
context.getMetrics(), Surface.ROTATION_0, hasNavigationBar);
|
||||
WindowManagerGlobal_Delegate.setWindowManagerService(iwm);
|
||||
|
||||
// build the inflater and parser.
|
||||
mInflater = new BridgeInflater(context, params.getLayoutlibCallback());
|
||||
context.setBridgeInflater(mInflater);
|
||||
|
||||
mBlockParser = new BridgeXmlBlockParser(
|
||||
params.getLayoutDescription(), context, false /* platformResourceFlag */);
|
||||
mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), context, false);
|
||||
|
||||
return SUCCESS.createResult();
|
||||
}
|
||||
@@ -240,164 +203,11 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
checkLock();
|
||||
|
||||
try {
|
||||
|
||||
mViewRoot = new Layout(mLayoutBuilder);
|
||||
mLayoutBuilder = null; // Done with the builder.
|
||||
mContentRoot = ((Layout) mViewRoot).getContentRoot();
|
||||
SessionParams params = getParams();
|
||||
HardwareConfig hardwareConfig = params.getHardwareConfig();
|
||||
BridgeContext context = getContext();
|
||||
boolean isRtl = Bridge.isLocaleRtl(params.getLocale());
|
||||
int layoutDirection = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
|
||||
|
||||
// the view group that receives the window background.
|
||||
ViewGroup backgroundView;
|
||||
|
||||
if (mWindowIsFloating || params.isForceNoDecor()) {
|
||||
backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
|
||||
mViewRoot.setLayoutDirection(layoutDirection);
|
||||
} else {
|
||||
int simulatedPlatformVersion = params.getSimulatedPlatformVersion();
|
||||
if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
|
||||
/*
|
||||
* This is a special case where the navigation bar is on the right.
|
||||
+-------------------------------------------------+---+
|
||||
| Status bar (always) | |
|
||||
+-------------------------------------------------+ |
|
||||
| (Layout with background drawable) | |
|
||||
| +---------------------------------------------+ | |
|
||||
| | Title/Action bar (optional) | | |
|
||||
| +---------------------------------------------+ | |
|
||||
| | Content, vertical extending | | |
|
||||
| | | | |
|
||||
| +---------------------------------------------+ | |
|
||||
+-------------------------------------------------+---+
|
||||
|
||||
So we create a horizontal layout, with the nav bar on the right,
|
||||
and the left part is the normal layout below without the nav bar at
|
||||
the bottom
|
||||
*/
|
||||
LinearLayout topLayout = new LinearLayout(context);
|
||||
topLayout.setLayoutDirection(layoutDirection);
|
||||
mViewRoot = topLayout;
|
||||
topLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
if (Config.showOnScreenNavBar(simulatedPlatformVersion)) {
|
||||
try {
|
||||
NavigationBar navigationBar = createNavigationBar(context,
|
||||
hardwareConfig.getDensity(), isRtl, params.isRtlSupported(),
|
||||
simulatedPlatformVersion);
|
||||
topLayout.addView(navigationBar);
|
||||
} catch (XmlPullParserException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* we're creating the following layout
|
||||
*
|
||||
+-------------------------------------------------+
|
||||
| Status bar (always) |
|
||||
+-------------------------------------------------+
|
||||
| (Layout with background drawable) |
|
||||
| +---------------------------------------------+ |
|
||||
| | Title/Action bar (optional) | |
|
||||
| +---------------------------------------------+ |
|
||||
| | Content, vertical extending | |
|
||||
| | | |
|
||||
| +---------------------------------------------+ |
|
||||
+-------------------------------------------------+
|
||||
| Navigation bar for soft buttons, maybe see above|
|
||||
+-------------------------------------------------+
|
||||
|
||||
*/
|
||||
|
||||
LinearLayout topLayout = new LinearLayout(context);
|
||||
topLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
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(
|
||||
topLayoutWidth, LayoutParams.MATCH_PARENT);
|
||||
topLayout.setLayoutParams(layoutParams);
|
||||
|
||||
// this is the case of soft buttons + vertical bar.
|
||||
// this top layout is the first layout in the horizontal layout. see above)
|
||||
if (isRtl && params.isRtlSupported()) {
|
||||
// If RTL is enabled, layoutlib will mirror the layouts. So, add the
|
||||
// topLayout to the right of Navigation Bar and layoutlib will draw it
|
||||
// to the left.
|
||||
mViewRoot.addView(topLayout);
|
||||
} else {
|
||||
// Add the top layout to the left of the Navigation Bar.
|
||||
mViewRoot.addView(topLayout, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (mStatusBarSize > 0) {
|
||||
// system bar
|
||||
try {
|
||||
StatusBar statusBar = createStatusBar(context, hardwareConfig.getDensity(),
|
||||
layoutDirection, params.isRtlSupported(),
|
||||
simulatedPlatformVersion);
|
||||
topLayout.addView(statusBar);
|
||||
} catch (XmlPullParserException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
LinearLayout backgroundLayout = new LinearLayout(context);
|
||||
backgroundView = backgroundLayout;
|
||||
backgroundLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
|
||||
LayoutParams.MATCH_PARENT, 0);
|
||||
layoutParams.weight = 1;
|
||||
backgroundLayout.setLayoutParams(layoutParams);
|
||||
topLayout.addView(backgroundLayout);
|
||||
|
||||
|
||||
// if the theme says no title/action bar, then the size will be 0
|
||||
if (mActionBarSize > 0) {
|
||||
BridgeActionBar actionBar = createActionBar(context, params, backgroundLayout);
|
||||
actionBar.createMenuPopup();
|
||||
mContentRoot = actionBar.getContentRoot();
|
||||
} else if (mTitleBarSize > 0) {
|
||||
try {
|
||||
TitleBar titleBar = createTitleBar(context,
|
||||
params.getAppLabel(),
|
||||
simulatedPlatformVersion);
|
||||
backgroundLayout.addView(titleBar);
|
||||
} catch (XmlPullParserException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// content frame
|
||||
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 (Config.showOnScreenNavBar(simulatedPlatformVersion) &&
|
||||
mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
|
||||
mNavigationBarSize > 0) {
|
||||
// system bar
|
||||
try {
|
||||
NavigationBar navigationBar = createNavigationBar(context,
|
||||
hardwareConfig.getDensity(), isRtl, params.isRtlSupported(),
|
||||
simulatedPlatformVersion);
|
||||
topLayout.addView(navigationBar);
|
||||
} catch (XmlPullParserException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sets the project callback (custom view loader) to the fragment delegate so that
|
||||
// it can instantiate the custom Fragment.
|
||||
@@ -408,7 +218,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
View view;
|
||||
if (isPreference) {
|
||||
view = Preference_Delegate.inflatePreference(getContext(), mBlockParser,
|
||||
mContentRoot);
|
||||
mContentRoot);
|
||||
} else {
|
||||
view = mInflater.inflate(mBlockParser, mContentRoot);
|
||||
}
|
||||
@@ -427,12 +237,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
|
||||
setActiveToolbar(view, context, params);
|
||||
|
||||
// get the background drawable
|
||||
if (mWindowBackground != null) {
|
||||
Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
|
||||
backgroundView.setBackground(d);
|
||||
}
|
||||
|
||||
return SUCCESS.createResult();
|
||||
} catch (PostInflateException e) {
|
||||
return ERROR_INFLATION.createResult(e.getMessage(), e);
|
||||
@@ -1073,198 +877,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void findBackground(RenderResources resources) {
|
||||
if (!getParams().isBgColorOverridden()) {
|
||||
mWindowBackground = resources.findItemInTheme("windowBackground",
|
||||
true /*isFrameworkAttr*/);
|
||||
if (mWindowBackground != null) {
|
||||
mWindowBackground = resources.resolveResValue(mWindowBackground);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSoftwareButtons() {
|
||||
return getParams().getHardwareConfig().hasSoftwareButtons();
|
||||
}
|
||||
|
||||
private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
|
||||
boolean windowFullscreen = getBooleanThemeValue(resources,
|
||||
"windowFullscreen", false, true);
|
||||
|
||||
if (!windowFullscreen && !mWindowIsFloating) {
|
||||
// default value
|
||||
mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
|
||||
|
||||
// get the real value
|
||||
ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
|
||||
"status_bar_height");
|
||||
|
||||
if (value != null) {
|
||||
TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
|
||||
value.getValue(), true /*requireUnit*/);
|
||||
if (typedValue != null) {
|
||||
// compute the pixel value based on the display metrics
|
||||
mStatusBarSize = (int)typedValue.getDimension(metrics);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
|
||||
if (mWindowIsFloating) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean windowActionBar = getBooleanThemeValue(resources,
|
||||
"windowActionBar", true, !isThemeAppCompat(resources));
|
||||
|
||||
// if there's a value and it's false (default is true)
|
||||
if (windowActionBar) {
|
||||
|
||||
// default size of the window title bar
|
||||
mActionBarSize = DEFAULT_TITLE_BAR_HEIGHT;
|
||||
|
||||
// get value from the theme.
|
||||
ResourceValue value = resources.findItemInTheme("actionBarSize",
|
||||
true /*isFrameworkAttr*/);
|
||||
|
||||
// resolve it
|
||||
value = resources.resolveResValue(value);
|
||||
|
||||
if (value != null) {
|
||||
// get the numerical value, if available
|
||||
TypedValue typedValue = ResourceHelper.getValue("actionBarSize", value.getValue(),
|
||||
true /*requireUnit*/);
|
||||
if (typedValue != null) {
|
||||
// compute the pixel value based on the display metrics
|
||||
mActionBarSize = (int)typedValue.getDimension(metrics);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// action bar overrides title bar so only look for this one if action bar is hidden
|
||||
boolean windowNoTitle = getBooleanThemeValue(resources, "windowNoTitle", false, true);
|
||||
|
||||
if (!windowNoTitle) {
|
||||
|
||||
// default size of the window title bar
|
||||
mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
|
||||
|
||||
// get value from the theme.
|
||||
ResourceValue value = resources.findItemInTheme("windowTitleSize",
|
||||
true /*isFrameworkAttr*/);
|
||||
|
||||
// resolve it
|
||||
value = resources.resolveResValue(value);
|
||||
|
||||
if (value != null) {
|
||||
// get the numerical value, if available
|
||||
TypedValue typedValue = ResourceHelper.getValue("windowTitleSize",
|
||||
value.getValue(), true /*requireUnit*/);
|
||||
if (typedValue != null) {
|
||||
// compute the pixel value based on the display metrics
|
||||
mTitleBarSize = (int)typedValue.getDimension(metrics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void findNavigationBar(RenderResources resources, DisplayMetrics metrics) {
|
||||
if (hasSoftwareButtons() && !mWindowIsFloating) {
|
||||
|
||||
// default value
|
||||
mNavigationBarSize = 48; // ??
|
||||
|
||||
HardwareConfig hardwareConfig = getParams().getHardwareConfig();
|
||||
|
||||
boolean barOnBottom = true;
|
||||
|
||||
if (hardwareConfig.getOrientation() == ScreenOrientation.LANDSCAPE) {
|
||||
// compute the dp of the screen.
|
||||
int shortSize = hardwareConfig.getScreenHeight();
|
||||
|
||||
// compute in dp
|
||||
int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT /
|
||||
hardwareConfig.getDensity().getDpiValue();
|
||||
|
||||
// 0-599dp: "phone" UI with bar on the side
|
||||
// 600+dp: "tablet" UI with bar on the bottom
|
||||
barOnBottom = shortSizeDp >= 600;
|
||||
}
|
||||
|
||||
if (barOnBottom) {
|
||||
mNavigationBarOrientation = LinearLayout.HORIZONTAL;
|
||||
} else {
|
||||
mNavigationBarOrientation = LinearLayout.VERTICAL;
|
||||
}
|
||||
|
||||
// get the real value
|
||||
ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
|
||||
barOnBottom ? "navigation_bar_height" : "navigation_bar_width");
|
||||
|
||||
if (value != null) {
|
||||
TypedValue typedValue = ResourceHelper.getValue("navigation_bar_height",
|
||||
value.getValue(), true /*requireUnit*/);
|
||||
if (typedValue != null) {
|
||||
// compute the pixel value based on the display metrics
|
||||
mNavigationBarSize = (int)typedValue.getDimension(metrics);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isThemeAppCompat(RenderResources resources) {
|
||||
// Ideally, we should check if the corresponding activity extends
|
||||
// android.support.v7.app.ActionBarActivity, and not care about the theme name at all.
|
||||
if (mIsThemeAppCompat == null) {
|
||||
StyleResourceValue defaultTheme = resources.getDefaultTheme();
|
||||
// We can't simply check for parent using resources.themeIsParentOf() since the
|
||||
// inheritance structure isn't really what one would expect. The first common parent
|
||||
// between Theme.AppCompat.Light and Theme.AppCompat is Theme.Material (for v21).
|
||||
boolean isThemeAppCompat = false;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (defaultTheme == null) {
|
||||
break;
|
||||
}
|
||||
// for loop ensures that we don't run into cyclic theme inheritance.
|
||||
if (defaultTheme.getName().startsWith("Theme.AppCompat")) {
|
||||
isThemeAppCompat = true;
|
||||
break;
|
||||
}
|
||||
defaultTheme = resources.getParent(defaultTheme);
|
||||
}
|
||||
mIsThemeAppCompat = isThemeAppCompat;
|
||||
}
|
||||
return mIsThemeAppCompat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for an attribute in the current theme.
|
||||
*
|
||||
* @param resources the render resources
|
||||
* @param name the name of the attribute
|
||||
* @param defaultValue the default value.
|
||||
* @param isFrameworkAttr if the attribute is in android namespace
|
||||
* @return the value of the attribute or the default one if not found.
|
||||
*/
|
||||
private boolean getBooleanThemeValue(RenderResources resources,
|
||||
String name, boolean defaultValue, boolean isFrameworkAttr) {
|
||||
|
||||
ResourceValue value = resources.findItemInTheme(name, isFrameworkAttr);
|
||||
|
||||
// because it may reference something else, we resolve it.
|
||||
value = resources.resolveResValue(value);
|
||||
|
||||
// if there's no value, return the default.
|
||||
if (value == null || value.getValue() == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post process on a view hierarchy that was just inflated.
|
||||
* <p/>
|
||||
@@ -1737,63 +1349,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
||||
mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the status bar with wifi and battery icons.
|
||||
*/
|
||||
private StatusBar createStatusBar(BridgeContext context, Density density, int direction,
|
||||
boolean isRtlSupported, int platformVersion) throws XmlPullParserException {
|
||||
StatusBar statusBar = new StatusBar(context, density,
|
||||
direction, isRtlSupported, platformVersion);
|
||||
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, int simulatedPlatformVersion)
|
||||
throws XmlPullParserException {
|
||||
NavigationBar navigationBar = new NavigationBar(context,
|
||||
density, mNavigationBarOrientation, isRtl,
|
||||
isRtlSupported, simulatedPlatformVersion);
|
||||
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, String title,
|
||||
int simulatedPlatformVersion)
|
||||
throws XmlPullParserException {
|
||||
TitleBar titleBar = new TitleBar(context, title, simulatedPlatformVersion);
|
||||
titleBar.setLayoutParams(
|
||||
new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, mTitleBarSize));
|
||||
return titleBar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the action bar. Also queries the project callback for missing information.
|
||||
*/
|
||||
private BridgeActionBar createActionBar(BridgeContext context, SessionParams params,
|
||||
ViewGroup parentView) {
|
||||
if (mIsThemeAppCompat == Boolean.TRUE) {
|
||||
return new AppCompatActionBar(context, params, parentView);
|
||||
} else {
|
||||
return new FrameworkActionBar(context, params, parentView);
|
||||
}
|
||||
}
|
||||
|
||||
public BufferedImage getImage() {
|
||||
return mImage;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.android.ide.common.rendering.api.DensityBasedResourceValue;
|
||||
import com.android.ide.common.rendering.api.LayoutLog;
|
||||
import com.android.ide.common.rendering.api.RenderResources;
|
||||
import com.android.ide.common.rendering.api.ResourceValue;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
||||
@@ -327,6 +328,25 @@ public final class ResourceHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for an attribute in the current theme.
|
||||
*
|
||||
* @param resources the render resources
|
||||
* @param name the name of the attribute
|
||||
* @param defaultValue the default value.
|
||||
* @param isFrameworkAttr if the attribute is in android namespace
|
||||
* @return the value of the attribute or the default one if not found.
|
||||
*/
|
||||
public static boolean getBooleanThemeValue(@NonNull RenderResources resources, String name,
|
||||
boolean isFrameworkAttr, boolean defaultValue) {
|
||||
ResourceValue value = resources.findItemInTheme(name, isFrameworkAttr);
|
||||
value = resources.resolveResValue(value);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
|
||||
}
|
||||
|
||||
// ------- TypedValue stuff
|
||||
// This is taken from //device/libs/utils/ResourceTypes.cpp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user