19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.tools.layoutlib.create;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
214306096a4351030cab4ea413b5e87460b60a84bfRaphael Mollimport java.util.List;
224306096a4351030cab4ea413b5e87460b60a84bfRaphael Mollimport java.util.Map;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Set;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26bc101806249eb883f89c4a770a8c27f9ac315837Raphael/**
27bc101806249eb883f89c4a770a8c27f9ac315837Raphael * Entry point for the layoutlib_create tool.
28bc101806249eb883f89c4a770a8c27f9ac315837Raphael * <p/>
29bc101806249eb883f89c4a770a8c27f9ac315837Raphael * The tool does not currently rely on any external configuration file.
30bc101806249eb883f89c4a770a8c27f9ac315837Raphael * Instead the configuration is mostly done via the {@link CreateInfo} class.
31bc101806249eb883f89c4a770a8c27f9ac315837Raphael * <p/>
32bc101806249eb883f89c4a770a8c27f9ac315837Raphael * For a complete description of the tool and its implementation, please refer to
33bc101806249eb883f89c4a770a8c27f9ac315837Raphael * the "README.txt" file at the root of this project.
34bc101806249eb883f89c4a770a8c27f9ac315837Raphael * <p/>
35bc101806249eb883f89c4a770a8c27f9ac315837Raphael * For a quick test, invoke this as follows:
36bc101806249eb883f89c4a770a8c27f9ac315837Raphael * <pre>
37bc101806249eb883f89c4a770a8c27f9ac315837Raphael * $ make layoutlib
38bc101806249eb883f89c4a770a8c27f9ac315837Raphael * </pre>
39bc101806249eb883f89c4a770a8c27f9ac315837Raphael * which does:
40bc101806249eb883f89c4a770a8c27f9ac315837Raphael * <pre>
41bc101806249eb883f89c4a770a8c27f9ac315837Raphael * $ make layoutlib_create &lt;bunch of framework jars&gt;
42caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll * $ java -jar out/host/linux-x86/framework/layoutlib_create.jar \
43bc101806249eb883f89c4a770a8c27f9ac315837Raphael *        out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar \
44bc101806249eb883f89c4a770a8c27f9ac315837Raphael *        out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar \
45bc101806249eb883f89c4a770a8c27f9ac315837Raphael *        out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
46bc101806249eb883f89c4a770a8c27f9ac315837Raphael * </pre>
47bc101806249eb883f89c4a770a8c27f9ac315837Raphael */
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Main {
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
50caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll    public static class Options {
51caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll        public boolean generatePublicAccess = true;
524306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        public boolean listAllDeps = false;
534306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        public boolean listOnlyMissingDeps = false;
54caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll    }
55caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll
56caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll    public static final Options sOptions = new Options();
57caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void main(String[] args) {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log log = new Log();
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<String> osJarPath = new ArrayList<String>();
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String[] osDestJar = { null };
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!processArgs(log, args, osJarPath, osDestJar)) {
66caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll            log.error("Usage: layoutlib_create [-v] [-p] output.jar input.jar ...");
674306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            log.error("Usage: layoutlib_create [-v] [--list-deps|--missing-deps] input.jar ...");
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.exit(1);
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
714306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        if (sOptions.listAllDeps || sOptions.listOnlyMissingDeps) {
724306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            System.exit(listDeps(osJarPath, log));
734306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll
744306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        } else {
754306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            System.exit(createLayoutLib(osDestJar[0], osJarPath, log));
764306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        }
774306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll
784306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll
794306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        System.exit(1);
804306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll    }
814306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll
824306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll    private static int createLayoutLib(String osDestJar, ArrayList<String> osJarPath, Log log) {
834306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        log.info("Output: %1$s", osDestJar);
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String path : osJarPath) {
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log.info("Input :      %1$s", path);
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
877953e7d89b1d4d7297176fbb6aeea882577df8e6Xavier Ducrohet
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
894306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            AsmGenerator agen = new AsmGenerator(log, osDestJar, new CreateInfo());
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath, agen,
927f7752439543db6e13c599bdd10cb10254c24528Xavier Ducrohet                    new String[] {                          // derived from
937f7752439543db6e13c599bdd10cb10254c24528Xavier Ducrohet                        "android.view.View",
947f7752439543db6e13c599bdd10cb10254c24528Xavier Ducrohet                        "android.app.Fragment"
957f7752439543db6e13c599bdd10cb10254c24528Xavier Ducrohet                    },
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    new String[] {                          // include classes
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.*", // for android.R
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.util.*",
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "com.android.internal.util.*",
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.view.*",
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.widget.*",
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "com.android.internal.widget.*",
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.text.**",
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.graphics.*",
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.graphics.drawable.*",
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.content.*",
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.content.res.*",
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "org.apache.harmony.xml.*",
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "com.android.internal.R**",
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.pim.*", // for datepicker
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "android.os.*",  // for android.os.Handler
112d815e3704850a513e8d02ba3b88fa47f41cea9a5Xavier Ducrohet                        "android.database.ContentObserver", // for Digital clock
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        });
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            aa.analyze();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            agen.generate();
1167953e7d89b1d4d7297176fbb6aeea882577df8e6Xavier Ducrohet
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Throw an error if any class failed to get renamed by the generator
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // IMPORTANT: if you're building the platform and you get this error message,
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // it means the renameClasses[] array in AsmGenerator needs to be updated: some
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // class should have been renamed but it was not found in the input JAR files.
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Set<String> notRenamed = agen.getClassesNotRenamed();
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (notRenamed.size() > 0) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // (80-column guide below for error formatting)
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // 01234567890123456789012345678901234567890123456789012345678901234567890123456789
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                log.error(
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ERROR when running layoutlib_create: the following classes are referenced\n" +
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "by tools/layoutlib/create but were not actually found in the input JAR files.\n" +
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "This may be due to some platform classes having been renamed.");
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (String fqcn : notRenamed) {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    log.error("- Class not found: %s", fqcn.replace('/', '.'));
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (String path : osJarPath) {
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    log.info("- Input JAR : %1$s", path);
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1364306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                return 1;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1387953e7d89b1d4d7297176fbb6aeea882577df8e6Xavier Ducrohet
1394306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            return 0;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log.exception(e, "Failed to load jar");
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (LogAbortException e) {
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.error(log);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1464306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        return 1;
1474306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll    }
1484306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll
1494306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll    private static int listDeps(ArrayList<String> osJarPath, Log log) {
1504306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        DependencyFinder df = new DependencyFinder(log);
1514306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        try {
1524306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            List<Map<String, Set<String>>> result = df.findDeps(osJarPath);
1534306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            if (sOptions.listAllDeps) {
1544306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                df.printAllDeps(result);
1554306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            } else if (sOptions.listOnlyMissingDeps) {
1564306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                df.printMissingDeps(result);
1574306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            }
1584306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        } catch (IOException e) {
1594306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            log.exception(e, "Failed to load jar");
1604306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        }
1614306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll
1624306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        return 0;
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if args where properly parsed.
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns false if program should exit with command-line usage.
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p/>
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: the String[0] is an output parameter wrapped in an array, since there is no
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * "out" parameter support.
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean processArgs(Log log, String[] args,
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> osJarPath, String[] osDestJar) {
1744306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        boolean needs_dest = true;
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < args.length; i++) {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String s = args[i];
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (s.equals("-v")) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                log.setVerbose(true);
179caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll            } else if (s.equals("-p")) {
180caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll                sOptions.generatePublicAccess = false;
1814306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            } else if (s.equals("--list-deps")) {
1824306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                sOptions.listAllDeps = true;
1834306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                needs_dest = false;
1844306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll            } else if (s.equals("--missing-deps")) {
1854306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                sOptions.listOnlyMissingDeps = true;
1864306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                needs_dest = false;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (!s.startsWith("-")) {
1884306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll                if (needs_dest && osDestJar[0] == null) {
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    osDestJar[0] = s;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    osJarPath.add(s);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                log.error("Unknow argument: %s", s);
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1987953e7d89b1d4d7297176fbb6aeea882577df8e6Xavier Ducrohet
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (osJarPath.isEmpty()) {
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log.error("Missing parameter: path to input jar");
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2034306096a4351030cab4ea413b5e87460b60a84bfRaphael Moll        if (needs_dest && osDestJar[0] == null) {
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log.error("Missing parameter: path to output jar");
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2087f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet        sOptions.generatePublicAccess = false;
2097f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
213