diff options
author | Xavier Ducrohet <xav@android.com> | 2011-09-01 18:27:32 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2011-09-23 09:37:08 -0700 |
commit | a9a28238f7b20d7c0a05c95afad02fcdb34e0d0e (patch) | |
tree | 5c3416656d6affb7f3f3bacb556a05805ff35e2e /anttasks | |
parent | e85fc5515d4507eb96c74f0d5c0969a09a7b4779 (diff) | |
download | sdk-a9a28238f7b20d7c0a05c95afad02fcdb34e0d0e.zip sdk-a9a28238f7b20d7c0a05c95afad02fcdb34e0d0e.tar.gz sdk-a9a28238f7b20d7c0a05c95afad02fcdb34e0d0e.tar.bz2 |
Add dependency support for ApkBuilder ant step.
Change-Id: I7230a2aa3df5fab8b420f1ed2f359621fbda7f5a
Diffstat (limited to 'anttasks')
-rw-r--r-- | anttasks/src/com/android/ant/AaptExecTask.java | 37 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/ApkBuilderTask.java | 184 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/BaseTask.java | 29 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/DependencyGraph.java | 116 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/DexExecTask.java | 6 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/InputPath.java | 94 |
6 files changed, 309 insertions, 157 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java index 4d16d1f..fc0de71 100644 --- a/anttasks/src/com/android/ant/AaptExecTask.java +++ b/anttasks/src/com/android/ant/AaptExecTask.java @@ -16,8 +16,6 @@ package com.android.ant; -import com.android.ant.DependencyGraph.InputPath; - import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.ExecTask; @@ -337,11 +335,6 @@ public final class AaptExecTask extends BaseTask { } } - // as is its AndroidManifest.xml - if (mManifest != null) { - paths.add(new File(mManifest)); - } - // and if libraries exist, their res folders folders too. if (libResRef instanceof Path) { for (String path : ((Path)libResRef).list()) { @@ -349,20 +342,17 @@ public final class AaptExecTask extends BaseTask { } } - // If we're here to generate a .ap_ file we need to use assets as an input path as well. - if (!generateRClass) { - File assetsDir = new File(mAssets); - if (mAssets != null && assetsDir.isDirectory()) { - paths.add(assetsDir); - } - } - // Now we figure out what we need to do if (generateRClass) { // in this case we only want to run aapt if an XML file was touched, or if any // file is added/removed List<InputPath> inputPaths = getInputPaths(paths, Collections.singleton("xml")); + // let's not forget the manifest as an input path (with no extension restrictions). + if (mManifest != null) { + inputPaths.add(new InputPath(new File(mManifest))); + } + // Check to see if our dependencies have changed. If not, then skip if (initDependencies(mRFolder + File.separator + "R.java.d", inputPaths) && dependenciesHaveChanged() == false) { @@ -372,10 +362,23 @@ public final class AaptExecTask extends BaseTask { System.out.println("Generating resource IDs..."); } } else { - // in this case we want to run aapt if any file updated/removed/added in any of the - // input path + // in this case we want to run aapt if any file was updated/removed/added in any of the + // input paths List<InputPath> inputPaths = getInputPaths(paths, null /*extensionsToCheck*/); + // let's not forget the manifest as an input path. + if (mManifest != null) { + inputPaths.add(new InputPath(new File(mManifest))); + } + + // If we're here to generate a .ap_ file we need to use assets as an input path as well. + if (mAssets != null) { + File assetsDir = new File(mAssets); + if (assetsDir.isDirectory()) { + inputPaths.add(new InputPath(assetsDir)); + } + } + // Find our dependency file. It should have the same name as our target .ap_ but // with a .d extension String dependencyFilePath = mApkFolder + File.separator + mApkName; diff --git a/anttasks/src/com/android/ant/ApkBuilderTask.java b/anttasks/src/com/android/ant/ApkBuilderTask.java index 3f8dec1..88bd59c 100644 --- a/anttasks/src/com/android/ant/ApkBuilderTask.java +++ b/anttasks/src/com/android/ant/ApkBuilderTask.java @@ -20,17 +20,18 @@ import com.android.sdklib.build.ApkBuilder; import com.android.sdklib.build.ApkCreationException; import com.android.sdklib.build.DuplicateFileException; import com.android.sdklib.build.SealedApkException; +import com.android.sdklib.build.ApkBuilder.FileEntry; import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Task; import org.apache.tools.ant.types.Path; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; +import java.util.List; import java.util.regex.Pattern; -public class ApkBuilderTask extends Task { +public class ApkBuilderTask extends BaseTask { private final static Pattern PATTERN_JAR_EXT = Pattern.compile("^.+\\.jar$", Pattern.CASE_INSENSITIVE); @@ -42,17 +43,30 @@ public class ApkBuilderTask extends Task { private boolean mDebugPackaging = false; private boolean mDebugSigning = false; private boolean mHasCode = true; - private String mAbiFilter = null; private Path mDexPath; private final ArrayList<Path> mZipList = new ArrayList<Path>(); - private final ArrayList<Path> mFileList = new ArrayList<Path>(); private final ArrayList<Path> mSourceList = new ArrayList<Path>(); private final ArrayList<Path> mJarfolderList = new ArrayList<Path>(); private final ArrayList<Path> mJarfileList = new ArrayList<Path>(); private final ArrayList<Path> mNativeList = new ArrayList<Path>(); + private static class SourceFolderInputPath extends InputPath { + public SourceFolderInputPath(File file) { + super(file); + } + + @Override + public boolean ignores(File file) { + if (file.isDirectory()) { + return !ApkBuilder.checkFolderForPackaging(file.getName()); + } else { + return !ApkBuilder.checkFileForPackaging(file.getName()); + } + } + } + /** * Sets the value of the "outfolder" attribute. * @param outFolder the value. @@ -113,21 +127,6 @@ public class ApkBuilderTask extends Task { } /** - * Sets an ABI filter. If non <code>null</code>, then only native libraries matching the given - * ABI will be packaged with the APK. - * @param abiFilter the ABI to accept (and reject all other). If null or empty string, no ABIs - * are rejected. This must be a single ABI name as defined by the Android NDK. For a list - * of valid ABI names, see $NDK/docs/CPU-ARCH-ABIS.TXT - */ - public void setAbifilter(String abiFilter) { - if (abiFilter != null && abiFilter.length() > 0) { - mAbiFilter = abiFilter.trim(); - } else { - mAbiFilter = null; - } - } - - /** * Sets the hascode attribute. Default is true. * If set to false, then <dex> and <sourcefolder> nodes are ignored and not processed. * @param hasCode the value of the attribute. @@ -159,17 +158,6 @@ public class ApkBuilderTask extends Task { } /** - * Returns an object representing a nested <var>file</var> element. - */ - public Object createFile() { - System.out.println("WARNING: Using deprecated <file> inner element in ApkBuilderTask." + - "Use <dex path=...> instead."); - Path path = new Path(getProject()); - mFileList.add(path); - return path; - } - - /** * Returns an object representing a nested <var>sourcefolder</var> element. */ public Object createSourcefolder() { @@ -236,48 +224,43 @@ public class ApkBuilderTask extends Task { } try { - if (mDebugSigning) { - System.out.println(String.format( - "Creating %s and signing it with a debug key...", outputFile.getName())); - } else { - System.out.println(String.format( - "Creating %s for release...", outputFile.getName())); - } + // build list of input files/folders to compute dependencies + // add the content of the zip files. + List<InputPath> inputPaths = new ArrayList<InputPath>(); - ApkBuilder apkBuilder = new ApkBuilder( - outputFile, - new File(mOutFolder, mResourceFile), - dexFile, - mDebugSigning ? ApkBuilder.getDebugKeystore() : null, - mVerbose ? System.out : null); - apkBuilder.setDebugMode(mDebugPackaging); + // resource file + InputPath resourceInputPath = new InputPath(new File(mOutFolder, mResourceFile)); + inputPaths.add(resourceInputPath); + // dex file + inputPaths.add(new InputPath(dexFile)); - // add the content of the zip files. + // zip input files + List<File> zipFiles = new ArrayList<File>(); for (Path pathList : mZipList) { for (String path : pathList.list()) { - apkBuilder.addZipFile(new File(path)); + File f = new File(path); + zipFiles.add(f); + inputPaths.add(new InputPath(f)); } } - // add the files that go to the root of the archive (this is deprecated) - for (Path pathList : mFileList) { - for (String path : pathList.list()) { - File f = new File(path); - apkBuilder.addFile(f, f.getName()); - } - } - - // now go through the list of file to directly add the to the list. + // now go through the list of source folders used to add non java files. + List<File> sourceFolderList = new ArrayList<File>(); if (mHasCode) { for (Path pathList : mSourceList) { for (String path : pathList.list()) { - apkBuilder.addSourceFolder(new File(path)); + File f = new File(path); + sourceFolderList.add(f); + // because this is a source folder but we only care about non + // java files. + inputPaths.add(new SourceFolderInputPath(f)); } } } // now go through the list of jar folders. + List<File> jarFileList = new ArrayList<File>(); for (Path pathList : mJarfolderList) { for (String path : pathList.list()) { // it's ok if top level folders are missing @@ -290,7 +273,9 @@ public class ApkBuilderTask extends Task { }); for (String filename : filenames) { - apkBuilder.addResourcesFromJar(new File(folder, filename)); + File f = new File(folder, filename); + jarFileList.add(f); + inputPaths.add(new InputPath(f)); } } } @@ -299,25 +284,101 @@ public class ApkBuilderTask extends Task { // now go through the list of jar files. for (Path pathList : mJarfileList) { for (String path : pathList.list()) { - apkBuilder.addResourcesFromJar(new File(path)); + File f = new File(path); + jarFileList.add(f); + inputPaths.add(new InputPath(f)); } } // now the native lib folder. + List<FileEntry> nativeFileList = new ArrayList<FileEntry>(); for (Path pathList : mNativeList) { for (String path : pathList.list()) { // it's ok if top level folders are missing File folder = new File(path); if (folder.isDirectory()) { - apkBuilder.addNativeLibraries(folder, mAbiFilter); + List<FileEntry> entries = ApkBuilder.getNativeFiles(folder, + mDebugPackaging); + // add the list to the list of native files and then create an input + // path for each file + nativeFileList.addAll(entries); + + for (FileEntry entry : entries) { + inputPaths.add(new InputPath(entry.mFile)); + } } } } + // Finally figure out the path to the dependency file. + String depFile = outputFile.getAbsolutePath() + ".d"; + + // check dependencies + if (initDependencies(depFile, inputPaths) && dependenciesHaveChanged() == false) { + System.out.println( + "No changes. No need to create apk."); + return; + } + + if (mDebugSigning) { + System.out.println(String.format( + "Creating %s and signing it with a debug key...", outputFile.getName())); + } else { + System.out.println(String.format( + "Creating %s for release...", outputFile.getName())); + } + + ApkBuilder apkBuilder = new ApkBuilder( + outputFile, + resourceInputPath.getFile(), + dexFile, + mDebugSigning ? ApkBuilder.getDebugKeystore() : null, + mVerbose ? System.out : null); + apkBuilder.setDebugMode(mDebugPackaging); + + + // add the content of the zip files. + for (File f : zipFiles) { + apkBuilder.addZipFile(f); + } + + // now go through the list of file to directly add the to the list. + for (File f : sourceFolderList) { + apkBuilder.addSourceFolder(f); + } + + // now go through the list of jar folders. + for (Path pathList : mJarfolderList) { + for (String path : pathList.list()) { + // it's ok if top level folders are missing + File folder = new File(path); + if (folder.isDirectory()) { + String[] filenames = folder.list(new FilenameFilter() { + public boolean accept(File dir, String name) { + return PATTERN_JAR_EXT.matcher(name).matches(); + } + }); + + for (String filename : filenames) { + apkBuilder.addResourcesFromJar(new File(folder, filename)); + } + } + } + } + + // now go through the list of jar files. + for (File f : jarFileList) { + apkBuilder.addResourcesFromJar(f); + } + + // and finally the native files + apkBuilder.addNativeLibraries(nativeFileList); // close the archive apkBuilder.sealApk(); + // and generate the dependency file + generateDependencyFile(depFile, inputPaths, outputFile.getAbsolutePath()); } catch (DuplicateFileException e) { System.err.println(String.format( "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s", @@ -331,4 +392,9 @@ public class ApkBuilderTask extends Task { throw new BuildException(e); } } + + @Override + protected String getExecTaskName() { + return "apkbuilder"; + } } diff --git a/anttasks/src/com/android/ant/BaseTask.java b/anttasks/src/com/android/ant/BaseTask.java index 8a82fe9..b1c37b8 100644 --- a/anttasks/src/com/android/ant/BaseTask.java +++ b/anttasks/src/com/android/ant/BaseTask.java @@ -16,8 +16,6 @@ package com.android.ant; -import com.android.ant.DependencyGraph.InputPath; - import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; @@ -113,11 +111,11 @@ public abstract class BaseTask extends Task { } protected void generateDependencyFile(String depFilePath, - List<File> inputs, String outputFile) { - File file = new File(depFilePath); + List<InputPath> inputs, String outputFile) { + File depFile = new File(depFilePath); try { - PrintStream ps = new PrintStream(file); + PrintStream ps = new PrintStream(depFile); // write the output file. ps.print(outputFile); @@ -126,11 +124,12 @@ public abstract class BaseTask extends Task { //write the input files int count = inputs.size(); for (int i = 0 ; i < count ; i++) { - File input = inputs.get(i); - if (input.isDirectory()) { - writeContent(ps, input); + InputPath input = inputs.get(i); + File file = input.getFile(); + if (file.isDirectory()) { + writeContent(ps, file, input); } else { - ps.print(input.getAbsolutePath()); + ps.print(file.getAbsolutePath()); ps.println(" \\"); } } @@ -141,13 +140,17 @@ public abstract class BaseTask extends Task { } } - private void writeContent(PrintStream ps, File input) { - File[] files = input.listFiles(); + private void writeContent(PrintStream ps, File file, InputPath input) { + if (input.ignores(file)) { + return; + } + + File[] files = file.listFiles(); if (files != null) { for (File f : files) { if (f.isDirectory()) { - writeContent(ps, f); - } else { + writeContent(ps, f, input); + } else if (input.ignores(f) == false) { ps.print(f.getAbsolutePath()); ps.println(" \\"); } diff --git a/anttasks/src/com/android/ant/DependencyGraph.java b/anttasks/src/com/android/ant/DependencyGraph.java index b51965d..9c5e8ad 100644 --- a/anttasks/src/com/android/ant/DependencyGraph.java +++ b/anttasks/src/com/android/ant/DependencyGraph.java @@ -47,22 +47,6 @@ public class DependencyGraph { private long mDepFileLastModified; private final List<InputPath> mNewInputs; - public static class InputPath { - File mFile; - /** - * A set of extensions. Only files with an extension in this set will - * be considered for a modification check. All deleted/created files will still be - * checked. If this is null, all files will be checked for modification date - */ - Set<String> mExtensionsToCheck; - - public InputPath(File file, Set<String> extensions) { - mFile = file; - mExtensionsToCheck = extensions; - } - } - - public DependencyGraph(String dependencyFilePath, List<InputPath> newInputPaths) { mNewInputs = newInputPaths; parseDependencyFile(dependencyFilePath); @@ -225,7 +209,7 @@ public class DependencyGraph { * This should be followed by a call to {@link #checkPrereqFiles(long)} which * will process the remaining files in the prereq list. * - * If a change is found, this will return immediatly with either + * If a change is found, this will return immediately with either * {@link DependencyStatus#NEW_FILE} or {@link DependencyStatus#UPDATED_FILE}. * * @param oldestTarget the timestamp of the oldest output file to compare against. @@ -236,15 +220,14 @@ public class DependencyGraph { private DependencyStatus checkInputs(long oldestTarget) { if (mNewInputs != null) { for (InputPath input : mNewInputs) { - if (input.mFile.isDirectory()) { - DependencyStatus status = checkInputFolder(input.mFile, - input.mExtensionsToCheck, oldestTarget); + File file = input.getFile(); + if (file.isDirectory()) { + DependencyStatus status = checkInputFolder(file, input, oldestTarget); if (status != DependencyStatus.NONE) { return status; } - } else if (input.mFile.isFile()) { - DependencyStatus status = checkInputFile(input.mFile, - input.mExtensionsToCheck, oldestTarget); + } else if (file.isFile()) { + DependencyStatus status = checkInputFile(file, input, oldestTarget); if (status != DependencyStatus.NONE) { return status; } @@ -260,31 +243,33 @@ public class DependencyGraph { * Check all the files in the tree under root and check to see if the files are * listed under the dependencies, or if they have been modified. Recurses into subdirs. * - * @param rootFolder the folder to search through. - * @param extensionsToCheck a set of extensions. Only files with an extension in this set will - * be considered for a modification check. All deleted/created files will still be - * checked. If this is null, all files will be checked for modification date + * @param folder the folder to search through. + * @param inputFolder the root level inputFolder * @param oldestTarget the time stamp of the oldest output file to compare against. * * @return the status of the file in the folder. */ - private DependencyStatus checkInputFolder(File rootFolder, Set<String> extensionsToCheck, + private DependencyStatus checkInputFolder(File folder, InputPath inputFolder, long oldestTarget) { - File[] files = rootFolder.listFiles(); + if (inputFolder.ignores(folder)) { + return DependencyStatus.NONE; + } + + File[] files = folder.listFiles(); if (files == null) { - System.err.println("ERROR " + rootFolder.toString() + " is not a dir or can't be read"); + System.err.println("ERROR " + folder.toString() + " is not a dir or can't be read"); return DependencyStatus.ERROR; } // Loop through files in this folder for (File file : files) { // If this is a directory, recurse into it if (file.isDirectory()) { - DependencyStatus status = checkInputFolder(file, extensionsToCheck, oldestTarget); + DependencyStatus status = checkInputFolder(file, inputFolder, oldestTarget); if (status != DependencyStatus.NONE) { return status; } } else if (file.isFile()) { - DependencyStatus status = checkInputFile(file, extensionsToCheck, oldestTarget); + DependencyStatus status = checkInputFile(file, inputFolder, oldestTarget); if (status != DependencyStatus.NONE) { return status; } @@ -294,8 +279,12 @@ public class DependencyGraph { return DependencyStatus.NONE; } - private DependencyStatus checkInputFile(File file, Set<String> extensionsToCheck, + private DependencyStatus checkInputFile(File file, InputPath inputFolder, long oldestTarget) { + if (inputFolder.ignores(file)) { + return DependencyStatus.NONE; + } + // if it's a file, remove it from the list of prereqs. // This way if files in this folder don't trigger a build we'll have less // files to go through manually @@ -303,9 +292,9 @@ public class DependencyGraph { // turns out this is a new file! return DependencyStatus.NEW_FILE; } else { - // check the time stamp on this file if it's a file we care about based on the - // list of extensions to check. - if (extensionsToCheck == null || extensionsToCheck.contains(getExtension(file))) { + // check the time stamp on this file if it's a file we care about based what the + // input folder decides. + if (inputFolder.checksForModification(file)) { if (file.lastModified() > oldestTarget) { return DependencyStatus.UPDATED_FILE; } @@ -324,31 +313,45 @@ public class DependencyGraph { * @return the status of the files */ private DependencyStatus checkPrereqFiles(long oldestTarget) { + // TODO: Optimize for the case of a specific file as inputPath. + // We should have a map of filepath to inputpath to quickly search through them? + // Loop through our prereq files and make sure they still exist for (File prereq : mPrereqs) { if (prereq.exists() == false) { return DependencyStatus.MISSING_FILE; } - // check the time stamp on this file if it's a file we care about based on the - // list of extensions to check. - // to get the extensions to check, we look in which input folder this file is. - Set<String> extensionsToCheck = null; + // check the time stamp on this file if it's a file we care about. + // To know if we care about the file we have to find the matching input. if (mNewInputs != null) { String filePath = prereq.getAbsolutePath(); for (InputPath input : mNewInputs) { - if (filePath.startsWith(input.mFile.getAbsolutePath())) { - extensionsToCheck = input.mExtensionsToCheck; - break; + File inputFile = input.getFile(); + // if the input path is a directory, check if the prereq file is in it, + // otherwise check if the prereq file match exactly the input path. + if (inputFile.isDirectory()) { + if (filePath.startsWith(inputFile.getAbsolutePath())) { + // ok file is inside a directory type input folder. + // check if we need to check this type of file, and if yes, check it. + if (input.checksForModification(prereq)) { + if (prereq.lastModified() > oldestTarget) { + return DependencyStatus.UPDATED_FILE; + } + } + } + } else { + // this is a file input path, we must check if the match is exact. + if (prereq.equals(inputFile)) { + if (input.checksForModification(prereq)) { + if (prereq.lastModified() > oldestTarget) { + return DependencyStatus.UPDATED_FILE; + } + } + } } } } - - if (extensionsToCheck == null || extensionsToCheck.contains(getExtension(prereq))) { - if (prereq.lastModified() > oldestTarget) { - return DependencyStatus.UPDATED_FILE; - } - } } // If we get this far, then all our prereq are okay @@ -415,19 +418,4 @@ public class DependencyGraph { } return null; } - - /** - * Gets the extension (if present) on a file by looking at the filename - * @param file the file to get the extension of - * @return the extension if present, or the empty string if the filename doesn't have - * and extension. - */ - private static String getExtension(File file) { - String filename = file.getName(); - if (filename.lastIndexOf('.') == -1) { - return ""; - } - // Don't include the leading '.' in the extension - return filename.substring(filename.lastIndexOf('.') + 1); - } } diff --git a/anttasks/src/com/android/ant/DexExecTask.java b/anttasks/src/com/android/ant/DexExecTask.java index e4296b2..4016417 100644 --- a/anttasks/src/com/android/ant/DexExecTask.java +++ b/anttasks/src/com/android/ant/DexExecTask.java @@ -16,8 +16,6 @@ package com.android.ant; -import com.android.ant.DependencyGraph.InputPath; - import org.apache.tools.ant.BuildException; import org.apache.tools.ant.taskdefs.ExecTask; import org.apache.tools.ant.types.FileSet; @@ -163,7 +161,7 @@ public class DexExecTask extends BaseTask { task.createArg().setValue(mOutput); - for (File f :paths) { + for (File f : paths) { task.createArg().setValue(f.getAbsolutePath()); } @@ -171,7 +169,7 @@ public class DexExecTask extends BaseTask { task.execute(); // generate the dependency file. - generateDependencyFile(depFile, paths, mOutput); + generateDependencyFile(depFile, inputPaths, mOutput); } @Override diff --git a/anttasks/src/com/android/ant/InputPath.java b/anttasks/src/com/android/ant/InputPath.java new file mode 100644 index 0000000..3327385 --- /dev/null +++ b/anttasks/src/com/android/ant/InputPath.java @@ -0,0 +1,94 @@ +/* + * 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.ant; + +import java.io.File; +import java.util.Set; + +public class InputPath { + + private final File mFile; + /** + * A set of extensions. Only files with an extension in this set will + * be considered for a modification check. All deleted/created files will still be + * checked. + */ + private final Set<String> mTouchedExtensions; + + public InputPath(File file) { + this(file, null); + } + + public InputPath(File file, Set<String> extensionsToCheck) { + mFile = file; + mTouchedExtensions = extensionsToCheck; + } + + public File getFile() { + return mFile; + } + + /** + * Returns whether this input path (likely actually a folder) must check this files for + * modification (all files are checked for add/delete). + * + * This is configured by constructing the {@link InputPath} with additional restriction + * parameters such as specific extensions. + * @param file the file to check + * @return true if the file must be checked for modification. + */ + public boolean checksForModification(File file) { + if (ignores(file)) { + return false; + } + + if (mTouchedExtensions != null && + mTouchedExtensions.contains(getExtension(file)) == false) { + return false; + } + + return true; + } + + /** + * Returns whether the InputPath ignores a given file or folder. If it is ignored then + * the file (or folder) is not checked for any event (modification/add/delete). + * If it's a folder, then it and its content are completely ignored. + * @param file the file or folder to check + * @return true if the file or folder are ignored. + */ + public boolean ignores(File file) { + return false; + } + + /** + * Gets the extension (if present) on a file by looking at the filename + * @param file the file to get the extension of + * @return the extension if present, or the empty string if the filename doesn't have + * and extension. + */ + protected static String getExtension(File file) { + String filename = file.getName(); + int index = filename.lastIndexOf('.'); + if (index == -1) { + return ""; + } + // Don't include the leading '.' in the extension + return filename.substring(index + 1); + } + +} |