Home | History | Annotate | Download | only in resources
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.common.resources;
     18 
     19 import static com.android.AndroidConstants.FD_RES_VALUES;
     20 
     21 import com.android.ide.common.log.ILogger;
     22 import com.android.io.IAbstractFile;
     23 import com.android.io.IAbstractFolder;
     24 import com.android.resources.ResourceType;
     25 
     26 import org.w3c.dom.Document;
     27 import org.w3c.dom.Element;
     28 import org.w3c.dom.Node;
     29 import org.w3c.dom.NodeList;
     30 import org.xml.sax.InputSource;
     31 
     32 import java.io.BufferedReader;
     33 import java.io.IOException;
     34 import java.io.InputStreamReader;
     35 import java.io.Reader;
     36 import java.util.ArrayList;
     37 import java.util.Collection;
     38 import java.util.Collections;
     39 import java.util.EnumMap;
     40 import java.util.List;
     41 import java.util.Map;
     42 
     43 import javax.xml.parsers.DocumentBuilder;
     44 import javax.xml.parsers.DocumentBuilderFactory;
     45 
     46 /**
     47  * Framework resources repository.
     48  *
     49  * This behaves the same as {@link ResourceRepository} except that it differentiates between
     50  * resources that are public and non public.
     51  * {@link #getResources(ResourceType)} and {@link #hasResourcesOfType(ResourceType)} only return
     52  * public resources. This is typically used to display resource lists in the UI.
     53  *
     54  * {@link #getConfiguredResources(com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration)}
     55  * returns all resources, even the non public ones so that this can be used for rendering.
     56  */
     57 public class FrameworkResources extends ResourceRepository {
     58 
     59     /**
     60      * Map of {@link ResourceType} to list of items. It is guaranteed to contain a list for all
     61      * possible values of ResourceType.
     62      */
     63     protected final Map<ResourceType, List<ResourceItem>> mPublicResourceMap =
     64         new EnumMap<ResourceType, List<ResourceItem>>(ResourceType.class);
     65 
     66     public FrameworkResources() {
     67         super(true /*isFrameworkRepository*/);
     68     }
     69 
     70     /**
     71      * Returns a {@link Collection} (always non null, but can be empty) of <b>public</b>
     72      * {@link ResourceItem} matching a given {@link ResourceType}.
     73      *
     74      * @param type the type of the resources to return
     75      * @return a collection of items, possible empty.
     76      */
     77     @Override
     78     public List<ResourceItem> getResourceItemsOfType(ResourceType type) {
     79         return mPublicResourceMap.get(type);
     80     }
     81 
     82     /**
     83      * Returns whether the repository has <b>public</b> resources of a given {@link ResourceType}.
     84      * @param type the type of resource to check.
     85      * @return true if the repository contains resources of the given type, false otherwise.
     86      */
     87     @Override
     88     public boolean hasResourcesOfType(ResourceType type) {
     89         return mPublicResourceMap.get(type).size() > 0;
     90     }
     91 
     92     @Override
     93     protected ResourceItem createResourceItem(String name) {
     94         return new FrameworkResourceItem(name);
     95     }
     96 
     97     /**
     98      * Reads the public.xml file in data/res/values/ for a given resource folder and builds up
     99      * a map of public resources.
    100      *
    101      * This map is a subset of the full resource map that only contains framework resources
    102      * that are public.
    103      *
    104      * @param osFrameworkResourcePath The root folder of the resources
    105      */
    106     public void loadPublicResources(IAbstractFolder resFolder, ILogger logger) {
    107         IAbstractFolder valueFolder = resFolder.getFolder(FD_RES_VALUES);
    108         if (valueFolder.exists() == false) {
    109             return;
    110         }
    111 
    112         IAbstractFile publicXmlFile = valueFolder.getFile("public.xml"); //$NON-NLS-1$
    113         if (publicXmlFile.exists()) {
    114             Document document = null;
    115             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    116             Reader reader = null;
    117             try {
    118                 reader = new BufferedReader(new InputStreamReader(publicXmlFile.getContents()));
    119                 InputSource is = new InputSource(reader);
    120                 factory.setNamespaceAware(true);
    121                 factory.setValidating(false);
    122                 DocumentBuilder builder = factory.newDocumentBuilder();
    123                 document = builder.parse(is);
    124 
    125                 ResourceType lastType = null;
    126                 String lastTypeName = "";
    127 
    128                 NodeList children = document.getDocumentElement().getChildNodes();
    129                 for (int i = 0, n = children.getLength(); i < n; i++) {
    130                     Node node = children.item(i);
    131                     if (node.getNodeType() == Node.ELEMENT_NODE) {
    132                         Element element = (Element) node;
    133                         String name = element.getAttribute("name"); //$NON-NLS-1$
    134                         if (name.length() > 0) {
    135                             String typeName = element.getAttribute("type"); //$NON-NLS-1$
    136                             ResourceType type = null;
    137                             if (typeName.equals(lastTypeName)) {
    138                                 type = lastType;
    139                             } else {
    140                                 type = ResourceType.getEnum(typeName);
    141                                 lastType = type;
    142                                 lastTypeName = typeName;
    143                             }
    144                             if (type != null) {
    145                                 List<ResourceItem> typeList = mResourceMap.get(type);
    146 
    147                                 ResourceItem match = null;
    148                                 if (typeList != null) {
    149                                     for (ResourceItem item : typeList) {
    150                                         if (name.equals(item.getName())) {
    151                                             match = item;
    152                                             break;
    153                                         }
    154                                     }
    155                                 }
    156 
    157                                 if (match != null) {
    158                                     List<ResourceItem> publicList = mPublicResourceMap.get(type);
    159                                     if (publicList == null) {
    160                                         publicList = new ArrayList<ResourceItem>();
    161                                         mPublicResourceMap.put(type, publicList);
    162                                     }
    163 
    164                                     publicList.add(match);
    165                                 } else {
    166                                     // log that there's a public resource that doesn't actually
    167                                     // exist?
    168                                 }
    169                             }
    170                         }
    171                     }
    172                 }
    173             } catch (Exception e) {
    174                 if (logger != null) {
    175                     logger.error(e, "Can't read and parse public attribute list");
    176                 }
    177             } finally {
    178                 if (reader != null) {
    179                     try {
    180                         reader.close();
    181                     } catch (IOException e) {
    182                         // Nothing to be done here - we don't care if it closed or not.
    183                     }
    184                 }
    185             }
    186         }
    187 
    188         // put unmodifiable list for all res type in the public resource map
    189         // this will simplify access
    190         for (ResourceType type : ResourceType.values()) {
    191             List<ResourceItem> list = mPublicResourceMap.get(type);
    192             if (list == null) {
    193                 list = Collections.emptyList();
    194             } else {
    195                 list = Collections.unmodifiableList(list);
    196             }
    197 
    198             // put the new list in the map
    199             mPublicResourceMap.put(type, list);
    200         }
    201     }
    202 }
    203