• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IdGeneratingResourceFile(IAbstractFile file, ResourceFolder folder, ResourceType type)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
load(ScanningContext context)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
update(ScanningContext context)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
dispose(ScanningContext context)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
getResourceTypes()113     public Collection<ResourceType> getResourceTypes() {
114         return mResourceTypeList;
115     }
116 
117     @Override
hasResources(ResourceType type)118     public boolean hasResources(ResourceType type) {
119         return (type == mFileType) || (type == ResourceType.ID && !mIdResources.isEmpty());
120     }
121 
122     @Override
getValue(ResourceType type, String name)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      */
parseFileForIds(ScanningContext context)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      */
updateResourceItems(ScanningContext context)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      */
getFileValue(IAbstractFile file, ResourceFolder folder)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      */
getFileName(ResourceType type)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 
addResourceValue(ResourceValue value)223     public void addResourceValue(ResourceValue value) {
224         // Just overwrite collisions. We're only interested in the unique
225         // IDs declared
226         mIdResources.put(value.getName(), value);
227     }
228 }
229