diff options
Diffstat (limited to 'tools/layoutlib/bridge/src')
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 = "-"; |
