diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk')
11 files changed, 0 insertions, 5092 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java deleted file mode 100755 index 2396a4c46..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.utils.ILogger; - -/** - * An {@link ILogger} logger that outputs to the ADT console. - */ -public class AdtConsoleSdkLog implements ILogger { - - private static final String TAG = "SDK Manager"; //$NON-NLS-1$ - - @Override - public void error(@Nullable Throwable t, @Nullable String errorFormat, Object... args) { - if (t != null) { - AdtPlugin.logAndPrintError(t, TAG, "Error: " + errorFormat, args); - } else { - AdtPlugin.printErrorToConsole(TAG, String.format(errorFormat, args)); - } - } - - @Override - public void info(@NonNull String msgFormat, Object... args) { - String msg = String.format(msgFormat, args); - for (String s : msg.split("\n")) { - if (s.trim().length() > 0) { - AdtPlugin.printToConsole(TAG, s); - } - } - } - - @Override - public void verbose(@NonNull String msgFormat, Object... args) { - info(msgFormat, args); - } - - @Override - public void warning(@NonNull String warningFormat, Object... args) { - AdtPlugin.printToConsole(TAG, String.format("Warning: " + warningFormat, args)); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtManifestMergeCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtManifestMergeCallback.java deleted file mode 100755 index dc539dcaa..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtManifestMergeCallback.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.annotations.NonNull; -import com.android.manifmerger.ICallback; -import com.android.manifmerger.ManifestMerger; -import com.android.sdklib.AndroidTargetHash; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; - -/** - * A {@link ManifestMerger} {@link ICallback} that returns the - * proper API level for known API codenames. - */ -public class AdtManifestMergeCallback implements ICallback { - @Override - public int queryCodenameApiLevel(@NonNull String codename) { - Sdk sdk = Sdk.getCurrent(); - if (sdk != null) { - try { - AndroidVersion version = new AndroidVersion(codename); - String hashString = AndroidTargetHash.getPlatformHashString(version); - IAndroidTarget t = sdk.getTargetFromHashString(hashString); - if (t != null) { - return t.getVersion().getApiLevel(); - } - } catch (AndroidVersion.AndroidVersionException ignore) {} - } - return ICallback.UNKNOWN_CODENAME; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidJarLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidJarLoader.java deleted file mode 100644 index 754cedf79..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidJarLoader.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.SdkConstants; -import com.google.common.io.Closeables; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.SubMonitor; - -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.management.InvalidAttributeValueException; - -/** - * Custom class loader able to load a class from the SDK jar file. - */ -public class AndroidJarLoader extends ClassLoader implements IAndroidClassLoader { - - /** - * Wrapper around a {@link Class} to provide the methods of - * {@link IAndroidClassLoader.IClassDescriptor}. - */ - public final static class ClassWrapper implements IClassDescriptor { - private Class<?> mClass; - - public ClassWrapper(Class<?> clazz) { - mClass = clazz; - } - - @Override - public String getFullClassName() { - return mClass.getCanonicalName(); - } - - @Override - public IClassDescriptor[] getDeclaredClasses() { - Class<?>[] classes = mClass.getDeclaredClasses(); - IClassDescriptor[] iclasses = new IClassDescriptor[classes.length]; - for (int i = 0 ; i < classes.length ; i++) { - iclasses[i] = new ClassWrapper(classes[i]); - } - - return iclasses; - } - - @Override - public IClassDescriptor getEnclosingClass() { - return new ClassWrapper(mClass.getEnclosingClass()); - } - - @Override - public String getSimpleName() { - return mClass.getSimpleName(); - } - - @Override - public IClassDescriptor getSuperclass() { - return new ClassWrapper(mClass.getSuperclass()); - } - - @Override - public boolean equals(Object clazz) { - if (clazz instanceof ClassWrapper) { - return mClass.equals(((ClassWrapper)clazz).mClass); - } - return super.equals(clazz); - } - - @Override - public int hashCode() { - return mClass.hashCode(); - } - - - @Override - public boolean isInstantiable() { - int modifiers = mClass.getModifiers(); - return Modifier.isAbstract(modifiers) == false && Modifier.isPublic(modifiers) == true; - } - - public Class<?> wrappedClass() { - return mClass; - } - - } - - private String mOsFrameworkLocation; - - /** A cache for binary data extracted from the zip */ - private final HashMap<String, byte[]> mEntryCache = new HashMap<String, byte[]>(); - /** A cache for already defined Classes */ - private final HashMap<String, Class<?> > mClassCache = new HashMap<String, Class<?> >(); - - /** - * Creates the class loader by providing the os path to the framework jar archive - * - * @param osFrameworkLocation OS Path of the framework JAR file - */ - public AndroidJarLoader(String osFrameworkLocation) { - super(); - mOsFrameworkLocation = osFrameworkLocation; - } - - @Override - public String getSource() { - return mOsFrameworkLocation; - } - - /** - * Pre-loads all class binary data that belong to the given package by reading the archive - * once and caching them internally. - * <p/> - * This does not actually preload "classes", it just reads the unzipped bytes for a given - * class. To obtain a class, one must call {@link #findClass(String)} later. - * <p/> - * All classes which package name starts with "packageFilter" will be included and can be - * found later. - * <p/> - * May throw some exceptions if the framework JAR cannot be read. - * - * @param packageFilter The package that contains all the class data to preload, using a fully - * qualified binary name (.e.g "com.my.package."). The matching algorithm - * is simple "startsWith". Use an empty string to include everything. - * @param taskLabel An optional task name for the sub monitor. Can be null. - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - public void preLoadClasses(String packageFilter, String taskLabel, IProgressMonitor monitor) - throws IOException, InvalidAttributeValueException, ClassFormatError { - // Transform the package name into a zip entry path - String pathFilter = packageFilter.replaceAll("\\.", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - - SubMonitor progress = SubMonitor.convert(monitor, taskLabel == null ? "" : taskLabel, 100); - - // create streams to read the intermediary archive - FileInputStream fis = new FileInputStream(mOsFrameworkLocation); - ZipInputStream zis = new ZipInputStream(fis); - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - // get the name of the entry. - String entryPath = entry.getName(); - - if (!entryPath.endsWith(SdkConstants.DOT_CLASS)) { - // only accept class files - continue; - } - - // check if it is part of the package to preload - if (pathFilter.length() > 0 && !entryPath.startsWith(pathFilter)) { - continue; - } - String className = entryPathToClassName(entryPath); - - if (!mEntryCache.containsKey(className)) { - long entrySize = entry.getSize(); - if (entrySize > Integer.MAX_VALUE) { - throw new InvalidAttributeValueException(); - } - byte[] data = readZipData(zis, (int)entrySize); - mEntryCache.put(className, data); - } - - // advance 5% of whatever is allocated on the progress bar - progress.setWorkRemaining(100); - progress.worked(5); - progress.subTask(String.format("Preload %1$s", className)); - } - } - - /** - * Finds and loads all classes that derive from a given set of super classes. - * <p/> - * As a side-effect this will load and cache most, if not all, classes in the input JAR file. - * - * @param packageFilter Base name of package of classes to find. - * Use an empty string to find everyting. - * @param superClasses The super classes of all the classes to find. - * @return An hash map which keys are the super classes looked for and which values are - * ArrayList of the classes found. The array lists are always created for all the - * valid keys, they are simply empty if no deriving class is found for a given - * super class. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - @SuppressWarnings("resource") // Eclipse doesn't understand Closeables.closeQuietly - @Override - public HashMap<String, ArrayList<IClassDescriptor>> findClassesDerivingFrom( - String packageFilter, - String[] superClasses) - throws IOException, InvalidAttributeValueException, ClassFormatError { - - packageFilter = packageFilter.replaceAll("\\.", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - - HashMap<String, ArrayList<IClassDescriptor>> mClassesFound = - new HashMap<String, ArrayList<IClassDescriptor>>(); - - for (String className : superClasses) { - mClassesFound.put(className, new ArrayList<IClassDescriptor>()); - } - - // create streams to read the intermediary archive - FileInputStream fis = new FileInputStream(mOsFrameworkLocation); - ZipInputStream zis = new ZipInputStream(fis); - try { - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - // get the name of the entry and convert to a class binary name - String entryPath = entry.getName(); - if (!entryPath.endsWith(SdkConstants.DOT_CLASS)) { - // only accept class files - continue; - } - if (packageFilter.length() > 0 && !entryPath.startsWith(packageFilter)) { - // only accept stuff from the requested root package. - continue; - } - String className = entryPathToClassName(entryPath); - - Class<?> loaded_class = mClassCache.get(className); - if (loaded_class == null) { - byte[] data = mEntryCache.get(className); - if (data == null) { - // Get the class and cache it - long entrySize = entry.getSize(); - if (entrySize > Integer.MAX_VALUE) { - throw new InvalidAttributeValueException(); - } - data = readZipData(zis, (int)entrySize); - } - try { - loaded_class = defineAndCacheClass(className, data); - } catch (NoClassDefFoundError error) { - if (error.getMessage().startsWith("java/")) { - // Can't define these; we just need to stop - // iteration here - continue; - } - throw error; - } - } - - for (Class<?> superClass = loaded_class.getSuperclass(); - superClass != null; - superClass = superClass.getSuperclass()) { - String superName = superClass.getCanonicalName(); - if (mClassesFound.containsKey(superName)) { - mClassesFound.get(superName).add(new ClassWrapper(loaded_class)); - break; - } - } - } - } finally { - Closeables.closeQuietly(zis); - } - - return mClassesFound; - } - - /** Helper method that converts a Zip entry path into a corresponding - * Java full qualified binary class name. - * <p/> - * F.ex, this converts "com/my/package/Foo.class" into "com.my.package.Foo". - */ - private String entryPathToClassName(String entryPath) { - return entryPath.replaceFirst("\\.class$", "").replaceAll("[/\\\\]", "."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - /** - * Finds the class with the specified binary name. - * - * {@inheritDoc} - */ - @Override - protected Class<?> findClass(String name) throws ClassNotFoundException { - try { - // try to find the class in the cache - Class<?> cached_class = mClassCache.get(name); - if (cached_class == ClassNotFoundException.class) { - // we already know we can't find this class, don't try again - throw new ClassNotFoundException(name); - } else if (cached_class != null) { - return cached_class; - } - - // if not found, look it up and cache it - byte[] data = loadClassData(name); - if (data != null) { - return defineAndCacheClass(name, data); - } else { - // if the class can't be found, record a CNFE class in the map so - // that we don't try to reload it next time - mClassCache.put(name, ClassNotFoundException.class); - throw new ClassNotFoundException(name); - } - } catch (ClassNotFoundException e) { - throw e; - } catch (Exception e) { - throw new ClassNotFoundException(e.getMessage()); - } - } - - /** - * Defines a class based on its binary data and caches the resulting class object. - * - * @param name The binary name of the class (i.e. package.class1$class2) - * @param data The binary data from the loader. - * @return The class defined - * @throws ClassFormatError if defineClass failed. - */ - private Class<?> defineAndCacheClass(String name, byte[] data) throws ClassFormatError { - Class<?> cached_class; - cached_class = defineClass(null, data, 0, data.length); - - if (cached_class != null) { - // Add new class to the cache class and remove it from the zip entry data cache - mClassCache.put(name, cached_class); - mEntryCache.remove(name); - } - return cached_class; - } - - /** - * Loads a class data from its binary name. - * <p/> - * This uses the class binary data that has been preloaded earlier by the preLoadClasses() - * method if possible. - * - * @param className the binary name - * @return an array of bytes representing the class data or null if not found - * @throws InvalidAttributeValueException - * @throws IOException - */ - private synchronized byte[] loadClassData(String className) - throws InvalidAttributeValueException, IOException { - - byte[] data = mEntryCache.get(className); - if (data != null) { - return data; - } - - // The name is a binary name. Something like "android.R", or "android.R$id". - // Make a path out of it. - String entryName = className.replaceAll("\\.", "/") + SdkConstants.DOT_CLASS; //$NON-NLS-1$ //$NON-NLS-2$ - - // create streams to read the intermediary archive - FileInputStream fis = new FileInputStream(mOsFrameworkLocation); - ZipInputStream zis = new ZipInputStream(fis); - try { - // loop on the entries of the intermediary package and put them in the final package. - ZipEntry entry; - - while ((entry = zis.getNextEntry()) != null) { - // get the name of the entry. - String currEntryName = entry.getName(); - - if (currEntryName.equals(entryName)) { - long entrySize = entry.getSize(); - if (entrySize > Integer.MAX_VALUE) { - throw new InvalidAttributeValueException(); - } - - data = readZipData(zis, (int)entrySize); - return data; - } - } - - return null; - } finally { - zis.close(); - } - } - - /** - * Reads data for the <em>current</em> entry from the zip input stream. - * - * @param zis The Zip input stream - * @param entrySize The entry size. -1 if unknown. - * @return The new data for the <em>current</em> entry. - * @throws IOException If ZipInputStream.read() fails. - */ - private byte[] readZipData(ZipInputStream zis, int entrySize) throws IOException { - int block_size = 1024; - int data_size = entrySize < 1 ? block_size : entrySize; - int offset = 0; - byte[] data = new byte[data_size]; - - while(zis.available() != 0) { - int count = zis.read(data, offset, data_size - offset); - if (count < 0) { // read data is done - break; - } - offset += count; - - if (entrySize >= 1 && offset >= entrySize) { // we know the size and we're done - break; - } - - // if we don't know the entry size and we're not done reading, - // expand the data buffer some more. - if (offset >= data_size) { - byte[] temp = new byte[data_size + block_size]; - System.arraycopy(data, 0, temp, 0, data_size); - data_size += block_size; - data = temp; - block_size *= 2; - } - } - - if (offset < data_size) { - // buffer was allocated too large, trim it - byte[] temp = new byte[offset]; - if (offset > 0) { - System.arraycopy(data, 0, temp, 0, offset); - } - data = temp; - } - - return data; - } - - /** - * Returns a {@link IAndroidClassLoader.IClassDescriptor} by its fully-qualified name. - * @param className the fully-qualified name of the class to return. - * @throws ClassNotFoundException - */ - @Override - public IClassDescriptor getClass(String className) throws ClassNotFoundException { - try { - return new ClassWrapper(loadClass(className)); - } catch (ClassNotFoundException e) { - throw e; // useful for debugging - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java deleted file mode 100644 index 85ae9fdc0..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.common.rendering.LayoutLibrary; -import com.android.ide.common.rendering.api.LayoutLog; -import com.android.ide.common.resources.ResourceRepository; -import com.android.ide.common.resources.platform.AttributeInfo; -import com.android.ide.common.sdk.LoadStatus; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.animator.AnimDescriptors; -import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors; -import com.android.ide.eclipse.adt.internal.editors.color.ColorDescriptors; -import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableDescriptors; -import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; -import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors; -import com.android.ide.eclipse.adt.internal.editors.otherxml.descriptors.OtherXmlDescriptors; -import com.android.ide.eclipse.adt.internal.editors.values.descriptors.ValuesDescriptors; -import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.IAndroidTarget.IOptionalLibrary; - -import org.eclipse.core.runtime.IStatus; - -import java.io.File; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.Map; - -/** - * This class contains the data of an Android Target as loaded from the SDK. - */ -public class AndroidTargetData { - - public final static int DESCRIPTOR_MANIFEST = 1; - public final static int DESCRIPTOR_LAYOUT = 2; - public final static int DESCRIPTOR_MENU = 3; - public final static int DESCRIPTOR_OTHER_XML = 4; - public final static int DESCRIPTOR_RESOURCES = 5; - public final static int DESCRIPTOR_SEARCHABLE = 6; - public final static int DESCRIPTOR_PREFERENCES = 7; - public final static int DESCRIPTOR_APPWIDGET_PROVIDER = 8; - public final static int DESCRIPTOR_DRAWABLE = 9; - public final static int DESCRIPTOR_ANIMATOR = 10; - public final static int DESCRIPTOR_ANIM = 11; - public final static int DESCRIPTOR_COLOR = 12; - - private final IAndroidTarget mTarget; - - /** - * mAttributeValues is a map { key => list [ values ] }. - * The key for the map is "(element-xml-name,attribute-namespace:attribute-xml-local-name)". - * The attribute namespace prefix must be: - * - "android" for SdkConstants.NS_RESOURCES - * - "xmlns" for the XMLNS URI. - * - * This is used for attributes that do not have a unique name, but still need to be populated - * with values in the UI. Uniquely named attributes have their values in {@link #mEnumValueMap}. - */ - private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>(); - - private AndroidManifestDescriptors mManifestDescriptors; - private DrawableDescriptors mDrawableDescriptors; - private AnimatorDescriptors mAnimatorDescriptors; - private AnimDescriptors mAnimDescriptors; - private ColorDescriptors mColorDescriptors; - private LayoutDescriptors mLayoutDescriptors; - private MenuDescriptors mMenuDescriptors; - private OtherXmlDescriptors mOtherXmlDescriptors; - - private Map<String, Map<String, Integer>> mEnumValueMap; - - private ResourceRepository mFrameworkResources; - private LayoutLibrary mLayoutLibrary; - private Map<String, AttributeInfo> mAttributeMap; - - private boolean mLayoutBridgeInit = false; - - AndroidTargetData(IAndroidTarget androidTarget) { - mTarget = androidTarget; - } - - /** - * Sets the associated map from string attribute name to - * {@link AttributeInfo} - * - * @param attributeMap the map - */ - public void setAttributeMap(@NonNull Map<String, AttributeInfo> attributeMap) { - mAttributeMap = attributeMap; - } - - /** - * Returns the associated map from string attribute name to - * {@link AttributeInfo} - * - * @return the map - */ - @Nullable - public Map<String, AttributeInfo> getAttributeMap() { - return mAttributeMap; - } - - /** - * Creates an AndroidTargetData object. - */ - void setExtraData( - AndroidManifestDescriptors manifestDescriptors, - LayoutDescriptors layoutDescriptors, - MenuDescriptors menuDescriptors, - OtherXmlDescriptors otherXmlDescriptors, - DrawableDescriptors drawableDescriptors, - AnimatorDescriptors animatorDescriptors, - AnimDescriptors animDescriptors, - ColorDescriptors colorDescriptors, - Map<String, Map<String, Integer>> enumValueMap, - String[] permissionValues, - String[] activityIntentActionValues, - String[] broadcastIntentActionValues, - String[] serviceIntentActionValues, - String[] intentCategoryValues, - String[] platformLibraries, - IOptionalLibrary[] optionalLibraries, - ResourceRepository frameworkResources, - LayoutLibrary layoutLibrary) { - - mManifestDescriptors = manifestDescriptors; - mDrawableDescriptors = drawableDescriptors; - mAnimatorDescriptors = animatorDescriptors; - mAnimDescriptors = animDescriptors; - mColorDescriptors = colorDescriptors; - mLayoutDescriptors = layoutDescriptors; - mMenuDescriptors = menuDescriptors; - mOtherXmlDescriptors = otherXmlDescriptors; - mEnumValueMap = enumValueMap; - mFrameworkResources = frameworkResources; - mLayoutLibrary = layoutLibrary; - - setPermissions(permissionValues); - setIntentFilterActionsAndCategories(activityIntentActionValues, broadcastIntentActionValues, - serviceIntentActionValues, intentCategoryValues); - setOptionalLibraries(platformLibraries, optionalLibraries); - } - - /** - * Returns an {@link IDescriptorProvider} from a given Id. - * The Id can be one of {@link #DESCRIPTOR_MANIFEST}, {@link #DESCRIPTOR_LAYOUT}, - * {@link #DESCRIPTOR_MENU}, or {@link #DESCRIPTOR_OTHER_XML}. - * All other values will throw an {@link IllegalArgumentException}. - */ - public IDescriptorProvider getDescriptorProvider(int descriptorId) { - switch (descriptorId) { - case DESCRIPTOR_MANIFEST: - return mManifestDescriptors; - case DESCRIPTOR_LAYOUT: - return mLayoutDescriptors; - case DESCRIPTOR_MENU: - return mMenuDescriptors; - case DESCRIPTOR_OTHER_XML: - return mOtherXmlDescriptors; - case DESCRIPTOR_RESOURCES: - // FIXME: since it's hard-coded the Resources Descriptors are not platform dependent. - return ValuesDescriptors.getInstance(); - case DESCRIPTOR_PREFERENCES: - return mOtherXmlDescriptors.getPreferencesProvider(); - case DESCRIPTOR_APPWIDGET_PROVIDER: - return mOtherXmlDescriptors.getAppWidgetProvider(); - case DESCRIPTOR_SEARCHABLE: - return mOtherXmlDescriptors.getSearchableProvider(); - case DESCRIPTOR_DRAWABLE: - return mDrawableDescriptors; - case DESCRIPTOR_ANIMATOR: - return mAnimatorDescriptors; - case DESCRIPTOR_ANIM: - return mAnimDescriptors; - case DESCRIPTOR_COLOR: - return mColorDescriptors; - default : - throw new IllegalArgumentException(); - } - } - - /** - * Returns the manifest descriptors. - */ - public AndroidManifestDescriptors getManifestDescriptors() { - return mManifestDescriptors; - } - - /** - * Returns the drawable descriptors - */ - public DrawableDescriptors getDrawableDescriptors() { - return mDrawableDescriptors; - } - - /** - * Returns the animation descriptors - */ - public AnimDescriptors getAnimDescriptors() { - return mAnimDescriptors; - } - - /** - * Returns the color descriptors - */ - public ColorDescriptors getColorDescriptors() { - return mColorDescriptors; - } - - /** - * Returns the animator descriptors - */ - public AnimatorDescriptors getAnimatorDescriptors() { - return mAnimatorDescriptors; - } - - /** - * Returns the layout Descriptors. - */ - public LayoutDescriptors getLayoutDescriptors() { - return mLayoutDescriptors; - } - - /** - * Returns the menu descriptors. - */ - public MenuDescriptors getMenuDescriptors() { - return mMenuDescriptors; - } - - /** - * Returns the XML descriptors - */ - public OtherXmlDescriptors getXmlDescriptors() { - return mOtherXmlDescriptors; - } - - /** - * Returns this list of possible values for an XML attribute. - * <p/>This should only be called for attributes for which possible values depend on the - * parent element node. - * <p/>For attributes that have the same values no matter the parent node, use - * {@link #getEnumValueMap()}. - * @param elementName the name of the element containing the attribute. - * @param attributeName the name of the attribute - * @return an array of String with the possible values, or <code>null</code> if no values were - * found. - */ - public String[] getAttributeValues(String elementName, String attributeName) { - String key = String.format("(%1$s,%2$s)", elementName, attributeName); //$NON-NLS-1$ - return mAttributeValues.get(key); - } - - /** - * Returns this list of possible values for an XML attribute. - * <p/>This should only be called for attributes for which possible values depend on the - * parent and great-grand-parent element node. - * <p/>The typical example of this is for the 'name' attribute under - * activity/intent-filter/action - * <p/>For attributes that have the same values no matter the parent node, use - * {@link #getEnumValueMap()}. - * @param elementName the name of the element containing the attribute. - * @param attributeName the name of the attribute - * @param greatGrandParentElementName the great-grand-parent node. - * @return an array of String with the possible values, or <code>null</code> if no values were - * found. - */ - public String[] getAttributeValues(String elementName, String attributeName, - String greatGrandParentElementName) { - if (greatGrandParentElementName != null) { - String key = String.format("(%1$s,%2$s,%3$s)", //$NON-NLS-1$ - greatGrandParentElementName, elementName, attributeName); - String[] values = mAttributeValues.get(key); - if (values != null) { - return values; - } - } - - return getAttributeValues(elementName, attributeName); - } - - /** - * Returns the enum values map. - * <p/>The map defines the possible values for XML attributes. The key is the attribute name - * and the value is a map of (string, integer) in which the key (string) is the name of - * the value, and the Integer is the numerical value in the compiled binary XML files. - */ - public Map<String, Map<String, Integer>> getEnumValueMap() { - return mEnumValueMap; - } - - /** - * Returns the {@link ProjectResources} containing the Framework Resources. - */ - public ResourceRepository getFrameworkResources() { - return mFrameworkResources; - } - - /** - * Returns a {@link LayoutLibrary} object possibly containing a {@link LayoutBridge} object. - * <p/>If {@link LayoutLibrary#getBridge()} is <code>null</code>, - * {@link LayoutBridge#getStatus()} will contain the reason (either {@link LoadStatus#LOADING} - * or {@link LoadStatus#FAILED}). - * <p/>Valid {@link LayoutBridge} objects are always initialized before being returned. - */ - public synchronized LayoutLibrary getLayoutLibrary() { - if (mLayoutBridgeInit == false && mLayoutLibrary.getStatus() == LoadStatus.LOADED) { - boolean ok = mLayoutLibrary.init( - mTarget.getProperties(), - new File(mTarget.getPath(IAndroidTarget.FONTS)), - getEnumValueMap(), - new LayoutLog() { - - @Override - public void error(String tag, String message, Throwable throwable, - Object data) { - AdtPlugin.log(throwable, message); - } - - @Override - public void error(String tag, String message, Object data) { - AdtPlugin.log(IStatus.ERROR, message); - } - - @Override - public void warning(String tag, String message, Object data) { - AdtPlugin.log(IStatus.WARNING, message); - } - }); - if (!ok) { - AdtPlugin.log(IStatus.ERROR, - "LayoutLibrary initialization failed"); - } - mLayoutBridgeInit = true; - } - - return mLayoutLibrary; - } - - /** - * Sets the permission values - * @param permissionValues the list of permissions - */ - private void setPermissions(String[] permissionValues) { - setValues("(uses-permission,android:name)", permissionValues); //$NON-NLS-1$ - setValues("(application,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(activity,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(receiver,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(service,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(provider,android:permission)", permissionValues); //$NON-NLS-1$ - } - - private void setIntentFilterActionsAndCategories(String[] activityIntentActions, - String[] broadcastIntentActions, String[] serviceIntentActions, - String[] intentCategoryValues) { - setValues("(activity,action,android:name)", activityIntentActions); //$NON-NLS-1$ - setValues("(receiver,action,android:name)", broadcastIntentActions); //$NON-NLS-1$ - setValues("(service,action,android:name)", serviceIntentActions); //$NON-NLS-1$ - setValues("(category,android:name)", intentCategoryValues); //$NON-NLS-1$ - } - - private void setOptionalLibraries(String[] platformLibraries, - IOptionalLibrary[] optionalLibraries) { - - ArrayList<String> libs = new ArrayList<String>(); - - if (platformLibraries != null) { - for (String name : platformLibraries) { - libs.add(name); - } - } - - if (optionalLibraries != null) { - for (int i = 0; i < optionalLibraries.length; i++) { - libs.add(optionalLibraries[i].getName()); - } - } - setValues("(uses-library,android:name)", libs.toArray(new String[libs.size()])); - } - - /** - * Sets a (name, values) pair in the hash map. - * <p/> - * If the name is already present in the map, it is first removed. - * @param name the name associated with the values. - * @param values The values to add. - */ - private void setValues(String name, String[] values) { - mAttributeValues.remove(name); - mAttributeValues.put(name, values); - } - - public void dispose() { - if (mLayoutLibrary != null) { - mLayoutLibrary.dispose(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java deleted file mode 100644 index 9a1fd3dc9..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.SdkConstants; -import com.android.ide.common.rendering.LayoutLibrary; -import com.android.ide.common.resources.ResourceRepository; -import com.android.ide.common.resources.platform.AttrsXmlParser; -import com.android.ide.common.resources.platform.DeclareStyleableInfo; -import com.android.ide.common.resources.platform.ViewClassInfo; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.animator.AnimDescriptors; -import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors; -import com.android.ide.eclipse.adt.internal.editors.color.ColorDescriptors; -import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableDescriptors; -import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; -import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors; -import com.android.ide.eclipse.adt.internal.editors.otherxml.descriptors.OtherXmlDescriptors; -import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.management.InvalidAttributeValueException; - -/** - * Parser for the platform data in an SDK. - * <p/> - * This gather the following information: - * <ul> - * <li>Resource ID from <code>android.R</code></li> - * <li>The list of permissions values from <code>android.Manifest$permission</code></li> - * <li></li> - * </ul> - */ -public final class AndroidTargetParser { - - private static final String TAG = "Framework Resource Parser"; - private final IAndroidTarget mAndroidTarget; - - /** - * Creates a platform data parser. - */ - public AndroidTargetParser(IAndroidTarget platformTarget) { - mAndroidTarget = platformTarget; - } - - /** - * Parses the framework, collects all interesting information and stores them in the - * {@link IAndroidTarget} given to the constructor. - * - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - * @return True if the SDK path was valid and parsing has been attempted. - */ - public IStatus run(IProgressMonitor monitor) { - try { - SubMonitor progress = SubMonitor.convert(monitor, - String.format("Parsing SDK %1$s", mAndroidTarget.getName()), - 16); - - AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget); - - // parse the rest of the data. - - AndroidJarLoader classLoader = - new AndroidJarLoader(mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR)); - - preload(classLoader, progress.newChild(40, SubMonitor.SUPPRESS_NONE)); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // get the permissions - progress.subTask("Permissions"); - String[] permissionValues = collectPermissions(classLoader); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // get the action and category values for the Intents. - progress.subTask("Intents"); - ArrayList<String> activity_actions = new ArrayList<String>(); - ArrayList<String> broadcast_actions = new ArrayList<String>(); - ArrayList<String> service_actions = new ArrayList<String>(); - ArrayList<String> categories = new ArrayList<String>(); - collectIntentFilterActionsAndCategories(activity_actions, broadcast_actions, - service_actions, categories); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // gather the attribute definition - progress.subTask("Attributes definitions"); - AttrsXmlParser attrsXmlParser = new AttrsXmlParser( - mAndroidTarget.getPath(IAndroidTarget.ATTRIBUTES), - AdtPlugin.getDefault(), - 1000); - attrsXmlParser.preload(); - - progress.worked(1); - - progress.subTask("Manifest definitions"); - AttrsXmlParser attrsManifestXmlParser = new AttrsXmlParser( - mAndroidTarget.getPath(IAndroidTarget.MANIFEST_ATTRIBUTES), - attrsXmlParser, - AdtPlugin.getDefault(), 1100); - attrsManifestXmlParser.preload(); - progress.worked(1); - - Collection<ViewClassInfo> mainList = new ArrayList<ViewClassInfo>(); - Collection<ViewClassInfo> groupList = new ArrayList<ViewClassInfo>(); - - // collect the layout/widgets classes - progress.subTask("Widgets and layouts"); - collectLayoutClasses(classLoader, attrsXmlParser, mainList, groupList, - progress.newChild(1)); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - ViewClassInfo[] layoutViewsInfo = mainList.toArray( - new ViewClassInfo[mainList.size()]); - ViewClassInfo[] layoutGroupsInfo = groupList.toArray( - new ViewClassInfo[groupList.size()]); - mainList.clear(); - groupList.clear(); - - // collect the preferences classes. - collectPreferenceClasses(classLoader, attrsXmlParser, mainList, groupList, - progress.newChild(1)); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - ViewClassInfo[] preferencesInfo = mainList.toArray(new ViewClassInfo[mainList.size()]); - ViewClassInfo[] preferenceGroupsInfo = groupList.toArray( - new ViewClassInfo[groupList.size()]); - - Map<String, DeclareStyleableInfo> xmlMenuMap = collectMenuDefinitions(attrsXmlParser); - Map<String, DeclareStyleableInfo> xmlSearchableMap = collectSearchableDefinitions( - attrsXmlParser); - Map<String, DeclareStyleableInfo> manifestMap = collectManifestDefinitions( - attrsManifestXmlParser); - Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues(); - - Map<String, DeclareStyleableInfo> xmlAppWidgetMap = null; - if (mAndroidTarget.getVersion().getApiLevel() >= 3) { - xmlAppWidgetMap = collectAppWidgetDefinitions(attrsXmlParser); - } - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // From the information that was collected, create the pieces that will be put in - // the PlatformData object. - AndroidManifestDescriptors manifestDescriptors = new AndroidManifestDescriptors(); - manifestDescriptors.updateDescriptors(manifestMap); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - LayoutDescriptors layoutDescriptors = new LayoutDescriptors(); - layoutDescriptors.updateDescriptors(layoutViewsInfo, layoutGroupsInfo, - attrsXmlParser.getDeclareStyleableList(), mAndroidTarget); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - MenuDescriptors menuDescriptors = new MenuDescriptors(); - menuDescriptors.updateDescriptors(xmlMenuMap); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - OtherXmlDescriptors otherXmlDescriptors = new OtherXmlDescriptors(); - otherXmlDescriptors.updateDescriptors( - xmlSearchableMap, - xmlAppWidgetMap, - preferencesInfo, - preferenceGroupsInfo); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - DrawableDescriptors drawableDescriptors = new DrawableDescriptors(); - Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList(); - drawableDescriptors.updateDescriptors(map); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - AnimatorDescriptors animatorDescriptors = new AnimatorDescriptors(); - animatorDescriptors.updateDescriptors(map); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - AnimDescriptors animDescriptors = new AnimDescriptors(); - animDescriptors.updateDescriptors(map); - progress.worked(1); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - ColorDescriptors colorDescriptors = new ColorDescriptors(); - colorDescriptors.updateDescriptors(map); - progress.worked(1); - - // load the framework resources. - ResourceRepository frameworkResources = - ResourceManager.getInstance().loadFrameworkResources(mAndroidTarget); - progress.worked(1); - - // now load the layout lib bridge - LayoutLibrary layoutBridge = LayoutLibrary.load( - mAndroidTarget.getPath(IAndroidTarget.LAYOUT_LIB), - AdtPlugin.getDefault(), - "ADT plug-in"); - - progress.worked(1); - - // and finally create the PlatformData with all that we loaded. - targetData.setExtraData( - manifestDescriptors, - layoutDescriptors, - menuDescriptors, - otherXmlDescriptors, - drawableDescriptors, - animatorDescriptors, - animDescriptors, - colorDescriptors, - enumValueMap, - permissionValues, - activity_actions.toArray(new String[activity_actions.size()]), - broadcast_actions.toArray(new String[broadcast_actions.size()]), - service_actions.toArray(new String[service_actions.size()]), - categories.toArray(new String[categories.size()]), - mAndroidTarget.getPlatformLibraries(), - mAndroidTarget.getOptionalLibraries(), - frameworkResources, - layoutBridge); - - targetData.setAttributeMap(attrsXmlParser.getAttributeMap()); - - Sdk.getCurrent().setTargetData(mAndroidTarget, targetData); - - return Status.OK_STATUS; - } catch (Exception e) { - AdtPlugin.logAndPrintError(e, TAG, "SDK parser failed"); //$NON-NLS-1$ - AdtPlugin.printToConsole("SDK parser failed", e.getMessage()); - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "SDK parser failed", e); - } - } - - /** - * Preloads all "interesting" classes from the framework SDK jar. - * <p/> - * Currently this preloads all classes from the framework jar - * - * @param classLoader The framework SDK jar classloader - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - private void preload(AndroidJarLoader classLoader, IProgressMonitor monitor) { - try { - classLoader.preLoadClasses("" /* all classes */, //$NON-NLS-1$ - mAndroidTarget.getName(), // monitor task label - monitor); - } catch (InvalidAttributeValueException e) { - AdtPlugin.log(e, "Problem preloading classes"); //$NON-NLS-1$ - } catch (IOException e) { - AdtPlugin.log(e, "Problem preloading classes"); //$NON-NLS-1$ - } - } - - /** - * Loads, collects and returns the list of default permissions from the framework. - * - * @param classLoader The framework SDK jar classloader - * @return a non null (but possibly empty) array containing the permission values. - */ - private String[] collectPermissions(AndroidJarLoader classLoader) { - try { - Class<?> permissionClass = - classLoader.loadClass(SdkConstants.CLASS_MANIFEST_PERMISSION); - - if (permissionClass != null) { - ArrayList<String> list = new ArrayList<String>(); - - Field[] fields = permissionClass.getFields(); - - for (Field f : fields) { - int modifiers = f.getModifiers(); - if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers) && - Modifier.isPublic(modifiers)) { - try { - Object value = f.get(null); - if (value instanceof String) { - list.add((String)value); - } - } catch (IllegalArgumentException e) { - // since we provide null this should not happen - } catch (IllegalAccessException e) { - // if the field is inaccessible we ignore it. - } catch (NullPointerException npe) { - // looks like this is not a static field. we can ignore. - } catch (ExceptionInInitializerError eiie) { - // lets just ignore the field again - } - } - } - - return list.toArray(new String[list.size()]); - } - } catch (ClassNotFoundException e) { - AdtPlugin.logAndPrintError(e, TAG, - "Collect permissions failed, class %1$s not found in %2$s", //$NON-NLS-1$ - SdkConstants.CLASS_MANIFEST_PERMISSION, - mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR)); - } - - return new String[0]; - } - - /** - * Loads and collects the action and category default values from the framework. - * The values are added to the <code>actions</code> and <code>categories</code> lists. - * - * @param activityActions the list which will receive the activity action values. - * @param broadcastActions the list which will receive the broadcast action values. - * @param serviceActions the list which will receive the service action values. - * @param categories the list which will receive the category values. - */ - private void collectIntentFilterActionsAndCategories(ArrayList<String> activityActions, - ArrayList<String> broadcastActions, - ArrayList<String> serviceActions, ArrayList<String> categories) { - collectValues(mAndroidTarget.getPath(IAndroidTarget.ACTIONS_ACTIVITY), - activityActions); - collectValues(mAndroidTarget.getPath(IAndroidTarget.ACTIONS_BROADCAST), - broadcastActions); - collectValues(mAndroidTarget.getPath(IAndroidTarget.ACTIONS_SERVICE), - serviceActions); - collectValues(mAndroidTarget.getPath(IAndroidTarget.CATEGORIES), - categories); - } - - /** - * Collects values from a text file located in the SDK - * @param osFilePath The path to the text file. - * @param values the {@link ArrayList} to fill with the values. - */ - private void collectValues(String osFilePath, ArrayList<String> values) { - FileReader fr = null; - BufferedReader reader = null; - try { - fr = new FileReader(osFilePath); - reader = new BufferedReader(fr); - - String line; - while ((line = reader.readLine()) != null) { - line = line.trim(); - if (line.length() > 0 && line.startsWith("#") == false) { //$NON-NLS-1$ - values.add(line); - } - } - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read SDK values"); //$NON-NLS-1$ - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read SDK values"); //$NON-NLS-1$ - } - - try { - if (fr != null) { - fr.close(); - } - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read SDK values"); //$NON-NLS-1$ - } - } - } - - /** - * Collects all layout classes information from the class loader and the - * attrs.xml and sets the corresponding structures in the resource manager. - * - * @param classLoader The framework SDK jar classloader in case we cannot get the widget from - * the platform directly - * @param attrsXmlParser The parser of the attrs.xml file - * @param mainList the Collection to receive the main list of {@link ViewClassInfo}. - * @param groupList the Collection to receive the group list of {@link ViewClassInfo}. - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - private void collectLayoutClasses(AndroidJarLoader classLoader, - AttrsXmlParser attrsXmlParser, - Collection<ViewClassInfo> mainList, - Collection<ViewClassInfo> groupList, - IProgressMonitor monitor) { - LayoutParamsParser ldp = null; - try { - WidgetClassLoader loader = new WidgetClassLoader( - mAndroidTarget.getPath(IAndroidTarget.WIDGETS)); - if (loader.parseWidgetList(monitor)) { - ldp = new LayoutParamsParser(loader, attrsXmlParser); - } - // if the parsing failed, we'll use the old loader below. - } catch (FileNotFoundException e) { - AdtPlugin.log(e, "Android Framework Parser"); //$NON-NLS-1$ - // the file does not exist, we'll use the old loader below. - } - - if (ldp == null) { - ldp = new LayoutParamsParser(classLoader, attrsXmlParser); - } - ldp.parseLayoutClasses(monitor); - - List<ViewClassInfo> views = ldp.getViews(); - List<ViewClassInfo> groups = ldp.getGroups(); - - if (views != null && groups != null) { - mainList.addAll(views); - groupList.addAll(groups); - } - } - - /** - * Collects all preferences definition information from the attrs.xml and - * sets the corresponding structures in the resource manager. - * - * @param classLoader The framework SDK jar classloader - * @param attrsXmlParser The parser of the attrs.xml file - * @param mainList the Collection to receive the main list of {@link ViewClassInfo}. - * @param groupList the Collection to receive the group list of {@link ViewClassInfo}. - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - private void collectPreferenceClasses(AndroidJarLoader classLoader, - AttrsXmlParser attrsXmlParser, Collection<ViewClassInfo> mainList, - Collection<ViewClassInfo> groupList, IProgressMonitor monitor) { - LayoutParamsParser ldp = new LayoutParamsParser(classLoader, attrsXmlParser); - - try { - ldp.parsePreferencesClasses(monitor); - - List<ViewClassInfo> prefs = ldp.getViews(); - List<ViewClassInfo> groups = ldp.getGroups(); - - if (prefs != null && groups != null) { - mainList.addAll(prefs); - groupList.addAll(groups); - } - } catch (NoClassDefFoundError e) { - AdtPlugin.logAndPrintError(e, TAG, - "Collect preferences failed, class %1$s not found in %2$s", - e.getMessage(), - classLoader.getSource()); - } catch (Throwable e) { - AdtPlugin.log(e, "Android Framework Parser: failed to collect preference classes"); //$NON-NLS-1$ - AdtPlugin.printErrorToConsole("Android Framework Parser", - "failed to collect preference classes"); - } - } - - /** - * Collects all menu definition information from the attrs.xml and returns it. - * - * @param attrsXmlParser The parser of the attrs.xml file - */ - private Map<String, DeclareStyleableInfo> collectMenuDefinitions( - AttrsXmlParser attrsXmlParser) { - Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList(); - Map<String, DeclareStyleableInfo> map2 = new HashMap<String, DeclareStyleableInfo>(); - for (String key : new String[] { "Menu", //$NON-NLS-1$ - "MenuItem", //$NON-NLS-1$ - "MenuGroup" }) { //$NON-NLS-1$ - if (map.containsKey(key)) { - map2.put(key, map.get(key)); - } else { - AdtPlugin.log(IStatus.WARNING, - "Menu declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath()); - AdtPlugin.printErrorToConsole("Android Framework Parser", - String.format("Menu declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath())); - } - } - - return Collections.unmodifiableMap(map2); - } - - /** - * Collects all searchable definition information from the attrs.xml and returns it. - * - * @param attrsXmlParser The parser of the attrs.xml file - */ - private Map<String, DeclareStyleableInfo> collectSearchableDefinitions( - AttrsXmlParser attrsXmlParser) { - Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList(); - Map<String, DeclareStyleableInfo> map2 = new HashMap<String, DeclareStyleableInfo>(); - for (String key : new String[] { "Searchable", //$NON-NLS-1$ - "SearchableActionKey" }) { //$NON-NLS-1$ - if (map.containsKey(key)) { - map2.put(key, map.get(key)); - } else { - AdtPlugin.log(IStatus.WARNING, - "Searchable declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath()); - AdtPlugin.printErrorToConsole("Android Framework Parser", - String.format("Searchable declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath())); - } - } - - return Collections.unmodifiableMap(map2); - } - - /** - * Collects all appWidgetProviderInfo definition information from the attrs.xml and returns it. - * - * @param attrsXmlParser The parser of the attrs.xml file - */ - private Map<String, DeclareStyleableInfo> collectAppWidgetDefinitions( - AttrsXmlParser attrsXmlParser) { - Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList(); - Map<String, DeclareStyleableInfo> map2 = new HashMap<String, DeclareStyleableInfo>(); - for (String key : new String[] { "AppWidgetProviderInfo" }) { //$NON-NLS-1$ - if (map.containsKey(key)) { - map2.put(key, map.get(key)); - } else { - AdtPlugin.log(IStatus.WARNING, - "AppWidget declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath()); - AdtPlugin.printErrorToConsole("Android Framework Parser", - String.format("AppWidget declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath())); - } - } - - return Collections.unmodifiableMap(map2); - } - - /** - * Collects all manifest definition information from the attrs_manifest.xml and returns it. - */ - private Map<String, DeclareStyleableInfo> collectManifestDefinitions( - AttrsXmlParser attrsXmlParser) { - - return attrsXmlParser.getDeclareStyleableList(); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/IAndroidClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/IAndroidClassLoader.java deleted file mode 100644 index ab78d2a9b..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/IAndroidClassLoader.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; - -import javax.management.InvalidAttributeValueException; - -/** - * Classes which implements this interface provide methods to access framework resource - * data loaded from the SDK. - */ -interface IAndroidClassLoader { - - /** - * Classes which implement this interface provide methods to describe a class. - */ - public interface IClassDescriptor { - - String getFullClassName(); - - IClassDescriptor getSuperclass(); - - String getSimpleName(); - - IClassDescriptor getEnclosingClass(); - - IClassDescriptor[] getDeclaredClasses(); - - boolean isInstantiable(); - } - - /** - * Finds and loads all classes that derive from a given set of super classes. - * - * @param rootPackage Root package of classes to find. Use an empty string to find everyting. - * @param superClasses The super classes of all the classes to find. - * @return An hash map which keys are the super classes looked for and which values are - * ArrayList of the classes found. The array lists are always created for all the - * valid keys, they are simply empty if no deriving class is found for a given - * super class. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - public HashMap<String, ArrayList<IClassDescriptor>> findClassesDerivingFrom( - String rootPackage, String[] superClasses) - throws IOException, InvalidAttributeValueException, ClassFormatError; - - /** - * Returns a {@link IClassDescriptor} by its fully-qualified name. - * @param className the fully-qualified name of the class to return. - * @throws ClassNotFoundException - */ - public IClassDescriptor getClass(String className) throws ClassNotFoundException; - - /** - * Returns a string indicating the source of the classes, typically for debugging - * or in error messages. This would typically be a JAR file name or some kind of - * identifier that would mean something to the user when looking at error messages. - * - * @return An informal string representing the source of the classes. - */ - public String getSource(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutParamsParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutParamsParser.java deleted file mode 100644 index d05c12a9e..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutParamsParser.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.SdkConstants; -import com.android.ide.common.resources.platform.AttrsXmlParser; -import com.android.ide.common.resources.platform.ViewClassInfo; -import com.android.ide.common.resources.platform.ViewClassInfo.LayoutParamsInfo; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.sdk.IAndroidClassLoader.IClassDescriptor; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.SubMonitor; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; - -import javax.management.InvalidAttributeValueException; - -/* - * TODO: refactor this. Could use some cleanup. - */ - -/** - * Parser for the framework library. - * <p/> - * This gather the following information: - * <ul> - * <li>Resource ID from <code>android.R</code></li> - * <li>The list of permissions values from <code>android.Manifest$permission</code></li> - * <li></li> - * </ul> - */ -public class LayoutParamsParser { - - /** - * Class extending {@link ViewClassInfo} by adding the notion of instantiability. - * {@link LayoutParamsParser#getViews()} and {@link LayoutParamsParser#getGroups()} should - * only return classes that can be instantiated. - */ - final static class ExtViewClassInfo extends ViewClassInfo { - - private boolean mIsInstantiable; - - ExtViewClassInfo(boolean instantiable, boolean isLayout, String canonicalClassName, - String shortClassName) { - super(isLayout, canonicalClassName, shortClassName); - mIsInstantiable = instantiable; - } - - boolean isInstantiable() { - return mIsInstantiable; - } - } - - /* Note: protected members/methods are overridden in unit tests */ - - /** Reference to android.view.View */ - protected IClassDescriptor mTopViewClass; - /** Reference to android.view.ViewGroup */ - protected IClassDescriptor mTopGroupClass; - /** Reference to android.view.ViewGroup$LayoutParams */ - protected IClassDescriptor mTopLayoutParamsClass; - - /** Input list of all classes deriving from android.view.View */ - protected ArrayList<IClassDescriptor> mViewList; - /** Input list of all classes deriving from android.view.ViewGroup */ - protected ArrayList<IClassDescriptor> mGroupList; - - /** Output map of FQCN => info on View classes */ - protected TreeMap<String, ExtViewClassInfo> mViewMap; - /** Output map of FQCN => info on ViewGroup classes */ - protected TreeMap<String, ExtViewClassInfo> mGroupMap; - /** Output map of FQCN => info on LayoutParams classes */ - protected HashMap<String, LayoutParamsInfo> mLayoutParamsMap; - - /** The attrs.xml parser */ - protected AttrsXmlParser mAttrsXmlParser; - - /** The android.jar class loader */ - protected IAndroidClassLoader mClassLoader; - - /** - * Instantiate a new LayoutParamsParser. - * @param classLoader The android.jar class loader - * @param attrsXmlParser The parser of the attrs.xml file - */ - public LayoutParamsParser(IAndroidClassLoader classLoader, - AttrsXmlParser attrsXmlParser) { - mClassLoader = classLoader; - mAttrsXmlParser = attrsXmlParser; - } - - /** Returns the map of FQCN => info on View classes */ - public List<ViewClassInfo> getViews() { - return getInstantiables(mViewMap); - } - - /** Returns the map of FQCN => info on ViewGroup classes */ - public List<ViewClassInfo> getGroups() { - return getInstantiables(mGroupMap); - } - - /** - * TODO: doc here. - * <p/> - * Note: on output we should have NO dependency on {@link IClassDescriptor}, - * otherwise we wouldn't be able to unload the class loader later. - * <p/> - * Note on Vocabulary: FQCN=Fully Qualified Class Name (e.g. "my.package.class$innerClass") - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - public void parseLayoutClasses(IProgressMonitor monitor) { - parseClasses(monitor, - SdkConstants.CLASS_VIEW, - SdkConstants.CLASS_VIEWGROUP, - SdkConstants.CLASS_VIEWGROUP_LAYOUTPARAMS); - } - - public void parsePreferencesClasses(IProgressMonitor monitor) { - parseClasses(monitor, - SdkConstants.CLASS_PREFERENCE, - SdkConstants.CLASS_PREFERENCEGROUP, - null /* paramsClassName */ ); - } - - private void parseClasses(IProgressMonitor monitor, - String rootClassName, - String groupClassName, - String paramsClassName) { - try { - SubMonitor progress = SubMonitor.convert(monitor, 100); - - String[] superClasses = new String[2 + (paramsClassName == null ? 0 : 1)]; - superClasses[0] = groupClassName; - superClasses[1] = rootClassName; - if (paramsClassName != null) { - superClasses[2] = paramsClassName; - } - HashMap<String, ArrayList<IClassDescriptor>> found = - mClassLoader.findClassesDerivingFrom("android.", superClasses); //$NON-NLS-1$ - mTopViewClass = mClassLoader.getClass(rootClassName); - mTopGroupClass = mClassLoader.getClass(groupClassName); - if (paramsClassName != null) { - mTopLayoutParamsClass = mClassLoader.getClass(paramsClassName); - } - - mViewList = found.get(rootClassName); - mGroupList = found.get(groupClassName); - - mViewMap = new TreeMap<String, ExtViewClassInfo>(); - mGroupMap = new TreeMap<String, ExtViewClassInfo>(); - if (mTopLayoutParamsClass != null) { - mLayoutParamsMap = new HashMap<String, LayoutParamsInfo>(); - } - - // Add top classes to the maps since by design they are not listed in classes deriving - // from themselves. - if (mTopGroupClass != null) { - addGroup(mTopGroupClass); - } - if (mTopViewClass != null) { - addView(mTopViewClass); - } - - // ViewGroup derives from View - ExtViewClassInfo vg = mGroupMap.get(groupClassName); - if (vg != null) { - vg.setSuperClass(mViewMap.get(rootClassName)); - } - - progress.setWorkRemaining(mGroupList.size() + mViewList.size()); - - for (IClassDescriptor groupChild : mGroupList) { - addGroup(groupChild); - progress.worked(1); - } - - for (IClassDescriptor viewChild : mViewList) { - if (viewChild != mTopGroupClass) { - addView(viewChild); - } - progress.worked(1); - } - } catch (ClassNotFoundException e) { - AdtPlugin.log(e, "Problem loading class %1$s or %2$s", //$NON-NLS-1$ - rootClassName, groupClassName); - } catch (InvalidAttributeValueException e) { - AdtPlugin.log(e, "Problem loading classes"); //$NON-NLS-1$ - } catch (ClassFormatError e) { - AdtPlugin.log(e, "Problem loading classes"); //$NON-NLS-1$ - } catch (IOException e) { - AdtPlugin.log(e, "Problem loading classes"); //$NON-NLS-1$ - } - } - - /** - * Parses a View class and adds a ExtViewClassInfo for it in mViewMap. - * It calls itself recursively to handle super classes which are also Views. - */ - private ExtViewClassInfo addView(IClassDescriptor viewClass) { - String fqcn = viewClass.getFullClassName(); - if (mViewMap.containsKey(fqcn)) { - return mViewMap.get(fqcn); - } else if (mGroupMap.containsKey(fqcn)) { - return mGroupMap.get(fqcn); - } - - ExtViewClassInfo info = new ExtViewClassInfo(viewClass.isInstantiable(), - false /* layout */, fqcn, viewClass.getSimpleName()); - mViewMap.put(fqcn, info); - - // All view classes derive from mTopViewClass by design. - // Do not lookup the super class for mTopViewClass itself. - if (viewClass.equals(mTopViewClass) == false) { - IClassDescriptor superClass = viewClass.getSuperclass(); - ExtViewClassInfo superClassInfo = addView(superClass); - info.setSuperClass(superClassInfo); - } - - mAttrsXmlParser.loadViewAttributes(info); - return info; - } - - /** - * Parses a ViewGroup class and adds a ExtViewClassInfo for it in mGroupMap. - * It calls itself recursively to handle super classes which are also ViewGroups. - */ - private ExtViewClassInfo addGroup(IClassDescriptor groupClass) { - String fqcn = groupClass.getFullClassName(); - if (mGroupMap.containsKey(fqcn)) { - return mGroupMap.get(fqcn); - } - - ExtViewClassInfo info = new ExtViewClassInfo(groupClass.isInstantiable(), - true /* layout */, fqcn, groupClass.getSimpleName()); - mGroupMap.put(fqcn, info); - - // All groups derive from android.view.ViewGroup, which in turns derives from - // android.view.View (i.e. mTopViewClass here). So the only group that can have View as - // its super class is the ViewGroup base class and we don't try to resolve it since groups - // are loaded before views. - IClassDescriptor superClass = groupClass.getSuperclass(); - - // Assertion: at this point, we should have - // superClass != mTopViewClass || fqcn.equals(SdkConstants.CLASS_VIEWGROUP); - - if (superClass != null && superClass.equals(mTopViewClass) == false) { - ExtViewClassInfo superClassInfo = addGroup(superClass); - - // Assertion: we should have superClassInfo != null && superClassInfo != info; - if (superClassInfo != null && superClassInfo != info) { - info.setSuperClass(superClassInfo); - } - } - - mAttrsXmlParser.loadViewAttributes(info); - if (mTopLayoutParamsClass != null) { - info.setLayoutParams(addLayoutParams(groupClass)); - } - return info; - } - - /** - * Parses a ViewGroup class and returns an info object on its inner LayoutParams. - * - * @return The {@link LayoutParamsInfo} for the ViewGroup class or null. - */ - private LayoutParamsInfo addLayoutParams(IClassDescriptor groupClass) { - - // Is there a LayoutParams in this group class? - IClassDescriptor layoutParamsClass = findLayoutParams(groupClass); - - // if there's no layout data in the group class, link to the one from the - // super class. - if (layoutParamsClass == null) { - for (IClassDescriptor superClass = groupClass.getSuperclass(); - layoutParamsClass == null && - superClass != null && - superClass.equals(mTopViewClass) == false; - superClass = superClass.getSuperclass()) { - layoutParamsClass = findLayoutParams(superClass); - } - } - - if (layoutParamsClass != null) { - return getLayoutParamsInfo(layoutParamsClass); - } - - return null; - } - - /** - * Parses a LayoutParams class and returns a LayoutParamsInfo object for it. - * It calls itself recursively to handle the super class of the LayoutParams. - */ - private LayoutParamsInfo getLayoutParamsInfo(IClassDescriptor layoutParamsClass) { - String fqcn = layoutParamsClass.getFullClassName(); - LayoutParamsInfo layoutParamsInfo = mLayoutParamsMap.get(fqcn); - - if (layoutParamsInfo != null) { - return layoutParamsInfo; - } - - // Find the link on the LayoutParams super class - LayoutParamsInfo superClassInfo = null; - if (layoutParamsClass.equals(mTopLayoutParamsClass) == false) { - IClassDescriptor superClass = layoutParamsClass.getSuperclass(); - superClassInfo = getLayoutParamsInfo(superClass); - } - - // Find the link on the enclosing ViewGroup - ExtViewClassInfo enclosingGroupInfo = addGroup(layoutParamsClass.getEnclosingClass()); - - layoutParamsInfo = new ExtViewClassInfo.LayoutParamsInfo( - enclosingGroupInfo, layoutParamsClass.getSimpleName(), superClassInfo); - mLayoutParamsMap.put(fqcn, layoutParamsInfo); - - mAttrsXmlParser.loadLayoutParamsAttributes(layoutParamsInfo); - - return layoutParamsInfo; - } - - /** - * Given a ViewGroup-derived class, looks for an inner class named LayoutParams - * and if found returns its class definition. - * <p/> - * This uses the actual defined inner classes and does not look at inherited classes. - * - * @param groupClass The ViewGroup derived class - * @return The Class of the inner LayoutParams or null if none is declared. - */ - private IClassDescriptor findLayoutParams(IClassDescriptor groupClass) { - IClassDescriptor[] innerClasses = groupClass.getDeclaredClasses(); - for (IClassDescriptor innerClass : innerClasses) { - if (innerClass.getSimpleName().equals(SdkConstants.CLASS_NAME_LAYOUTPARAMS)) { - return innerClass; - } - } - return null; - } - - /** - * Computes and return a list of ViewClassInfo from a map by filtering out the class that - * cannot be instantiated. - */ - private List<ViewClassInfo> getInstantiables(SortedMap<String, ExtViewClassInfo> map) { - Collection<ExtViewClassInfo> values = map.values(); - ArrayList<ViewClassInfo> list = new ArrayList<ViewClassInfo>(); - - for (ExtViewClassInfo info : values) { - if (info.isInstantiable()) { - list.add(info); - } - } - - return list; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/ProjectState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/ProjectState.java deleted file mode 100644 index 74c985784..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/ProjectState.java +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.internal.project.ProjectProperties; -import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; - -/** - * Centralized state for Android Eclipse project. - * <p>This gives raw access to the properties (from <code>project.properties</code>), as well - * as direct access to target and library information. - * - * This also gives access to library information. - * - * {@link #isLibrary()} indicates if the project is a library. - * {@link #hasLibraries()} and {@link #getLibraries()} give access to the libraries through - * instances of {@link LibraryState}. A {@link LibraryState} instance is a link between a main - * project and its library. Theses instances are owned by the {@link ProjectState}. - * - * {@link #isMissingLibraries()} will indicate if the project has libraries that are not resolved. - * Unresolved libraries are libraries that do not have any matching opened Eclipse project. - * When there are missing libraries, the {@link LibraryState} instance for them will return null - * for {@link LibraryState#getProjectState()}. - * - */ -public final class ProjectState { - - /** - * A class that represents a library linked to a project. - * <p/>It does not represent the library uniquely. Instead the {@link LibraryState} is linked - * to the main project which is accessible through {@link #getMainProjectState()}. - * <p/>If a library is used by two different projects, then there will be two different - * instances of {@link LibraryState} for the library. - * - * @see ProjectState#getLibrary(IProject) - */ - public final class LibraryState { - private String mRelativePath; - private ProjectState mProjectState; - private String mPath; - - private LibraryState(String relativePath) { - mRelativePath = relativePath; - } - - /** - * Returns the {@link ProjectState} of the main project using this library. - */ - public ProjectState getMainProjectState() { - return ProjectState.this; - } - - /** - * Closes the library. This resets the IProject from this object ({@link #getProjectState()} will - * return <code>null</code>), and updates the main project data so that the library - * {@link IProject} object does not show up in the return value of - * {@link ProjectState#getFullLibraryProjects()}. - */ - public void close() { - mProjectState.removeParentProject(getMainProjectState()); - mProjectState = null; - mPath = null; - - getMainProjectState().updateFullLibraryList(); - } - - private void setRelativePath(String relativePath) { - mRelativePath = relativePath; - } - - private void setProject(ProjectState project) { - mProjectState = project; - mPath = project.getProject().getLocation().toOSString(); - mProjectState.addParentProject(getMainProjectState()); - - getMainProjectState().updateFullLibraryList(); - } - - /** - * Returns the relative path of the library from the main project. - * <p/>This is identical to the value defined in the main project's project.properties. - */ - public String getRelativePath() { - return mRelativePath; - } - - /** - * Returns the {@link ProjectState} item for the library. This can be null if the project - * is not actually opened in Eclipse. - */ - public ProjectState getProjectState() { - return mProjectState; - } - - /** - * Returns the OS-String location of the library project. - * <p/>This is based on location of the Eclipse project that matched - * {@link #getRelativePath()}. - * - * @return The project location, or null if the project is not opened in Eclipse. - */ - public String getProjectLocation() { - return mPath; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof LibraryState) { - // the only thing that's always non-null is the relative path. - LibraryState objState = (LibraryState)obj; - return mRelativePath.equals(objState.mRelativePath) && - getMainProjectState().equals(objState.getMainProjectState()); - } else if (obj instanceof ProjectState || obj instanceof IProject) { - return mProjectState != null && mProjectState.equals(obj); - } else if (obj instanceof String) { - return normalizePath(mRelativePath).equals(normalizePath((String) obj)); - } - - return false; - } - - @Override - public int hashCode() { - return normalizePath(mRelativePath).hashCode(); - } - } - - private final IProject mProject; - private final ProjectProperties mProperties; - private IAndroidTarget mTarget; - private BuildToolInfo mBuildToolInfo; - - /** - * list of libraries. Access to this list must be protected by - * <code>synchronized(mLibraries)</code>, but it is important that such code do not call - * out to other classes (especially those protected by {@link Sdk#getLock()}.) - */ - private final ArrayList<LibraryState> mLibraries = new ArrayList<LibraryState>(); - /** Cached list of all IProject instances representing the resolved libraries, including - * indirect dependencies. This must never be null. */ - private List<IProject> mLibraryProjects = Collections.emptyList(); - /** - * List of parent projects. When this instance is a library ({@link #isLibrary()} returns - * <code>true</code>) then this is filled with projects that depends on this project. - */ - private final ArrayList<ProjectState> mParentProjects = new ArrayList<ProjectState>(); - - ProjectState(IProject project, ProjectProperties properties) { - if (project == null || properties == null) { - throw new NullPointerException(); - } - - mProject = project; - mProperties = properties; - - // load the libraries - synchronized (mLibraries) { - int index = 1; - while (true) { - String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); - String rootPath = mProperties.getProperty(propName); - - if (rootPath == null) { - break; - } - - mLibraries.add(new LibraryState(convertPath(rootPath))); - } - } - } - - public IProject getProject() { - return mProject; - } - - public ProjectProperties getProperties() { - return mProperties; - } - - public @Nullable String getProperty(@NonNull String name) { - if (mProperties != null) { - return mProperties.getProperty(name); - } - - return null; - } - - public void setTarget(IAndroidTarget target) { - mTarget = target; - } - - /** - * Returns the project's target's hash string. - * <p/>If {@link #getTarget()} returns a valid object, then this returns the value of - * {@link IAndroidTarget#hashString()}. - * <p/>Otherwise this will return the value of the property - * {@link ProjectProperties#PROPERTY_TARGET} from {@link #getProperties()} (if valid). - * @return the target hash string or null if not found. - */ - public String getTargetHashString() { - if (mTarget != null) { - return mTarget.hashString(); - } - - return mProperties.getProperty(ProjectProperties.PROPERTY_TARGET); - } - - public IAndroidTarget getTarget() { - return mTarget; - } - - public void setBuildToolInfo(BuildToolInfo buildToolInfo) { - mBuildToolInfo = buildToolInfo; - } - - public BuildToolInfo getBuildToolInfo() { - return mBuildToolInfo; - } - - /** - * Returns the build tools version from the project's properties. - * @return the value or null - */ - @Nullable - public String getBuildToolInfoVersion() { - return mProperties.getProperty(ProjectProperties.PROPERTY_BUILD_TOOLS); - } - - public boolean getRenderScriptSupportMode() { - String supportModeValue = mProperties.getProperty(ProjectProperties.PROPERTY_RS_SUPPORT); - if (supportModeValue != null) { - return Boolean.parseBoolean(supportModeValue); - } - - return false; - } - - public static class LibraryDifference { - public boolean removed = false; - public boolean added = false; - - public boolean hasDiff() { - return removed || added; - } - } - - /** - * Reloads the content of the properties. - * <p/>This also reset the reference to the target as it may have changed, therefore this - * should be followed by a call to {@link Sdk#loadTarget(ProjectState)}. - * - * <p/>If the project libraries changes, they are updated to a certain extent.<br> - * Removed libraries are removed from the state list, and added to the {@link LibraryDifference} - * object that is returned so that they can be processed.<br> - * Added libraries are added to the state (as new {@link LibraryState} objects), but their - * IProject is not resolved. {@link ProjectState#needs(ProjectState)} should be called - * afterwards to properly initialize the libraries. - * - * @return an instance of {@link LibraryDifference} describing the change in libraries. - */ - public LibraryDifference reloadProperties() { - mTarget = null; - mProperties.reload(); - - // compare/reload the libraries. - - // if the order change it won't impact the java part, so instead try to detect removed/added - // libraries. - - LibraryDifference diff = new LibraryDifference(); - - synchronized (mLibraries) { - List<LibraryState> oldLibraries = new ArrayList<LibraryState>(mLibraries); - mLibraries.clear(); - - // load the libraries - int index = 1; - while (true) { - String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); - String rootPath = mProperties.getProperty(propName); - - if (rootPath == null) { - break; - } - - // search for a library with the same path (not exact same string, but going - // to the same folder). - String convertedPath = convertPath(rootPath); - boolean found = false; - for (int i = 0 ; i < oldLibraries.size(); i++) { - LibraryState libState = oldLibraries.get(i); - if (libState.equals(convertedPath)) { - // it's a match. move it back to mLibraries and remove it from the - // old library list. - found = true; - mLibraries.add(libState); - oldLibraries.remove(i); - break; - } - } - - if (found == false) { - diff.added = true; - mLibraries.add(new LibraryState(convertedPath)); - } - } - - // whatever's left in oldLibraries is removed. - diff.removed = oldLibraries.size() > 0; - - // update the library with what IProjet are known at the time. - updateFullLibraryList(); - } - - return diff; - } - - /** - * Returns the list of {@link LibraryState}. - */ - public List<LibraryState> getLibraries() { - synchronized (mLibraries) { - return Collections.unmodifiableList(mLibraries); - } - } - - /** - * Returns all the <strong>resolved</strong> library projects, including indirect dependencies. - * The list is ordered to match the library priority order for resource processing with - * <code>aapt</code>. - * <p/>If some dependencies are not resolved (or their projects is not opened in Eclipse), - * they will not show up in this list. - * @return the resolved projects as an unmodifiable list. May be an empty. - */ - public List<IProject> getFullLibraryProjects() { - return mLibraryProjects; - } - - /** - * Returns whether this is a library project. - */ - public boolean isLibrary() { - String value = mProperties.getProperty(ProjectProperties.PROPERTY_LIBRARY); - return value != null && Boolean.valueOf(value); - } - - /** - * Returns whether the project depends on one or more libraries. - */ - public boolean hasLibraries() { - synchronized (mLibraries) { - return mLibraries.size() > 0; - } - } - - /** - * Returns whether the project is missing some required libraries. - */ - public boolean isMissingLibraries() { - synchronized (mLibraries) { - for (LibraryState state : mLibraries) { - if (state.getProjectState() == null) { - return true; - } - } - } - - return false; - } - - /** - * Returns the {@link LibraryState} object for a given {@link IProject}. - * </p>This can only return a non-null object if the link between the main project's - * {@link IProject} and the library's {@link IProject} was done. - * - * @return the matching LibraryState or <code>null</code> - * - * @see #needs(ProjectState) - */ - public LibraryState getLibrary(IProject library) { - synchronized (mLibraries) { - for (LibraryState state : mLibraries) { - ProjectState ps = state.getProjectState(); - if (ps != null && ps.getProject().equals(library)) { - return state; - } - } - } - - return null; - } - - /** - * Returns the {@link LibraryState} object for a given <var>name</var>. - * </p>This can only return a non-null object if the link between the main project's - * {@link IProject} and the library's {@link IProject} was done. - * - * @return the matching LibraryState or <code>null</code> - * - * @see #needs(IProject) - */ - public LibraryState getLibrary(String name) { - synchronized (mLibraries) { - for (LibraryState state : mLibraries) { - ProjectState ps = state.getProjectState(); - if (ps != null && ps.getProject().getName().equals(name)) { - return state; - } - } - } - - return null; - } - - - /** - * Returns whether a given library project is needed by the receiver. - * <p/>If the library is needed, this finds the matching {@link LibraryState}, initializes it - * so that it contains the library's {@link IProject} object (so that - * {@link LibraryState#getProjectState()} does not return null) and then returns it. - * - * @param libraryProject the library project to check. - * @return a non null object if the project is a library dependency, - * <code>null</code> otherwise. - * - * @see LibraryState#getProjectState() - */ - public LibraryState needs(ProjectState libraryProject) { - // compute current location - File projectFile = mProject.getLocation().toFile(); - - // get the location of the library. - File libraryFile = libraryProject.getProject().getLocation().toFile(); - - // loop on all libraries and check if the path match - synchronized (mLibraries) { - for (LibraryState state : mLibraries) { - if (state.getProjectState() == null) { - File library = new File(projectFile, state.getRelativePath()); - try { - File absPath = library.getCanonicalFile(); - if (absPath.equals(libraryFile)) { - state.setProject(libraryProject); - return state; - } - } catch (IOException e) { - // ignore this library - } - } - } - } - - return null; - } - - /** - * Returns whether the project depends on a given <var>library</var> - * @param library the library to check. - * @return true if the project depends on the library. This is not affected by whether the link - * was done through {@link #needs(ProjectState)}. - */ - public boolean dependsOn(ProjectState library) { - synchronized (mLibraries) { - for (LibraryState state : mLibraries) { - if (state != null && state.getProjectState() != null && - library.getProject().equals(state.getProjectState().getProject())) { - return true; - } - } - } - - return false; - } - - - /** - * Updates a library with a new path. - * <p/>This method acts both as a check and an action. If the project does not depend on the - * given <var>oldRelativePath</var> then no action is done and <code>null</code> is returned. - * <p/>If the project depends on the library, then the project is updated with the new path, - * and the {@link LibraryState} for the library is returned. - * <p/>Updating the project does two things:<ul> - * <li>Update LibraryState with new relative path and new {@link IProject} object.</li> - * <li>Update the main project's <code>project.properties</code> with the new relative path - * for the changed library.</li> - * </ul> - * - * @param oldRelativePath the old library path relative to this project - * @param newRelativePath the new library path relative to this project - * @param newLibraryState the new {@link ProjectState} object. - * @return a non null object if the project depends on the library. - * - * @see LibraryState#getProjectState() - */ - public LibraryState updateLibrary(String oldRelativePath, String newRelativePath, - ProjectState newLibraryState) { - // compute current location - File projectFile = mProject.getLocation().toFile(); - - // loop on all libraries and check if the path matches - synchronized (mLibraries) { - for (LibraryState state : mLibraries) { - if (state.getProjectState() == null) { - try { - // oldRelativePath may not be the same exact string as the - // one in the project properties (trailing separator could be different - // for instance). - // Use java.io.File to deal with this and also do a platform-dependent - // path comparison - File library1 = new File(projectFile, oldRelativePath); - File library2 = new File(projectFile, state.getRelativePath()); - if (library1.getCanonicalPath().equals(library2.getCanonicalPath())) { - // save the exact property string to replace. - String oldProperty = state.getRelativePath(); - - // then update the LibraryPath. - state.setRelativePath(newRelativePath); - state.setProject(newLibraryState); - - // update the project.properties file - IStatus status = replaceLibraryProperty(oldProperty, newRelativePath); - if (status != null) { - if (status.getSeverity() != IStatus.OK) { - // log the error somehow. - } - } else { - // This should not happen since the library wouldn't be here in the - // first place - } - - // return the LibraryState object. - return state; - } - } catch (IOException e) { - // ignore this library - } - } - } - } - - return null; - } - - - private void addParentProject(ProjectState parentState) { - mParentProjects.add(parentState); - } - - private void removeParentProject(ProjectState parentState) { - mParentProjects.remove(parentState); - } - - public List<ProjectState> getParentProjects() { - return Collections.unmodifiableList(mParentProjects); - } - - /** - * Computes the transitive closure of projects referencing this project as a - * library project - * - * @return a collection (in any order) of project states for projects that - * directly or indirectly include this project state's project as a - * library project - */ - public Collection<ProjectState> getFullParentProjects() { - Set<ProjectState> result = new HashSet<ProjectState>(); - addParentProjects(result, this); - return result; - } - - /** Adds all parent projects of the given project, transitively, into the given parent set */ - private static void addParentProjects(Set<ProjectState> parents, ProjectState state) { - for (ProjectState s : state.mParentProjects) { - if (!parents.contains(s)) { - parents.add(s); - addParentProjects(parents, s); - } - } - } - - /** - * Update the value of a library dependency. - * <p/>This loops on all current dependency looking for the value to replace and then replaces - * it. - * <p/>This both updates the in-memory {@link #mProperties} values and on-disk - * project.properties file. - * @param oldValue the old value to replace - * @param newValue the new value to set. - * @return the status of the replacement. If null, no replacement was done (value not found). - */ - private IStatus replaceLibraryProperty(String oldValue, String newValue) { - int index = 1; - while (true) { - String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); - String rootPath = mProperties.getProperty(propName); - - if (rootPath == null) { - break; - } - - if (rootPath.equals(oldValue)) { - // need to update the properties. Get a working copy to change it and save it on - // disk since ProjectProperties is read-only. - ProjectPropertiesWorkingCopy workingCopy = mProperties.makeWorkingCopy(); - workingCopy.setProperty(propName, newValue); - try { - workingCopy.save(); - - // reload the properties with the new values from the disk. - mProperties.reload(); - } catch (Exception e) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format( - "Failed to save %1$s for project %2$s", - mProperties.getType() .getFilename(), mProject.getName()), - e); - - } - return Status.OK_STATUS; - } - } - - return null; - } - - /** - * Update the full library list, including indirect dependencies. The result is returned by - * {@link #getFullLibraryProjects()}. - */ - void updateFullLibraryList() { - ArrayList<IProject> list = new ArrayList<IProject>(); - synchronized (mLibraries) { - buildFullLibraryDependencies(mLibraries, list); - } - - mLibraryProjects = Collections.unmodifiableList(list); - } - - /** - * Resolves a given list of libraries, finds out if they depend on other libraries, and - * returns a full list of all the direct and indirect dependencies in the proper order (first - * is higher priority when calling aapt). - * @param inLibraries the libraries to resolve - * @param outLibraries where to store all the libraries. - */ - private void buildFullLibraryDependencies(List<LibraryState> inLibraries, - ArrayList<IProject> outLibraries) { - // loop in the inverse order to resolve dependencies on the libraries, so that if a library - // is required by two higher level libraries it can be inserted in the correct place - for (int i = inLibraries.size() - 1 ; i >= 0 ; i--) { - LibraryState library = inLibraries.get(i); - - // get its libraries if possible - ProjectState libProjectState = library.getProjectState(); - if (libProjectState != null) { - List<LibraryState> dependencies = libProjectState.getLibraries(); - - // build the dependencies for those libraries - buildFullLibraryDependencies(dependencies, outLibraries); - - // and add the current library (if needed) in front (higher priority) - if (outLibraries.contains(libProjectState.getProject()) == false) { - outLibraries.add(0, libProjectState.getProject()); - } - } - } - } - - - /** - * Converts a path containing only / by the proper platform separator. - */ - private String convertPath(String path) { - return path.replaceAll("/", Matcher.quoteReplacement(File.separator)); //$NON-NLS-1$ - } - - /** - * Normalizes a relative path. - */ - private String normalizePath(String path) { - path = convertPath(path); - if (path.endsWith("/")) { //$NON-NLS-1$ - path = path.substring(0, path.length() - 1); - } - return path; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ProjectState) { - return mProject.equals(((ProjectState) obj).mProject); - } else if (obj instanceof IProject) { - return mProject.equals(obj); - } - - return false; - } - - @Override - public int hashCode() { - return mProject.hashCode(); - } - - @Override - public String toString() { - return mProject.getName(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java deleted file mode 100644 index 7ff06fc40..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java +++ /dev/null @@ -1,1620 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import static com.android.SdkConstants.DOT_XML; -import static com.android.SdkConstants.EXT_JAR; -import static com.android.SdkConstants.FD_RES; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ddmlib.IDevice; -import com.android.ide.common.rendering.LayoutLibrary; -import com.android.ide.common.sdk.LoadStatus; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.build.DexWrapper; -import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.LibraryClasspathContainerInitializer; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor; -import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener; -import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IProjectListener; -import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IResourceEventListener; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryDifference; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryState; -import com.android.io.StreamException; -import com.android.prefs.AndroidLocation.AndroidLocationException; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkManager; -import com.android.sdklib.devices.DeviceManager; -import com.android.sdklib.internal.avd.AvdManager; -import com.android.sdklib.internal.project.ProjectProperties; -import com.android.sdklib.internal.project.ProjectProperties.PropertyType; -import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy; -import com.android.sdklib.repository.FullRevision; -import com.android.utils.ILogger; -import com.google.common.collect.Maps; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.ui.IEditorDescriptor; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPartSite; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.ide.IDE; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used - * at the same time. - * - * To start using an SDK, call {@link #loadSdk(String)} which returns the instance of - * the Sdk object. - * - * To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}. - */ -public final class Sdk { - private final static boolean DEBUG = false; - - private final static Object LOCK = new Object(); - - private static Sdk sCurrentSdk = null; - - /** - * Map associating {@link IProject} and their state {@link ProjectState}. - * <p/>This <b>MUST NOT</b> be accessed directly. Instead use {@link #getProjectState(IProject)}. - */ - private final static HashMap<IProject, ProjectState> sProjectStateMap = - new HashMap<IProject, ProjectState>(); - - /** - * Data bundled using during the load of Target data. - * <p/>This contains the {@link LoadStatus} and a list of projects that attempted - * to compile before the loading was finished. Those projects will be recompiled - * at the end of the loading. - */ - private final static class TargetLoadBundle { - LoadStatus status; - final HashSet<IJavaProject> projectsToReload = new HashSet<IJavaProject>(); - } - - private final SdkManager mManager; - private final Map<String, DexWrapper> mDexWrappers = Maps.newHashMap(); - private final AvdManager mAvdManager; - private final DeviceManager mDeviceManager; - - /** Map associating an {@link IAndroidTarget} to an {@link AndroidTargetData} */ - private final HashMap<IAndroidTarget, AndroidTargetData> mTargetDataMap = - new HashMap<IAndroidTarget, AndroidTargetData>(); - /** Map associating an {@link IAndroidTarget} and its {@link TargetLoadBundle}. */ - private final HashMap<IAndroidTarget, TargetLoadBundle> mTargetDataStatusMap = - new HashMap<IAndroidTarget, TargetLoadBundle>(); - - /** - * If true the target data will never load anymore. The only way to reload them is to - * completely reload the SDK with {@link #loadSdk(String)} - */ - private boolean mDontLoadTargetData = false; - - private final String mDocBaseUrl; - - /** - * Classes implementing this interface will receive notification when targets are changed. - */ - public interface ITargetChangeListener { - /** - * Sent when project has its target changed. - */ - void onProjectTargetChange(IProject changedProject); - - /** - * Called when the targets are loaded (either the SDK finished loading when Eclipse starts, - * or the SDK is changed). - */ - void onTargetLoaded(IAndroidTarget target); - - /** - * Called when the base content of the SDK is parsed. - */ - void onSdkLoaded(); - } - - /** - * Basic abstract implementation of the ITargetChangeListener for the case where both - * {@link #onProjectTargetChange(IProject)} and {@link #onTargetLoaded(IAndroidTarget)} - * use the same code based on a simple test requiring to know the current IProject. - */ - public static abstract class TargetChangeListener implements ITargetChangeListener { - /** - * Returns the {@link IProject} associated with the listener. - */ - public abstract IProject getProject(); - - /** - * Called when the listener needs to take action on the event. This is only called - * if {@link #getProject()} and the {@link IAndroidTarget} associated with the project - * match the values received in {@link #onProjectTargetChange(IProject)} and - * {@link #onTargetLoaded(IAndroidTarget)}. - */ - public abstract void reload(); - - @Override - public void onProjectTargetChange(IProject changedProject) { - if (changedProject != null && changedProject.equals(getProject())) { - reload(); - } - } - - @Override - public void onTargetLoaded(IAndroidTarget target) { - IProject project = getProject(); - if (target != null && target.equals(Sdk.getCurrent().getTarget(project))) { - reload(); - } - } - - @Override - public void onSdkLoaded() { - // do nothing; - } - } - - /** - * Returns the lock object used to synchronize all operations dealing with SDK, targets and - * projects. - */ - @NonNull - public static final Object getLock() { - return LOCK; - } - - /** - * Loads an SDK and returns an {@link Sdk} object if success. - * <p/>If the SDK failed to load, it displays an error to the user. - * @param sdkLocation the OS path to the SDK. - */ - @Nullable - public static Sdk loadSdk(String sdkLocation) { - synchronized (LOCK) { - if (sCurrentSdk != null) { - sCurrentSdk.dispose(); - sCurrentSdk = null; - } - - final AtomicBoolean hasWarning = new AtomicBoolean(); - final AtomicBoolean hasError = new AtomicBoolean(); - final ArrayList<String> logMessages = new ArrayList<String>(); - ILogger log = new ILogger() { - @Override - public void error(@Nullable Throwable throwable, @Nullable String errorFormat, - Object... arg) { - hasError.set(true); - if (errorFormat != null) { - logMessages.add(String.format("Error: " + errorFormat, arg)); - } - - if (throwable != null) { - logMessages.add(throwable.getMessage()); - } - } - - @Override - public void warning(@NonNull String warningFormat, Object... arg) { - hasWarning.set(true); - logMessages.add(String.format("Warning: " + warningFormat, arg)); - } - - @Override - public void info(@NonNull String msgFormat, Object... arg) { - logMessages.add(String.format(msgFormat, arg)); - } - - @Override - public void verbose(@NonNull String msgFormat, Object... arg) { - info(msgFormat, arg); - } - }; - - // get an SdkManager object for the location - SdkManager manager = SdkManager.createManager(sdkLocation, log); - try { - if (manager == null) { - hasError.set(true); - } else { - // create the AVD Manager - AvdManager avdManager = null; - try { - avdManager = AvdManager.getInstance(manager.getLocalSdk(), log); - } catch (AndroidLocationException e) { - log.error(e, "Error parsing the AVDs"); - } - sCurrentSdk = new Sdk(manager, avdManager); - return sCurrentSdk; - } - } finally { - if (hasError.get() || hasWarning.get()) { - StringBuilder sb = new StringBuilder( - String.format("%s when loading the SDK:\n", - hasError.get() ? "Error" : "Warning")); - for (String msg : logMessages) { - sb.append('\n'); - sb.append(msg); - } - if (hasError.get()) { - AdtPlugin.printErrorToConsole("Android SDK", sb.toString()); - AdtPlugin.displayError("Android SDK", sb.toString()); - } else { - AdtPlugin.printToConsole("Android SDK", sb.toString()); - } - } - } - return null; - } - } - - /** - * Returns the current {@link Sdk} object. - */ - @Nullable - public static Sdk getCurrent() { - synchronized (LOCK) { - return sCurrentSdk; - } - } - - /** - * Returns the location of the current SDK as an OS path string. - * Guaranteed to be terminated by a platform-specific path separator. - * <p/> - * Due to {@link File} canonicalization, this MAY differ from the string used to initialize - * the SDK path. - * - * @return The SDK OS path or null if no SDK is setup. - * @deprecated Consider using {@link #getSdkFileLocation()} instead. - * @see #getSdkFileLocation() - */ - @Deprecated - @Nullable - public String getSdkOsLocation() { - String path = mManager == null ? null : mManager.getLocation(); - if (path != null) { - // For backward compatibility make sure it ends with a separator. - // This used to be the case when the SDK Manager was created from a String path - // but now that a File is internally used the trailing dir separator is lost. - if (path.length() > 0 && !path.endsWith(File.separator)) { - path = path + File.separator; - } - } - return path; - } - - /** - * Returns the location of the current SDK as a {@link File} or null. - * - * @return The SDK OS path or null if no SDK is setup. - */ - @Nullable - public File getSdkFileLocation() { - if (mManager == null || mManager.getLocalSdk() == null) { - return null; - } - return mManager.getLocalSdk().getLocation(); - } - - /** - * Returns a <em>new</em> {@link SdkManager} that can parse the SDK located - * at the current {@link #getSdkOsLocation()}. - * <p/> - * Implementation detail: The {@link Sdk} has its own internal manager with - * a custom logger which is not designed to be useful for outsiders. Callers - * who need their own {@link SdkManager} for parsing will often want to control - * the logger for their own need. - * <p/> - * This is just a convenient method equivalent to writing: - * <pre>SdkManager.createManager(Sdk.getCurrent().getSdkLocation(), log);</pre> - * - * @param log The logger for the {@link SdkManager}. - * @return A new {@link SdkManager} parsing the same location. - */ - public @Nullable SdkManager getNewSdkManager(@NonNull ILogger log) { - return SdkManager.createManager(getSdkOsLocation(), log); - } - - /** - * Returns the URL to the local documentation. - * Can return null if no documentation is found in the current SDK. - * - * @return A file:// URL on the local documentation folder if it exists or null. - */ - @Nullable - public String getDocumentationBaseUrl() { - return mDocBaseUrl; - } - - /** - * Returns the list of targets that are available in the SDK. - */ - public IAndroidTarget[] getTargets() { - return mManager.getTargets(); - } - - /** - * Queries the underlying SDK Manager to check whether the platforms or addons - * directories have changed on-disk. Does not reload the SDK. - * <p/> - * This is a quick test based on the presence of the directories, their timestamps - * and a quick checksum of the source.properties files. It's possible to have - * false positives (e.g. if a file is manually modified in a platform) or false - * negatives (e.g. if a platform data file is changed manually in a 2nd level - * directory without altering the source.properties.) - */ - public boolean haveTargetsChanged() { - return mManager.hasChanged(); - } - - /** - * Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}. - * - * @param hash the {@link IAndroidTarget} hash string. - * @return The matching {@link IAndroidTarget} or null. - */ - @Nullable - public IAndroidTarget getTargetFromHashString(@NonNull String hash) { - return mManager.getTargetFromHashString(hash); - } - - @Nullable - public BuildToolInfo getBuildToolInfo(@Nullable String buildToolVersion) { - if (buildToolVersion != null) { - try { - return mManager.getBuildTool(FullRevision.parseRevision(buildToolVersion)); - } catch (Exception e) { - // ignore, return null below. - } - } - - return null; - } - - @Nullable - public BuildToolInfo getLatestBuildTool() { - return mManager.getLatestBuildTool(); - } - - /** - * Initializes a new project with a target. This creates the <code>project.properties</code> - * file. - * @param project the project to initialize - * @param target the project's target. - * @throws IOException if creating the file failed in any way. - * @throws StreamException if processing the project property file fails - */ - public void initProject(@Nullable IProject project, @Nullable IAndroidTarget target) - throws IOException, StreamException { - if (project == null || target == null) { - return; - } - - synchronized (LOCK) { - // check if there's already a state? - ProjectState state = getProjectState(project); - - ProjectPropertiesWorkingCopy properties = null; - - if (state != null) { - properties = state.getProperties().makeWorkingCopy(); - } - - if (properties == null) { - IPath location = project.getLocation(); - if (location == null) { // can return null when the project is being deleted. - // do nothing and return null; - return; - } - - properties = ProjectProperties.create(location.toOSString(), PropertyType.PROJECT); - } - - // save the target hash string in the project persistent property - properties.setProperty(ProjectProperties.PROPERTY_TARGET, target.hashString()); - properties.save(); - } - } - - /** - * Returns the {@link ProjectState} object associated with a given project. - * <p/> - * This method is the only way to properly get the project's {@link ProjectState} - * If the project has not yet been loaded, then it is loaded. - * <p/>Because this methods deals with projects, it's not linked to an actual {@link Sdk} - * objects, and therefore is static. - * <p/>The value returned by {@link ProjectState#getTarget()} will change as {@link Sdk} objects - * are replaced. - * @param project the request project - * @return the ProjectState for the project. - */ - @Nullable - @SuppressWarnings("deprecation") - public static ProjectState getProjectState(IProject project) { - if (project == null) { - return null; - } - - synchronized (LOCK) { - ProjectState state = sProjectStateMap.get(project); - if (state == null) { - // load the project.properties from the project folder. - IPath location = project.getLocation(); - if (location == null) { // can return null when the project is being deleted. - // do nothing and return null; - return null; - } - - String projectLocation = location.toOSString(); - - ProjectProperties properties = ProjectProperties.load(projectLocation, - PropertyType.PROJECT); - if (properties == null) { - // legacy support: look for default.properties and rename it if needed. - properties = ProjectProperties.load(projectLocation, - PropertyType.LEGACY_DEFAULT); - - if (properties == null) { - AdtPlugin.log(IStatus.ERROR, - "Failed to load properties file for project '%s'", - project.getName()); - return null; - } else { - //legacy mode. - // get a working copy with the new type "project" - ProjectPropertiesWorkingCopy wc = properties.makeWorkingCopy( - PropertyType.PROJECT); - // and save it - try { - wc.save(); - - // delete the old file. - ProjectProperties.delete(projectLocation, PropertyType.LEGACY_DEFAULT); - - // make sure to use the new properties - properties = ProjectProperties.load(projectLocation, - PropertyType.PROJECT); - } catch (Exception e) { - AdtPlugin.log(IStatus.ERROR, - "Failed to rename properties file to %1$s for project '%s2$'", - PropertyType.PROJECT.getFilename(), project.getName()); - } - } - } - - state = new ProjectState(project, properties); - sProjectStateMap.put(project, state); - - // try to resolve the target - if (AdtPlugin.getDefault().getSdkLoadStatus() == LoadStatus.LOADED) { - sCurrentSdk.loadTargetAndBuildTools(state); - } - } - - return state; - } - } - - /** - * Returns the {@link IAndroidTarget} object associated with the given {@link IProject}. - */ - @Nullable - public IAndroidTarget getTarget(IProject project) { - if (project == null) { - return null; - } - - ProjectState state = getProjectState(project); - if (state != null) { - return state.getTarget(); - } - - return null; - } - - /** - * Loads the {@link IAndroidTarget} and BuildTools for a given project. - * <p/>This method will get the target hash string from the project properties, and resolve - * it to an {@link IAndroidTarget} object and store it inside the {@link ProjectState}. - * @param state the state representing the project to load. - * @return the target that was loaded. - */ - @Nullable - public IAndroidTarget loadTargetAndBuildTools(ProjectState state) { - IAndroidTarget target = null; - if (state != null) { - String hash = state.getTargetHashString(); - if (hash != null) { - state.setTarget(target = getTargetFromHashString(hash)); - } - - String markerMessage = null; - String buildToolInfoVersion = state.getBuildToolInfoVersion(); - if (buildToolInfoVersion != null) { - BuildToolInfo buildToolsInfo = getBuildToolInfo(buildToolInfoVersion); - - if (buildToolsInfo != null) { - state.setBuildToolInfo(buildToolsInfo); - } else { - markerMessage = String.format("Unable to resolve %s property value '%s'", - ProjectProperties.PROPERTY_BUILD_TOOLS, - buildToolInfoVersion); - } - } else { - // this is ok, we'll use the latest one automatically. - state.setBuildToolInfo(null); - } - - handleBuildToolsMarker(state.getProject(), markerMessage); - } - - return target; - } - - /** - * Adds or edit a build tools marker from the given project. This is done through a Job. - * @param project the project - * @param markerMessage the message. if null the marker is removed. - */ - private void handleBuildToolsMarker(final IProject project, final String markerMessage) { - Job markerJob = new Job("Android SDK: Build Tools Marker") { - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - if (project.isAccessible()) { - // always delete existing marker first - project.deleteMarkers(AdtConstants.MARKER_BUILD_TOOLS, true, - IResource.DEPTH_ZERO); - - // add the new one if needed. - if (markerMessage != null) { - BaseProjectHelper.markProject(project, - AdtConstants.MARKER_BUILD_TOOLS, - markerMessage, IMarker.SEVERITY_ERROR, - IMarker.PRIORITY_HIGH); - } - } - } catch (CoreException e2) { - AdtPlugin.log(e2, null); - // Don't return e2.getStatus(); the job control will then produce - // a popup with this error, which isn't very interesting for the - // user. - } - - return Status.OK_STATUS; - } - }; - - // build jobs are run after other interactive jobs - markerJob.setPriority(Job.BUILD); - markerJob.setRule(ResourcesPlugin.getWorkspace().getRoot()); - markerJob.schedule(); - } - - /** - * Checks and loads (if needed) the data for a given target. - * <p/> The data is loaded in a separate {@link Job}, and opened editors will be notified - * through their implementation of {@link ITargetChangeListener#onTargetLoaded(IAndroidTarget)}. - * <p/>An optional project as second parameter can be given to be recompiled once the target - * data is finished loading. - * <p/>The return value is non-null only if the target data has already been loaded (and in this - * case is the status of the load operation) - * @param target the target to load. - * @param project an optional project to be recompiled when the target data is loaded. - * If the target is already loaded, nothing happens. - * @return The load status if the target data is already loaded. - */ - @NonNull - public LoadStatus checkAndLoadTargetData(final IAndroidTarget target, IJavaProject project) { - boolean loadData = false; - - synchronized (LOCK) { - if (mDontLoadTargetData) { - return LoadStatus.FAILED; - } - - TargetLoadBundle bundle = mTargetDataStatusMap.get(target); - if (bundle == null) { - bundle = new TargetLoadBundle(); - mTargetDataStatusMap.put(target,bundle); - - // set status to loading - bundle.status = LoadStatus.LOADING; - - // add project to bundle - if (project != null) { - bundle.projectsToReload.add(project); - } - - // and set the flag to start the loading below - loadData = true; - } else if (bundle.status == LoadStatus.LOADING) { - // add project to bundle - if (project != null) { - bundle.projectsToReload.add(project); - } - - return bundle.status; - } else if (bundle.status == LoadStatus.LOADED || bundle.status == LoadStatus.FAILED) { - return bundle.status; - } - } - - if (loadData) { - Job job = new Job(String.format("Loading data for %1$s", target.getFullName())) { - @Override - protected IStatus run(IProgressMonitor monitor) { - AdtPlugin plugin = AdtPlugin.getDefault(); - try { - IStatus status = new AndroidTargetParser(target).run(monitor); - - IJavaProject[] javaProjectArray = null; - - synchronized (LOCK) { - TargetLoadBundle bundle = mTargetDataStatusMap.get(target); - - if (status.getCode() != IStatus.OK) { - bundle.status = LoadStatus.FAILED; - bundle.projectsToReload.clear(); - } else { - bundle.status = LoadStatus.LOADED; - - // Prepare the array of project to recompile. - // The call is done outside of the synchronized block. - javaProjectArray = bundle.projectsToReload.toArray( - new IJavaProject[bundle.projectsToReload.size()]); - - // and update the UI of the editors that depend on the target data. - plugin.updateTargetListeners(target); - } - } - - if (javaProjectArray != null) { - ProjectHelper.updateProjects(javaProjectArray); - } - - return status; - } catch (Throwable t) { - synchronized (LOCK) { - TargetLoadBundle bundle = mTargetDataStatusMap.get(target); - bundle.status = LoadStatus.FAILED; - } - - AdtPlugin.log(t, "Exception in checkAndLoadTargetData."); //$NON-NLS-1$ - String message = String.format("Parsing Data for %1$s failed", target.hashString()); - if (t instanceof UnsupportedClassVersionError) { - message = "To use this platform, run Eclipse with JDK 7 or later. (" + message + ")"; - } - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, t); - } - } - }; - job.setPriority(Job.BUILD); // build jobs are run after other interactive jobs - job.setRule(ResourcesPlugin.getWorkspace().getRoot()); - job.schedule(); - } - - // The only way to go through here is when the loading starts through the Job. - // Therefore the current status of the target is LOADING. - return LoadStatus.LOADING; - } - - /** - * Return the {@link AndroidTargetData} for a given {@link IAndroidTarget}. - */ - @Nullable - public AndroidTargetData getTargetData(IAndroidTarget target) { - synchronized (LOCK) { - return mTargetDataMap.get(target); - } - } - - /** - * Return the {@link AndroidTargetData} for a given {@link IProject}. - */ - @Nullable - public AndroidTargetData getTargetData(IProject project) { - synchronized (LOCK) { - IAndroidTarget target = getTarget(project); - if (target != null) { - return getTargetData(target); - } - } - - return null; - } - - /** - * Returns a {@link DexWrapper} object to be used to execute dx commands. If dx.jar was not - * loaded properly, then this will return <code>null</code>. - */ - @Nullable - public DexWrapper getDexWrapper(@Nullable BuildToolInfo buildToolInfo) { - if (buildToolInfo == null) { - return null; - } - synchronized (LOCK) { - String dexLocation = buildToolInfo.getPath(BuildToolInfo.PathId.DX_JAR); - DexWrapper dexWrapper = mDexWrappers.get(dexLocation); - - if (dexWrapper == null) { - // load DX. - dexWrapper = new DexWrapper(); - IStatus res = dexWrapper.loadDex(dexLocation); - if (res != Status.OK_STATUS) { - AdtPlugin.log(null, res.getMessage()); - dexWrapper = null; - } else { - mDexWrappers.put(dexLocation, dexWrapper); - } - } - - return dexWrapper; - } - } - - public void unloadDexWrappers() { - synchronized (LOCK) { - for (DexWrapper wrapper : mDexWrappers.values()) { - wrapper.unload(); - } - mDexWrappers.clear(); - } - } - - /** - * Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could - * be <code>null</code>. - */ - @Nullable - public AvdManager getAvdManager() { - return mAvdManager; - } - - @Nullable - public static AndroidVersion getDeviceVersion(@NonNull IDevice device) { - try { - Map<String, String> props = device.getProperties(); - String apiLevel = props.get(IDevice.PROP_BUILD_API_LEVEL); - if (apiLevel == null) { - return null; - } - - return new AndroidVersion(Integer.parseInt(apiLevel), - props.get((IDevice.PROP_BUILD_CODENAME))); - } catch (NumberFormatException e) { - return null; - } - } - - @NonNull - public DeviceManager getDeviceManager() { - return mDeviceManager; - } - - /** - * Returns a list of {@link ProjectState} representing projects depending, directly or - * indirectly on a given library project. - * @param project the library project. - * @return a possibly empty list of ProjectState. - */ - @NonNull - public static Set<ProjectState> getMainProjectsFor(IProject project) { - synchronized (LOCK) { - // first get the project directly depending on this. - Set<ProjectState> list = new HashSet<ProjectState>(); - - // loop on all project and see if ProjectState.getLibrary returns a non null - // project. - for (Entry<IProject, ProjectState> entry : sProjectStateMap.entrySet()) { - if (project != entry.getKey()) { - LibraryState library = entry.getValue().getLibrary(project); - if (library != null) { - list.add(entry.getValue()); - } - } - } - - // now look for projects depending on the projects directly depending on the library. - HashSet<ProjectState> result = new HashSet<ProjectState>(list); - for (ProjectState p : list) { - if (p.isLibrary()) { - Set<ProjectState> set = getMainProjectsFor(p.getProject()); - result.addAll(set); - } - } - - return result; - } - } - - /** - * Unload the SDK's target data. - * - * If <var>preventReload</var>, this effect is final until the SDK instance is changed - * through {@link #loadSdk(String)}. - * - * The goal is to unload the targets to be able to replace existing targets with new ones, - * before calling {@link #loadSdk(String)} to fully reload the SDK. - * - * @param preventReload prevent the data from being loaded again for the remaining live of - * this {@link Sdk} instance. - */ - public void unloadTargetData(boolean preventReload) { - synchronized (LOCK) { - mDontLoadTargetData = preventReload; - - // dispose of the target data. - for (AndroidTargetData data : mTargetDataMap.values()) { - data.dispose(); - } - - mTargetDataMap.clear(); - } - } - - private Sdk(SdkManager manager, AvdManager avdManager) { - mManager = manager; - mAvdManager = avdManager; - - // listen to projects closing - GlobalProjectMonitor monitor = GlobalProjectMonitor.getMonitor(); - // need to register the resource event listener first because the project listener - // is called back during registration with project opened in the workspace. - monitor.addResourceEventListener(mResourceEventListener); - monitor.addProjectListener(mProjectListener); - monitor.addFileListener(mFileListener, - IResourceDelta.CHANGED | IResourceDelta.ADDED | IResourceDelta.REMOVED); - - // pre-compute some paths - mDocBaseUrl = getDocumentationBaseUrl(manager.getLocation() + - SdkConstants.OS_SDK_DOCS_FOLDER); - - mDeviceManager = DeviceManager.createInstance(manager.getLocalSdk().getLocation(), - AdtPlugin.getDefault()); - - // update whatever ProjectState is already present with new IAndroidTarget objects. - synchronized (LOCK) { - for (Entry<IProject, ProjectState> entry: sProjectStateMap.entrySet()) { - loadTargetAndBuildTools(entry.getValue()); - } - } - } - - /** - * Cleans and unloads the SDK. - */ - private void dispose() { - GlobalProjectMonitor monitor = GlobalProjectMonitor.getMonitor(); - monitor.removeProjectListener(mProjectListener); - monitor.removeFileListener(mFileListener); - monitor.removeResourceEventListener(mResourceEventListener); - - // the IAndroidTarget objects are now obsolete so update the project states. - synchronized (LOCK) { - for (Entry<IProject, ProjectState> entry: sProjectStateMap.entrySet()) { - entry.getValue().setTarget(null); - } - - // dispose of the target data. - for (AndroidTargetData data : mTargetDataMap.values()) { - data.dispose(); - } - - mTargetDataMap.clear(); - } - } - - void setTargetData(IAndroidTarget target, AndroidTargetData data) { - synchronized (LOCK) { - mTargetDataMap.put(target, data); - } - } - - /** - * Returns the URL to the local documentation. - * Can return null if no documentation is found in the current SDK. - * - * @param osDocsPath Path to the documentation folder in the current SDK. - * The folder may not actually exist. - * @return A file:// URL on the local documentation folder if it exists or null. - */ - private String getDocumentationBaseUrl(String osDocsPath) { - File f = new File(osDocsPath); - - if (f.isDirectory()) { - try { - // Note: to create a file:// URL, one would typically use something like - // f.toURI().toURL().toString(). However this generates a broken path on - // Windows, namely "C:\\foo" is converted to "file:/C:/foo" instead of - // "file:///C:/foo" (i.e. there should be 3 / after "file:"). So we'll - // do the correct thing manually. - - String path = f.getAbsolutePath(); - if (File.separatorChar != '/') { - path = path.replace(File.separatorChar, '/'); - } - - // For some reason the URL class doesn't add the mandatory "//" after - // the "file:" protocol name, so it has to be hacked into the path. - URL url = new URL("file", null, "//" + path); //$NON-NLS-1$ //$NON-NLS-2$ - String result = url.toString(); - return result; - } catch (MalformedURLException e) { - // ignore malformed URLs - } - } - - return null; - } - - /** - * Delegate listener for project changes. - */ - private IProjectListener mProjectListener = new IProjectListener() { - @Override - public void projectClosed(IProject project) { - onProjectRemoved(project, false /*deleted*/); - } - - @Override - public void projectDeleted(IProject project) { - onProjectRemoved(project, true /*deleted*/); - } - - private void onProjectRemoved(IProject removedProject, boolean deleted) { - if (DEBUG) { - System.out.println(">>> CLOSED: " + removedProject.getName()); - } - - // get the target project - synchronized (LOCK) { - // Don't use getProject() as it could create the ProjectState if it's not - // there yet and this is not what we want. We want the current object. - // Therefore, direct access to the map. - ProjectState removedState = sProjectStateMap.get(removedProject); - if (removedState != null) { - // 1. clear the layout lib cache associated with this project - IAndroidTarget target = removedState.getTarget(); - if (target != null) { - // get the bridge for the target, and clear the cache for this project. - AndroidTargetData data = mTargetDataMap.get(target); - if (data != null) { - LayoutLibrary layoutLib = data.getLayoutLibrary(); - if (layoutLib != null && layoutLib.getStatus() == LoadStatus.LOADED) { - layoutLib.clearCaches(removedProject); - } - } - } - - // 2. if the project is a library, make sure to update the - // LibraryState for any project referencing it. - // Also, record the updated projects that are libraries, to update - // projects that depend on them. - for (ProjectState projectState : sProjectStateMap.values()) { - LibraryState libState = projectState.getLibrary(removedProject); - if (libState != null) { - // Close the library right away. - // This remove links between the LibraryState and the projectState. - // This is because in case of a rename of a project, projectClosed and - // projectOpened will be called before any other job is run, so we - // need to make sure projectOpened is closed with the main project - // state up to date. - libState.close(); - - // record that this project changed, and in case it's a library - // that its parents need to be updated as well. - markProject(projectState, projectState.isLibrary()); - } - } - - // now remove the project for the project map. - sProjectStateMap.remove(removedProject); - } - } - - if (DEBUG) { - System.out.println("<<<"); - } - } - - @Override - public void projectOpened(IProject project) { - onProjectOpened(project); - } - - @Override - public void projectOpenedWithWorkspace(IProject project) { - // no need to force recompilation when projects are opened with the workspace. - onProjectOpened(project); - } - - @Override - public void allProjectsOpenedWithWorkspace() { - // Correct currently open editors - fixOpenLegacyEditors(); - } - - private void onProjectOpened(final IProject openedProject) { - - ProjectState openedState = getProjectState(openedProject); - if (openedState != null) { - if (DEBUG) { - System.out.println(">>> OPENED: " + openedProject.getName()); - } - - synchronized (LOCK) { - final boolean isLibrary = openedState.isLibrary(); - final boolean hasLibraries = openedState.hasLibraries(); - - if (isLibrary || hasLibraries) { - boolean foundLibraries = false; - // loop on all the existing project and update them based on this new - // project - for (ProjectState projectState : sProjectStateMap.values()) { - if (projectState != openedState) { - // If the project has libraries, check if this project - // is a reference. - if (hasLibraries) { - // ProjectState#needs() both checks if this is a missing library - // and updates LibraryState to contains the new values. - // This must always be called. - LibraryState libState = openedState.needs(projectState); - - if (libState != null) { - // found a library! Add the main project to the list of - // modified project - foundLibraries = true; - } - } - - // if the project is a library check if the other project depend - // on it. - if (isLibrary) { - // ProjectState#needs() both checks if this is a missing library - // and updates LibraryState to contains the new values. - // This must always be called. - LibraryState libState = projectState.needs(openedState); - - if (libState != null) { - // There's a dependency! Add the project to the list of - // modified project, but also to a list of projects - // that saw one of its dependencies resolved. - markProject(projectState, projectState.isLibrary()); - } - } - } - } - - // if the project has a libraries and we found at least one, we add - // the project to the list of modified project. - // Since we already went through the parent, no need to update them. - if (foundLibraries) { - markProject(openedState, false /*updateParents*/); - } - } - } - - // Correct file editor associations. - fixEditorAssociations(openedProject); - - // Fix classpath entries in a job since the workspace might be locked now. - Job fixCpeJob = new Job("Adjusting Android Project Classpath") { - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - ProjectHelper.fixProjectClasspathEntries( - JavaCore.create(openedProject)); - } catch (JavaModelException e) { - AdtPlugin.log(e, "error fixing classpath entries"); - // Don't return e2.getStatus(); the job control will then produce - // a popup with this error, which isn't very interesting for the - // user. - } - - return Status.OK_STATUS; - } - }; - - // build jobs are run after other interactive jobs - fixCpeJob.setPriority(Job.BUILD); - fixCpeJob.setRule(ResourcesPlugin.getWorkspace().getRoot()); - fixCpeJob.schedule(); - - - if (DEBUG) { - System.out.println("<<<"); - } - } - } - - @Override - public void projectRenamed(IProject project, IPath from) { - // we don't actually care about this anymore. - } - }; - - /** - * Delegate listener for file changes. - */ - private IFileListener mFileListener = new IFileListener() { - @Override - public void fileChanged(final @NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas, - int kind, @Nullable String extension, int flags, boolean isAndroidPRoject) { - if (!isAndroidPRoject) { - return; - } - - if (SdkConstants.FN_PROJECT_PROPERTIES.equals(file.getName()) && - file.getParent() == file.getProject()) { - try { - // reload the content of the project.properties file and update - // the target. - IProject iProject = file.getProject(); - - ProjectState state = Sdk.getProjectState(iProject); - - // get the current target and build tools - IAndroidTarget oldTarget = state.getTarget(); - boolean oldRsSupportMode = state.getRenderScriptSupportMode(); - - // get the current library flag - boolean wasLibrary = state.isLibrary(); - - LibraryDifference diff = state.reloadProperties(); - - // load the (possibly new) target. - IAndroidTarget newTarget = loadTargetAndBuildTools(state); - - // reload the libraries if needed - if (diff.hasDiff()) { - if (diff.added) { - synchronized (LOCK) { - for (ProjectState projectState : sProjectStateMap.values()) { - if (projectState != state) { - // need to call needs to do the libraryState link, - // but no need to look at the result, as we'll compare - // the result of getFullLibraryProjects() - // this is easier to due to indirect dependencies. - state.needs(projectState); - } - } - } - } - - markProject(state, wasLibrary || state.isLibrary()); - } - - // apply the new target if needed. - if (newTarget != oldTarget || - oldRsSupportMode != state.getRenderScriptSupportMode()) { - IJavaProject javaProject = BaseProjectHelper.getJavaProject( - file.getProject()); - if (javaProject != null) { - ProjectHelper.updateProject(javaProject); - } - - // update the editors to reload with the new target - AdtPlugin.getDefault().updateTargetListeners(iProject); - } - } catch (CoreException e) { - // This can't happen as it's only for closed project (or non existing) - // but in that case we can't get a fileChanged on this file. - } - } else if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) { - // check if it's an add/remove on a jar files inside libs - if (EXT_JAR.equals(extension) && - file.getProjectRelativePath().segmentCount() == 2 && - file.getParent().getName().equals(SdkConstants.FD_NATIVE_LIBS)) { - // need to update the project and whatever depend on it. - - processJarFileChange(file); - } - } - } - - private void processJarFileChange(final IFile file) { - try { - IProject iProject = file.getProject(); - - if (iProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) { - return; - } - - List<IJavaProject> projectList = new ArrayList<IJavaProject>(); - IJavaProject javaProject = BaseProjectHelper.getJavaProject(iProject); - if (javaProject != null) { - projectList.add(javaProject); - } - - ProjectState state = Sdk.getProjectState(iProject); - - if (state != null) { - Collection<ProjectState> parents = state.getFullParentProjects(); - for (ProjectState s : parents) { - javaProject = BaseProjectHelper.getJavaProject(s.getProject()); - if (javaProject != null) { - projectList.add(javaProject); - } - } - - ProjectHelper.updateProjects( - projectList.toArray(new IJavaProject[projectList.size()])); - } - } catch (CoreException e) { - // This can't happen as it's only for closed project (or non existing) - // but in that case we can't get a fileChanged on this file. - } - } - }; - - /** List of modified projects. This is filled in - * {@link IProjectListener#projectOpened(IProject)}, - * {@link IProjectListener#projectOpenedWithWorkspace(IProject)}, - * {@link IProjectListener#projectClosed(IProject)}, and - * {@link IProjectListener#projectDeleted(IProject)} and processed in - * {@link IResourceEventListener#resourceChangeEventEnd()}. - */ - private final List<ProjectState> mModifiedProjects = new ArrayList<ProjectState>(); - private final List<ProjectState> mModifiedChildProjects = new ArrayList<ProjectState>(); - - private void markProject(ProjectState projectState, boolean updateParents) { - if (mModifiedProjects.contains(projectState) == false) { - if (DEBUG) { - System.out.println("\tMARKED: " + projectState.getProject().getName()); - } - mModifiedProjects.add(projectState); - } - - // if the project is resolved also add it to this list. - if (updateParents) { - if (mModifiedChildProjects.contains(projectState) == false) { - if (DEBUG) { - System.out.println("\tMARKED(child): " + projectState.getProject().getName()); - } - mModifiedChildProjects.add(projectState); - } - } - } - - /** - * Delegate listener for resource changes. This is called before and after any calls to the - * project and file listeners (for a given resource change event). - */ - private IResourceEventListener mResourceEventListener = new IResourceEventListener() { - @Override - public void resourceChangeEventStart() { - mModifiedProjects.clear(); - mModifiedChildProjects.clear(); - } - - @Override - public void resourceChangeEventEnd() { - if (mModifiedProjects.size() == 0) { - return; - } - - // first make sure all the parents are updated - updateParentProjects(); - - // for all modified projects, update their library list - // and gather their IProject - final List<IJavaProject> projectList = new ArrayList<IJavaProject>(); - for (ProjectState state : mModifiedProjects) { - state.updateFullLibraryList(); - projectList.add(JavaCore.create(state.getProject())); - } - - Job job = new Job("Android Library Update") { //$NON-NLS-1$ - @Override - protected IStatus run(IProgressMonitor monitor) { - LibraryClasspathContainerInitializer.updateProjects( - projectList.toArray(new IJavaProject[projectList.size()])); - - for (IJavaProject javaProject : projectList) { - try { - javaProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD, - monitor); - } catch (CoreException e) { - // pass - } - } - return Status.OK_STATUS; - } - }; - job.setPriority(Job.BUILD); - job.setRule(ResourcesPlugin.getWorkspace().getRoot()); - job.schedule(); - } - }; - - /** - * Updates all existing projects with a given list of new/updated libraries. - * This loops through all opened projects and check if they depend on any of the given - * library project, and if they do, they are linked together. - */ - private void updateParentProjects() { - if (mModifiedChildProjects.size() == 0) { - return; - } - - ArrayList<ProjectState> childProjects = new ArrayList<ProjectState>(mModifiedChildProjects); - mModifiedChildProjects.clear(); - synchronized (LOCK) { - // for each project for which we must update its parent, we loop on the parent - // projects and adds them to the list of modified projects. If they are themselves - // libraries, we add them too. - for (ProjectState state : childProjects) { - if (DEBUG) { - System.out.println(">>> Updating parents of " + state.getProject().getName()); - } - List<ProjectState> parents = state.getParentProjects(); - for (ProjectState parent : parents) { - markProject(parent, parent.isLibrary()); - } - if (DEBUG) { - System.out.println("<<<"); - } - } - } - - // done, but there may be parents that are also libraries. Need to update their parents. - updateParentProjects(); - } - - /** - * Fix editor associations for the given project, if not already done. - * <p/> - * Eclipse has a per-file setting for which editor should be used for each file - * (see {@link IDE#setDefaultEditor(IFile, String)}). - * We're using this flag to pick between the various XML editors (layout, drawable, etc) - * since they all have the same file name extension. - * <p/> - * Unfortunately, the file setting can be "wrong" for two reasons: - * <ol> - * <li> The editor type was added <b>after</b> a file had been seen by the IDE. - * For example, we added new editors for animations and for drawables around - * ADT 12, but any file seen by ADT in earlier versions will continue to use - * the vanilla Eclipse XML editor instead. - * <li> A bug in ADT 14 and ADT 15 (see issue 21124) meant that files created in new - * folders would end up with wrong editor associations. Even though that bug - * is fixed in ADT 16, the fix only affects new files, it cannot retroactively - * fix editor associations that were set incorrectly by ADT 14 or 15. - * </ol> - * <p/> - * This method attempts to fix the editor bindings retroactively by scanning all the - * resource XML files and resetting the editor associations. - * Since this is a potentially slow operation, this is only done "once"; we use a - * persistent project property to avoid looking repeatedly. In the future if we add - * additional editors, we can rev the scanned version value. - */ - private void fixEditorAssociations(final IProject project) { - QualifiedName KEY = new QualifiedName(AdtPlugin.PLUGIN_ID, "editorbinding"); //$NON-NLS-1$ - - try { - String value = project.getPersistentProperty(KEY); - int currentVersion = 0; - if (value != null) { - try { - currentVersion = Integer.parseInt(value); - } catch (Exception ingore) { - } - } - - // The target version we're comparing to. This must be incremented each time - // we change the processing here so that a new version of the plugin would - // try to fix existing user projects. - final int targetVersion = 2; - - if (currentVersion >= targetVersion) { - return; - } - - // Set to specific version such that we can rev the version in the future - // to trigger further scanning - project.setPersistentProperty(KEY, Integer.toString(targetVersion)); - - // Now update the actual editor associations. - Job job = new Job("Update Android editor bindings") { //$NON-NLS-1$ - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - for (IResource folderResource : project.getFolder(FD_RES).members()) { - if (folderResource instanceof IFolder) { - IFolder folder = (IFolder) folderResource; - - for (IResource resource : folder.members()) { - if (resource instanceof IFile && - resource.getName().endsWith(DOT_XML)) { - fixXmlFile((IFile) resource); - } - } - } - } - - // TODO change AndroidManifest.xml ID too - - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - - return Status.OK_STATUS; - } - - /** - * Attempt to fix the editor ID for the given /res XML file. - */ - private void fixXmlFile(final IFile file) { - // Fix the default editor ID for this resource. - // This has no effect on currently open editors. - IEditorDescriptor desc = IDE.getDefaultEditor(file); - - if (desc == null || !CommonXmlEditor.ID.equals(desc.getId())) { - IDE.setDefaultEditor(file, CommonXmlEditor.ID); - } - } - }; - job.setPriority(Job.BUILD); - job.schedule(); - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - } - - /** - * Tries to fix all currently open Android legacy editors. - * <p/> - * If an editor is found to match one of the legacy ids, we'll try to close it. - * If that succeeds, we try to reopen it using the new common editor ID. - * <p/> - * This method must be run from the UI thread. - */ - private void fixOpenLegacyEditors() { - - AdtPlugin adt = AdtPlugin.getDefault(); - if (adt == null) { - return; - } - - final IPreferenceStore store = adt.getPreferenceStore(); - int currentValue = store.getInt(AdtPrefs.PREFS_FIX_LEGACY_EDITORS); - // The target version we're comparing to. This must be incremented each time - // we change the processing here so that a new version of the plugin would - // try to fix existing editors. - final int targetValue = 1; - - if (currentValue >= targetValue) { - return; - } - - // To be able to close and open editors we need to make sure this is done - // in the UI thread, which this isn't invoked from. - PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - HashSet<String> legacyIds = - new HashSet<String>(Arrays.asList(CommonXmlEditor.LEGACY_EDITOR_IDS)); - - for (IWorkbenchWindow win : PlatformUI.getWorkbench().getWorkbenchWindows()) { - for (IWorkbenchPage page : win.getPages()) { - for (IEditorReference ref : page.getEditorReferences()) { - try { - IEditorInput input = ref.getEditorInput(); - if (input instanceof IFileEditorInput) { - IFile file = ((IFileEditorInput)input).getFile(); - IEditorPart part = ref.getEditor(true /*restore*/); - if (part != null) { - IWorkbenchPartSite site = part.getSite(); - if (site != null) { - String id = site.getId(); - if (legacyIds.contains(id)) { - // This editor matches one of legacy editor IDs. - fixEditor(page, part, input, file, id); - } - } - } - } - } catch (Exception e) { - // ignore - } - } - } - } - - // Remember that we managed to do fix all editors - store.setValue(AdtPrefs.PREFS_FIX_LEGACY_EDITORS, targetValue); - } - - private void fixEditor( - IWorkbenchPage page, - IEditorPart part, - IEditorInput input, - IFile file, - String id) { - IDE.setDefaultEditor(file, CommonXmlEditor.ID); - - boolean ok = page.closeEditor(part, true /*save*/); - - AdtPlugin.log(IStatus.INFO, - "Closed legacy editor ID %s for %s: %s", //$NON-NLS-1$ - id, - file.getFullPath(), - ok ? "Success" : "Failed");//$NON-NLS-1$ //$NON-NLS-2$ - - if (ok) { - // Try to reopen it with the new ID - try { - page.openEditor(input, CommonXmlEditor.ID); - } catch (PartInitException e) { - AdtPlugin.log(e, - "Failed to reopen %s", //$NON-NLS-1$ - file.getFullPath()); - } - } - } - }); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/WidgetClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/WidgetClassLoader.java deleted file mode 100644 index 682d6e538..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/WidgetClassLoader.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.eclipse.adt.internal.sdk; - -import com.android.SdkConstants; - -import org.eclipse.core.runtime.IProgressMonitor; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.TreeMap; - -import javax.management.InvalidAttributeValueException; - -/** - * Parser for the text file containing the list of widgets, layouts and layout params. - * <p/> - * The file is a straight text file containing one class per line.<br> - * Each line is in the following format<br> - * <code>[code][class name] [super class name] [super class name]...</code> - * where code is a single letter (W for widget, L for layout, P for layout params), and class names - * are the fully qualified name of the classes. - */ -public final class WidgetClassLoader implements IAndroidClassLoader { - - /** - * Basic class containing the class descriptions found in the text file. - */ - private final static class ClassDescriptor implements IClassDescriptor { - - private String mFqcn; - private String mSimpleName; - private ClassDescriptor mSuperClass; - private ClassDescriptor mEnclosingClass; - private final ArrayList<IClassDescriptor> mDeclaredClasses = - new ArrayList<IClassDescriptor>(); - private boolean mIsInstantiable = false; - - ClassDescriptor(String fqcn) { - mFqcn = fqcn; - mSimpleName = getSimpleName(fqcn); - } - - @Override - public String getFullClassName() { - return mFqcn; - } - - @Override - public String getSimpleName() { - return mSimpleName; - } - - @Override - public IClassDescriptor[] getDeclaredClasses() { - return mDeclaredClasses.toArray(new IClassDescriptor[mDeclaredClasses.size()]); - } - - private void addDeclaredClass(ClassDescriptor declaredClass) { - mDeclaredClasses.add(declaredClass); - } - - @Override - public IClassDescriptor getEnclosingClass() { - return mEnclosingClass; - } - - void setEnclosingClass(ClassDescriptor enclosingClass) { - // set the enclosing class. - mEnclosingClass = enclosingClass; - - // add this to the list of declared class in the enclosing class. - mEnclosingClass.addDeclaredClass(this); - - // finally change the name of declared class to make sure it uses the - // convention: package.enclosing$declared instead of package.enclosing.declared - mFqcn = enclosingClass.mFqcn + "$" + mFqcn.substring(enclosingClass.mFqcn.length() + 1); - } - - @Override - public IClassDescriptor getSuperclass() { - return mSuperClass; - } - - void setSuperClass(ClassDescriptor superClass) { - mSuperClass = superClass; - } - - @Override - public boolean equals(Object clazz) { - if (clazz instanceof ClassDescriptor) { - return mFqcn.equals(((ClassDescriptor)clazz).mFqcn); - } - return super.equals(clazz); - } - - @Override - public int hashCode() { - return mFqcn.hashCode(); - } - - @Override - public boolean isInstantiable() { - return mIsInstantiable; - } - - void setInstantiable(boolean state) { - mIsInstantiable = state; - } - - private String getSimpleName(String fqcn) { - String[] segments = fqcn.split("\\."); - return segments[segments.length-1]; - } - } - - private BufferedReader mReader; - - /** Output map of FQCN => descriptor on all classes */ - private final Map<String, ClassDescriptor> mMap = new TreeMap<String, ClassDescriptor>(); - /** Output map of FQCN => descriptor on View classes */ - private final Map<String, ClassDescriptor> mWidgetMap = new TreeMap<String, ClassDescriptor>(); - /** Output map of FQCN => descriptor on ViewGroup classes */ - private final Map<String, ClassDescriptor> mLayoutMap = new TreeMap<String, ClassDescriptor>(); - /** Output map of FQCN => descriptor on LayoutParams classes */ - private final Map<String, ClassDescriptor> mLayoutParamsMap = - new HashMap<String, ClassDescriptor>(); - /** File path of the source text file */ - private String mOsFilePath; - - /** - * Creates a loader with a given file path. - * @param osFilePath the OS path of the file to load. - * @throws FileNotFoundException if the file is not found. - */ - WidgetClassLoader(String osFilePath) throws FileNotFoundException { - mOsFilePath = osFilePath; - mReader = new BufferedReader(new FileReader(osFilePath)); - } - - @Override - public String getSource() { - return mOsFilePath; - } - - /** - * Parses the text file and return true if the file was successfully parsed. - * @param monitor - */ - boolean parseWidgetList(IProgressMonitor monitor) { - try { - String line; - while ((line = mReader.readLine()) != null) { - if (line.length() > 0) { - char prefix = line.charAt(0); - String[] classes = null; - ClassDescriptor clazz = null; - switch (prefix) { - case 'W': - classes = line.substring(1).split(" "); - clazz = processClass(classes, 0, null /* map */); - if (clazz != null) { - clazz.setInstantiable(true); - mWidgetMap.put(classes[0], clazz); - } - break; - case 'L': - classes = line.substring(1).split(" "); - clazz = processClass(classes, 0, null /* map */); - if (clazz != null) { - clazz.setInstantiable(true); - mLayoutMap.put(classes[0], clazz); - } - break; - case 'P': - classes = line.substring(1).split(" "); - clazz = processClass(classes, 0, mLayoutParamsMap); - if (clazz != null) { - clazz.setInstantiable(true); - } - break; - case '#': - // comment, do nothing - break; - default: - throw new IllegalArgumentException(); - } - } - } - - // reconciliate the layout and their layout params - postProcess(); - - return true; - } catch (IOException e) { - } finally { - try { - mReader.close(); - } catch (IOException e) { - } - } - - return false; - } - - /** - * Parses a View class and adds a ViewClassInfo for it in mWidgetMap. - * It calls itself recursively to handle super classes which are also Views. - * @param classes the inheritance list of the class to process. - * @param index the index of the class to process in the <code>classes</code> array. - * @param map an optional map in which to put every {@link ClassDescriptor} created. - */ - private ClassDescriptor processClass(String[] classes, int index, - Map<String, ClassDescriptor> map) { - if (index >= classes.length) { - return null; - } - - String fqcn = classes[index]; - - if ("java.lang.Object".equals(fqcn)) { //$NON-NLS-1$ - return null; - } - - // check if the ViewInfoClass has not yet been created. - if (mMap.containsKey(fqcn)) { - return mMap.get(fqcn); - } - - // create the custom class. - ClassDescriptor clazz = new ClassDescriptor(fqcn); - mMap.put(fqcn, clazz); - if (map != null) { - map.put(fqcn, clazz); - } - - // get the super class - ClassDescriptor superClass = processClass(classes, index+1, map); - if (superClass != null) { - clazz.setSuperClass(superClass); - } - - return clazz; - } - - /** - * Goes through the layout params and look for the enclosed class. If the layout params - * has no known enclosed type it is dropped. - */ - private void postProcess() { - Collection<ClassDescriptor> params = mLayoutParamsMap.values(); - - for (ClassDescriptor param : params) { - String fqcn = param.getFullClassName(); - - // get the enclosed name. - String enclosed = getEnclosedName(fqcn); - - // look for a match in the layouts. We don't use the layout map as it only contains the - // end classes, but in this case we also need to process the layout params for the base - // layout classes. - ClassDescriptor enclosingType = mMap.get(enclosed); - if (enclosingType != null) { - param.setEnclosingClass(enclosingType); - - // remove the class from the map, and put it back with the fixed name - mMap.remove(fqcn); - mMap.put(param.getFullClassName(), param); - } - } - } - - private String getEnclosedName(String fqcn) { - int index = fqcn.lastIndexOf('.'); - return fqcn.substring(0, index); - } - - /** - * Finds and loads all classes that derive from a given set of super classes. - * - * @param rootPackage Root package of classes to find. Use an empty string to find everyting. - * @param superClasses The super classes of all the classes to find. - * @return An hash map which keys are the super classes looked for and which values are - * ArrayList of the classes found. The array lists are always created for all the - * valid keys, they are simply empty if no deriving class is found for a given - * super class. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - @Override - public HashMap<String, ArrayList<IClassDescriptor>> findClassesDerivingFrom(String rootPackage, - String[] superClasses) throws IOException, InvalidAttributeValueException, - ClassFormatError { - HashMap<String, ArrayList<IClassDescriptor>> map = - new HashMap<String, ArrayList<IClassDescriptor>>(); - - ArrayList<IClassDescriptor> list = new ArrayList<IClassDescriptor>(); - list.addAll(mWidgetMap.values()); - map.put(SdkConstants.CLASS_VIEW, list); - - list = new ArrayList<IClassDescriptor>(); - list.addAll(mLayoutMap.values()); - map.put(SdkConstants.CLASS_VIEWGROUP, list); - - list = new ArrayList<IClassDescriptor>(); - list.addAll(mLayoutParamsMap.values()); - map.put(SdkConstants.CLASS_VIEWGROUP_LAYOUTPARAMS, list); - - return map; - } - - /** - * Returns a {@link IAndroidClassLoader.IClassDescriptor} by its fully-qualified name. - * @param className the fully-qualified name of the class to return. - * @throws ClassNotFoundException - */ - @Override - public IClassDescriptor getClass(String className) throws ClassNotFoundException { - return mMap.get(className); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-devices.xsd b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-devices.xsd deleted file mode 100755 index a4ea6c42e..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-devices.xsd +++ /dev/null @@ -1,345 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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. ---> -<xsd:schema - targetNamespace="http://schemas.android.com/sdk/android/layout-devices/1" - xmlns:xsd="http://www.w3.org/2001/XMLSchema" - xmlns:c="http://schemas.android.com/sdk/android/layout-devices/1" - elementFormDefault="qualified" - attributeFormDefault="unqualified" - version="1"> - - <!-- The root element layout-devices defines a sequence of 0..n device elements. --> - - <xsd:element name="layout-devices" type="c:layoutDevicesType" /> - - <xsd:complexType name="layoutDevicesType"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - The "layout-devices" element is the root element of this schema. - - It must contain zero or more "device" elements that each define the configurations - available for a given device. - - These definitions are used in the Graphical Layout Editor in the - Android Development Tools (ADT) plugin for Eclipse. - </xsd:documentation> - </xsd:annotation> - - <xsd:sequence> - <!-- layout-devices defines a sequence of 0..n device elements. --> - <xsd:element name="device" minOccurs="0" maxOccurs="unbounded"> - - <xsd:annotation> - <xsd:documentation xml:lang="en"> - A device element must contain at most one "default" element - followed by one or more "config" elements. - - The "default" element defines all the default parameters - inherited by the following "config" elements. - Each "config" element can override the default values, if any. - - A "device" element also has a required "name" attribute that - represents the user-interface name of this device. - </xsd:documentation> - </xsd:annotation> - - <xsd:complexType> - <!-- device defines a choice of 0..1 default element - and 1..n config elements. --> - - <xsd:sequence> - <xsd:element name="default" type="c:parametersType" - minOccurs="0" maxOccurs="1" /> - <xsd:element name="config" type="c:configType" - minOccurs="1" maxOccurs="unbounded" /> - </xsd:sequence> - - <xsd:attribute name="name" type="xsd:normalizedString" use="required" /> - </xsd:complexType> - - </xsd:element> - </xsd:sequence> - </xsd:complexType> - - <!-- The type of a device>default element. - This is overridden by configType below for the device>config element. - --> - <xsd:complexType name="parametersType"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - The parametersType define all the parameters that can happen either in a - "default" element or in a named "config" element. - Each parameter element can appear once at most. - - Parameters here are the same as those used to specify alternate Android - resources, as documented by - http://d.android.com/guide/topics/resources/resources-i18n.html#AlternateResources - </xsd:documentation> - </xsd:annotation> - - <xsd:all> - <!-- parametersType says that 0..1 of each of these elements must be declared. --> - - <xsd:element name="country-code" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the configuration is for a particular Mobile Country Code. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:float"> - <xsd:minInclusive value="100" /> - <xsd:maxInclusive value="999" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="network-code" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the configuration is for a particular Mobile Network Code. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:float"> - <xsd:minExclusive value="0" /> - <xsd:maxExclusive value="1000" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="screen-size" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies that the configuration is for a particular class of screen. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="small" /> - <xsd:enumeration value="normal" /> - <xsd:enumeration value="large" /> - <xsd:enumeration value="xlarge" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="screen-ratio" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies that the configuration is for a taller/wider than traditional - screen. This is based purely on the aspect ration of the screen: QVGA, - HVGA, and VGA are notlong; WQVGA, WVGA, FWVGA are long. Note that long - may mean either wide or tall, depending on the current orientation. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="long" /> - <xsd:enumeration value="notlong" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="screen-orientation" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies that the configuration is for a screen that is tall (port) or - wide (land). - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="port" /> - <xsd:enumeration value="land" /> - <xsd:enumeration value="square" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="pixel-density" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the screen density the configuration is defined for. The medium - density of traditional HVGA screens (mdpi) is defined to be approximately - 160dpi; low density (ldpi) is 120, and high density (hdpi) is 240. There - is thus a 4:3 scaling factor between each density, so a 9x9 bitmap in ldpi - would be 12x12 is mdpi and 16x16 in hdpi. - The special nodpi density that can be used in resource qualifiers is not - a valid keyword here. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="ldpi" /> - <xsd:enumeration value="mdpi" /> - <xsd:enumeration value="tvdpi" /> - <xsd:enumeration value="hdpi" /> - <xsd:enumeration value="xhdpi" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="touch-type" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the touch type the configuration is defined for. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="notouch" /> - <xsd:enumeration value="stylus" /> - <xsd:enumeration value="finger" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="keyboard-state" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - If your configuration uses a soft keyboard, use the keyssoft value. - If it doesn't and has a real keyboard, use keysexposed or keyshidden. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="keysexposed" /> - <xsd:enumeration value="keyshidden" /> - <xsd:enumeration value="keyssoft" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="text-input-method" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the primary text input method the configuration is designed for. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="nokeys" /> - <xsd:enumeration value="qwerty" /> - <xsd:enumeration value="12key" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="nav-state" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies whether the primary non-touchscreen navigation control is - exposed or hidden. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="navexposed" /> - <xsd:enumeration value="navhidden" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="nav-method" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the primary non-touchscreen navigation method the configuration - is designed for. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:token"> - <xsd:enumeration value="dpad" /> - <xsd:enumeration value="trackball" /> - <xsd:enumeration value="wheel" /> - <xsd:enumeration value="nonav" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="screen-dimension" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the device screen resolution, in pixels. - </xsd:documentation> - </xsd:annotation> - <xsd:complexType> - <xsd:sequence minOccurs="2" maxOccurs="2"> - - <xsd:element name="size"> - <xsd:simpleType> - <xsd:restriction base="xsd:positiveInteger" /> - </xsd:simpleType> - </xsd:element> - - </xsd:sequence> - </xsd:complexType> - </xsd:element> - - <xsd:element name="xdpi" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the actual density in X of the device screen. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:float"> - <xsd:minExclusive value="0" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - <xsd:element name="ydpi" minOccurs="0"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - Specifies the actual density in Y of the device screen. - </xsd:documentation> - </xsd:annotation> - <xsd:simpleType> - <xsd:restriction base="xsd:float"> - <xsd:minExclusive value="0" /> - </xsd:restriction> - </xsd:simpleType> - </xsd:element> - - </xsd:all> - </xsd:complexType> - - <!-- The type definition of a device>config element. - This type is basically all the element defined by parametersType and an extra - required "name" attribute for the user-interface configuration name. - --> - <xsd:complexType name="configType"> - <xsd:annotation> - <xsd:documentation> - The configType defines the content of a "config" element in a "device" element. - - A "config" element can have all the parameters elements defined by - "parameterType". It also has a required "name" attribute that indicates the - user-interface name for this configuration. - </xsd:documentation> - </xsd:annotation> - - <xsd:complexContent> - <xsd:extension base="c:parametersType"> - <xsd:attribute name="name" type="xsd:normalizedString" use="required" /> - </xsd:extension> - </xsd:complexContent> - </xsd:complexType> - -</xsd:schema> |