aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java271
1 files changed, 271 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
new file mode 100644
index 000000000..7c3fd4c13
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
@@ -0,0 +1,271 @@
+/*
+ * 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.resources.manager;
+
+import com.android.SdkConstants;
+import com.android.annotations.NonNull;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.IntArrayWrapper;
+import com.android.ide.common.resources.ResourceFolder;
+import com.android.ide.common.resources.ResourceItem;
+import com.android.ide.common.resources.ResourceRepository;
+import com.android.ide.common.resources.configuration.FolderConfiguration;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.ide.eclipse.adt.io.IFolderWrapper;
+import com.android.io.IAbstractFolder;
+import com.android.resources.ResourceType;
+import com.android.util.Pair;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Represents the resources of a project.
+ * On top of the regular {@link ResourceRepository} features it provides:
+ *<ul>
+ *<li>configured resources contain the resources coming from the libraries.</li>
+ *<li>resolution to and from resource integer (compiled value in R.java).</li>
+ *<li>handles resource integer for non existing values of type ID. This is used when rendering.</li>
+ *<li>layouts that have no been saved yet. This is handled by generating dynamic IDs
+ * on the fly.</li>
+ *</ul>
+ */
+@SuppressWarnings("deprecation")
+public class ProjectResources extends ResourceRepository {
+ // project resources are defined as 0x7FXX#### where XX is the resource type (layout, drawable,
+ // etc...). Using FF as the type allows for 255 resource types before we get a collision
+ // which should be fine.
+ private final static int DYNAMIC_ID_SEED_START = 0x7fff0000;
+
+ /** Map of (name, id) for resources of type {@link ResourceType#ID} coming from R.java */
+ private Map<ResourceType, Map<String, Integer>> mResourceValueMap;
+ /** Map of (id, [name, resType]) for all resources coming from R.java */
+ private Map<Integer, Pair<ResourceType, String>> mResIdValueToNameMap;
+ /** Map of (int[], name) for styleable resources coming from R.java */
+ private Map<IntArrayWrapper, String> mStyleableValueToNameMap;
+
+ private final DynamicIdMap mDynamicIdMap = new DynamicIdMap(DYNAMIC_ID_SEED_START);
+ private final IntArrayWrapper mWrapper = new IntArrayWrapper(null);
+ private final IProject mProject;
+
+ public static ProjectResources create(IProject project) {
+ IFolder resFolder = project.getFolder(SdkConstants.FD_RESOURCES);
+
+ return new ProjectResources(project, new IFolderWrapper(resFolder));
+ }
+
+ /**
+ * Makes a ProjectResources for a given <var>project</var>.
+ * @param project the project.
+ */
+ private ProjectResources(IProject project, IAbstractFolder resFolder) {
+ super(resFolder, false /*isFrameworkRepository*/);
+ mProject = project;
+ }
+
+ /**
+ * Returns the resources values matching a given {@link FolderConfiguration}, this will
+ * include library dependency.
+ *
+ * @param referenceConfig the configuration that each value must match.
+ * @return a map with guaranteed to contain an entry for each {@link ResourceType}
+ */
+ @Override
+ @NonNull
+ public Map<ResourceType, Map<String, ResourceValue>> getConfiguredResources(
+ @NonNull FolderConfiguration referenceConfig) {
+ ensureInitialized();
+
+ Map<ResourceType, Map<String, ResourceValue>> resultMap =
+ new EnumMap<ResourceType, Map<String, ResourceValue>>(ResourceType.class);
+
+ // if the project contains libraries, we need to add the libraries resources here
+ // so that they are accessible to the layout rendering.
+ if (mProject != null) {
+ ProjectState state = Sdk.getProjectState(mProject);
+ if (state != null) {
+ List<IProject> libraries = state.getFullLibraryProjects();
+
+ ResourceManager resMgr = ResourceManager.getInstance();
+
+ // because aapt put all the library in their order in this array, the first
+ // one will have priority over the 2nd one. So it's better to loop in the inverse
+ // order and fill the map with resources that will be overwritten by higher
+ // priority resources
+ for (int i = libraries.size() - 1 ; i >= 0 ; i--) {
+ IProject library = libraries.get(i);
+
+ ProjectResources libRes = resMgr.getProjectResources(library);
+ if (libRes != null) {
+ // get the library resources, and only the library, not the dependencies
+ // so call doGetConfiguredResources() directly.
+ Map<ResourceType, Map<String, ResourceValue>> libMap =
+ libRes.doGetConfiguredResources(referenceConfig);
+
+ // we don't want to simply replace the whole map, but instead merge the
+ // content of any sub-map
+ for (Entry<ResourceType, Map<String, ResourceValue>> libEntry :
+ libMap.entrySet()) {
+
+ // get the map currently in the result map for this resource type
+ Map<String, ResourceValue> tempMap = resultMap.get(libEntry.getKey());
+ if (tempMap == null) {
+ // since there's no current map for this type, just add the map
+ // directly coming from the library resources
+ resultMap.put(libEntry.getKey(), libEntry.getValue());
+ } else {
+ // already a map for this type. add the resources from the
+ // library, this will override existing value, which is why
+ // we loop in a specific library order.
+ tempMap.putAll(libEntry.getValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // now the project resources themselves.
+ Map<ResourceType, Map<String, ResourceValue>> thisProjectMap =
+ doGetConfiguredResources(referenceConfig);
+
+ // now merge the maps.
+ for (Entry<ResourceType, Map<String, ResourceValue>> entry : thisProjectMap.entrySet()) {
+ ResourceType type = entry.getKey();
+ Map<String, ResourceValue> typeMap = resultMap.get(type);
+ if (typeMap == null) {
+ resultMap.put(type, entry.getValue());
+ } else {
+ typeMap.putAll(entry.getValue());
+ }
+ }
+
+ return resultMap;
+ }
+
+ /**
+ * Returns the {@link ResourceFolder} associated with a {@link IFolder}.
+ * @param folder The {@link IFolder} object.
+ * @return the {@link ResourceFolder} or null if it was not found.
+ *
+ * @see ResourceRepository#getResourceFolder(com.android.io.IAbstractFolder)
+ */
+ public ResourceFolder getResourceFolder(IFolder folder) {
+ return getResourceFolder(new IFolderWrapper(folder));
+ }
+
+ /**
+ * Resolves a compiled resource id into the resource name and type
+ * @param id the resource integer id.
+ * @return a {@link Pair} of 2 strings { name, type } or null if the id could not be resolved
+ */
+ public Pair<ResourceType, String> resolveResourceId(int id) {
+ Pair<ResourceType, String> result = null;
+ if (mResIdValueToNameMap != null) {
+ result = mResIdValueToNameMap.get(id);
+ }
+
+ if (result == null) {
+ synchronized (mDynamicIdMap) {
+ result = mDynamicIdMap.resolveId(id);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Resolves a compiled styleable id of type int[] into the styleable name.
+ */
+ public String resolveStyleable(int[] id) {
+ if (mStyleableValueToNameMap != null) {
+ mWrapper.set(id);
+ return mStyleableValueToNameMap.get(mWrapper);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the integer id of a resource given its type and name.
+ * <p/>If the resource is of type {@link ResourceType#ID} and does not exist in the
+ * internal map, then new id values are dynamically generated (and stored so that queries
+ * with the same names will return the same value).
+ */
+ public Integer getResourceId(ResourceType type, String name) {
+ Integer result = null;
+ if (mResourceValueMap != null) {
+ Map<String, Integer> map = mResourceValueMap.get(type);
+ if (map != null) {
+ result = map.get(name);
+ }
+ }
+
+ if (result == null) {
+ synchronized (mDynamicIdMap) {
+ result = mDynamicIdMap.getId(type, name);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Resets the list of dynamic Ids. This list is used by
+ * {@link #getResourceId(String, String)} when the resource query is an ID that doesn't
+ * exist (for example for ID automatically generated in layout files that are not saved yet.)
+ * <p/>This method resets those dynamic ID and must be called whenever the actual list of IDs
+ * change.
+ */
+ public void resetDynamicIds() {
+ synchronized (mDynamicIdMap) {
+ mDynamicIdMap.reset(DYNAMIC_ID_SEED_START);
+ }
+ }
+
+ @Override
+ @NonNull
+ protected ResourceItem createResourceItem(@NonNull String name) {
+ return new ResourceItem(name);
+ }
+
+ /**
+ * Sets compiled resource information.
+ *
+ * @param resIdValueToNameMap a map of compiled resource id to resource name.
+ * The map is acquired by the {@link ProjectResources} object.
+ * @param styleableValueMap a map of (int[], name) for the styleable information. The map is
+ * acquired by the {@link ProjectResources} object.
+ * @param resourceValueMap a map of (name, id) for resources of type {@link ResourceType#ID}.
+ * The list is acquired by the {@link ProjectResources} object.
+ */
+ void setCompiledResources(Map<Integer, Pair<ResourceType, String>> resIdValueToNameMap,
+ Map<IntArrayWrapper, String> styleableValueMap,
+ Map<ResourceType, Map<String, Integer>> resourceValueMap) {
+ mResourceValueMap = resourceValueMap;
+ mResIdValueToNameMap = resIdValueToNameMap;
+ mStyleableValueToNameMap = styleableValueMap;
+
+ resetDynamicIds();
+ }
+}