summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge/src
diff options
context:
space:
mode:
Diffstat (limited to 'tools/layoutlib/bridge/src')
-rw-r--r--tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java30
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java5
-rw-r--r--tools/layoutlib/bridge/src/android/widget/TimePickerClockDelegate_Delegate.java (renamed from tools/layoutlib/bridge/src/android/widget/TimePickerSpinnerDelegate_Delegate.java)8
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java3
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java68
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java8
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java206
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java3
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java23
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java75
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java2
17 files changed, 406 insertions, 50 deletions
diff --git a/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java
index 8cd1a69..1e4f213 100644
--- a/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/format/DateFormat_Delegate.java
@@ -34,4 +34,9 @@ public class DateFormat_Delegate {
/*package*/ static boolean is24HourFormat(Context context) {
return false;
}
+
+ @LayoutlibDelegate
+ /*package*/ static boolean is24HourFormat(Context context, int userHandle) {
+ return false;
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 7e4ff69..fbd5e2a 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -22,9 +22,13 @@ import com.android.ide.common.rendering.api.MergeCookie;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
+import com.android.layoutlib.bridge.android.support.RecyclerViewUtil.LayoutManagerType;
import com.android.layoutlib.bridge.impl.ParserFactory;
+import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.resources.ResourceType;
import com.android.util.Pair;
@@ -111,8 +115,7 @@ public final class BridgeInflater extends LayoutInflater {
} catch (Exception e) {
// Wrap the real exception in a ClassNotFoundException, so that the calling method
// can deal with it.
- ClassNotFoundException exception = new ClassNotFoundException("onCreateView", e);
- throw exception;
+ throw new ClassNotFoundException("onCreateView", e);
}
setupViewInContext(view, attrs);
@@ -123,7 +126,7 @@ public final class BridgeInflater extends LayoutInflater {
@Override
public View createViewFromTag(View parent, String name, AttributeSet attrs,
boolean inheritContext) {
- View view = null;
+ View view;
try {
view = super.createViewFromTag(parent, name, attrs, inheritContext);
} catch (InflateException e) {
@@ -134,7 +137,7 @@ public final class BridgeInflater extends LayoutInflater {
// Wrap the real exception in an InflateException so that the calling
// method can deal with it.
InflateException exception = new InflateException();
- if (e2.getClass().equals(ClassNotFoundException.class) == false) {
+ if (!e2.getClass().equals(ClassNotFoundException.class)) {
exception.initCause(e2);
} else {
exception.initCause(e);
@@ -184,7 +187,7 @@ public final class BridgeInflater extends LayoutInflater {
return inflate(bridgeParser, root);
} catch (Exception e) {
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- "Failed to parse file " + f.getAbsolutePath(), e, null /*data*/);
+ "Failed to parse file " + f.getAbsolutePath(), e, null);
return null;
}
@@ -194,8 +197,7 @@ public final class BridgeInflater extends LayoutInflater {
return null;
}
- private View loadCustomView(String name, AttributeSet attrs) throws ClassNotFoundException,
- Exception{
+ private View loadCustomView(String name, AttributeSet attrs) throws Exception {
if (mProjectCallback != null) {
// first get the classname in case it's not the node name
if (name.equals("view")) {
@@ -227,6 +229,20 @@ public final class BridgeInflater extends LayoutInflater {
if (viewKey != null) {
bc.addViewKey(view, viewKey);
}
+ if (RenderSessionImpl.isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
+ String type = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES,
+ BridgeConstants.ATTR_LAYOUT_MANAGER_TYPE);
+ if (type != null) {
+ LayoutManagerType layoutManagerType = LayoutManagerType.getByDisplayName(type);
+ if (layoutManagerType == null) {
+ Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED,
+ "LayoutManager (" + type + ") not found, falling back to " +
+ "LinearLayoutManager", null);
+ } else {
+ bc.addCookie(view, layoutManagerType);
+ }
+ }
+ }
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index c403ce6..5176419 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -228,6 +228,11 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void overridePendingAppTransitionInPlace(String packageName, int anim) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
diff --git a/tools/layoutlib/bridge/src/android/widget/TimePickerSpinnerDelegate_Delegate.java b/tools/layoutlib/bridge/src/android/widget/TimePickerClockDelegate_Delegate.java
index c9d35b9..1bd9830 100644
--- a/tools/layoutlib/bridge/src/android/widget/TimePickerSpinnerDelegate_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/widget/TimePickerClockDelegate_Delegate.java
@@ -21,16 +21,16 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.view.KeyEvent;
/**
- * Delegate used to provide new implementation of few methods in {@link TimePickerSpinnerDelegate}.
+ * Delegate used to provide new implementation of few methods in {@link TimePickerClockDelegate}.
*/
-public class TimePickerSpinnerDelegate_Delegate {
+public class TimePickerClockDelegate_Delegate {
- // Copied from TimePickerSpinnerDelegate.
+ // Copied from TimePickerClockDelegate.
private static final int AM = 0;
private static final int PM = 1;
@LayoutlibDelegate
- static int getAmOrPmKeyCode(TimePickerSpinnerDelegate tpsd, int amOrPm) {
+ static int getAmOrPmKeyCode(TimePickerClockDelegate tpcd, int amOrPm) {
// We don't care about locales here.
if (amOrPm == AM) {
return KeyEvent.KEYCODE_A;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index eb9e7f1..fdb4567 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -48,4 +48,7 @@ public class BridgeConstants {
public final static String MATCH_PARENT = "match_parent";
public final static String FILL_PARENT = "fill_parent";
public final static String WRAP_CONTENT = "wrap_content";
+
+ /** Attribute in the tools namespace used to specify layout manager for RecyclerView. */
+ public static final String ATTR_LAYOUT_MANAGER_TYPE = "layoutManagerType";
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index 89288bf..e4cbb2f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -90,7 +90,7 @@ public final class BridgeContentProvider implements IContentProvider {
@Override
public ParcelFileDescriptor openFile(
- String callingPackage, Uri arg0, String arg1, ICancellationSignal signal)
+ String callingPackage, Uri arg0, String arg1, ICancellationSignal signal, IBinder token)
throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
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 7c86f75..aa4b560 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
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.android;
+import android.os.IBinder;
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.AssetRepository;
import com.android.ide.common.rendering.api.ILayoutPullParser;
@@ -93,6 +94,7 @@ import java.util.Map;
/**
* Custom implementation of Context/Activity to handle non compiled resources.
*/
+@SuppressWarnings("deprecation") // For use of Pair.
public final class BridgeContext extends Context {
/** The map adds cookies to each view so that IDE can link xml tags to views. */
@@ -568,7 +570,7 @@ public final class BridgeContext extends Context {
// Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
if (set instanceof BridgeXmlBlockParser) {
- BridgeXmlBlockParser parser = null;
+ BridgeXmlBlockParser parser;
parser = (BridgeXmlBlockParser)set;
isPlatformFile = parser.isPlatformFile();
@@ -589,7 +591,7 @@ public final class BridgeContext extends Context {
} else if (set != null) { // null parser is ok
// really this should not be happening since its instantiated in Bridge
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Parser is not a BridgeXmlBlockParser!", null /*data*/);
+ "Parser is not a BridgeXmlBlockParser!", null);
return null;
}
@@ -601,7 +603,7 @@ public final class BridgeContext extends Context {
// look for a custom style.
String customStyle = null;
if (set != null) {
- customStyle = set.getAttributeValue(null /* namespace*/, "style");
+ customStyle = set.getAttributeValue(null, "style");
}
StyleResourceValue customStyleValues = null;
@@ -624,31 +626,39 @@ public final class BridgeContext extends Context {
// get the name from the int.
Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr);
- if (defaultPropMap != null) {
- String defStyleName = defStyleAttribute.getFirst();
- if (defStyleAttribute.getSecond()) {
- defStyleName = "android:" + defStyleName;
+ if (defStyleAttribute == null) {
+ // This should be rare. Happens trying to map R.style.foo to @style/foo fails.
+ // This will happen if the user explicitly used a non existing int value for
+ // defStyleAttr or there's something wrong with the project structure/build.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
+ "Failed to find the style corresponding to the id " + defStyleAttr, null);
+ } else {
+ if (defaultPropMap != null) {
+ String defStyleName = defStyleAttribute.getFirst();
+ if (defStyleAttribute.getSecond()) {
+ defStyleName = "android:" + defStyleName;
+ }
+ defaultPropMap.put("style", defStyleName);
}
- defaultPropMap.put("style", defStyleName);
- }
- // look for the style in the current theme, and its parent:
- ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(),
- defStyleAttribute.getSecond());
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(),
+ defStyleAttribute.getSecond());
- if (item != null) {
- // item is a reference to a style entry. Search for it.
- item = mRenderResources.findResValue(item.getValue(), item.isFramework());
+ if (item != null) {
+ // item is a reference to a style entry. Search for it.
+ item = mRenderResources.findResValue(item.getValue(), item.isFramework());
- if (item instanceof StyleResourceValue) {
- defStyleValues = (StyleResourceValue)item;
+ if (item instanceof StyleResourceValue) {
+ defStyleValues = (StyleResourceValue) item;
+ }
+ } else {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
+ String.format(
+ "Failed to find style '%s' in current theme",
+ defStyleAttribute.getFirst()),
+ null);
}
- } else {
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
- String.format(
- "Failed to find style '%s' in current theme",
- defStyleAttribute.getFirst()),
- null /*data*/);
}
} else if (defStyleRes != 0) {
boolean isFrameworkRes = true;
@@ -963,12 +973,24 @@ public final class BridgeContext extends Context {
}
@Override
+ public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) {
+ // pass
+ return 0;
+ }
+
+ @Override
public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
// pass
return 0;
}
@Override
+ public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3, IBinder arg4) {
+ // pass
+ return 0;
+ }
+
+ @Override
public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
int arg4, int arg5) {
// pass
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 05a6fd6..39ebdfc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -116,11 +116,6 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
- public void setMaximumScreenOffTimeoutFromDeviceAdmin(int arg0) throws RemoteException {
- // pass for now.
- }
-
- @Override
public void setStayOnSetting(int arg0) throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 997b199..4c4454d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -95,6 +95,10 @@ public final class BridgeWindow implements IWindow {
}
@Override
+ public void dispatchWindowShown() {
+ }
+
+ @Override
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 0ed6ab1..0f51d00 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -38,7 +38,7 @@ import android.view.WindowManager.LayoutParams;
public final class BridgeWindowSession implements IWindowSession {
@Override
- public int add(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3,
+ public int add(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3, Rect arg4,
InputChannel outInputchannel)
throws RemoteException {
// pass for now.
@@ -47,7 +47,7 @@ public final class BridgeWindowSession implements IWindowSession {
@Override
public int addToDisplay(IWindow arg0, int seq, LayoutParams arg1, int arg2, int displayId,
- Rect arg3, InputChannel outInputchannel)
+ Rect arg3, Rect arg4, InputChannel outInputchannel)
throws RemoteException {
// pass for now.
return 0;
@@ -55,7 +55,7 @@ public final class BridgeWindowSession implements IWindowSession {
@Override
public int addWithoutInputChannel(IWindow arg0, int seq, LayoutParams arg1, int arg2,
- Rect arg3)
+ Rect arg3, Rect arg4)
throws RemoteException {
// pass for now.
return 0;
@@ -63,7 +63,7 @@ public final class BridgeWindowSession implements IWindowSession {
@Override
public int addToDisplayWithoutInputChannel(IWindow arg0, int seq, LayoutParams arg1, int arg2,
- int displayId, Rect arg3)
+ int displayId, Rect arg3, Rect arg4)
throws RemoteException {
// pass for now.
return 0;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
index e00ea6a..22b5192 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
@@ -29,6 +29,8 @@ public final class SessionParamsFlags {
public static final SessionParams.Key<String> FLAG_KEY_ROOT_TAG =
new SessionParams.Key<String>("rootTag", String.class);
+ public static final SessionParams.Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT =
+ new SessionParams.Key<Boolean>("recyclerViewSupport", Boolean.class);
// Disallow instances.
private SessionParamsFlags() {}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
new file mode 100644
index 0000000..2feab7a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -0,0 +1,206 @@
+/*
+ * 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.android.support;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.SessionParamsFlags;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+import static com.android.layoutlib.bridge.util.ReflectionUtils.*;
+
+/**
+ * Utility class for working with android.support.v7.widget.RecyclerView
+ */
+@SuppressWarnings("SpellCheckingInspection") // for "recycler".
+public class RecyclerViewUtil {
+
+ /**
+ * Used by {@link LayoutManagerType}.
+ * <p/>
+ * Not declared inside the enum, since it needs to be accessible in the constructor.
+ */
+ private static final Object CONTEXT = new Object();
+
+ public static final String CN_RECYCLER_VIEW = "android.support.v7.widget.RecyclerView";
+ private static final String CN_LAYOUT_MANAGER = CN_RECYCLER_VIEW + "$LayoutManager";
+ private static final String CN_ADAPTER = CN_RECYCLER_VIEW + "$Adapter";
+
+ /**
+ * Tries to create an Adapter ({@code android.support.v7.widget.RecyclerView.Adapter} and a
+ * LayoutManager {@code RecyclerView.LayoutManager} and assign these to the {@code RecyclerView}
+ * that is passed.
+ * <p/>
+ * Any exceptions thrown during the process are logged in {@link Bridge#getLog()}
+ */
+ public static void setAdapter(@NonNull View recyclerView, @NonNull BridgeContext context,
+ @NonNull SessionParams params) {
+ try {
+ setLayoutManager(recyclerView, context, params.getProjectCallback());
+ Object adapter = createAdapter(params);
+ setProperty(recyclerView, CN_ADAPTER, adapter, "setAdapter");
+ } catch (ReflectionException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Error occured while trying to setup RecyclerView.", e, null);
+ }
+ }
+
+ private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context,
+ @NonNull IProjectCallback callback) throws ReflectionException {
+ Object cookie = context.getCookie(recyclerView);
+ assert cookie == null || cookie instanceof LayoutManagerType;
+ if (cookie == null) {
+ cookie = LayoutManagerType.getDefault();
+ }
+ Object layoutManager = createLayoutManager((LayoutManagerType) cookie, context, callback);
+ setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager");
+ }
+
+ @Nullable
+ private static Object createLayoutManager(@Nullable LayoutManagerType type,
+ @NonNull Context context, @NonNull IProjectCallback callback)
+ throws ReflectionException {
+ if (type == null) {
+ type = LayoutManagerType.getDefault();
+ }
+ try {
+ return callback.loadView(type.getClassName(), type.getSignature(), type.getArgs(context));
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ @Nullable
+ private static Object createAdapter(@NonNull SessionParams params) throws ReflectionException {
+ Boolean ideSupport = params.getFlag(SessionParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT);
+ if (ideSupport != Boolean.TRUE) {
+ return null;
+ }
+ try {
+ return params.getProjectCallback().loadView(CN_ADAPTER, new Class[0], new Object[0]);
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ private static void setProperty(@NonNull View recyclerView, @NonNull String propertyClassName,
+ @Nullable Object propertyValue, @NonNull String propertySetter)
+ throws ReflectionException {
+ if (propertyValue != null) {
+ Class<?> layoutManagerClass = getClassInstance(propertyValue, propertyClassName);
+ Method setLayoutManager = getMethod(recyclerView.getClass(),
+ propertySetter, layoutManagerClass);
+ if (setLayoutManager != null) {
+ invoke(setLayoutManager, recyclerView, propertyValue);
+ }
+ }
+ }
+
+ /**
+ * Looks through the class hierarchy of {@code object} at runtime and returns the class matching
+ * the name {@code className}.
+ * <p/>
+ * This is used when we cannot use Class.forName() since the class we want was loaded from a
+ * different ClassLoader.
+ */
+ @NonNull
+ private static Class<?> getClassInstance(@NonNull Object object, @NonNull String className) {
+ Class<?> superClass = object.getClass();
+ while (superClass != null) {
+ if (className.equals(superClass.getName())) {
+ return superClass;
+ }
+ superClass = superClass.getSuperclass();
+ }
+ throw new RuntimeException("invalid object/classname combination.");
+ }
+
+ /** Supported LayoutManagers. */
+ public enum LayoutManagerType {
+ LINEAR_LAYOUT_MANGER("Linear",
+ "android.support.v7.widget.LinearLayoutManager",
+ new Class[]{Context.class}, new Object[]{CONTEXT}),
+ GRID_LAYOUT_MANAGER("Grid",
+ "android.support.v7.widget.GridLayoutManager",
+ new Class[]{Context.class, int.class}, new Object[]{CONTEXT, 2}),
+ STAGGERED_GRID_LAYOUT_MANAGER("StaggeredGrid",
+ "android.support.v7.widget.StaggeredGridLayoutManager",
+ new Class[]{int.class, int.class}, new Object[]{2, LinearLayout.VERTICAL});
+
+ private String mDisplayName;
+ private String mClassName;
+ private Class[] mSignature;
+ private Object[] mArgs;
+
+ private static final HashMap<String, LayoutManagerType> sDisplayNameLookup =
+ new HashMap<String, LayoutManagerType>();
+
+ static {
+ for (LayoutManagerType type : LayoutManagerType.values()) {
+ sDisplayNameLookup.put(type.mDisplayName, type);
+ }
+ }
+
+ LayoutManagerType(String displayName, String className, Class[] signature, Object[] args) {
+ mDisplayName = displayName;
+ mClassName = className;
+ mSignature = signature;
+ mArgs = args;
+ }
+
+ String getClassName() {
+ return mClassName;
+ }
+
+ Class[] getSignature() {
+ return mSignature;
+ }
+
+ @NonNull
+ Object[] getArgs(Context context) {
+ Object[] args = new Object[mArgs.length];
+ System.arraycopy(mArgs, 0, args, 0, mArgs.length);
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] == CONTEXT) {
+ args[i] = context;
+ }
+ }
+ return args;
+ }
+
+ @NonNull
+ public static LayoutManagerType getDefault() {
+ return LINEAR_LAYOUT_MANGER;
+ }
+
+ @Nullable
+ public static LayoutManagerType getByDisplayName(@Nullable String className) {
+ return sDisplayNameLookup.get(className);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index 82a5130..dde041b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -73,7 +73,7 @@ public class Config {
public static String getTime(int platformVersion) {
if (platformVersion == 0) {
- return "5:00";
+ return "5:10";
}
if (platformVersion < GINGERBREAD) {
return "2:20";
@@ -87,9 +87,12 @@ public class Config {
if (platformVersion < KITKAT) {
return "4:30";
}
- if (platformVersion <= KITKAT_WATCH) {
+ if (platformVersion < LOLLIPOP) {
return "4:40";
}
+ if (platformVersion < LOLLIPOP_MR1) {
+ return "5:00";
+ }
// Should never happen.
return "4:04";
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 669e6b5..6513c5f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -16,8 +16,6 @@
package com.android.layoutlib.bridge.impl;
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
-
import com.android.ide.common.rendering.api.DrawableParams;
import com.android.ide.common.rendering.api.HardwareConfig;
import com.android.ide.common.rendering.api.ResourceValue;
@@ -38,7 +36,6 @@ import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
-import java.io.IOException;
/**
* Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
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 58acab9..b6b63b1 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
@@ -23,6 +23,8 @@ import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.HardwareConfig;
import com.android.ide.common.rendering.api.IAnimationListener;
@@ -51,6 +53,7 @@ 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.android.support.RecyclerViewUtil;
import com.android.layoutlib.bridge.bars.BridgeActionBar;
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
import com.android.layoutlib.bridge.bars.Config;
@@ -1327,6 +1330,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
}
}
+ } else if (isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
+ RecyclerViewUtil.setAdapter(view, getContext(), getParams());
} else if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
@@ -1338,6 +1343,22 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
/**
+ * Check if the object is an instance of a class named {@code className}. This doesn't work
+ * for interfaces.
+ */
+ public static boolean isInstanceOf(Object object, String className) {
+ Class superClass = object.getClass();
+ while (superClass != null) {
+ String name = superClass.getName();
+ if (name.equals(className)) {
+ return true;
+ }
+ superClass = superClass.getSuperclass();
+ }
+ return false;
+ }
+
+ /**
* Sets up a {@link TabHost} object.
* @param tabHost the TabHost to setup.
* @param projectCallback The project callback object to access the project R class.
@@ -1494,6 +1515,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
* index 1 is with the offset.
*/
+ @NonNull
private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
ViewInfo[] result = new ViewInfo[2];
if (view == null) {
@@ -1589,6 +1611,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* The cookie for menu items are stored in menu item and not in the map from View stored in
* BridgeContext.
*/
+ @Nullable
private Object getViewKey(View view) {
BridgeContext context = getContext();
if (!(view instanceof MenuView.ItemView)) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
new file mode 100644
index 0000000..8e61edf
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
@@ -0,0 +1,75 @@
+/*
+ * 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.util;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Utility to convert checked Reflection exceptions to unchecked exceptions.
+ */
+public class ReflectionUtils {
+
+ @Nullable
+ public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name,
+ @Nullable Class<?>... params) throws ReflectionException {
+ try {
+ return clazz.getMethod(name, params);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ @Nullable
+ public static Object invoke(@NonNull Method method, @Nullable Object object,
+ @Nullable Object... args) throws ReflectionException {
+ Exception ex;
+ try {
+ return method.invoke(object, args);
+ } catch (IllegalAccessException e) {
+ ex = e;
+ } catch (InvocationTargetException e) {
+ ex = e;
+ }
+ throw new ReflectionException(ex);
+ }
+
+ /**
+ * Wraps all reflection related exceptions. Created since ReflectiveOperationException was
+ * introduced in 1.7 and we are still on 1.6
+ */
+ public static class ReflectionException extends Exception {
+ public ReflectionException() {
+ super();
+ }
+
+ public ReflectionException(String message) {
+ super(message);
+ }
+
+ public ReflectionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ReflectionException(Throwable cause) {
+ super(cause);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 8898856..b8b5fed 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -223,7 +223,7 @@ public class ICU_Delegate {
result.decimalSeparator = '.';
result.groupingSeparator = ',';
result.patternSeparator = ' ';
- result.percent = '%';
+ result.percent = "%";
result.perMill = '\u2030';
result.monetarySeparator = ' ';
result.minusSign = "-";