From f29be828de51dbe2f55508cd620142e35cd19cbd Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Wed, 10 Nov 2010 16:18:58 -0800 Subject: Make ADT use the new layoutlib API. ADT now exclusively use the new API. The older platforms that still use the old API are accessed through a compatibility layer provided by the class LayoutBridgeWrapper that converts the old to the new API (both input and output). The wrapper and the loading code for the bridge have moved to layoutlib_utils, but into the ide.common package. Layoutlib_utils is to be renamed ide-common later. .sdk.LoadStatus has moved into .ide.common too since it's used by the bridge loading code. As we'll move more code into ide-common it's ok to have it there anyway. Also did some minor fix to the API: - missing implementation of ViewInfo - Made a singleton for SUCCESS state of SceneResult. Change-Id: I5e7130ca03b92ad71dc9c293b2ffc40566df645c --- .../ide/common/layoutlib/BasicLayoutScene.java | 58 ++++++ .../layoutlib/DensityBasedResourceValue.java | 34 +++ .../ide/common/layoutlib/LayoutBridgeWrapper.java | 201 ++++++++++++++++++ .../ide/common/layoutlib/LayoutLibrary.java | 143 +++++++++++++ .../ide/common/layoutlib/ResourceValue.java | 63 ++++++ .../ide/common/layoutlib/StyleResourceValue.java | 60 ++++++ .../ide/common/layoutlib/ValueResourceParser.java | 227 +++++++++++++++++++++ .../src/com/android/ide/common/log/ILogger.java | 64 ++++++ .../src/com/android/ide/common/sdk/LoadStatus.java | 24 +++ .../layoutlib/utils/DensityBasedResourceValue.java | 34 --- .../com/android/layoutlib/utils/ResourceValue.java | 63 ------ .../layoutlib/utils/StyleResourceValue.java | 60 ------ .../layoutlib/utils/ValueResourceParser.java | 227 --------------------- 13 files changed, 874 insertions(+), 384 deletions(-) create mode 100644 layoutlib_utils/src/com/android/ide/common/layoutlib/BasicLayoutScene.java create mode 100644 layoutlib_utils/src/com/android/ide/common/layoutlib/DensityBasedResourceValue.java create mode 100644 layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutBridgeWrapper.java create mode 100644 layoutlib_utils/src/com/android/ide/common/layoutlib/LayoutLibrary.java create mode 100644 layoutlib_utils/src/com/android/ide/common/layoutlib/ResourceValue.java create mode 100644 layoutlib_utils/src/com/android/ide/common/layoutlib/StyleResourceValue.java create mode 100644 layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java create mode 100644 layoutlib_utils/src/com/android/ide/common/log/ILogger.java create mode 100644 layoutlib_utils/src/com/android/ide/common/sdk/LoadStatus.java delete mode 100644 layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java delete mode 100644 layoutlib_utils/src/com/android/layoutlib/utils/ResourceValue.java delete mode 100644 layoutlib_utils/src/com/android/layoutlib/utils/StyleResourceValue.java delete mode 100644 layoutlib_utils/src/com/android/layoutlib/utils/ValueResourceParser.java (limited to 'layoutlib_utils') 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}. + *

+ * 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/ide/common/layoutlib/DensityBasedResourceValue.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/DensityBasedResourceValue.java new file mode 100644 index 0000000..e1c0caa --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/DensityBasedResourceValue.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 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.IDensityBasedResourceValue; + +public class DensityBasedResourceValue extends ResourceValue implements IDensityBasedResourceValue { + + private Density mDensity; + + public DensityBasedResourceValue(String type, String name, String value, Density density, + boolean isFramework) { + super(type, name, value, isFramework); + mDensity = density; + } + + public Density getDensity() { + return mDensity; + } +} 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}. + *

+ * 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> 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 convertedChildren = new ArrayList(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. + *

+ * 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/ide/common/layoutlib/ResourceValue.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/ResourceValue.java new file mode 100644 index 0000000..382d961 --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/ResourceValue.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 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.IResourceValue; + +public class ResourceValue implements IResourceValue { + private final String mType; + private final String mName; + private String mValue = null; + private final boolean mIsFramwork; + + public ResourceValue(String type, String name, boolean isFramwork) { + mType = type; + mName = name; + mIsFramwork = isFramwork; + } + + public ResourceValue(String type, String name, String value, boolean isFramework) { + mType = type; + mName = name; + mValue = value; + mIsFramwork = isFramework; + } + + public String getType() { + return mType; + } + + public final String getName() { + return mName; + } + + public final String getValue() { + return mValue; + } + + public final void setValue(String value) { + mValue = value; + } + + public void replaceWith(ResourceValue value) { + mValue = value.mValue; + } + + public boolean isFramework() { + return mIsFramwork; + } +} diff --git a/layoutlib_utils/src/com/android/ide/common/layoutlib/StyleResourceValue.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/StyleResourceValue.java new file mode 100644 index 0000000..721b16c --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/StyleResourceValue.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 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.IResourceValue; +import com.android.layoutlib.api.IStyleResourceValue; + +import java.util.HashMap; + +public final class StyleResourceValue extends ResourceValue implements IStyleResourceValue { + + private String mParentStyle = null; + private HashMap mItems = new HashMap(); + + public StyleResourceValue(String type, String name, boolean isFramework) { + super(type, name, isFramework); + } + + public StyleResourceValue(String type, String name, String parentStyle, boolean isFramework) { + super(type, name, isFramework); + mParentStyle = parentStyle; + } + + public String getParentStyle() { + return mParentStyle; + } + + public IResourceValue findItem(String name) { + return mItems.get(name); + } + + public void addItem(IResourceValue value) { + mItems.put(value.getName(), value); + } + + @Override + public void replaceWith(ResourceValue value) { + super.replaceWith(value); + + if (value instanceof StyleResourceValue) { + mItems.clear(); + mItems.putAll(((StyleResourceValue)value).mItems); + } + } + +} diff --git a/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java new file mode 100644 index 0000000..c784f1f --- /dev/null +++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2008 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 org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * SAX handler to parser value resource files. + */ +public final class ValueResourceParser extends DefaultHandler { + + // TODO: reuse definitions from somewhere else. + private final static String NODE_RESOURCES = "resources"; + private final static String NODE_ITEM = "item"; + private final static String ATTR_NAME = "name"; + private final static String ATTR_TYPE = "type"; + private final static String ATTR_PARENT = "parent"; + + // Resource type definition + private final static String RES_STYLE = "style"; + private final static String RES_ATTR = "attr"; + + private final static String DEFAULT_NS_PREFIX = "android:"; + private final static int DEFAULT_NS_PREFIX_LEN = DEFAULT_NS_PREFIX.length(); + + public interface IValueResourceRepository { + void addResourceValue(String resType, ResourceValue value); + } + + private boolean inResources = false; + private int mDepth = 0; + private StyleResourceValue mCurrentStyle = null; + private ResourceValue mCurrentValue = null; + private IValueResourceRepository mRepository; + private final boolean mIsFramework; + + public ValueResourceParser(IValueResourceRepository repository, boolean isFramework) { + mRepository = repository; + mIsFramework = isFramework; + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (mCurrentValue != null) { + mCurrentValue.setValue(trimXmlWhitespaces(mCurrentValue.getValue())); + } + + if (inResources && qName.equals(NODE_RESOURCES)) { + inResources = false; + } else if (mDepth == 2) { + mCurrentValue = null; + mCurrentStyle = null; + } else if (mDepth == 3) { + mCurrentValue = null; + } + + mDepth--; + super.endElement(uri, localName, qName); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + try { + mDepth++; + if (inResources == false && mDepth == 1) { + if (qName.equals(NODE_RESOURCES)) { + inResources = true; + } + } else if (mDepth == 2 && inResources == true) { + String type; + + // if the node is , we get the type from the attribute "type" + if (NODE_ITEM.equals(qName)) { + type = attributes.getValue(ATTR_TYPE); + } else { + // the type is the name of the node. + type = qName; + } + + if (type != null) { + if (RES_ATTR.equals(type) == false) { + // get the resource name + String name = attributes.getValue(ATTR_NAME); + if (name != null) { + if (RES_STYLE.equals(type)) { + String parent = attributes.getValue(ATTR_PARENT); + mCurrentStyle = new StyleResourceValue(type, name, parent, mIsFramework); + mRepository.addResourceValue(type, mCurrentStyle); + } else { + mCurrentValue = new ResourceValue(type, name, mIsFramework); + mRepository.addResourceValue(type, mCurrentValue); + } + } + } + } + } else if (mDepth == 3 && mCurrentStyle != null) { + // get the resource name + String name = attributes.getValue(ATTR_NAME); + if (name != null) { + // the name can, in some cases, contain a prefix! we remove it. + if (name.startsWith(DEFAULT_NS_PREFIX)) { + name = name.substring(DEFAULT_NS_PREFIX_LEN); + } + + mCurrentValue = new ResourceValue(null, name, mIsFramework); + mCurrentStyle.addItem(mCurrentValue); + } + } + } finally { + super.startElement(uri, localName, qName, attributes); + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (mCurrentValue != null) { + String value = mCurrentValue.getValue(); + if (value == null) { + mCurrentValue.setValue(new String(ch, start, length)); + } else { + mCurrentValue.setValue(value + new String(ch, start, length)); + } + } + } + + public static String trimXmlWhitespaces(String value) { + if (value == null) { + return null; + } + + // look for carriage return and replace all whitespace around it by just 1 space. + int index; + + while ((index = value.indexOf('\n')) != -1) { + // look for whitespace on each side + int left = index - 1; + while (left >= 0) { + if (Character.isWhitespace(value.charAt(left))) { + left--; + } else { + break; + } + } + + int right = index + 1; + int count = value.length(); + while (right < count) { + if (Character.isWhitespace(value.charAt(right))) { + right++; + } else { + break; + } + } + + // remove all between left and right (non inclusive) and replace by a single space. + String leftString = null; + if (left >= 0) { + leftString = value.substring(0, left + 1); + } + String rightString = null; + if (right < count) { + rightString = value.substring(right); + } + + if (leftString != null) { + value = leftString; + if (rightString != null) { + value += " " + rightString; + } + } else { + value = rightString != null ? rightString : ""; + } + } + + // now we un-escape the string + int length = value.length(); + char[] buffer = value.toCharArray(); + + for (int i = 0 ; i < length ; i++) { + if (buffer[i] == '\\' && i + 1 < length) { + if (buffer[i+1] == 'u') { + if (i + 5 < length) { + // this is unicode char \u1234 + int unicodeChar = Integer.parseInt(new String(buffer, i+2, 4), 16); + + // put the unicode char at the location of the \ + buffer[i] = (char)unicodeChar; + + // offset the rest of the buffer since we go from 6 to 1 char + if (i + 6 < buffer.length) { + System.arraycopy(buffer, i+6, buffer, i+1, length - i - 6); + } + length -= 5; + } + } else { + if (buffer[i+1] == 'n') { + // replace the 'n' char with \n + buffer[i+1] = '\n'; + } + + // offset the buffer to erase the \ + System.arraycopy(buffer, i+1, buffer, i, length - i - 1); + length--; + } + } + } + + return new String(buffer, 0, length); + } +} 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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; +} diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java b/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java deleted file mode 100644 index 59de463..0000000 --- a/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2008 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.utils; - -import com.android.layoutlib.api.IDensityBasedResourceValue; - -public class DensityBasedResourceValue extends ResourceValue implements IDensityBasedResourceValue { - - private Density mDensity; - - public DensityBasedResourceValue(String type, String name, String value, Density density, - boolean isFramework) { - super(type, name, value, isFramework); - mDensity = density; - } - - public Density getDensity() { - return mDensity; - } -} diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/ResourceValue.java b/layoutlib_utils/src/com/android/layoutlib/utils/ResourceValue.java deleted file mode 100644 index 98b4de6..0000000 --- a/layoutlib_utils/src/com/android/layoutlib/utils/ResourceValue.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2008 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.utils; - -import com.android.layoutlib.api.IResourceValue; - -public class ResourceValue implements IResourceValue { - private final String mType; - private final String mName; - private String mValue = null; - private final boolean mIsFramwork; - - public ResourceValue(String type, String name, boolean isFramwork) { - mType = type; - mName = name; - mIsFramwork = isFramwork; - } - - public ResourceValue(String type, String name, String value, boolean isFramework) { - mType = type; - mName = name; - mValue = value; - mIsFramwork = isFramework; - } - - public String getType() { - return mType; - } - - public final String getName() { - return mName; - } - - public final String getValue() { - return mValue; - } - - public final void setValue(String value) { - mValue = value; - } - - public void replaceWith(ResourceValue value) { - mValue = value.mValue; - } - - public boolean isFramework() { - return mIsFramwork; - } -} diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/StyleResourceValue.java b/layoutlib_utils/src/com/android/layoutlib/utils/StyleResourceValue.java deleted file mode 100644 index a32ac1b..0000000 --- a/layoutlib_utils/src/com/android/layoutlib/utils/StyleResourceValue.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2008 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.utils; - -import com.android.layoutlib.api.IResourceValue; -import com.android.layoutlib.api.IStyleResourceValue; - -import java.util.HashMap; - -public final class StyleResourceValue extends ResourceValue implements IStyleResourceValue { - - private String mParentStyle = null; - private HashMap mItems = new HashMap(); - - public StyleResourceValue(String type, String name, boolean isFramework) { - super(type, name, isFramework); - } - - public StyleResourceValue(String type, String name, String parentStyle, boolean isFramework) { - super(type, name, isFramework); - mParentStyle = parentStyle; - } - - public String getParentStyle() { - return mParentStyle; - } - - public IResourceValue findItem(String name) { - return mItems.get(name); - } - - public void addItem(IResourceValue value) { - mItems.put(value.getName(), value); - } - - @Override - public void replaceWith(ResourceValue value) { - super.replaceWith(value); - - if (value instanceof StyleResourceValue) { - mItems.clear(); - mItems.putAll(((StyleResourceValue)value).mItems); - } - } - -} diff --git a/layoutlib_utils/src/com/android/layoutlib/utils/ValueResourceParser.java b/layoutlib_utils/src/com/android/layoutlib/utils/ValueResourceParser.java deleted file mode 100644 index 4682d90..0000000 --- a/layoutlib_utils/src/com/android/layoutlib/utils/ValueResourceParser.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2008 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.utils; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -/** - * SAX handler to parser value resource files. - */ -public final class ValueResourceParser extends DefaultHandler { - - // TODO: reuse definitions from somewhere else. - private final static String NODE_RESOURCES = "resources"; - private final static String NODE_ITEM = "item"; - private final static String ATTR_NAME = "name"; - private final static String ATTR_TYPE = "type"; - private final static String ATTR_PARENT = "parent"; - - // Resource type definition - private final static String RES_STYLE = "style"; - private final static String RES_ATTR = "attr"; - - private final static String DEFAULT_NS_PREFIX = "android:"; - private final static int DEFAULT_NS_PREFIX_LEN = DEFAULT_NS_PREFIX.length(); - - public interface IValueResourceRepository { - void addResourceValue(String resType, ResourceValue value); - } - - private boolean inResources = false; - private int mDepth = 0; - private StyleResourceValue mCurrentStyle = null; - private ResourceValue mCurrentValue = null; - private IValueResourceRepository mRepository; - private final boolean mIsFramework; - - public ValueResourceParser(IValueResourceRepository repository, boolean isFramework) { - mRepository = repository; - mIsFramework = isFramework; - } - - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - if (mCurrentValue != null) { - mCurrentValue.setValue(trimXmlWhitespaces(mCurrentValue.getValue())); - } - - if (inResources && qName.equals(NODE_RESOURCES)) { - inResources = false; - } else if (mDepth == 2) { - mCurrentValue = null; - mCurrentStyle = null; - } else if (mDepth == 3) { - mCurrentValue = null; - } - - mDepth--; - super.endElement(uri, localName, qName); - } - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - try { - mDepth++; - if (inResources == false && mDepth == 1) { - if (qName.equals(NODE_RESOURCES)) { - inResources = true; - } - } else if (mDepth == 2 && inResources == true) { - String type; - - // if the node is , we get the type from the attribute "type" - if (NODE_ITEM.equals(qName)) { - type = attributes.getValue(ATTR_TYPE); - } else { - // the type is the name of the node. - type = qName; - } - - if (type != null) { - if (RES_ATTR.equals(type) == false) { - // get the resource name - String name = attributes.getValue(ATTR_NAME); - if (name != null) { - if (RES_STYLE.equals(type)) { - String parent = attributes.getValue(ATTR_PARENT); - mCurrentStyle = new StyleResourceValue(type, name, parent, mIsFramework); - mRepository.addResourceValue(type, mCurrentStyle); - } else { - mCurrentValue = new ResourceValue(type, name, mIsFramework); - mRepository.addResourceValue(type, mCurrentValue); - } - } - } - } - } else if (mDepth == 3 && mCurrentStyle != null) { - // get the resource name - String name = attributes.getValue(ATTR_NAME); - if (name != null) { - // the name can, in some cases, contain a prefix! we remove it. - if (name.startsWith(DEFAULT_NS_PREFIX)) { - name = name.substring(DEFAULT_NS_PREFIX_LEN); - } - - mCurrentValue = new ResourceValue(null, name, mIsFramework); - mCurrentStyle.addItem(mCurrentValue); - } - } - } finally { - super.startElement(uri, localName, qName, attributes); - } - } - - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - if (mCurrentValue != null) { - String value = mCurrentValue.getValue(); - if (value == null) { - mCurrentValue.setValue(new String(ch, start, length)); - } else { - mCurrentValue.setValue(value + new String(ch, start, length)); - } - } - } - - public static String trimXmlWhitespaces(String value) { - if (value == null) { - return null; - } - - // look for carriage return and replace all whitespace around it by just 1 space. - int index; - - while ((index = value.indexOf('\n')) != -1) { - // look for whitespace on each side - int left = index - 1; - while (left >= 0) { - if (Character.isWhitespace(value.charAt(left))) { - left--; - } else { - break; - } - } - - int right = index + 1; - int count = value.length(); - while (right < count) { - if (Character.isWhitespace(value.charAt(right))) { - right++; - } else { - break; - } - } - - // remove all between left and right (non inclusive) and replace by a single space. - String leftString = null; - if (left >= 0) { - leftString = value.substring(0, left + 1); - } - String rightString = null; - if (right < count) { - rightString = value.substring(right); - } - - if (leftString != null) { - value = leftString; - if (rightString != null) { - value += " " + rightString; - } - } else { - value = rightString != null ? rightString : ""; - } - } - - // now we un-escape the string - int length = value.length(); - char[] buffer = value.toCharArray(); - - for (int i = 0 ; i < length ; i++) { - if (buffer[i] == '\\' && i + 1 < length) { - if (buffer[i+1] == 'u') { - if (i + 5 < length) { - // this is unicode char \u1234 - int unicodeChar = Integer.parseInt(new String(buffer, i+2, 4), 16); - - // put the unicode char at the location of the \ - buffer[i] = (char)unicodeChar; - - // offset the rest of the buffer since we go from 6 to 1 char - if (i + 6 < buffer.length) { - System.arraycopy(buffer, i+6, buffer, i+1, length - i - 6); - } - length -= 5; - } - } else { - if (buffer[i+1] == 'n') { - // replace the 'n' char with \n - buffer[i+1] = '\n'; - } - - // offset the buffer to erase the \ - System.arraycopy(buffer, i+1, buffer, i, length - i - 1); - length--; - } - } - } - - return new String(buffer, 0, length); - } -} -- cgit v1.1