ApkDeltaVisitorpublic class ApkDeltaVisitor extends com.android.ide.eclipse.adt.build.BaseBuilder.BaseDeltaVisitor implements org.eclipse.core.resources.IResourceDeltaVisitorDelta resource visitor looking for changes that will trigger a new packaging of an Android
application.
This looks for the following changes:
- Any change to the AndroidManifest.xml file
- Any change inside the assets/ folder
- Any file change inside the res/ folder
- Any .class file change inside the output folder
- Any change to the classes.dex inside the output folder
- Any change to the packaged resources file inside the output folder
- Any change to a non java/aidl file inside the source folders
- Any change to .so file inside the lib (native library) folder
|
Fields Summary |
---|
private boolean | mConvertToDexcompile flag. This is set to true if one of the changed/added/removed
file is a .class file. Upon visiting all the delta resources, if this
flag is true, then we know we'll have to make the "classes.dex" file. | private boolean | mPackageResourcescompile flag. This is set to true if one of the changed/added/removed
file is a resource file. Upon visiting all the delta resources, if
this flag is true, then we know we'll have to make the intermediate
apk file. | private boolean | mMakeFinalPackageFinal package flag. This is set to true if one of the changed/added/removed
file is a non java file (or aidl) in the resource folder. Upon visiting all the
delta resources, if this flag is true, then we know we'll have to make the final
package. | private ArrayList | mSourceFoldersList of source folders. | private org.eclipse.core.runtime.IPath | mOutputPath | private org.eclipse.core.runtime.IPath | mAssetPath | private org.eclipse.core.runtime.IPath | mResPath | private org.eclipse.core.runtime.IPath | mLibFolder |
Constructors Summary |
---|
public ApkDeltaVisitor(BaseBuilder builder, ArrayList sourceFolders, org.eclipse.core.resources.IFolder outputfolder)Builds the object with a specified output folder.
super(builder);
mSourceFolders = sourceFolders;
if (outputfolder != null) {
mOutputPath = outputfolder.getFullPath();
}
IResource assetFolder = builder.getProject().findMember(SdkConstants.FD_ASSETS);
if (assetFolder != null) {
mAssetPath = assetFolder.getFullPath();
}
IResource resFolder = builder.getProject().findMember(SdkConstants.FD_RESOURCES);
if (resFolder != null) {
mResPath = resFolder.getFullPath();
}
IResource libFolder = builder.getProject().findMember(SdkConstants.FD_NATIVE_LIBS);
if (libFolder != null) {
mLibFolder = libFolder.getFullPath();
}
|
Methods Summary |
---|
public boolean | getConvertToDex()
return mConvertToDex;
| public boolean | getMakeFinalPackage()
return mMakeFinalPackage;
| public boolean | getPackageResources()
return mPackageResources;
| public boolean | visit(org.eclipse.core.resources.IResourceDelta delta){@inheritDoc}
// if all flags are true, we can stop going through the resource delta.
if (mConvertToDex && mPackageResources && mMakeFinalPackage) {
return false;
}
// we are only going to look for changes in res/, src/ and in
// AndroidManifest.xml since the delta visitor goes through the main
// folder before its childre we can check when the path segment
// count is 2 (format will be /$Project/folder) and make sure we are
// processing res/, src/ or AndroidManifest.xml
IResource resource = delta.getResource();
IPath path = resource.getFullPath();
String[] pathSegments = path.segments();
int type = resource.getType();
// since the delta visitor also visits the root we return true if
// segments.length = 1
if (pathSegments.length == 1) {
return true;
}
// check the manifest.
if (pathSegments.length == 2 &&
AndroidConstants.FN_ANDROID_MANIFEST.equalsIgnoreCase(pathSegments[1])) {
// if the manifest changed we have to repackage the
// resources.
mPackageResources = true;
mMakeFinalPackage = true;
// we don't want to go to the children, not like they are
// any for this resource anyway.
return false;
}
// check the other folders.
if (mOutputPath != null && mOutputPath.isPrefixOf(path)) {
// a resource changed inside the output folder.
if (type == IResource.FILE) {
// just check this is a .class file. Any modification will
// trigger a change in the classes.dex file
String ext = resource.getFileExtension();
if (AndroidConstants.EXT_CLASS.equalsIgnoreCase(ext)) {
mConvertToDex = true;
mMakeFinalPackage = true;
// no need to check the children, as we are in a package
// and there can only be subpackage children containing
// only .class files
return false;
}
// check for a few files directly in the output folder and force
// rebuild if they have been deleted.
if (delta.getKind() == IResourceDelta.REMOVED) {
IPath parentPath = path.removeLastSegments(1);
if (mOutputPath.equals(parentPath)) {
String resourceName = resource.getName();
// check if classes.dex was removed
if (resourceName.equalsIgnoreCase(AndroidConstants.FN_CLASSES_DEX)) {
mConvertToDex = true;
mMakeFinalPackage = true;
} else if (resourceName.equalsIgnoreCase(
AndroidConstants.FN_RESOURCES_AP_) ||
AndroidConstants.PATTERN_RESOURCES_S_AP_.matcher(
resourceName).matches()) {
// or if the default resources.ap_ or a configured version
// (resources-###.ap_) was removed.
mPackageResources = true;
mMakeFinalPackage = true;
}
}
}
}
// if this is a folder, we only go visit it if we don't already know
// that we need to convert to dex already.
return mConvertToDex == false;
} else if (mResPath != null && mResPath.isPrefixOf(path)) {
// in the res folder we are looking for any file modification
// (we don't care about folder being added/removed, only content
// is important)
if (type == IResource.FILE) {
mPackageResources = true;
mMakeFinalPackage = true;
return false;
}
// for folders, return true only if we don't already know we have to
// package the resources.
return mPackageResources == false;
} else if (mAssetPath != null && mAssetPath.isPrefixOf(path)) {
// this is the assets folder that was modified.
// we don't care what content was changed. All we care
// about is that something changed inside. No need to visit
// the children even.
mPackageResources = true;
mMakeFinalPackage = true;
return false;
} else if (mLibFolder != null && mLibFolder.isPrefixOf(path)) {
// inside the native library folder. Test if the changed resource is a .so file.
if (type == IResource.FILE &&
path.getFileExtension().equalsIgnoreCase(AndroidConstants.EXT_NATIVE_LIB)) {
mMakeFinalPackage = true;
return false; // return false for file.
}
// for folders, return true only if we don't already know we have to make the
// final package.
return mMakeFinalPackage == false;
} else {
// we are in a folder that is neither the resource folders, nor the output.
// check against all the source folders, unless we already know we need to do
// the final package.
// This could be a source folder or a folder leading to a source folder.
// However we only check this if we don't already know that we need to build the
// package anyway
if (mMakeFinalPackage == false) {
for (IPath sourcePath : mSourceFolders) {
if (sourcePath.isPrefixOf(path)) {
// In the source folders, we are looking for any kind of
// modification related to file that are not java files.
// Also excluded are aidl files, and package.html files
if (type == IResource.FOLDER) {
// always visit the subfolders, unless the folder is not to be included
return ApkBuilder.checkFolderForPackaging((IFolder)resource);
} else if (type == IResource.FILE) {
if (ApkBuilder.checkFileForPackaging((IFile)resource)) {
mMakeFinalPackage = true;
}
return false;
}
}
}
}
}
// if the folder is not inside one of the folders we are interested in (res, assets, output,
// source folders), it could be a folder leading to them, so we return true.
return true;
|
|