aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java621
1 files changed, 0 insertions, 621 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java
deleted file mode 100644
index 6df6929a7..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java
+++ /dev/null
@@ -1,621 +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.editors.layout.descriptors;
-
-import static com.android.SdkConstants.ANDROID_NS_NAME_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.AUTO_URI;
-import static com.android.SdkConstants.CLASS_VIEWGROUP;
-import static com.android.SdkConstants.URI_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.resources.ResourceFile;
-import com.android.ide.common.resources.ResourceItem;
-import com.android.ide.common.resources.platform.AttributeInfo;
-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.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.resources.ResourceType;
-import com.android.sdklib.IAndroidTarget;
-import com.google.common.collect.Maps;
-import com.google.common.collect.ObjectArrays;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspaceRoot;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.jdt.core.IClassFile;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.ITypeHierarchy;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.swt.graphics.Image;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Service responsible for creating/managing {@link ViewElementDescriptor} objects for custom
- * View classes per project.
- * <p/>
- * The service provides an on-demand monitoring of custom classes to check for changes. Monitoring
- * starts once a request for an {@link ViewElementDescriptor} object has been done for a specific
- * class.
- * <p/>
- * The monitoring will notify a listener of any changes in the class triggering a change in its
- * associated {@link ViewElementDescriptor} object.
- * <p/>
- * If the custom class does not exist, no monitoring is put in place to avoid having to listen
- * to all class changes in the projects.
- */
-public final class CustomViewDescriptorService {
-
- private static CustomViewDescriptorService sThis = new CustomViewDescriptorService();
-
- /**
- * Map where keys are the project, and values are another map containing all the known
- * custom View class for this project. The custom View class are stored in a map
- * where the keys are the fully qualified class name, and the values are their associated
- * {@link ViewElementDescriptor}.
- */
- private HashMap<IProject, HashMap<String, ViewElementDescriptor>> mCustomDescriptorMap =
- new HashMap<IProject, HashMap<String, ViewElementDescriptor>>();
-
- /**
- * TODO will be used to update the ViewElementDescriptor of the custom view when it
- * is modified (either the class itself or its attributes.xml)
- */
- @SuppressWarnings("unused")
- private ICustomViewDescriptorListener mListener;
-
- /**
- * Classes which implements this interface provide a method that deal with modifications
- * in custom View class triggering a change in its associated {@link ViewClassInfo} object.
- */
- public interface ICustomViewDescriptorListener {
- /**
- * Sent when a custom View class has changed and
- * its {@link ViewElementDescriptor} was modified.
- *
- * @param project the project containing the class.
- * @param className the fully qualified class name.
- * @param descriptor the updated ElementDescriptor.
- */
- public void updatedClassInfo(IProject project,
- String className,
- ViewElementDescriptor descriptor);
- }
-
- /**
- * Returns the singleton instance of {@link CustomViewDescriptorService}.
- */
- public static CustomViewDescriptorService getInstance() {
- return sThis;
- }
-
- /**
- * Sets the listener receiving custom View class modification notifications.
- * @param listener the listener to receive the notifications.
- *
- * TODO will be used to update the ViewElementDescriptor of the custom view when it
- * is modified (either the class itself or its attributes.xml)
- */
- public void setListener(ICustomViewDescriptorListener listener) {
- mListener = listener;
- }
-
- /**
- * Returns the {@link ViewElementDescriptor} for a particular project/class when the
- * fully qualified class name actually matches a class from the given project.
- * <p/>
- * Custom descriptors are created as needed.
- * <p/>
- * If it is the first time the {@link ViewElementDescriptor} is requested, the method
- * will check that the specified class is in fact a custom View class. Once this is
- * established, a monitoring for that particular class is initiated. Any change will
- * trigger a notification to the {@link ICustomViewDescriptorListener}.
- *
- * @param project the project containing the class.
- * @param fqcn the fully qualified name of the class.
- * @return a {@link ViewElementDescriptor} or <code>null</code> if the class was not
- * a custom View class.
- */
- public ViewElementDescriptor getDescriptor(IProject project, String fqcn) {
- // look in the map first
- synchronized (mCustomDescriptorMap) {
- HashMap<String, ViewElementDescriptor> map = mCustomDescriptorMap.get(project);
-
- if (map != null) {
- ViewElementDescriptor descriptor = map.get(fqcn);
- if (descriptor != null) {
- return descriptor;
- }
- }
-
- // if we step here, it looks like we haven't created it yet.
- // First lets check this is in fact a valid type in the project
-
- try {
- // We expect the project to be both opened and of java type (since it's an android
- // project), so we can create a IJavaProject object from our IProject.
- IJavaProject javaProject = JavaCore.create(project);
-
- // replace $ by . in the class name
- String javaClassName = fqcn.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS-2$
-
- // look for the IType object for this class
- IType type = javaProject.findType(javaClassName);
- if (type != null && type.exists()) {
- // the type exists. Let's get the parent class and its ViewClassInfo.
-
- // get the type hierarchy
- ITypeHierarchy hierarchy = type.newSupertypeHierarchy(
- new NullProgressMonitor());
-
- ViewElementDescriptor parentDescriptor = createViewDescriptor(
- hierarchy.getSuperclass(type), project, hierarchy);
-
- if (parentDescriptor != null) {
- // we have a valid parent, lets create a new ViewElementDescriptor.
- List<AttributeDescriptor> attrList = new ArrayList<AttributeDescriptor>();
- List<AttributeDescriptor> paramList = new ArrayList<AttributeDescriptor>();
- Map<ResourceFile, Long> files = findCustomDescriptors(project, type,
- attrList, paramList);
-
- AttributeDescriptor[] attributes =
- getAttributeDescriptor(type, parentDescriptor);
- if (!attrList.isEmpty()) {
- attributes = join(attrList, attributes);
- }
- AttributeDescriptor[] layoutAttributes =
- getLayoutAttributeDescriptors(type, parentDescriptor);
- if (!paramList.isEmpty()) {
- layoutAttributes = join(paramList, layoutAttributes);
- }
- String name = DescriptorsUtils.getBasename(fqcn);
- ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn,
- attributes,
- layoutAttributes,
- parentDescriptor.getChildren(),
- project, files);
- descriptor.setSuperClass(parentDescriptor);
-
- synchronized (mCustomDescriptorMap) {
- map = mCustomDescriptorMap.get(project);
- if (map == null) {
- map = new HashMap<String, ViewElementDescriptor>();
- mCustomDescriptorMap.put(project, map);
- }
-
- map.put(fqcn, descriptor);
- }
-
- //TODO setup listener on this resource change.
-
- return descriptor;
- }
- }
- } catch (JavaModelException e) {
- // there was an error accessing any of the IType, we'll just return null;
- }
- }
-
- return null;
- }
-
- private static AttributeDescriptor[] join(
- @NonNull List<AttributeDescriptor> attributeList,
- @NonNull AttributeDescriptor[] attributes) {
- if (!attributeList.isEmpty()) {
- return ObjectArrays.concat(
- attributeList.toArray(new AttributeDescriptor[attributeList.size()]),
- attributes,
- AttributeDescriptor.class);
- } else {
- return attributes;
- }
-
- }
-
- /** Cache used by {@link #getParser(ResourceFile)} */
- private Map<ResourceFile, AttrsXmlParser> mParserCache;
-
- private AttrsXmlParser getParser(ResourceFile file) {
- if (mParserCache == null) {
- mParserCache = new HashMap<ResourceFile, AttrsXmlParser>();
- }
-
- AttrsXmlParser parser = mParserCache.get(file);
- if (parser == null) {
- parser = new AttrsXmlParser(
- file.getFile().getOsLocation(),
- AdtPlugin.getDefault(), 20);
- parser.preload();
- mParserCache.put(file, parser);
- }
-
- return parser;
- }
-
- /** Compute/find the styleable resources for the given type, if possible */
- private Map<ResourceFile, Long> findCustomDescriptors(
- IProject project,
- IType type,
- List<AttributeDescriptor> customAttributes,
- List<AttributeDescriptor> customLayoutAttributes) {
- // Look up the project where the type is declared (could be a library project;
- // we cannot use type.getJavaProject().getProject())
- IProject library = getProjectDeclaringType(type);
- if (library == null) {
- library = project;
- }
-
- String className = type.getElementName();
- Set<ResourceFile> resourceFiles = findAttrsFiles(library, className);
- if (resourceFiles != null && resourceFiles.size() > 0) {
- String appUri = getAppResUri(project);
- Map<ResourceFile, Long> timestamps =
- Maps.newHashMapWithExpectedSize(resourceFiles.size());
- for (ResourceFile file : resourceFiles) {
- AttrsXmlParser attrsXmlParser = getParser(file);
- String fqcn = type.getFullyQualifiedName();
-
- // Attributes
- ViewClassInfo classInfo = new ViewClassInfo(true, fqcn, className);
- attrsXmlParser.loadViewAttributes(classInfo);
- appendAttributes(customAttributes, classInfo.getAttributes(), appUri);
-
- // Layout params
- LayoutParamsInfo layoutInfo = new ViewClassInfo.LayoutParamsInfo(
- classInfo, "Layout", null /*superClassInfo*/); //$NON-NLS-1$
- attrsXmlParser.loadLayoutParamsAttributes(layoutInfo);
- appendAttributes(customLayoutAttributes, layoutInfo.getAttributes(), appUri);
-
- timestamps.put(file, file.getFile().getModificationStamp());
- }
-
- return timestamps;
- }
-
- return null;
- }
-
- /**
- * Finds the set of XML files (if any) in the given library declaring
- * attributes for the given class name
- */
- @Nullable
- private static Set<ResourceFile> findAttrsFiles(IProject library, String className) {
- Set<ResourceFile> resourceFiles = null;
- ResourceManager manager = ResourceManager.getInstance();
- ProjectResources resources = manager.getProjectResources(library);
- if (resources != null) {
- Collection<ResourceItem> items =
- resources.getResourceItemsOfType(ResourceType.DECLARE_STYLEABLE);
- for (ResourceItem item : items) {
- String viewName = item.getName();
- if (viewName.equals(className)
- || (viewName.startsWith(className)
- && viewName.equals(className + "_Layout"))) { //$NON-NLS-1$
- if (resourceFiles == null) {
- resourceFiles = new HashSet<ResourceFile>();
- }
- resourceFiles.addAll(item.getSourceFileList());
- }
- }
- }
- return resourceFiles;
- }
-
- /**
- * Find the project containing this type declaration. We cannot use
- * {@link IType#getJavaProject()} since that will return the including
- * project and we're after the library project such that we can find the
- * attrs.xml file in the same project.
- */
- @Nullable
- private static IProject getProjectDeclaringType(IType type) {
- IClassFile classFile = type.getClassFile();
- if (classFile != null) {
- IPath path = classFile.getPath();
- IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot();
- IResource resource;
- if (path.isAbsolute()) {
- resource = AdtUtils.fileToResource(path.toFile());
- } else {
- resource = workspace.findMember(path);
- }
- if (resource != null && resource.getProject() != null) {
- return resource.getProject();
- }
- }
-
- return null;
- }
-
- /** Returns the name space to use for application attributes */
- private static String getAppResUri(IProject project) {
- String appResource;
- ProjectState projectState = Sdk.getProjectState(project);
- if (projectState != null && projectState.isLibrary()) {
- appResource = AUTO_URI;
- } else {
- ManifestInfo manifestInfo = ManifestInfo.get(project);
- appResource = URI_PREFIX + manifestInfo.getPackage();
- }
- return appResource;
- }
-
-
- /** Append the {@link AttributeInfo} objects converted {@link AttributeDescriptor}
- * objects into the given attribute list.
- * <p>
- * This is nearly identical to
- * {@link DescriptorsUtils#appendAttribute(List, String, String, AttributeInfo, boolean, Map)}
- * but it handles namespace declarations in the attrs.xml file where the android:
- * namespace is included in the names.
- */
- private static void appendAttributes(List<AttributeDescriptor> attributes,
- AttributeInfo[] attributeInfos, String appResource) {
- // Custom attributes
- for (AttributeInfo info : attributeInfos) {
- String nsUri;
- if (info.getName().startsWith(ANDROID_NS_NAME_PREFIX)) {
- info.setName(info.getName().substring(ANDROID_NS_NAME_PREFIX.length()));
- nsUri = ANDROID_URI;
- } else {
- nsUri = appResource;
- }
-
- DescriptorsUtils.appendAttribute(attributes,
- null /*elementXmlName*/, nsUri, info, false /*required*/,
- null /*overrides*/);
- }
- }
-
- /**
- * Computes (if needed) and returns the {@link ViewElementDescriptor} for the specified type.
- *
- * @return A {@link ViewElementDescriptor} or null if type or typeHierarchy is null.
- */
- private ViewElementDescriptor createViewDescriptor(IType type, IProject project,
- ITypeHierarchy typeHierarchy) {
- // check if the type is a built-in View class.
- List<ViewElementDescriptor> builtInList = null;
-
- // give up if there's no type
- if (type == null) {
- return null;
- }
-
- String fqcn = type.getFullyQualifiedName();
-
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget target = currentSdk.getTarget(project);
- if (target != null) {
- AndroidTargetData data = currentSdk.getTargetData(target);
- if (data != null) {
- LayoutDescriptors descriptors = data.getLayoutDescriptors();
- ViewElementDescriptor d = descriptors.findDescriptorByClass(fqcn);
- if (d != null) {
- return d;
- }
- builtInList = descriptors.getViewDescriptors();
- }
- }
- }
-
- // it's not a built-in class? Lets look if the superclass is built-in
- // give up if there's no type
- if (typeHierarchy == null) {
- return null;
- }
-
- IType parentType = typeHierarchy.getSuperclass(type);
- if (parentType != null) {
- ViewElementDescriptor parentDescriptor = createViewDescriptor(parentType, project,
- typeHierarchy);
-
- if (parentDescriptor != null) {
- // parent class is a valid View class with a descriptor, so we create one
- // for this class.
- String name = DescriptorsUtils.getBasename(fqcn);
- // A custom view accepts children if its parent descriptor also does.
- // The only exception to this is ViewGroup, which accepts children even though
- // its parent does not.
- boolean isViewGroup = fqcn.equals(CLASS_VIEWGROUP);
- boolean hasChildren = isViewGroup || parentDescriptor.hasChildren();
- ViewElementDescriptor[] children = null;
- if (hasChildren && builtInList != null) {
- // We can't figure out what the allowable children are by just
- // looking at the class, so assume any View is valid
- children = builtInList.toArray(new ViewElementDescriptor[builtInList.size()]);
- }
- ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn,
- getAttributeDescriptor(type, parentDescriptor),
- getLayoutAttributeDescriptors(type, parentDescriptor),
- children, project, null);
- descriptor.setSuperClass(parentDescriptor);
-
- // add it to the map
- synchronized (mCustomDescriptorMap) {
- HashMap<String, ViewElementDescriptor> map = mCustomDescriptorMap.get(project);
-
- if (map == null) {
- map = new HashMap<String, ViewElementDescriptor>();
- mCustomDescriptorMap.put(project, map);
- }
-
- map.put(fqcn, descriptor);
-
- }
-
- //TODO setup listener on this resource change.
-
- return descriptor;
- }
- }
-
- // class is neither a built-in view class, nor extend one. return null.
- return null;
- }
-
- /**
- * Returns the array of {@link AttributeDescriptor} for the specified {@link IType}.
- * <p/>
- * The array should contain the descriptor for this type and all its supertypes.
- *
- * @param type the type for which the {@link AttributeDescriptor} are returned.
- * @param parentDescriptor the {@link ViewElementDescriptor} of the direct superclass.
- */
- private static AttributeDescriptor[] getAttributeDescriptor(IType type,
- ViewElementDescriptor parentDescriptor) {
- // TODO add the class attribute descriptors to the parent descriptors.
- return parentDescriptor.getAttributes();
- }
-
- private static AttributeDescriptor[] getLayoutAttributeDescriptors(IType type,
- ViewElementDescriptor parentDescriptor) {
- return parentDescriptor.getLayoutAttributes();
- }
-
- private class CustomViewDescriptor extends ViewElementDescriptor {
- private Map<ResourceFile, Long> mTimeStamps;
- private IProject mProject;
-
- public CustomViewDescriptor(String name, String fqcn, AttributeDescriptor[] attributes,
- AttributeDescriptor[] layoutAttributes,
- ElementDescriptor[] children, IProject project,
- Map<ResourceFile, Long> timestamps) {
- super(
- fqcn, // xml name
- name, // ui name
- fqcn, // full class name
- fqcn, // tooltip
- null, // sdk_url
- attributes,
- layoutAttributes,
- children,
- false // mandatory
- );
- mTimeStamps = timestamps;
- mProject = project;
- }
-
- @Override
- public Image getGenericIcon() {
- IconFactory iconFactory = IconFactory.getInstance();
-
- int index = mXmlName.lastIndexOf('.');
- if (index != -1) {
- return iconFactory.getIcon(mXmlName.substring(index + 1),
- "customView"); //$NON-NLS-1$
- }
-
- return iconFactory.getIcon("customView"); //$NON-NLS-1$
- }
-
- @Override
- public boolean syncAttributes() {
- // Check if any of the descriptors
- if (mTimeStamps != null) {
- // Prevent checking actual file timestamps too frequently on rapid burst calls
- long now = System.currentTimeMillis();
- if (now - sLastCheck < 1000) {
- return true;
- }
- sLastCheck = now;
-
- // Check whether the resource files (typically just one) which defined
- // custom attributes for this custom view have changed, and if so,
- // refresh the attribute descriptors.
- // This doesn't work the cases where you add descriptors for a custom
- // view after using it, or add attributes in a separate file, but those
- // scenarios aren't quite as common (and would require a bit more expensive
- // analysis.)
- for (Map.Entry<ResourceFile, Long> entry : mTimeStamps.entrySet()) {
- ResourceFile file = entry.getKey();
- Long timestamp = entry.getValue();
- boolean recompute = false;
- if (file.getFile().getModificationStamp() > timestamp.longValue()) {
- // One or more attributes changed: recompute
- recompute = true;
- mParserCache.remove(file);
- }
-
- if (recompute) {
- IJavaProject javaProject = JavaCore.create(mProject);
- String fqcn = getFullClassName();
- IType type = null;
- try {
- type = javaProject.findType(fqcn);
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
- if (type == null || !type.exists()) {
- return true;
- }
-
- List<AttributeDescriptor> attrList = new ArrayList<AttributeDescriptor>();
- List<AttributeDescriptor> paramList = new ArrayList<AttributeDescriptor>();
-
- mTimeStamps = findCustomDescriptors(mProject, type, attrList, paramList);
-
- ViewElementDescriptor parentDescriptor = getSuperClassDesc();
- AttributeDescriptor[] attributes =
- getAttributeDescriptor(type, parentDescriptor);
- if (!attrList.isEmpty()) {
- attributes = join(attrList, attributes);
- }
- attributes = attrList.toArray(new AttributeDescriptor[attrList.size()]);
- setAttributes(attributes);
-
- return false;
- }
- }
- }
-
- return true;
- }
- }
-
- /** Timestamp of the most recent {@link CustomViewDescriptor#syncAttributes} check */
- private static long sLastCheck;
-}