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 com.android.ide.common.rendering.api.DensityBasedResourceValue;
     20 import com.android.ide.common.rendering.api.ResourceValue;
     21 import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository;
     22 import com.android.ide.common.resources.configuration.DensityQualifier;
     23 import com.android.io.IAbstractFile;
     24 import com.android.io.StreamException;
     25 import com.android.resources.ResourceType;
     26 
     27 import java.io.IOException;
     28 import java.util.Collection;
     29 import java.util.HashMap;
     30 import java.util.HashSet;
     31 import java.util.Map;
     32 import java.util.Set;
     33 
     34 /**
     35  * Represents a resource file that also generates ID resources.
     36  * <p/>
     37  * This is typically an XML file in res/layout or res/menu
     38  */
     39 public final class IdGeneratingResourceFile extends ResourceFile
     40                                             implements IValueResourceRepository {
     41 
     42     private final Map<String, ResourceValue> mIdResources =
     43         new HashMap<String, ResourceValue>();
     44 
     45     private final Collection<ResourceType> mResourceTypeList;
     46 
     47     private final String mFileName;
     48 
     49     private final ResourceType mFileType;
     50 
     51     private final ResourceValue mFileValue;
     52 
     53     public IdGeneratingResourceFile(IAbstractFile file, ResourceFolder folder, ResourceType type) {
     54         super(file, folder);
     55 
     56         mFileType = type;
     57 
     58         // Set up our resource types
     59         mResourceTypeList = new HashSet<ResourceType>();
     60         mResourceTypeList.add(mFileType);
     61         mResourceTypeList.add(ResourceType.ID);
     62 
     63         // compute the resource name
     64         mFileName = getFileName(type);
     65 
     66         // Get the resource value of this file as a whole layout
     67         mFileValue = getFileValue(file, folder);
     68     }
     69 
     70     @Override
     71     protected void load(ScanningContext context) {
     72         // Parse the file and look for @+id/ entries
     73         parseFileForIds(context);
     74 
     75         // create the resource items in the repository
     76         updateResourceItems(context);
     77     }
     78 
     79     @Override
     80     protected void update(ScanningContext context) {
     81         // Copy the previous list of ID names
     82         Set<String> oldIdNames = new HashSet<String>(mIdResources.keySet());
     83 
     84         // reset current content.
     85         mIdResources.clear();
     86 
     87         // need to parse the file and find the IDs.
     88         if (!parseFileForIds(context)) {
     89             context.requestFullAapt();
     90             return;
     91         }
     92 
     93         // We only need to update the repository if our IDs have changed
     94         Set<String> keySet = mIdResources.keySet();
     95         assert keySet != oldIdNames;
     96         if (oldIdNames.equals(keySet) == false) {
     97             updateResourceItems(context);
     98         }
     99     }
    100 
    101     @Override
    102     protected void dispose(ScanningContext context) {
    103         ResourceRepository repository = getRepository();
    104 
    105         // Remove declarations from this file from the repository
    106         repository.removeFile(mResourceTypeList, this);
    107 
    108         // Ask for an ID refresh since we'll be taking away ID generating items
    109         context.requestFullAapt();
    110     }
    111 
    112     @Override
    113     public Collection<ResourceType> getResourceTypes() {
    114         return mResourceTypeList;
    115     }
    116 
    117     @Override
    118     public boolean hasResources(ResourceType type) {
    119         return (type == mFileType) || (type == ResourceType.ID && !mIdResources.isEmpty());
    120     }
    121 
    122     @Override
    123     public ResourceValue getValue(ResourceType type, String name) {
    124         // Check to see if they're asking for one of the right types:
    125         if (type != mFileType && type != ResourceType.ID) {
    126             return null;
    127         }
    128 
    129         // If they're looking for a resource of this type with this name give them the whole file
    130         if (type == mFileType && name.equals(mFileName)) {
    131             return mFileValue;
    132         } else {
    133             // Otherwise try to return them an ID
    134             // the map will return null if it's not found
    135             return mIdResources.get(name);
    136         }
    137     }
    138 
    139     /**
    140      * Looks through the file represented for Ids and adds them to
    141      * our id repository
    142      *
    143      * @return true if parsing succeeds and false if it fails
    144      */
    145     private boolean parseFileForIds(ScanningContext context) {
    146         IdResourceParser parser = new IdResourceParser(this, context, isFramework());
    147         try {
    148             IAbstractFile file = getFile();
    149             return parser.parse(mFileType, file.getOsLocation(), file.getContents());
    150         } catch (IOException e) {
    151             // Pass
    152         } catch (StreamException e) {
    153             // Pass
    154         }
    155 
    156         return false;
    157     }
    158 
    159     /**
    160      * Add the resources represented by this file to the repository
    161      */
    162     private void updateResourceItems(ScanningContext context) {
    163         ResourceRepository repository = getRepository();
    164 
    165         // remove this file from all existing ResourceItem.
    166         repository.removeFile(mResourceTypeList, this);
    167 
    168         // First add this as a layout file
    169         ResourceItem item = repository.getResourceItem(mFileType, mFileName);
    170         item.add(this);
    171 
    172         // Now iterate through our IDs and add
    173         for (String idName : mIdResources.keySet()) {
    174             item = repository.getResourceItem(ResourceType.ID, idName);
    175             // add this file to the list of files generating ID resources.
    176             item.add(this);
    177         }
    178 
    179         //  Ask the repository for an ID refresh
    180         context.requestFullAapt();
    181     }
    182 
    183     /**
    184      * Returns the resource value associated with this whole file as a layout resource
    185      * @param file the file handler that represents this file
    186      * @param folder the folder this file is under
    187      * @return a resource value associated with this layout
    188      */
    189     private ResourceValue getFileValue(IAbstractFile file, ResourceFolder folder) {
    190         // test if there's a density qualifier associated with the resource
    191         DensityQualifier qualifier = folder.getConfiguration().getDensityQualifier();
    192 
    193         ResourceValue value;
    194         if (qualifier == null) {
    195             value = new ResourceValue(mFileType, mFileName,
    196                     file.getOsLocation(), isFramework());
    197         } else {
    198             value = new DensityBasedResourceValue(
    199                     mFileType, mFileName,
    200                     file.getOsLocation(),
    201                     qualifier.getValue(),
    202                     isFramework());
    203         }
    204         return value;
    205     }
    206 
    207 
    208     /**
    209      * Returns the name of this resource.
    210      */
    211     private String getFileName(ResourceType type) {
    212         // get the name from the filename.
    213         String name = getFile().getName();
    214 
    215         int pos = name.indexOf('.');
    216         if (pos != -1) {
    217             name = name.substring(0, pos);
    218         }
    219 
    220         return name;
    221     }
    222 
    223     @Override
    224     public void addResourceValue(ResourceValue value) {
    225         // Just overwrite collisions. We're only interested in the unique
    226         // IDs declared
    227         mIdResources.put(value.getName(), value);
    228     }
    229 }
    230