ProcessExpressions.java revision e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10
197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar/*
297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar *
497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * you may not use this file except in compliance with the License.
697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * You may obtain a copy of the License at
797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar *
897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar *
1097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Unless required by applicable law or agreed to in writing, software
1197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
1297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * See the License for the specific language governing permissions and
1497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * limitations under the License.
1597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar */
1697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.annotationprocessor;
18e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount
19a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport org.apache.commons.io.FileUtils;
201b9940e612fc73202837fbe9db2f9035f307b5d1George Mountimport org.apache.commons.io.IOUtils;
21b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyarimport org.apache.commons.lang3.StringUtils;
221b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.BindingBuildInfo;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.CompilerChef;
25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.SdkUtil;
26fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.ResourceBundle;
27fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.GenerationalClassUtil;
28fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L;
294df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyarimport android.databinding.tool.writer.BRWriter;
301b9940e612fc73202837fbe9db2f9035f307b5d1George Mount
3197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.io.File;
32a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.FilenameFilter;
33e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport java.io.IOException;
34a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.InputStream;
35a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.io.Serializable;
36a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.HashMap;
37a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.List;
38a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.Map;
39b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyarimport java.util.Set;
40e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount
41a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport javax.annotation.processing.ProcessingEnvironment;
42e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mountimport javax.annotation.processing.RoundEnvironment;
438e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBContext;
448e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBException;
458e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.Unmarshaller;
46e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount
47a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarpublic class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
484df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar    public ProcessExpressions() {
4961630faa88ee4817834d47294a0e17f19d8e1c51George Mount    }
5061630faa88ee4817834d47294a0e17f19d8e1c51George Mount
51a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    @Override
52a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public boolean onHandleStep(RoundEnvironment roundEnvironment,
53a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) {
54a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        ResourceBundle resourceBundle;
55a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        SdkUtil.initialize(buildInfo.minSdk(), new File(buildInfo.sdkRoot()));
56a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        resourceBundle = new ResourceBundle(buildInfo.modulePackage());
57a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        List<Intermediate> intermediateList =
58e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar                GenerationalClassUtil.loadObjects(
59e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar                        GenerationalClassUtil.ExtensionFilter.LAYOUT);
60a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        IntermediateV1 mine = createIntermediateFromLayouts(buildInfo.layoutInfoDir());
61a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        if (mine != null) {
62a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            mine.removeOverridden(intermediateList);
63a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            intermediateList.add(mine);
64a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            saveIntermediate(processingEnvironment, buildInfo, mine);
65a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
66a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        // generate them here so that bindable parser can read
67a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        try {
68a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            generateBinders(resourceBundle, buildInfo, intermediateList);
69a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        } catch (Throwable t) {
70a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            L.e(t, "cannot generate view binders");
71a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
72a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return true;
73a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
74a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
75a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private void saveIntermediate(ProcessingEnvironment processingEnvironment,
76a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            BindingBuildInfo buildInfo, IntermediateV1 intermediate) {
77a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        GenerationalClassUtil.writeIntermediateFile(processingEnvironment,
78e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar                buildInfo.modulePackage(), buildInfo.modulePackage() +
79e8609ca3a9e95cb730d74f8a6114bc2ae11b6a10Yigit Boyar                        GenerationalClassUtil.ExtensionFilter.LAYOUT.getExtension(),
80a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                intermediate);
81a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
82a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
83a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    @Override
84a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public void onProcessingOver(RoundEnvironment roundEnvironment,
85a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) {
86a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
87a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
88a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private void generateBinders(ResourceBundle resourceBundle, BindingBuildInfo buildInfo,
89a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            List<Intermediate> intermediates)
90a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            throws Throwable {
91a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        for (Intermediate intermediate : intermediates) {
92a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            intermediate.appendTo(resourceBundle);
93a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
94b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar        writeResourceBundle(resourceBundle, buildInfo.isLibrary(), buildInfo.minSdk(),
95b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar                buildInfo.exportClassListTo());
96a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
97a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
98a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    private IntermediateV1 createIntermediateFromLayouts(String layoutInfoFolderPath) {
99a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        final File layoutInfoFolder = new File(layoutInfoFolderPath);
100a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        if (!layoutInfoFolder.isDirectory()) {
101a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            L.d("layout info folder does not exist, skipping for %s", layoutInfoFolderPath);
102a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            return null;
103a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
104a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        IntermediateV1 result = new IntermediateV1();
105a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        for (File layoutFile : layoutInfoFolder.listFiles(new FilenameFilter() {
106a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            @Override
107a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            public boolean accept(File dir, String name) {
108a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                return name.endsWith(".xml");
10900da715547ee7d5d38a3b8576090ca427a94daa5George Mount            }
110a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        })) {
111a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            try {
112a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                result.addEntry(layoutFile.getName(), FileUtils.readFileToString(layoutFile));
113a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            } catch (IOException e) {
114a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                L.e(e, "cannot load layout file information. Try a clean build");
1151b9940e612fc73202837fbe9db2f9035f307b5d1George Mount            }
116a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
117a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        return result;
118a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
119a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
120e7c2a5e45d7651899790bd347da635875f9c73fbGeorge Mount    private void writeResourceBundle(ResourceBundle resourceBundle, boolean forLibraryModule,
1214df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar            final int minSdk, String exportClassNamesTo)
122a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            throws JAXBException {
1234df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        final CompilerChef compilerChef = CompilerChef.createChef(resourceBundle, getWriter());
124a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        if (compilerChef.hasAnythingToGenerate()) {
125dea555cf42dc3583604699c8c018d22681f56166George Mount            compilerChef.writeViewBinderInterfaces(forLibraryModule);
126a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            if (!forLibraryModule) {
12796e1c821dd446d1ed78f8ae61131550588f60a24George Mount                compilerChef.writeViewBinders(minSdk);
1281b9940e612fc73202837fbe9db2f9035f307b5d1George Mount            }
1291b9940e612fc73202837fbe9db2f9035f307b5d1George Mount        }
130b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar        if (forLibraryModule && exportClassNamesTo == null) {
131b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            L.e("When compiling a library module, build info must include exportClassListTo path");
132b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar        }
133b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar        if (forLibraryModule) {
134b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            Set<String> classNames = compilerChef.getWrittenClassNames();
135b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            String out = StringUtils.join(classNames, System.getProperty("line.separator"));
136b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            L.d("Writing list of classes to %s . \nList:%s", exportClassNamesTo, out);
137b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            try {
1384df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                //noinspection ConstantConditions
1394df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar                FileUtils.write(new File(exportClassNamesTo), out);
140b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            } catch (IOException e) {
141b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar                L.e(e, "Cannot create list of written classes");
142b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar            }
1431bbaf7cdf7f9d93ae09365192abb2288cf0dfb41George Mount        }
1444df4ba38a62b791bbbc25e923efe8d9c2f9a52e9Yigit Boyar        mCallback.onChefReady(compilerChef, forLibraryModule, minSdk);
145a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    }
146e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount
147a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public static interface Intermediate extends Serializable {
148a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
149a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        Intermediate upgrade();
150a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
151a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        public void appendTo(ResourceBundle resourceBundle) throws Throwable;
1528e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount    }
1538e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
154a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar    public static class IntermediateV1 implements Intermediate {
155a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
156a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        transient Unmarshaller mUnmarshaller;
157a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
158a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        // name to xml content map
159b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar        Map<String, String> mLayoutInfoMap = new HashMap<String, String>();
160a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
161a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        @Override
162a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        public Intermediate upgrade() {
163a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            return this;
164a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
165a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar
166a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        @Override
167a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        public void appendTo(ResourceBundle resourceBundle) throws JAXBException {
168a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            if (mUnmarshaller == null) {
169a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                JAXBContext context = JAXBContext
170a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                        .newInstance(ResourceBundle.LayoutFileBundle.class);
171a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                mUnmarshaller = context.createUnmarshaller();
1728e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount            }
173a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            for (String content : mLayoutInfoMap.values()) {
174a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                final InputStream is = IOUtils.toInputStream(content);
175a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                try {
176a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    final ResourceBundle.LayoutFileBundle bundle
177a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                            = (ResourceBundle.LayoutFileBundle) mUnmarshaller.unmarshal(is);
1780390898cf7c4fcad255e8cfd6802f722b516cb2cGeorge Mount                    resourceBundle.addLayoutBundle(bundle);
179a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    L.d("loaded layout info file %s", bundle);
180a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                } finally {
181a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    IOUtils.closeQuietly(is);
1821b9940e612fc73202837fbe9db2f9035f307b5d1George Mount                }
1831b9940e612fc73202837fbe9db2f9035f307b5d1George Mount            }
184a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        }
1858e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
186a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        public void addEntry(String name, String contents) {
187a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            mLayoutInfoMap.put(name, contents);
1881b9940e612fc73202837fbe9db2f9035f307b5d1George Mount        }
1898e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount
190a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar        public void removeOverridden(List<Intermediate> existing) {
191a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            // this is the way we get rid of files that are copied from previous modules
192a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            // it is important to do this before saving the intermediate file
193a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            for (Intermediate old : existing) {
194a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                if (old instanceof IntermediateV1) {
195a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    IntermediateV1 other = (IntermediateV1) old;
196a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    for (String key : other.mLayoutInfoMap.keySet()) {
197a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                        // TODO we should consider the original file as the key here
198a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                        // but aapt probably cannot provide that information
199a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                        if (mLayoutInfoMap.remove(key) != null) {
200a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                            L.d("removing %s from bundle because it came from another module", key);
201a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                        }
202a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                    }
203a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar                }
204a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar            }
20500da715547ee7d5d38a3b8576090ca427a94daa5George Mount        }
206e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount    }
207e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount}
208