diff options
Diffstat (limited to 'layoutlib_utils')
9 files changed, 494 insertions, 4 deletions
diff --git a/layoutlib_utils/src/com/android/ide/common/layoutlib/BasicLayoutScene.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/BasicLayoutScene.java new file mode 100644 index 0000000..dfb3992 --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/BasicLayoutScene.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 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.ide.common.layoutlib; + +import com.android.layoutlib.api.LayoutScene; +import com.android.layoutlib.api.SceneResult; +import com.android.layoutlib.api.ViewInfo; + +import java.awt.image.BufferedImage; + +/** + * Basic LayoutScene returning a given {@link SceneResult}, {@link ViewInfo} and + * {@link BufferedImage}. + * <p/> + * All other methods are untouched from the base implementation provided by the API. + * + */ +public class BasicLayoutScene extends LayoutScene { + + private final SceneResult mResult; + private final ViewInfo mRootViewInfo; + private final BufferedImage mImage; + + public BasicLayoutScene(SceneResult result, ViewInfo rootViewInfo, BufferedImage image) { + mResult = result; + mRootViewInfo = rootViewInfo; + mImage = image; + } + + @Override + public SceneResult getResult() { + return mResult; + } + + @Override + public ViewInfo getRootView() { + return mRootViewInfo; + } + + @Override + public BufferedImage getImage() { + return mImage; + } +} diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/DensityBasedResourceValue.java index 59de463..e1c0caa 100644 --- a/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/DensityBasedResourceValue.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.layoutlib.utils; +package com.android.ide.common.layoutlib; import com.android.layoutlib.api.IDensityBasedResourceValue; diff --git a/layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutBridgeWrapper.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutBridgeWrapper.java new file mode 100644 index 0000000..f4c99bd --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutBridgeWrapper.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2010 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.ide.common.layoutlib; + +import com.android.layoutlib.api.ILayoutBridge; +import com.android.layoutlib.api.ILayoutResult; +import com.android.layoutlib.api.LayoutBridge; +import com.android.layoutlib.api.LayoutScene; +import com.android.layoutlib.api.SceneParams; +import com.android.layoutlib.api.SceneResult; +import com.android.layoutlib.api.ViewInfo; +import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Map; + +/** + * {@link LayoutBridge} wrapper around a {@link ILayoutBridge}. + * <p/> + * The goal is to let tools only uses the latest API by providing a conversion interface + * between the really old API ({@link ILayoutBridge}) and the new one ({@link ILayoutBridge}). + * + */ +@SuppressWarnings("deprecation") +class LayoutBridgeWrapper extends LayoutBridge { + + private final ILayoutBridge mBridge; + private final ClassLoader mClassLoader; + + LayoutBridgeWrapper(ILayoutBridge bridge, ClassLoader classLoader) { + mBridge = bridge; + mClassLoader = classLoader; + } + + @Override + public int getApiLevel() { + int apiLevel = 1; + try { + apiLevel = mBridge.getApiLevel(); + } catch (AbstractMethodError e) { + // the first version of the api did not have this method + // so this is 1 + } + + return apiLevel; + } + + @Override + public boolean init(String fontOsLocation, Map<String, Map<String, Integer>> enumValueMap) { + return mBridge.init(fontOsLocation, enumValueMap); + } + + @Override + public boolean dispose() { + // there's no dispose in ILayoutBridge + return true; + } + + + @Override + public LayoutScene createScene(SceneParams params) { + int apiLevel = mBridge.getApiLevel(); + + ILayoutResult result = null; + + if (apiLevel == 4) { + // Final ILayoutBridge API added support for "render full height" + result = mBridge.computeLayout( + params.getLayoutDescription(), params.getProjectKey(), + params.getScreenWidth(), params.getScreenHeight(), params.getRenderFullSize(), + params.getDensity(), params.getXdpi(), params.getYdpi(), + params.getThemeName(), params.getIsProjectTheme(), + params.getProjectResources(), params.getFrameworkResources(), + params.getProjectCallback(), params.getLogger()); + } else if (apiLevel == 3) { + // api 3 add density support. + result = mBridge.computeLayout( + params.getLayoutDescription(), params.getProjectKey(), + params.getScreenWidth(), params.getScreenHeight(), + params.getDensity(), params.getXdpi(), params.getYdpi(), + params.getThemeName(), params.getIsProjectTheme(), + params.getProjectResources(), params.getFrameworkResources(), + params.getProjectCallback(), params.getLogger()); + } else if (apiLevel == 2) { + // api 2 added boolean for separation of project/framework theme + result = mBridge.computeLayout( + params.getLayoutDescription(), params.getProjectKey(), + params.getScreenWidth(), params.getScreenHeight(), + params.getThemeName(), params.getIsProjectTheme(), + params.getProjectResources(), params.getFrameworkResources(), + params.getProjectCallback(), params.getLogger()); + } else { + // First api with no density/dpi, and project theme boolean mixed + // into the theme name. + + // change the string if it's a custom theme to make sure we can + // differentiate them + String themeName = params.getThemeName(); + if (params.getIsProjectTheme()) { + themeName = "*" + themeName; //$NON-NLS-1$ + } + + result = mBridge.computeLayout( + params.getLayoutDescription(), params.getProjectKey(), + params.getScreenWidth(), params.getScreenHeight(), + themeName, + params.getProjectResources(), params.getFrameworkResources(), + params.getProjectCallback(), params.getLogger()); + } + + // clean up that is not done by the ILayoutBridge itself + cleanUp(); + + return convertToScene(result); + } + + + @Override + public void clearCaches(Object projectKey) { + mBridge.clearCaches(projectKey); + } + + /** + * Converts a {@link ILayoutResult} to a {@link LayoutScene}. + */ + private LayoutScene convertToScene(ILayoutResult result) { + + SceneResult sceneResult; + ViewInfo rootViewInfo; + + if (result.getSuccess() == ILayoutResult.SUCCESS) { + sceneResult = SceneResult.SUCCESS; + rootViewInfo = convertToViewInfo(result.getRootView()); + } else { + sceneResult = new SceneResult(result.getErrorMessage()); + rootViewInfo = null; + } + + // create a BasicLayoutScene. This will return the given values but return the default + // implementation for all method. + // ADT should gracefully handle the default implementations of LayoutScene + return new BasicLayoutScene(sceneResult, rootViewInfo, result.getImage()); + } + + /** + * Converts a {@link ILayoutViewInfo} (and its children) to a {@link ViewInfo}. + */ + private ViewInfo convertToViewInfo(ILayoutViewInfo view) { + // create the view info. + ViewInfo viewInfo = new ViewInfo(view.getName(), view.getViewKey(), + view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); + + // then convert the children + ILayoutViewInfo[] children = view.getChildren(); + if (children != null) { + ArrayList<ViewInfo> convertedChildren = new ArrayList<ViewInfo>(children.length); + for (ILayoutViewInfo child : children) { + convertedChildren.add(convertToViewInfo(child)); + } + viewInfo.setChildren(convertedChildren); + } + + return viewInfo; + } + + /** + * Post rendering clean-up that must be done here because it's not done in any layoutlib using + * {@link ILayoutBridge}. + */ + private void cleanUp() { + try { + Class<?> looperClass = mClassLoader.loadClass("android.os.Looper"); //$NON-NLS-1$ + Field threadLocalField = looperClass.getField("sThreadLocal"); //$NON-NLS-1$ + if (threadLocalField != null) { + threadLocalField.setAccessible(true); + // get object. Field is static so no need to pass an object + ThreadLocal<?> threadLocal = (ThreadLocal<?>) threadLocalField.get(null); + if (threadLocal != null) { + threadLocal.remove(); + } + } + } catch (Exception e) { + // do nothing. + } + } +} diff --git a/layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutLibrary.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutLibrary.java new file mode 100644 index 0000000..5ec7ae5 --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutLibrary.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2010 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.ide.common.layoutlib; + +import com.android.ide.common.log.ILogger; +import com.android.ide.common.sdk.LoadStatus; +import com.android.layoutlib.api.ILayoutBridge; +import com.android.layoutlib.api.LayoutBridge; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Class representing and allowing to load the layoutlib jar file. + */ +@SuppressWarnings("deprecation") +public class LayoutLibrary { + + public final static String CLASS_BRIDGE = "com.android.layoutlib.bridge.Bridge"; //$NON-NLS-1$ + + /** Link to the layout bridge */ + private final LayoutBridge mBridge; + /** Status of the layoutlib.jar loading */ + private final LoadStatus mStatus; + /** classloader used to load the jar file */ + private final ClassLoader mClassLoader; + + /** + * Returns the loaded {@link LayoutBridge} object or null if the loading failed. + */ + public LayoutBridge getBridge() { + return mBridge; + } + + /** + * Returns the {@link LoadStatus} of the loading of the layoutlib jar file. + */ + public LoadStatus getStatus() { + return mStatus; + } + + /** + * Returns the classloader used to load the classes in the layoutlib jar file. + */ + public ClassLoader getClassLoader() { + return mClassLoader; + } + + /** + * Loads the layoutlib.jar file located at the given path and returns a {@link LayoutLibrary} + * object representing the result. + * <p/> + * If loading failed {@link #getStatus()} will reflect this, and {@link #getBridge()} will + * return null. + * + * @param layoutLibJarOsPath the path of the jar file + * @param log an optional log file. + * @return a {@link LayoutLibrary} object always. + */ + public static LayoutLibrary load(String layoutLibJarOsPath, ILogger log) { + + LoadStatus status = LoadStatus.LOADING; + LayoutBridge bridge = null; + ClassLoader classLoader = null; + + try { + // get the URL for the file. + File f = new File(layoutLibJarOsPath); + if (f.isFile() == false) { + if (log != null) { + log.error(null, "layoutlib.jar is missing!"); //$NON-NLS-1$ + } + } else { + URI uri = f.toURI(); + URL url = uri.toURL(); + + // create a class loader. Because this jar reference interfaces + // that are in the editors plugin, it's important to provide + // a parent class loader. + classLoader = new URLClassLoader( + new URL[] { url }, + LayoutLibrary.class.getClassLoader()); + + // load the class + Class<?> clazz = classLoader.loadClass(CLASS_BRIDGE); + if (clazz != null) { + // instantiate an object of the class. + Constructor<?> constructor = clazz.getConstructor(); + if (constructor != null) { + Object bridgeObject = constructor.newInstance(); + if (bridgeObject instanceof LayoutBridge) { + bridge = (LayoutBridge)bridgeObject; + } else if (bridgeObject instanceof ILayoutBridge) { + bridge = new LayoutBridgeWrapper((ILayoutBridge) bridgeObject, + classLoader); + } + } + } + + if (bridge == null) { + status = LoadStatus.FAILED; + if (log != null) { + log.error(null, "Failed to load " + CLASS_BRIDGE); //$NON-NLS-1$ + } + } else { + // mark the lib as loaded. + status = LoadStatus.LOADED; + } + } + } catch (Throwable t) { + status = LoadStatus.FAILED; + // log the error. + if (log != null) { + log.error(t, "Failed to load the LayoutLib"); + } + } + + return new LayoutLibrary(bridge, classLoader, status); + } + + private LayoutLibrary(LayoutBridge bridge, ClassLoader classLoader, LoadStatus status) { + mBridge = bridge; + mClassLoader = classLoader; + mStatus = status; + } +} diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/ResourceValue.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/ResourceValue.java index 98b4de6..382d961 100644 --- a/layoutlib_utils/src/com/android/layoutlib/utils/ResourceValue.java +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/ResourceValue.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.layoutlib.utils; +package com.android.ide.common.layoutlib; import com.android.layoutlib.api.IResourceValue; diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/StyleResourceValue.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/StyleResourceValue.java index a32ac1b..721b16c 100644 --- a/layoutlib_utils/src/com/android/layoutlib/utils/StyleResourceValue.java +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/StyleResourceValue.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.layoutlib.utils; +package com.android.ide.common.layoutlib; import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.api.IStyleResourceValue; diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/ValueResourceParser.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java index 4682d90..c784f1f 100644 --- a/layoutlib_utils/src/com/android/layoutlib/utils/ValueResourceParser.java +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.layoutlib.utils; +package com.android.ide.common.layoutlib; import org.xml.sax.Attributes; import org.xml.sax.SAXException; diff --git a/layoutlib_utils/src/com/android/ide/common/log/ILogger.java b/layoutlib_utils/src/com/android/ide/common/log/ILogger.java new file mode 100644 index 0000000..1ad602e --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/log/ILogger.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 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.ide.common.log; + +import java.util.Formatter; + +public interface ILogger { + + /** + * Prints a warning message on stdout. + * <p/> + * The message will be tagged with "Warning" on the output so the caller does not + * need to put such a prefix in the format string. + * <p/> + * Implementations should only display warnings in verbose mode. + * + * @param warningFormat is an optional error format. If non-null, it will be printed + * using a {@link Formatter} with the provided arguments. + * @param args provides the arguments for warningFormat. + */ + void warning(String warningFormat, Object... args); + + /** + * Prints an error message on stderr. + * <p/> + * The message will be tagged with "Error" on the output so the caller does not + * need to put such a prefix in the format string. + * <p/> + * Implementation should always display errors, independent of verbose mode. + * + * @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's + * message will be printed out. + * @param errorFormat is an optional error format. If non-null, it will be printed + * using a {@link Formatter} with the provided arguments. + * @param args provides the arguments for errorFormat. + */ + void error(Throwable t, String errorFormat, Object... args); + + /** + * Prints a message as-is on stdout. + * <p/> + * Implementation should always display errors, independent of verbose mode. + * No prefix is used, the message is printed as-is after formatting. + * + * @param msgFormat is an optional error format. If non-null, it will be printed + * using a {@link Formatter} with the provided arguments. + * @param args provides the arguments for msgFormat. + */ + void printf(String msgFormat, Object... args); +} diff --git a/layoutlib_utils/src/com/android/ide/common/sdk/LoadStatus.java b/layoutlib_utils/src/com/android/ide/common/sdk/LoadStatus.java new file mode 100644 index 0000000..babbd63 --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/sdk/LoadStatus.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2010 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.ide.common.sdk; + +/** + * Enum for loading status of various SDK parts. + */ +public enum LoadStatus { + LOADING, LOADED, FAILED; +} |