blob: 9ff17481fb65713315b3b2cf35b8128ccd50c41b [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.common.resources;
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository;
import com.android.ide.common.resources.configuration.DensityQualifier;
import com.android.io.IAbstractFile;
import com.android.io.StreamException;
import com.android.resources.ResourceType;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Represents a resource file that also generates ID resources.
* <p/>
* This is typically an XML file in res/layout or res/menu
*/
public final class IdGeneratingResourceFile extends ResourceFile
implements IValueResourceRepository {
private final Map<String, ResourceValue> mIdResources =
new HashMap<String, ResourceValue>();
private final Collection<ResourceType> mResourceTypeList;
private final String mFileName;
private final ResourceType mFileType;
private final ResourceValue mFileValue;
public IdGeneratingResourceFile(IAbstractFile file, ResourceFolder folder, ResourceType type) {
super(file, folder);
mFileType = type;
// Set up our resource types
mResourceTypeList = new HashSet<ResourceType>();
mResourceTypeList.add(mFileType);
mResourceTypeList.add(ResourceType.ID);
// compute the resource name
mFileName = getFileName(type);
// Get the resource value of this file as a whole layout
mFileValue = getFileValue(file, folder);
}
@Override
protected void load(ScanningContext context) {
// Parse the file and look for @+id/ entries
parseFileForIds(context);
// create the resource items in the repository
updateResourceItems(context);
}
@Override
protected void update(ScanningContext context) {
// Copy the previous list of ID names
Set<String> oldIdNames = new HashSet<String>(mIdResources.keySet());
// reset current content.
mIdResources.clear();
// need to parse the file and find the IDs.
if (!parseFileForIds(context)) {
context.requestFullAapt();
// Continue through to updating the resource item here since it
// will make for example layout rendering more accurate until
// aapt is re-run
}
// We only need to update the repository if our IDs have changed
Set<String> keySet = mIdResources.keySet();
assert keySet != oldIdNames;
if (oldIdNames.equals(keySet) == false) {
updateResourceItems(context);
}
}
@Override
protected void dispose(ScanningContext context) {
ResourceRepository repository = getRepository();
// Remove declarations from this file from the repository
repository.removeFile(mResourceTypeList, this);
// Ask for an ID refresh since we'll be taking away ID generating items
context.requestFullAapt();
}
@Override
public Collection<ResourceType> getResourceTypes() {
return mResourceTypeList;
}
@Override
public boolean hasResources(ResourceType type) {
return (type == mFileType) || (type == ResourceType.ID && !mIdResources.isEmpty());
}
@Override
public ResourceValue getValue(ResourceType type, String name) {
// Check to see if they're asking for one of the right types:
if (type != mFileType && type != ResourceType.ID) {
return null;
}
// If they're looking for a resource of this type with this name give them the whole file
if (type == mFileType && name.equals(mFileName)) {
return mFileValue;
} else {
// Otherwise try to return them an ID
// the map will return null if it's not found
return mIdResources.get(name);
}
}
/**
* Looks through the file represented for Ids and adds them to
* our id repository
*
* @return true if parsing succeeds and false if it fails
*/
private boolean parseFileForIds(ScanningContext context) {
IdResourceParser parser = new IdResourceParser(this, context, isFramework());
try {
IAbstractFile file = getFile();
return parser.parse(mFileType, file.getOsLocation(), file.getContents());
} catch (IOException e) {
// Pass
} catch (StreamException e) {
// Pass
}
return false;
}
/**
* Add the resources represented by this file to the repository
*/
private void updateResourceItems(ScanningContext context) {
ResourceRepository repository = getRepository();
// remove this file from all existing ResourceItem.
repository.removeFile(mResourceTypeList, this);
// First add this as a layout file
ResourceItem item = repository.getResourceItem(mFileType, mFileName);
item.add(this);
// Now iterate through our IDs and add
for (String idName : mIdResources.keySet()) {
item = repository.getResourceItem(ResourceType.ID, idName);
// add this file to the list of files generating ID resources.
item.add(this);
}
// Ask the repository for an ID refresh
context.requestFullAapt();
}
/**
* Returns the resource value associated with this whole file as a layout resource
* @param file the file handler that represents this file
* @param folder the folder this file is under
* @return a resource value associated with this layout
*/
private ResourceValue getFileValue(IAbstractFile file, ResourceFolder folder) {
// test if there's a density qualifier associated with the resource
DensityQualifier qualifier = folder.getConfiguration().getDensityQualifier();
ResourceValue value;
if (qualifier == null) {
value = new ResourceValue(mFileType, mFileName,
file.getOsLocation(), isFramework());
} else {
value = new DensityBasedResourceValue(
mFileType, mFileName,
file.getOsLocation(),
qualifier.getValue(),
isFramework());
}
return value;
}
/**
* Returns the name of this resource.
*/
private String getFileName(ResourceType type) {
// get the name from the filename.
String name = getFile().getName();
int pos = name.indexOf('.');
if (pos != -1) {
name = name.substring(0, pos);
}
return name;
}
@Override
public void addResourceValue(ResourceValue value) {
// Just overwrite collisions. We're only interested in the unique
// IDs declared
mIdResources.put(value.getName(), value);
}
@Override
public boolean hasResourceValue(ResourceType type, String name) {
if (type == ResourceType.ID) {
return mIdResources.containsKey(name);
}
return false;
}
}