LayoutXmlProcessor.java revision 4ba16229a40e9758db86d4fb1df5119fdcb8aa2a
18e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount/*
28e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Copyright (C) 2015 The Android Open Source Project
38e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Licensed under the Apache License, Version 2.0 (the "License");
48e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * you may not use this file except in compliance with the License.
58e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * You may obtain a copy of the License at
68e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount *      http://www.apache.org/licenses/LICENSE-2.0
78e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Unless required by applicable law or agreed to in writing, software
88e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * distributed under the License is distributed on an "AS IS" BASIS,
98e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
108e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * See the License for the specific language governing permissions and
118e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * limitations under the License.
128e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount */
138e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
14fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool;
158e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
164ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Guptaimport com.google.common.escape.Escaper;
174ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta
189784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyarimport org.apache.commons.io.FileUtils;
198e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport org.xml.sax.SAXException;
208e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.BindingBuildInfo;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.LayoutFileParser;
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.ResourceBundle;
249784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyarimport android.databinding.tool.util.Preconditions;
254ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Guptaimport android.databinding.tool.util.SourceCodeEscapers;
26fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.JavaFileWriter;
27a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
288e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.File;
298e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.FilenameFilter;
308e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.IOException;
319784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyarimport java.net.URI;
32a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.ArrayList;
338e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.util.List;
348e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.util.UUID;
358e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
368e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBException;
378e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.parsers.ParserConfigurationException;
388e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.xpath.XPathExpressionException;
398e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
408e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount/**
418e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Processes the layout XML, stripping the binding attributes and elements
428e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * and writes the information into an annotated class file for the annotation
438e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * processor to work with.
448e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount */
458e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountpublic class LayoutXmlProcessor {
46a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    // hardcoded in baseAdapters
47fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount    public static final String RESOURCE_BUNDLE_PACKAGE = "android.databinding.layouts";
48a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public static final String CLASS_NAME = "DataBindingInfo";
498e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private final JavaFileWriter mFileWriter;
508e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private final ResourceBundle mResourceBundle;
5197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar    private final int mMinSdk;
5297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar
538e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private boolean mProcessingComplete;
548e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private boolean mWritten;
55a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private final boolean mIsLibrary;
568e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private final String mBuildId = UUID.randomUUID().toString();
579784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private final OriginalFileLookup mOriginalFileLookup;
588e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
599784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    public LayoutXmlProcessor(String applicationPackage,
609784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            JavaFileWriter fileWriter, int minSdk, boolean isLibrary,
619784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            OriginalFileLookup originalFileLookup) {
628e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mFileWriter = fileWriter;
638e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mResourceBundle = new ResourceBundle(applicationPackage);
6497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar        mMinSdk = minSdk;
65a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        mIsLibrary = isLibrary;
669784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        mOriginalFileLookup = originalFileLookup;
67a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
68a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
699784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private static void processIncrementalInputFiles(ResourceInput input,
709784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            ProcessFileCallback callback)
719784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            throws IOException, ParserConfigurationException, XPathExpressionException,
729784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            SAXException {
739784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        processExistingIncrementalFiles(input.getRootInputFolder(), input.getAdded(), callback);
749784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        processExistingIncrementalFiles(input.getRootInputFolder(), input.getChanged(), callback);
759784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        processRemovedIncrementalFiles(input.getRootInputFolder(), input.getRemoved(), callback);
76890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    }
77890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar
789784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private static void processExistingIncrementalFiles(File inputRoot, List<File> files,
799784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            ProcessFileCallback callback)
809784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            throws IOException, XPathExpressionException, SAXException,
819784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            ParserConfigurationException {
829784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        for (File file : files) {
839784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            File parent = file.getParentFile();
849784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            if (inputRoot.equals(parent)) {
859784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                callback.processOtherRootFile(file);
869784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            } else if (layoutFolderFilter.accept(parent, parent.getName())) {
879784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                callback.processLayoutFile(file);
889784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            } else {
899784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                callback.processOtherFile(parent, file);
900c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar            }
919784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
929784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
939784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
949784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private static void processRemovedIncrementalFiles(File inputRoot, List<File> files,
959784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            ProcessFileCallback callback)
969784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            throws IOException {
979784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        for (File file : files) {
989784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            File parent = file.getParentFile();
999784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            if (inputRoot.equals(parent)) {
1009784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                callback.processRemovedOtherRootFile(file);
1019784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            } else if (layoutFolderFilter.accept(parent, parent.getName())) {
1029784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                callback.processRemovedLayoutFile(file);
1039784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            } else {
1049784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                callback.processRemovedOtherFile(parent, file);
1059784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
1069784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
1079784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
108a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
1099784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private static void processAllInputFiles(ResourceInput input, ProcessFileCallback callback)
1109784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            throws IOException, XPathExpressionException, SAXException,
1119784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            ParserConfigurationException {
1129784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        FileUtils.deleteDirectory(input.getRootOutputFolder());
1139784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        Preconditions.check(input.getRootOutputFolder().mkdirs(), "out dir should be re-created");
1149784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        Preconditions.check(input.getRootInputFolder().isDirectory(), "it must be a directory");
1159784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        for (File firstLevel : input.getRootInputFolder().listFiles()) {
1169784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            if (firstLevel.isDirectory()) {
1179784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                if (layoutFolderFilter.accept(firstLevel, firstLevel.getName())) {
1189784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    callback.processLayoutFolder(firstLevel);
1199784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    for (File xmlFile : firstLevel.listFiles(xmlFileFilter)) {
1209784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                        callback.processLayoutFile(xmlFile);
1219784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    }
1229784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                } else {
1239784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    callback.processOtherFolder(firstLevel);
1249784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    for (File file : firstLevel.listFiles()) {
1259784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                        callback.processOtherFile(firstLevel, file);
1269784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    }
127a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                }
1289784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            } else {
1299784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                callback.processOtherRootFile(firstLevel);
130a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            }
1319784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
132a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
133a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
134a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
135a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    /**
136a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     * used by the studio plugin
137a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     */
138a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public ResourceBundle getResourceBundle() {
139a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return mResourceBundle;
1408e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
1418e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
1429784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    public boolean processResources(final ResourceInput input)
1438e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            throws ParserConfigurationException, SAXException, XPathExpressionException,
1448e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            IOException {
1458e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        if (mProcessingComplete) {
1468e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return false;
1478e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
1489784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        final LayoutFileParser layoutFileParser = new LayoutFileParser();
1499784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        final URI inputRootUri = input.getRootInputFolder().toURI();
1509784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        ProcessFileCallback callback = new ProcessFileCallback() {
1519784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            private File convertToOutFile(File file) {
1529784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                final String subPath = toSystemDependentPath(inputRootUri
1539784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                        .relativize(file.toURI()).getPath());
1549784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                return new File(input.getRootOutputFolder(), subPath);
1559784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
1569784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
1579784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processLayoutFile(File file)
1589784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    throws ParserConfigurationException, SAXException, XPathExpressionException,
1599784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    IOException {
1609784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                File output = convertToOutFile(file);
1619784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser
1629784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                        .parseXml(file, output, mResourceBundle.getAppPackage(), mOriginalFileLookup);
1639784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                if (bindingLayout != null && !bindingLayout.isEmpty()) {
1649784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    mResourceBundle.addLayoutBundle(bindingLayout);
1659784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                }
1669784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
1679784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
1689784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
1699784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processOtherFile(File parentFolder, File file) throws IOException {
1709784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                File outParent = convertToOutFile(parentFolder);
1719784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                FileUtils.copyFile(file, new File(outParent, file.getName()));
1729784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
1739784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
1749784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
1759784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processRemovedLayoutFile(File file) {
1769784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                mResourceBundle.addRemovedFile(file);
1778e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            }
1789784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
1799784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
1809784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processRemovedOtherFile(File parentFolder, File file) throws IOException {
1819784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                File outParent = convertToOutFile(parentFolder);
1829784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                FileUtils.forceDelete(new File(outParent, file.getName()));
1839784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
1849784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
1859784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
1869784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processOtherFolder(File folder) {
1879784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                //noinspection ResultOfMethodCallIgnored
1889784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                convertToOutFile(folder).mkdirs();
1899784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
1909784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
1919784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
1929784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processLayoutFolder(File folder) {
1939784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                //noinspection ResultOfMethodCallIgnored
1949784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                convertToOutFile(folder).mkdirs();
1959784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
1969784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
1979784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
1989784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processOtherRootFile(File file) throws IOException {
1999784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                File outFile = convertToOutFile(file);
2009784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                if (file.isDirectory()) {
2019784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    FileUtils.copyDirectory(file, outFile);
2029784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                } else {
2039784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    FileUtils.copyFile(file, outFile);
2049784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                }
2059784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
2069784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
2079784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            @Override
2089784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            public void processRemovedOtherRootFile(File file) throws IOException {
2099784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                final File outFile = convertToOutFile(file);
2109784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                if (file.isDirectory()) {
2119784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    FileUtils.deleteDirectory(outFile);
2129784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                } else {
2139784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                    FileUtils.deleteQuietly(outFile);
2149784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                }
2159784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            }
2169784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        };
2179784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        if (input.isIncremental()) {
2189784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            processIncrementalInputFiles(input, callback);
2199784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        } else {
2209784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            processAllInputFiles(input, callback);
2218e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
2228e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mProcessingComplete = true;
2238e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        return true;
2248e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
2258e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
2269784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    public static String toSystemDependentPath(String path) {
2279784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        if (File.separatorChar != '/') {
2289784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            path = path.replace('/', File.separatorChar);
2299784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
2309784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        return path;
2319784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
2329784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
233be83770af82294c1841eef414513653646b88dc6Yigit Boyar    public void writeLayoutInfoFiles(File xmlOutDir) throws JAXBException {
2348e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        if (mWritten) {
2358e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return;
2368e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
2378e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        for (List<ResourceBundle.LayoutFileBundle> layouts : mResourceBundle.getLayoutBundles()
2388e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount                .values()) {
2398e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            for (ResourceBundle.LayoutFileBundle layout : layouts) {
24028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar                writeXmlFile(xmlOutDir, layout);
2418e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            }
2428e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
2439784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        for (File file : mResourceBundle.getRemovedFiles()) {
2449784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            String exportFileName = generateExportFileName(file);
2459784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            FileUtils.deleteQuietly(new File(xmlOutDir, exportFileName));
2469784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
2478e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mWritten = true;
2488e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
2498e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
25028e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar    private void writeXmlFile(File xmlOutDir, ResourceBundle.LayoutFileBundle layout)
25128e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar            throws JAXBException {
2529784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        String filename = generateExportFileName(layout);
25328e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar        mFileWriter.writeToFile(new File(xmlOutDir, filename), layout.toXML());
254a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
255a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
256a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public String getInfoClassFullName() {
257a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME;
258a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
259a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
260a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    /**
261a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     * Generates a string identifier that can uniquely identify the given layout bundle.
262a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     * This identifier can be used when we need to export data about this layout bundle.
263a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     */
2649784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private static String generateExportFileName(ResourceBundle.LayoutFileBundle layout) {
2659784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        return generateExportFileName(layout.getFileName(), layout.getDirectory());
2669784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
2679784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
2689784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private static String generateExportFileName(File file) {
2699784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        final String fileName = file.getName();
2709784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        return generateExportFileName(fileName.substring(0, fileName.lastIndexOf('.')),
2719784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                file.getParentFile().getName());
2729784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
2739784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
2749784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    public static String generateExportFileName(String fileName, String dirName) {
27528e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar        return fileName + '-' + dirName + ".xml";
27628e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar    }
27728e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar
27828e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar    public static String exportLayoutNameFromInfoFileName(String infoFileName) {
27928e7064d455e2ef9da31c817dfc05ec7405c60dfYigit Boyar        return infoFileName.substring(0, infoFileName.indexOf('-'));
2808e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
2818e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
282b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar    public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir,
283b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            /*Nullable*/ File exportClassListTo) {
28408119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar        writeInfoClass(sdkDir, xmlOutDir, exportClassListTo, false, false);
285b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar    }
286b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar
2879784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    public String getPackage() {
2889784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        return mResourceBundle.getAppPackage();
2899784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
2909784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
291b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar    public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir, File exportClassListTo,
29208119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar            boolean enableDebugLogs, boolean printEncodedErrorLogs) {
2934ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta        Escaper javaEscaper = SourceCodeEscapers.javaCharEscaper();
2944ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta        final String sdkPath = sdkDir == null ? null : javaEscaper.escape(sdkDir.getAbsolutePath());
295a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        final Class annotation = BindingBuildInfo.class;
2964ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta        final String layoutInfoPath = javaEscaper.escape(xmlOutDir.getAbsolutePath());
297b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar        final String exportClassListToPath = exportClassListTo == null ? "" :
2984ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta                javaEscaper.escape(exportClassListTo.getAbsolutePath());
299a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        String classString = "package " + RESOURCE_BUNDLE_PACKAGE + ";\n\n" +
300a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "import " + annotation.getCanonicalName() + ";\n\n" +
301a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "@" + annotation.getSimpleName() + "(buildId=\"" + mBuildId + "\", " +
302a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "modulePackage=\"" + mResourceBundle.getAppPackage() + "\", " +
303ae161289a90f6ac69ffe6411ac8c09653c81d04dYigit Boyar                "sdkRoot=" + "\"" + (sdkPath == null ? "" : sdkPath) + "\"," +
304a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "layoutInfoDir=\"" + layoutInfoPath + "\"," +
305b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar                "exportClassListTo=\"" + exportClassListToPath + "\"," +
306a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "isLibrary=" + mIsLibrary + "," +
307b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar                "minSdk=" + mMinSdk + "," +
30808119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar                "enableDebugLogs=" + enableDebugLogs + "," +
30908119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar                "printEncodedError=" + printEncodedErrorLogs + ")\n" +
310a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "public class " + CLASS_NAME + " {}\n";
311fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount        mFileWriter.writeToFile(RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME, classString);
3128e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
3138e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
314a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private static final FilenameFilter layoutFolderFilter = new FilenameFilter() {
3158e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        @Override
3168e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        public boolean accept(File dir, String name) {
3178e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return name.startsWith("layout");
3188e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
3198e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    };
3208e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
321a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private static final FilenameFilter xmlFileFilter = new FilenameFilter() {
3228e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        @Override
3238e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        public boolean accept(File dir, String name) {
3248e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return name.toLowerCase().endsWith(".xml");
3258e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
3268e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    };
327890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar
328890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    /**
329890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar     * Helper interface that can find the original copy of a resource XML.
330890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar     */
331890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    public interface OriginalFileLookup {
332890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar
333890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar        /**
334890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar         * @param file The intermediate build file
335890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar         * @return The original file or null if original File cannot be found.
336890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar         */
337890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar        File getOriginalFileFor(File file);
338890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    }
3399784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3409784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    /**
3419784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar     * API agnostic class to get resource changes incrementally.
3429784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar     */
3439784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    public static class ResourceInput {
3449784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        private final boolean mIncremental;
3459784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        private final File mRootInputFolder;
3469784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        private final File mRootOutputFolder;
3479784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3489784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        private List<File> mAdded = new ArrayList<File>();
3499784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        private List<File> mRemoved = new ArrayList<File>();
3509784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        private List<File> mChanged = new ArrayList<File>();
3519784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3529784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        public ResourceInput(boolean incremental, File rootInputFolder, File rootOutputFolder) {
3539784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mIncremental = incremental;
3549784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mRootInputFolder = rootInputFolder;
3559784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mRootOutputFolder = rootOutputFolder;
3569784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3579784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3589784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        public void added(File file) {
3599784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mAdded.add(file);
3609784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3619784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        public void removed(File file) {
3629784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mRemoved.add(file);
3639784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3649784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        public void changed(File file) {
3659784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            mChanged.add(file);
3669784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3679784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3689784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        public boolean shouldCopy() {
3699784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            return !mRootInputFolder.equals(mRootOutputFolder);
3709784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3719784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3729784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<File> getAdded() {
3739784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            return mAdded;
3749784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3759784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3769784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<File> getRemoved() {
3779784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            return mRemoved;
3789784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3799784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3809784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<File> getChanged() {
3819784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            return mChanged;
3829784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3839784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3849784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        File getRootInputFolder() {
3859784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            return mRootInputFolder;
3869784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3879784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3889784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        File getRootOutputFolder() {
3899784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            return mRootOutputFolder;
3909784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3919784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3929784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        public boolean isIncremental() {
3939784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar            return mIncremental;
3949784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        }
3959784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
3969784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
3979784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    private interface ProcessFileCallback {
3989784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processLayoutFile(File file)
3999784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                throws ParserConfigurationException, SAXException, XPathExpressionException,
4009784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar                IOException;
4019784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processOtherFile(File parentFolder, File file) throws IOException;
4029784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processRemovedLayoutFile(File file);
4039784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processRemovedOtherFile(File parentFolder, File file) throws IOException;
4049784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
4059784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processOtherFolder(File folder);
4069784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
4079784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processLayoutFolder(File folder);
4089784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
4099784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processOtherRootFile(File file) throws IOException;
4109784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar
4119784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        void processRemovedOtherRootFile(File file) throws IOException;
4129784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar    }
4138e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount}
414