summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java166
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java159
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java)122
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java)97
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java32
5 files changed, 452 insertions, 124 deletions
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
new file mode 100644
index 0000000..e5023b8
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
@@ -0,0 +1,166 @@
+/*
+ * 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.bars;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+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.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.ResourceType;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+/**
+ * Assumes that the AppCompat library is present in the project's classpath and creates an
+ * actionbar around it.
+ */
+public class AppCompatActionBar extends BridgeActionBar {
+
+ private Object mWindowDecorActionBar;
+ private static final String WINDOW_ACTION_BAR_CLASS = "android.support.v7.internal.app.WindowDecorActionBar";
+ private Class<?> mWindowActionBarClass;
+
+ /**
+ * 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);
+ int contentRootId = context.getProjectResourceValue(ResourceType.ID,
+ "action_bar_activity_content", 0);
+ View contentView = getDecorContent().findViewById(contentRootId);
+ if (contentView != null) {
+ assert contentView instanceof FrameLayout;
+ setContentRoot(((FrameLayout) contentView));
+ } else {
+ // Something went wrong. Create a new FrameLayout in the enclosing layout.
+ FrameLayout contentRoot = new FrameLayout(context);
+ setMatchParent(contentRoot);
+ mEnclosingLayout.addView(contentRoot);
+ setContentRoot(contentRoot);
+ }
+ try {
+ Class[] constructorParams = {View.class};
+ Object[] constructorArgs = {getDecorContent()};
+ mWindowDecorActionBar = params.getProjectCallback().loadView(WINDOW_ACTION_BAR_CLASS,
+ constructorParams, constructorArgs);
+
+ mWindowActionBarClass = mWindowDecorActionBar == null ? null :
+ mWindowDecorActionBar.getClass();
+ setupActionBar();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected ResourceValue getLayoutResource(BridgeContext context) {
+ // We always assume that the app has requested the action bar.
+ return context.getRenderResources().getProjectResource(ResourceType.LAYOUT,
+ "abc_screen_toolbar");
+ }
+
+ @Override
+ protected void setTitle(CharSequence title) {
+ if (title != null && mWindowDecorActionBar != null) {
+ Method setTitle = getMethod(mWindowActionBarClass, "setTitle", CharSequence.class);
+ invoke(setTitle, mWindowDecorActionBar, title);
+ }
+ }
+
+ @Override
+ protected void setSubtitle(CharSequence subtitle) {
+ if (subtitle != null && mWindowDecorActionBar != null) {
+ Method setSubtitle = getMethod(mWindowActionBarClass, "setSubtitle", CharSequence.class);
+ invoke(setSubtitle, mWindowDecorActionBar, subtitle);
+ }
+ }
+
+ @Override
+ protected void setIcon(String icon) {
+ // Do this only if the action bar doesn't already have an icon.
+ if (icon != null && !icon.isEmpty() && mWindowDecorActionBar != null) {
+ if (((Boolean) invoke(getMethod(mWindowActionBarClass, "hasIcon"), mWindowDecorActionBar)
+ )) {
+ Drawable iconDrawable = getDrawable(icon, false);
+ if (iconDrawable != null) {
+ Method setIcon = getMethod(mWindowActionBarClass, "setIcon", Drawable.class);
+ invoke(setIcon, mWindowDecorActionBar, iconDrawable);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void setHomeAsUp(boolean homeAsUp) {
+ if (mWindowDecorActionBar != null) {
+ Method setHomeAsUp = getMethod(mWindowActionBarClass,
+ "setDefaultDisplayHomeAsUpEnabled", boolean.class);
+ invoke(setHomeAsUp, mWindowDecorActionBar, homeAsUp);
+ }
+ }
+
+ @Override
+ public void createMenuPopup() {
+ // it's hard to addd menus to appcompat's actionbar, since it'll use a lot of reflection.
+ // so we skip it for now.
+ }
+
+ @Nullable
+ private static Method getMethod(Class<?> owner, String name, Class<?>... parameterTypes) {
+ try {
+ return owner == null ? null : owner.getMethod(name, parameterTypes);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Nullable
+ private static Object invoke(Method method, Object owner, Object... args) {
+ try {
+ return method == null ? null : method.invoke(owner, args);
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ // TODO: this is duplicated from FrameworkActionBarWrapper$WindowActionBarWrapper
+ @Nullable
+ private Drawable getDrawable(@NonNull String name, boolean isFramework) {
+ RenderResources res = mBridgeContext.getRenderResources();
+ ResourceValue value = res.findResValue(name, isFramework);
+ value = res.resolveResValue(value);
+ if (value != null) {
+ return ResourceHelper.getDrawable(value, mBridgeContext);
+ }
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
new file mode 100644
index 0000000..b29d25f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
@@ -0,0 +1,159 @@
+/*
+ * 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.bars;
+
+import com.android.annotations.NonNull;
+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.layoutlib.bridge.android.BridgeContext;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+/**
+ * An abstraction over two implementations of the ActionBar - framework and appcompat.
+ */
+public abstract class BridgeActionBar {
+ // Store a reference to the context so that we don't have to cast it repeatedly.
+ @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;
+
+ private final View mDecorContent;
+ private final ActionBarCallback mCallback;
+
+ @NonNull private FrameLayout mContentRoot;
+
+ public BridgeActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
+ @NonNull ViewGroup parentView) {
+ mBridgeContext = context;
+ mParams = params;
+ mCallback = params.getProjectCallback().getActionBarCallback();
+ ResourceValue layoutName = getLayoutResource(context);
+ if (layoutName == null) {
+ throw new RuntimeException("Unable to find the layout for Action Bar.");
+ }
+ int layoutId;
+ if (layoutName.isFramework()) {
+ layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
+ layoutName.getName(), 0);
+ } else {
+ layoutId = context.getProjectResourceValue(layoutName.getResourceType(),
+ layoutName.getName(), 0);
+
+ }
+ if (layoutId == 0) {
+ throw new RuntimeException(
+ String.format("Unable to resolve attribute \"%1$s\" of type \"%2$s\"",
+ layoutName.getName(), layoutName.getResourceType()));
+ }
+ if (mCallback.isOverflowPopupNeeded()) {
+ // Create a RelativeLayout around the action bar, to which the overflow popup may be
+ // added.
+ mEnclosingLayout = new RelativeLayout(mBridgeContext);
+ setMatchParent(mEnclosingLayout);
+ parentView.addView(mEnclosingLayout);
+ } else {
+ mEnclosingLayout = parentView;
+ }
+
+ // Inflate action bar layout.
+ mDecorContent = LayoutInflater.from(context).inflate(layoutId, mEnclosingLayout, true);
+
+ }
+
+ /**
+ * Returns the Layout Resource that should be used to inflate the action bar. This layout
+ * should cover the complete screen, and have a FrameLayout included, where the content will
+ * be inflated.
+ */
+ protected abstract ResourceValue getLayoutResource(BridgeContext context);
+
+ protected void setContentRoot(FrameLayout contentRoot) {
+ mContentRoot = contentRoot;
+ }
+
+ @NonNull
+ public FrameLayout getContentRoot() {
+ return mContentRoot;
+ }
+
+ /**
+ * Returns the view inflated. This should contain both the ActionBar and the app content in it.
+ */
+ protected View getDecorContent() {
+ return mDecorContent;
+ }
+
+ /** Setup things like the title, subtitle, icon etc. */
+ protected void setupActionBar() {
+ setTitle();
+ setSutTitle();
+ setIcon();
+ setHomeAsUp(mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP);
+ }
+
+ protected abstract void setTitle(CharSequence title);
+ protected abstract void setSubtitle(CharSequence subtitle);
+ protected abstract void setIcon(String icon);
+ protected abstract void setHomeAsUp(boolean homeAsUp);
+
+ private void setTitle() {
+ RenderResources res = mBridgeContext.getRenderResources();
+
+ String title = mParams.getAppLabel();
+ ResourceValue titleValue = res.findResValue(title, false);
+ if (titleValue != null && titleValue.getValue() != null) {
+ setTitle(titleValue.getValue());
+ } else {
+ setTitle(title);
+ }
+ }
+
+ private void setSutTitle() {
+ String subTitle = mCallback.getSubTitle();
+ if (subTitle != null) {
+ setSubtitle(subTitle);
+ }
+ }
+
+ private void setIcon() {
+ String appIcon = mParams.getAppIcon();
+ if (appIcon != null) {
+ setIcon(appIcon);
+ }
+ }
+
+ public abstract void createMenuPopup();
+
+ public ActionBarCallback getCallBack() {
+ return mCallback;
+ }
+
+ protected static void setMatchParent(View view) {
+ view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT));
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
index 2ff8d37..a1c9065 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
@@ -31,7 +31,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.util.DisplayMetrics;
import android.util.TypedValue;
-import android.view.LayoutInflater;
+import android.view.InflateException;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
@@ -44,70 +44,30 @@ import android.widget.RelativeLayout;
import java.util.ArrayList;
-public class ActionBarLayout {
+/**
+ * Creates the ActionBar as done by the framework.
+ */
+public class FrameworkActionBar extends BridgeActionBar {
private static final String LAYOUT_ATTR_NAME = "windowActionBarFullscreenDecorLayout";
// The Action Bar
- @NonNull
- private CustomActionBarWrapper mActionBar;
-
- // Store another reference to the context so that we don't have to cast it repeatedly.
- @NonNull
- private final BridgeContext mBridgeContext;
-
- @NonNull
- private FrameLayout mContentRoot;
+ @NonNull private FrameworkActionBarWrapper mActionBar;
// A fake parent for measuring views.
- @Nullable
- private ViewGroup mMeasureParent;
-
- // A Layout that contains the inflated action bar. The menu popup is added to this layout.
- @NonNull
- private final RelativeLayout mEnclosingLayout;
+ @Nullable private ViewGroup mMeasureParent;
/**
* Inflate the action bar and attach it to {@code parentView}
*/
- public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params,
+ public FrameworkActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
@NonNull ViewGroup parentView) {
+ super(context, params, parentView);
- mBridgeContext = context;
-
- ResourceValue layoutName = context.getRenderResources()
- .findItemInTheme(LAYOUT_ATTR_NAME, true);
- if (layoutName != null) {
- // We may need to resolve the reference obtained.
- layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
- layoutName.isFramework());
- }
- int layoutId = 0;
- String error = null;
- if (layoutName == null) {
- error = "Unable to find action bar layout (" + LAYOUT_ATTR_NAME
- + ") in the current theme.";
- } else {
- layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
- layoutName.getName(), 0);
- if (layoutId == 0) {
- error = String.format("Unable to resolve attribute \"%s\" of type \"%s\"",
- layoutName.getName(), layoutName.getResourceType());
- }
- }
- if (layoutId == 0) {
- throw new RuntimeException(error);
- }
- // Create a RelativeLayout to hold the action bar. The layout is needed so that we may
- // add the menu popup to it.
- mEnclosingLayout = new RelativeLayout(mBridgeContext);
- setMatchParent(mEnclosingLayout);
- parentView.addView(mEnclosingLayout);
-
- // Inflate action bar layout.
- View decorContent = LayoutInflater.from(context).inflate(layoutId, mEnclosingLayout, true);
+ View decorContent = getDecorContent();
- mActionBar = CustomActionBarWrapper.getActionBarWrapper(context, params, decorContent);
+ mActionBar = FrameworkActionBarWrapper.getActionBarWrapper(context, getCallBack(),
+ decorContent);
FrameLayout contentRoot = (FrameLayout) mEnclosingLayout.findViewById(android.R.id.content);
@@ -117,27 +77,62 @@ public class ActionBarLayout {
contentRoot = new FrameLayout(context);
setMatchParent(contentRoot);
mEnclosingLayout.addView(contentRoot);
- mContentRoot = contentRoot;
+ setContentRoot(contentRoot);
} else {
- mContentRoot = contentRoot;
- mActionBar.setupActionBar();
+ setContentRoot(contentRoot);
+ setupActionBar();
mActionBar.inflateMenus();
}
}
- private void setMatchParent(View view) {
- view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.MATCH_PARENT));
+ @Override
+ protected ResourceValue getLayoutResource(BridgeContext context) {
+ ResourceValue layoutName =
+ context.getRenderResources().findItemInTheme(LAYOUT_ATTR_NAME, true);
+ if (layoutName != null) {
+ // We may need to resolve the reference obtained.
+ layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
+ layoutName.isFramework());
+ }
+ if (layoutName == null) {
+ throw new InflateException("Unable to find action bar layout (" + LAYOUT_ATTR_NAME
+ + ") in the current theme.");
+ }
+ return layoutName;
+ }
+
+ @Override
+ protected void setupActionBar() {
+ super.setupActionBar();
+ mActionBar.setupActionBar();
+ }
+
+ @Override
+ protected void setHomeAsUp(boolean homeAsUp) {
+ mActionBar.setHomeAsUp(homeAsUp);
+ }
+
+ @Override
+ protected void setTitle(CharSequence title) {
+ mActionBar.setTitle(title);
+ }
+
+ @Override
+ protected void setSubtitle(CharSequence subtitle) {
+ mActionBar.setSubTitle(subtitle);
+ }
+
+ @Override
+ protected void setIcon(String icon) {
+ mActionBar.setIcon(icon);
}
/**
* Creates a Popup and adds it to the content frame. It also adds another {@link FrameLayout} to
* the content frame which shall serve as the new content root.
*/
+ @Override
public void createMenuPopup() {
- assert mEnclosingLayout.getChildCount() == 1
- : "Action Bar Menus have already been created.";
-
if (!isOverflowPopupNeeded()) {
return;
}
@@ -193,11 +188,6 @@ public class ActionBarLayout {
return needed;
}
- @NonNull
- public FrameLayout getContentRoot() {
- return mContentRoot;
- }
-
// Copied from com.android.internal.view.menu.MenuPopHelper.measureContentWidth()
private int measureContentWidth(@NonNull ListAdapter adapter) {
// Menus don't tend to be long, so this is more sane than it looks.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
index 6db722e..44c2cd8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
@@ -19,10 +19,8 @@ package com.android.layoutlib.bridge.bars;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.ActionBarCallback;
-import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.SessionParams;
import com.android.internal.R;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
@@ -54,10 +52,9 @@ import static com.android.resources.ResourceType.MENU;
/**
* A common API to access {@link ToolbarActionBar} and {@link WindowDecorActionBar}.
*/
-public abstract class CustomActionBarWrapper {
+public abstract class FrameworkActionBarWrapper {
@NonNull protected ActionBar mActionBar;
- @NonNull protected SessionParams mParams;
@NonNull protected ActionBarCallback mCallback;
@NonNull protected BridgeContext mContext;
@@ -68,49 +65,48 @@ public abstract class CustomActionBarWrapper {
* ?attr/windowActionBarFullscreenDecorLayout
*/
@NonNull
- public static CustomActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
- @NonNull SessionParams params, @NonNull View decorContent) {
+ public static FrameworkActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
+ @NonNull ActionBarCallback callback, @NonNull View decorContent) {
View view = decorContent.findViewById(R.id.action_bar);
if (view instanceof Toolbar) {
- return new ToolbarWrapper(context, params, ((Toolbar) view));
+ return new ToolbarWrapper(context, callback, (Toolbar) view);
} else if (view instanceof ActionBarView) {
- return new WindowActionBarWrapper(context, params, decorContent,
- ((ActionBarView) view));
+ return new WindowActionBarWrapper(context, callback, decorContent,
+ (ActionBarView) view);
} else {
throw new IllegalStateException("Can't make an action bar out of " +
view.getClass().getSimpleName());
}
}
- CustomActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+ FrameworkActionBarWrapper(@NonNull BridgeContext context, ActionBarCallback callback,
@NonNull ActionBar actionBar) {
mActionBar = actionBar;
- mParams = params;
- mCallback = params.getProjectCallback().getActionBarCallback();
+ mCallback = callback;
mContext = context;
}
+ /** A call to setup any custom properties. */
protected void setupActionBar() {
- // Do the things that are common to all implementations.
- RenderResources res = mContext.getRenderResources();
+ // Nothing to do here.
+ }
- String title = mParams.getAppLabel();
- ResourceValue titleValue = res.findResValue(title, false);
- if (titleValue != null && titleValue.getValue() != null) {
- mActionBar.setTitle(titleValue.getValue());
- } else {
- mActionBar.setTitle(title);
- }
+ public void setTitle(CharSequence title) {
+ mActionBar.setTitle(title);
+ }
- String subTitle = mCallback.getSubTitle();
+ public void setSubTitle(CharSequence subTitle) {
if (subTitle != null) {
mActionBar.setSubtitle(subTitle);
}
+ }
- // Add show home as up icon.
- if (mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP) {
- mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
- }
+ public void setHomeAsUp(boolean homeAsUp) {
+ mActionBar.setDisplayHomeAsUpEnabled(homeAsUp);
+ }
+
+ public void setIcon(String icon) {
+ // Nothing to do.
}
protected boolean isSplit() {
@@ -186,15 +182,14 @@ public abstract class CustomActionBarWrapper {
* Material theme uses {@link Toolbar} as the action bar. This wrapper provides access to
* Toolbar using a common API.
*/
- private static class ToolbarWrapper extends CustomActionBarWrapper {
+ private static class ToolbarWrapper extends FrameworkActionBarWrapper {
@NonNull
private final Toolbar mToolbar; // This is the view.
- ToolbarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+ ToolbarWrapper(@NonNull BridgeContext context, @NonNull ActionBarCallback callback,
@NonNull Toolbar toolbar) {
- super(context, params, new ToolbarActionBar(toolbar, "", new WindowCallback())
- );
+ super(context, callback, new ToolbarActionBar(toolbar, "", new WindowCallback()));
mToolbar = toolbar;
}
@@ -248,19 +243,17 @@ public abstract class CustomActionBarWrapper {
* Holo theme uses {@link WindowDecorActionBar} as the action bar. This wrapper provides
* access to it using a common API.
*/
- private static class WindowActionBarWrapper extends CustomActionBarWrapper {
+ private static class WindowActionBarWrapper extends FrameworkActionBarWrapper {
- @NonNull
- private final WindowDecorActionBar mActionBar;
- @NonNull
- private final ActionBarView mActionBarView;
- @NonNull
- private final View mDecorContentRoot;
+ @NonNull private final WindowDecorActionBar mActionBar;
+ @NonNull private final ActionBarView mActionBarView;
+ @NonNull private final View mDecorContentRoot;
private MenuBuilder mMenuBuilder;
- public WindowActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
- @NonNull View decorContentRoot, @NonNull ActionBarView actionBarView) {
- super(context, params, new WindowDecorActionBar(decorContentRoot));
+ public WindowActionBarWrapper(@NonNull BridgeContext context,
+ @NonNull ActionBarCallback callback, @NonNull View decorContentRoot,
+ @NonNull ActionBarView actionBarView) {
+ super(context, callback, new WindowDecorActionBar(decorContentRoot));
mActionBarView = actionBarView;
mActionBar = ((WindowDecorActionBar) super.mActionBar);
mDecorContentRoot = decorContentRoot;
@@ -268,7 +261,6 @@ public abstract class CustomActionBarWrapper {
@Override
protected void setupActionBar() {
- super.setupActionBar();
// Set the navigation mode.
int navMode = mCallback.getNavigationMode();
@@ -278,16 +270,6 @@ public abstract class CustomActionBarWrapper {
setupTabs(3);
}
- String icon = mParams.getAppIcon();
- // If the action bar style doesn't specify an icon, set the icon obtained from the
- // session params.
- if (!mActionBar.hasIcon() && icon != null) {
- Drawable iconDrawable = getDrawable(icon, false);
- if (iconDrawable != null) {
- mActionBar.setIcon(iconDrawable);
- }
- }
-
// Set action bar to be split, if needed.
ViewGroup splitView = (ViewGroup) mDecorContentRoot.findViewById(R.id.split_action_bar);
if (splitView != null) {
@@ -300,6 +282,17 @@ public abstract class CustomActionBarWrapper {
}
@Override
+ public void setIcon(String icon) {
+ // Set the icon only if the action bar doesn't specify an icon.
+ if (!mActionBar.hasIcon() && icon != null) {
+ Drawable iconDrawable = getDrawable(icon, false);
+ if (iconDrawable != null) {
+ mActionBar.setIcon(iconDrawable);
+ }
+ }
+ }
+
+ @Override
protected void inflateMenus() {
super.inflateMenus();
// The super implementation doesn't set the menu on the view. Set it here.
@@ -340,7 +333,7 @@ public abstract class CustomActionBarWrapper {
@Override
int getMenuPopupMargin() {
- return -ActionBarLayout.getPixelValue("10dp", mContext.getMetrics());
+ return -FrameworkActionBar.getPixelValue("10dp", mContext.getMetrics());
}
// TODO: Use an adapter, like List View to set up tabs.
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 fd976af..84ee914 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
@@ -51,11 +51,13 @@ 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.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.bars.BridgeActionBar;
+import com.android.layoutlib.bridge.bars.AppCompatActionBar;
import com.android.layoutlib.bridge.bars.Config;
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.bars.ActionBarLayout;
+import com.android.layoutlib.bridge.bars.FrameworkActionBar;
import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
import com.android.resources.Density;
@@ -354,7 +356,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// if the theme says no title/action bar, then the size will be 0
if (mActionBarSize > 0) {
- ActionBarLayout actionBar = createActionBar(context, params, backgroundLayout);
+ BridgeActionBar actionBar = createActionBar(context, params, backgroundLayout);
actionBar.createMenuPopup();
mContentRoot = actionBar.getContentRoot();
} else if (mTitleBarSize > 0) {
@@ -1190,8 +1192,22 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// android.support.v7.app.ActionBarActivity, and not care about the theme name at all.
if (mIsThemeAppCompat == null) {
StyleResourceValue defaultTheme = resources.getDefaultTheme();
- StyleResourceValue val = resources.getStyle("Theme.AppCompat", false);
- mIsThemeAppCompat = defaultTheme == val || resources.themeIsParentOf(val, defaultTheme);
+ // 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++) {
+ // 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);
+ if (defaultTheme == null) {
+ break;
+ }
+ }
+ mIsThemeAppCompat = isThemeAppCompat;
}
return mIsThemeAppCompat;
}
@@ -1647,9 +1663,13 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
/**
* Creates the action bar. Also queries the project callback for missing information.
*/
- private ActionBarLayout createActionBar(BridgeContext context, SessionParams params,
+ private BridgeActionBar createActionBar(BridgeContext context, SessionParams params,
ViewGroup parentView) {
- return new ActionBarLayout(context, params, parentView);
+ if (mIsThemeAppCompat == Boolean.TRUE) {
+ return new AppCompatActionBar(context, params, parentView);
+ } else {
+ return new FrameworkActionBar(context, params, parentView);
+ }
}
public BufferedImage getImage() {