LayoutXmlProcessor.java revision 890b4850c628f04eb75397e427ba7074e4f9c386
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
1697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport org.apache.commons.lang3.StringEscapeUtils;
178e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport org.xml.sax.SAXException;
188e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.BindingBuildInfo;
20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.LayoutFileParser;
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.ResourceBundle;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.JavaFileWriter;
23a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
248e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.File;
258e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.FilenameFilter;
268e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.IOException;
278e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.StringWriter;
28a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.ArrayList;
298e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.util.List;
308e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.util.UUID;
318e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
328e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBContext;
338e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBException;
348e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.Marshaller;
358e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.parsers.ParserConfigurationException;
368e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.xpath.XPathExpressionException;
378e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
388e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount/**
398e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Processes the layout XML, stripping the binding attributes and elements
408e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * and writes the information into an annotated class file for the annotation
418e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * processor to work with.
428e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount */
438e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountpublic class LayoutXmlProcessor {
44a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    // hardcoded in baseAdapters
45fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount    public static final String RESOURCE_BUNDLE_PACKAGE = "android.databinding.layouts";
46a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public static final String CLASS_NAME = "DataBindingInfo";
478e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private final JavaFileWriter mFileWriter;
488e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private final ResourceBundle mResourceBundle;
4997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar    private final int mMinSdk;
5097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar
518e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private boolean mProcessingComplete;
528e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private boolean mWritten;
53a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private final boolean mIsLibrary;
548e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    private final String mBuildId = UUID.randomUUID().toString();
55a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    // can be a list of xml files or folders that contain XML files
56a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private final List<File> mResources;
57890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    private OriginalFileLookup mOriginalFileLookup;
588e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
59a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public LayoutXmlProcessor(String applicationPackage, List<File> resources,
60a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            JavaFileWriter fileWriter, int minSdk, boolean isLibrary) {
618e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mFileWriter = fileWriter;
628e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mResourceBundle = new ResourceBundle(applicationPackage);
63a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        mResources = resources;
6497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar        mMinSdk = minSdk;
65a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        mIsLibrary = isLibrary;
66a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
67a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
68890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    public void setOriginalFileLookup(OriginalFileLookup originalFileLookup) {
69890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar        mOriginalFileLookup = originalFileLookup;
70890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    }
71890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar
72a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public static List<File> getLayoutFiles(List<File> resources) {
73a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        List<File> result = new ArrayList<File>();
740c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar        for (File resource : resources) {
750c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar            if (!resource.exists() || !resource.canRead()) {
760c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar                continue;
770c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar            }
78a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            if (resource.isDirectory()) {
79a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                for (File layoutFolder : resource.listFiles(layoutFolderFilter)) {
80a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    for (File xmlFile : layoutFolder.listFiles(xmlFileFilter)) {
81a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                        result.add(xmlFile);
82a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    }
83a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
84a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                }
85a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            } else if (xmlFileFilter.accept(resource.getParentFile(), resource.getName())) {
86a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                result.add(resource);
87a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            }
88a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
89a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return result;
90a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
91a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
92a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    /**
93a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     * used by the studio plugin
94a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     */
95a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public ResourceBundle getResourceBundle() {
96a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return mResourceBundle;
978e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
988e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
994d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount    public boolean processResources(int minSdk)
1008e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            throws ParserConfigurationException, SAXException, XPathExpressionException,
1018e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            IOException {
1028e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        if (mProcessingComplete) {
1038e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return false;
1048e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
1058e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        LayoutFileParser layoutFileParser = new LayoutFileParser();
106a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        for (File xmlFile : getLayoutFiles(mResources)) {
107a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser
108890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar                    .parseXml(xmlFile, mResourceBundle.getAppPackage(), mOriginalFileLookup);
109a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            if (bindingLayout != null && !bindingLayout.isEmpty()) {
1100390898cf7c4fcad255e8cfd6802f722b516cb2cGeorge Mount                mResourceBundle.addLayoutBundle(bindingLayout);
1118e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            }
1128e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
1138e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mProcessingComplete = true;
1148e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        return true;
1158e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
1168e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
117be83770af82294c1841eef414513653646b88dc6Yigit Boyar    public void writeLayoutInfoFiles(File xmlOutDir) throws JAXBException {
1188e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        if (mWritten) {
1198e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return;
1208e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
1218e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        JAXBContext context = JAXBContext.newInstance(ResourceBundle.LayoutFileBundle.class);
1228e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        Marshaller marshaller = context.createMarshaller();
123be83770af82294c1841eef414513653646b88dc6Yigit Boyar
1248e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        for (List<ResourceBundle.LayoutFileBundle> layouts : mResourceBundle.getLayoutBundles()
1258e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount                .values()) {
1268e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            for (ResourceBundle.LayoutFileBundle layout : layouts) {
127a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                writeXmlFile(xmlOutDir, layout, marshaller);
1288e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            }
1298e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
1308e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        mWritten = true;
1318e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
1328e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
133a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private void writeXmlFile(File xmlOutDir, ResourceBundle.LayoutFileBundle layout,
134a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            Marshaller marshaller) throws JAXBException {
135a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        String filename = generateExportFileName(layout) + ".xml";
136a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        String xml = toXML(layout, marshaller);
137a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        mFileWriter.writeToFile(new File(xmlOutDir, filename), xml);
138a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
139a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
140a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public String getInfoClassFullName() {
141a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME;
142a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
143a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
144a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private String toXML(ResourceBundle.LayoutFileBundle layout, Marshaller marshaller)
1458e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            throws JAXBException {
146a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        StringWriter writer = new StringWriter();
147a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        marshaller.marshal(layout, writer);
148a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return writer.getBuffer().toString();
149a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
150a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
151a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    /**
152a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     * Generates a string identifier that can uniquely identify the given layout bundle.
153a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     * This identifier can be used when we need to export data about this layout bundle.
154a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar     */
15530cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount    public String generateExportFileName(ResourceBundle.LayoutFileBundle layout) {
156a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        StringBuilder name = new StringBuilder(layout.getFileName());
157a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        name.append('-').append(layout.getDirectory());
158a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        for (int i = name.length() - 1; i >= 0; i--) {
159a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            char c = name.charAt(i);
1608e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            if (c == '-') {
161a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                name.deleteCharAt(i);
162a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                c = Character.toUpperCase(name.charAt(i));
163a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                name.setCharAt(i, c);
1648e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            }
1658e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
166a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return name.toString();
1678e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
1688e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
169b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar    public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir,
170b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            /*Nullable*/ File exportClassListTo) {
17108119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar        writeInfoClass(sdkDir, xmlOutDir, exportClassListTo, false, false);
172b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar    }
173b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar
174b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar    public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir, File exportClassListTo,
17508119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar            boolean enableDebugLogs, boolean printEncodedErrorLogs) {
176ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar        final String sdkPath = sdkDir == null ? null : StringEscapeUtils.escapeJava(sdkDir.getAbsolutePath());
177a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        final Class annotation = BindingBuildInfo.class;
178a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        final String layoutInfoPath = StringEscapeUtils.escapeJava(xmlOutDir.getAbsolutePath());
179b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar        final String exportClassListToPath = exportClassListTo == null ? "" :
180b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar                StringEscapeUtils.escapeJava(exportClassListTo.getAbsolutePath());
181a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        String classString = "package " + RESOURCE_BUNDLE_PACKAGE + ";\n\n" +
182a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "import " + annotation.getCanonicalName() + ";\n\n" +
183a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "@" + annotation.getSimpleName() + "(buildId=\"" + mBuildId + "\", " +
184a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "modulePackage=\"" + mResourceBundle.getAppPackage() + "\", " +
185ae161289a90f6ac69ffe6411ac8c09653c81d04dYigit Boyar                "sdkRoot=" + "\"" + (sdkPath == null ? "" : sdkPath) + "\"," +
186a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "layoutInfoDir=\"" + layoutInfoPath + "\"," +
187b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar                "exportClassListTo=\"" + exportClassListToPath + "\"," +
188a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "isLibrary=" + mIsLibrary + "," +
189b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar                "minSdk=" + mMinSdk + "," +
19008119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar                "enableDebugLogs=" + enableDebugLogs + "," +
19108119ea342cb47910ca80ff646d746f00e4663ceYigit Boyar                "printEncodedError=" + printEncodedErrorLogs + ")\n" +
192a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                "public class " + CLASS_NAME + " {}\n";
193fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount        mFileWriter.writeToFile(RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME, classString);
1948e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
1958e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
196a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private static final FilenameFilter layoutFolderFilter = new FilenameFilter() {
1978e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        @Override
1988e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        public boolean accept(File dir, String name) {
1998e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return name.startsWith("layout");
2008e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
2018e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    };
2028e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
203a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private static final FilenameFilter xmlFileFilter = new FilenameFilter() {
2048e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        @Override
2058e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        public boolean accept(File dir, String name) {
2068e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            return name.toLowerCase().endsWith(".xml");
2078e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount        }
2088e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    };
209890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar
210890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    /**
211890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar     * Helper interface that can find the original copy of a resource XML.
212890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar     */
213890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    public interface OriginalFileLookup {
214890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar
215890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar        /**
216890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar         * @param file The intermediate build file
217890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar         * @return The original file or null if original File cannot be found.
218890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar         */
219890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar        File getOriginalFileFor(File file);
220890b4850c628f04eb75397e427ba7074e4f9c386Yigit Boyar    }
2218e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount}
222