aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/java
diff options
context:
space:
mode:
authorGravatar Alex Humesky <ahumesky@google.com>2016-01-11 22:46:40 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-01-11 22:52:15 +0000
commit6ba5c97e9ad94b307b3383d9d18c9ef30e3f8322 (patch)
tree61fb67478b11fcd1e1e32cbb46a9218b760270dc /third_party/java
parent195ed9aa345cfbe7bc9e5258a963674cef86aea4 (diff)
Adds ApkBuilder from the Android SDK to bazel's third_party with some
modifications to remove deprecation warnings, to create deterministic apks (removes timestamps), and to make calling ApkBuilder more convenient. RELNOTES: Timestamps within Android apks are removed to make apks deterministic. -- MOS_MIGRATED_REVID=111890659
Diffstat (limited to 'third_party/java')
-rw-r--r--third_party/java/apkbuilder/BUILD20
-rw-r--r--third_party/java/apkbuilder/BUILD.tools15
-rw-r--r--third_party/java/apkbuilder/LICENSE189
-rw-r--r--third_party/java/apkbuilder/java/com/android/SdkConstants.java1359
-rw-r--r--third_party/java/apkbuilder/java/com/android/annotations/NonNull.java38
-rw-r--r--third_party/java/apkbuilder/java/com/android/annotations/Nullable.java49
-rw-r--r--third_party/java/apkbuilder/java/com/android/prefs/AndroidLocation.java166
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilder.java1005
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilderMain.java264
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/build/ApkCreationException.java36
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/build/DuplicateFileException.java55
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/build/IArchiveBuilder.java35
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/build/SealedApkException.java36
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/internal/build/DebugKeyProvider.java215
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/internal/build/KeystoreHelper.java173
-rw-r--r--third_party/java/apkbuilder/java/com/android/sdklib/internal/build/SignedJarBuilder.java399
-rw-r--r--third_party/java/apkbuilder/java/com/android/utils/GrabProcessOutput.java193
17 files changed, 4247 insertions, 0 deletions
diff --git a/third_party/java/apkbuilder/BUILD b/third_party/java/apkbuilder/BUILD
new file mode 100644
index 0000000000..b7f1248306
--- /dev/null
+++ b/third_party/java/apkbuilder/BUILD
@@ -0,0 +1,20 @@
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "embedded_tools",
+ srcs = [
+ "BUILD.tools",
+ "apkbuilder_deploy.jar",
+ ],
+ visibility = ["//src:__pkg__"],
+)
+
+java_binary(
+ name = "apkbuilder",
+ srcs = glob(["java/**/*.java"]),
+ main_class = "com.android.sdklib.build.ApkBuilderMain",
+ deps = [
+ "//src/java_tools/singlejar:libSingleJar",
+ "//third_party:guava",
+ ],
+)
diff --git a/third_party/java/apkbuilder/BUILD.tools b/third_party/java/apkbuilder/BUILD.tools
new file mode 100644
index 0000000000..580ada40d2
--- /dev/null
+++ b/third_party/java/apkbuilder/BUILD.tools
@@ -0,0 +1,15 @@
+# The build file for apkbuilder when it's in bazel's embedded tools repo.
+
+licenses(["notice"]) # Apache 2.0
+
+java_binary(
+ name = "embedded_apkbuilder",
+ main_class = "com.android.sdklib.build.ApkBuilderMain",
+ runtime_deps = [":apkbuilder_deploy_jar"],
+ visibility = ["//visibility:public"],
+)
+
+java_import(
+ name = "apkbuilder_deploy_jar",
+ jars = [":apkbuilder_deploy.jar"]
+)
diff --git a/third_party/java/apkbuilder/LICENSE b/third_party/java/apkbuilder/LICENSE
new file mode 100644
index 0000000000..da6a0e7222
--- /dev/null
+++ b/third_party/java/apkbuilder/LICENSE
@@ -0,0 +1,189 @@
+Copyright (c) 2005-2008, The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
diff --git a/third_party/java/apkbuilder/java/com/android/SdkConstants.java b/third_party/java/apkbuilder/java/com/android/SdkConstants.java
new file mode 100644
index 0000000000..56b6a14f22
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/SdkConstants.java
@@ -0,0 +1,1359 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android;
+
+import java.io.File;
+
+/**
+ * Constant definition class.<br>
+ * <br>
+ * Most constants have a prefix defining the content.
+ * <ul>
+ * <li><code>OS_</code> OS path constant. These paths are different depending on the platform.</li>
+ * <li><code>FN_</code> File name constant.</li>
+ * <li><code>FD_</code> Folder name constant.</li>
+ * <li><code>TAG_</code> XML element tag name</li>
+ * <li><code>ATTR_</code> XML attribute name</li>
+ * <li><code>VALUE_</code> XML attribute value</li>
+ * <li><code>CLASS_</code> Class name</li>
+ * <li><code>DOT_</code> File name extension, including the dot </li>
+ * <li><code>EXT_</code> File name extension, without the dot </li>
+ * </ul>
+ */
+@SuppressWarnings("javadoc") // Not documenting all the fields here
+public final class SdkConstants {
+ public static final int PLATFORM_UNKNOWN = 0;
+ public static final int PLATFORM_LINUX = 1;
+ public static final int PLATFORM_WINDOWS = 2;
+ public static final int PLATFORM_DARWIN = 3;
+
+ /**
+ * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
+ * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
+ */
+ public static final int CURRENT_PLATFORM = currentPlatform();
+
+ /** Environment variable that specifies the path of an Android SDK. */
+ public static final String ANDROID_HOME_ENV = "ANDROID_HOME";
+
+ /** Property in local.properties file that specifies the path of the Android SDK. */
+ public static final String SDK_DIR_PROPERTY = "sdk.dir";
+
+ /** Property in gradle-wrapper.properties file that specifies the URL to the correct Gradle distribution. */
+ public static final String GRADLE_DISTRIBUTION_URL_PROPERTY = "distributionUrl"; //$NON-NLS-1$
+
+ /**
+ * The encoding we strive to use for all files we write.
+ * <p>
+ * When possible, use the APIs which take a {@link java.nio.charset.Charset} and pass in
+ * {@link com.google.common.base.Charsets#UTF_8} instead of using the String encoding
+ * method.
+ */
+ public static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
+
+ /**
+ * Charset for the ini file handled by the SDK.
+ */
+ public static final String INI_CHARSET = UTF_8;
+
+ /** Path separator used by Gradle */
+ public static final String GRADLE_PATH_SEPARATOR = ":"; //$NON-NLS-1$
+
+ /** An SDK Project's AndroidManifest.xml file */
+ public static final String FN_ANDROID_MANIFEST_XML= "AndroidManifest.xml"; //$NON-NLS-1$
+ /** pre-dex jar filename. i.e. "classes.jar" */
+ public static final String FN_CLASSES_JAR = "classes.jar"; //$NON-NLS-1$
+ /** Dex filename inside the APK. i.e. "classes.dex" */
+ public static final String FN_APK_CLASSES_DEX = "classes.dex"; //$NON-NLS-1$
+
+ /** An SDK Project's build.xml file */
+ public static final String FN_BUILD_XML = "build.xml"; //$NON-NLS-1$
+ /** An SDK Project's build.gradle file */
+ public static final String FN_BUILD_GRADLE = "build.gradle"; //$NON-NLS-1$
+ /** An SDK Project's settings.gradle file */
+ public static final String FN_SETTINGS_GRADLE = "settings.gradle"; //$NON-NLS-1$
+ /** An SDK Project's gradle.properties file */
+ public static final String FN_GRADLE_PROPERTIES = "gradle.properties"; //$NON-NLS-1$
+ /** An SDK Project's gradle daemon executable */
+ public static final String FN_GRADLE_UNIX = "gradle"; //$NON-NLS-1$
+ /** An SDK Project's gradle.bat daemon executable (gradle for windows) */
+ public static final String FN_GRADLE_WIN = FN_GRADLE_UNIX + ".bat"; //$NON-NLS-1$
+ /** An SDK Project's gradlew file */
+ public static final String FN_GRADLE_WRAPPER_UNIX = "gradlew"; //$NON-NLS-1$
+ /** An SDK Project's gradlew.bat file (gradlew for windows) */
+ public static final String FN_GRADLE_WRAPPER_WIN = FN_GRADLE_WRAPPER_UNIX + ".bat"; //$NON-NLS-1$
+ /** An SDK Project's gradle wrapper library */
+ public static final String FN_GRADLE_WRAPPER_JAR = "gradle-wrapper.jar"; //$NON-NLS-1$
+ /** Name of the framework library, i.e. "android.jar" */
+ public static final String FN_FRAMEWORK_LIBRARY = "android.jar"; //$NON-NLS-1$
+ /** Name of the framework library, i.e. "uiautomator.jar" */
+ public static final String FN_UI_AUTOMATOR_LIBRARY = "uiautomator.jar"; //$NON-NLS-1$
+ /** Name of the layout attributes, i.e. "attrs.xml" */
+ public static final String FN_ATTRS_XML = "attrs.xml"; //$NON-NLS-1$
+ /** Name of the layout attributes, i.e. "attrs_manifest.xml" */
+ public static final String FN_ATTRS_MANIFEST_XML = "attrs_manifest.xml"; //$NON-NLS-1$
+ /** framework aidl import file */
+ public static final String FN_FRAMEWORK_AIDL = "framework.aidl"; //$NON-NLS-1$
+ /** framework renderscript folder */
+ public static final String FN_FRAMEWORK_RENDERSCRIPT = "renderscript"; //$NON-NLS-1$
+ /** framework include folder */
+ public static final String FN_FRAMEWORK_INCLUDE = "include"; //$NON-NLS-1$
+ /** framework include (clang) folder */
+ public static final String FN_FRAMEWORK_INCLUDE_CLANG = "clang-include"; //$NON-NLS-1$
+ /** layoutlib.jar file */
+ public static final String FN_LAYOUTLIB_JAR = "layoutlib.jar"; //$NON-NLS-1$
+ /** widget list file */
+ public static final String FN_WIDGETS = "widgets.txt"; //$NON-NLS-1$
+ /** Intent activity actions list file */
+ public static final String FN_INTENT_ACTIONS_ACTIVITY = "activity_actions.txt"; //$NON-NLS-1$
+ /** Intent broadcast actions list file */
+ public static final String FN_INTENT_ACTIONS_BROADCAST = "broadcast_actions.txt"; //$NON-NLS-1$
+ /** Intent service actions list file */
+ public static final String FN_INTENT_ACTIONS_SERVICE = "service_actions.txt"; //$NON-NLS-1$
+ /** Intent category list file */
+ public static final String FN_INTENT_CATEGORIES = "categories.txt"; //$NON-NLS-1$
+
+ /** annotations support jar */
+ public static final String FN_ANNOTATIONS_JAR = "annotations.jar"; //$NON-NLS-1$
+
+ /** platform build property file */
+ public static final String FN_BUILD_PROP = "build.prop"; //$NON-NLS-1$
+ /** plugin properties file */
+ public static final String FN_PLUGIN_PROP = "plugin.prop"; //$NON-NLS-1$
+ /** add-on manifest file */
+ public static final String FN_MANIFEST_INI = "manifest.ini"; //$NON-NLS-1$
+ /** add-on layout device XML file. */
+ public static final String FN_DEVICES_XML = "devices.xml"; //$NON-NLS-1$
+ /** hardware properties definition file */
+ public static final String FN_HARDWARE_INI = "hardware-properties.ini"; //$NON-NLS-1$
+
+ /** project property file */
+ public static final String FN_PROJECT_PROPERTIES = "project.properties"; //$NON-NLS-1$
+
+ /** project local property file */
+ public static final String FN_LOCAL_PROPERTIES = "local.properties"; //$NON-NLS-1$
+
+ /** project ant property file */
+ public static final String FN_ANT_PROPERTIES = "ant.properties"; //$NON-NLS-1$
+
+ /** project local property file */
+ public static final String FN_GRADLE_WRAPPER_PROPERTIES = "gradle-wrapper.properties"; //$NON-NLS-1$
+
+ /** Skin layout file */
+ public static final String FN_SKIN_LAYOUT = "layout"; //$NON-NLS-1$
+
+ /** dx.jar file */
+ public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
+
+ /** dx executable (with extension for the current OS) */
+ public static final String FN_DX =
+ "dx" + ext(".bat", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** aapt executable (with extension for the current OS) */
+ public static final String FN_AAPT =
+ "aapt" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** aidl executable (with extension for the current OS) */
+ public static final String FN_AIDL =
+ "aidl" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** renderscript executable (with extension for the current OS) */
+ public static final String FN_RENDERSCRIPT =
+ "llvm-rs-cc" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** renderscript support exe (with extension for the current OS) */
+ public static final String FN_BCC_COMPAT =
+ "bcc_compat" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** renderscript support linker for ARM (with extension for the current OS) */
+ public static final String FN_LD_ARM =
+ "arm-linux-androideabi-ld" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** renderscript support linker for X86 (with extension for the current OS) */
+ public static final String FN_LD_X86 =
+ "i686-linux-android-ld" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** renderscript support linker for MIPS (with extension for the current OS) */
+ public static final String FN_LD_MIPS =
+ "mipsel-linux-android-ld" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** adb executable (with extension for the current OS) */
+ public static final String FN_ADB =
+ "adb" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** emulator executable for the current OS */
+ public static final String FN_EMULATOR =
+ "emulator" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** zipalign executable (with extension for the current OS) */
+ public static final String FN_ZIPALIGN =
+ "zipalign" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** dexdump executable (with extension for the current OS) */
+ public static final String FN_DEXDUMP =
+ "dexdump" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** proguard executable (with extension for the current OS) */
+ public static final String FN_PROGUARD =
+ "proguard" + ext(".bat", ".sh"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** find_lock for Windows (with extension for the current OS) */
+ public static final String FN_FIND_LOCK =
+ "find_lock" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** hprof-conv executable (with extension for the current OS) */
+ public static final String FN_HPROF_CONV =
+ "hprof-conv" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /** properties file for SDK Updater packages */
+ public static final String FN_SOURCE_PROP = "source.properties"; //$NON-NLS-1$
+ /** properties file for content hash of installed packages */
+ public static final String FN_CONTENT_HASH_PROP = "content_hash.properties"; //$NON-NLS-1$
+ /** properties file for the SDK */
+ public static final String FN_SDK_PROP = "sdk.properties"; //$NON-NLS-1$
+
+
+ public static final String FN_RENDERSCRIPT_V8_JAR = "renderscript-v8.jar"; //$NON-NLS-1$
+
+ /**
+ * filename for gdbserver.
+ */
+ public static final String FN_GDBSERVER = "gdbserver"; //$NON-NLS-1$
+ public static final String FN_GDB_SETUP = "gdb.setup"; //$NON-NLS-1$
+
+ /** global Android proguard config file */
+ public static final String FN_ANDROID_PROGUARD_FILE = "proguard-android.txt"; //$NON-NLS-1$
+ /** global Android proguard config file with optimization enabled */
+ public static final String FN_ANDROID_OPT_PROGUARD_FILE = "proguard-android-optimize.txt"; //$NON-NLS-1$
+ /** default proguard config file with new file extension (for project specific stuff) */
+ public static final String FN_PROJECT_PROGUARD_FILE = "proguard-project.txt"; //$NON-NLS-1$
+
+ /* Folder Names for Android Projects . */
+
+ /** Resources folder name, i.e. "res". */
+ public static final String FD_RESOURCES = "res"; //$NON-NLS-1$
+ /** Assets folder name, i.e. "assets" */
+ public static final String FD_ASSETS = "assets"; //$NON-NLS-1$
+ /** Default source folder name in an SDK project, i.e. "src".
+ * <p/>
+ * Note: this is not the same as {@link #FD_PKG_SOURCES}
+ * which is an SDK sources folder for packages. */
+ public static final String FD_SOURCES = "src"; //$NON-NLS-1$
+ /** Default main source set folder name, i.e. "main" */
+ public static final String FD_MAIN = "main"; //$NON-NLS-1$
+ /** Default test source set folder name, i.e. "androidTest" */
+ public static final String FD_TEST = "androidTest"; //$NON-NLS-1$
+ /** Default java code folder name, i.e. "java" */
+ public static final String FD_JAVA = "java"; //$NON-NLS-1$
+ /** Default gradle folder name, i.e. "gradle" */
+ public static final String FD_GRADLE = "gradle"; //$NON-NLS-1$
+ /** Default gradle wrapper folder name, i.e. "gradle/wrapper" */
+ public static final String FD_GRADLE_WRAPPER = FD_GRADLE + File.separator + "wrapper"; //$NON-NLS-1$
+ /** Default generated source folder name, i.e. "gen" */
+ public static final String FD_GEN_SOURCES = "gen"; //$NON-NLS-1$
+ /** Default native library folder name inside the project, i.e. "libs"
+ * While the folder inside the .apk is "lib", we call that one libs because
+ * that's what we use in ant for both .jar and .so and we need to make the 2 development ways
+ * compatible. */
+ public static final String FD_NATIVE_LIBS = "libs"; //$NON-NLS-1$
+ /** Native lib folder inside the APK: "lib" */
+ public static final String FD_APK_NATIVE_LIBS = "lib"; //$NON-NLS-1$
+ /** Default output folder name, i.e. "bin" */
+ public static final String FD_OUTPUT = "bin"; //$NON-NLS-1$
+ /** Classes output folder name, i.e. "classes" */
+ public static final String FD_CLASSES_OUTPUT = "classes"; //$NON-NLS-1$
+ /** proguard output folder for mapping, etc.. files */
+ public static final String FD_PROGUARD = "proguard"; //$NON-NLS-1$
+ /** aidl output folder for copied aidl files */
+ public static final String FD_AIDL = "aidl"; //$NON-NLS-1$
+
+ /** rs Libs output folder for support mode */
+ public static final String FD_RS_LIBS = "rsLibs"; //$NON-NLS-1$
+ /** rs Libs output folder for support mode */
+ public static final String FD_RS_OBJ = "rsObj"; //$NON-NLS-1$
+
+ /* Folder Names for the Android SDK */
+
+ /** Name of the SDK platforms folder. */
+ public static final String FD_PLATFORMS = "platforms"; //$NON-NLS-1$
+ /** Name of the SDK addons folder. */
+ public static final String FD_ADDONS = "add-ons"; //$NON-NLS-1$
+ /** Name of the SDK system-images folder. */
+ public static final String FD_SYSTEM_IMAGES = "system-images"; //$NON-NLS-1$
+ /** Name of the SDK sources folder where source packages are installed.
+ * <p/>
+ * Note this is not the same as {@link #FD_SOURCES} which is the folder name where sources
+ * are installed inside a project. */
+ public static final String FD_PKG_SOURCES = "sources"; //$NON-NLS-1$
+ /** Name of the SDK tools folder. */
+ public static final String FD_TOOLS = "tools"; //$NON-NLS-1$
+ /** Name of the SDK tools/support folder. */
+ public static final String FD_SUPPORT = "support"; //$NON-NLS-1$
+ /** Name of the SDK platform tools folder. */
+ public static final String FD_PLATFORM_TOOLS = "platform-tools"; //$NON-NLS-1$
+ /** Name of the SDK build tools folder. */
+ public static final String FD_BUILD_TOOLS = "build-tools"; //$NON-NLS-1$
+ /** Name of the SDK tools/lib folder. */
+ public static final String FD_LIB = "lib"; //$NON-NLS-1$
+ /** Name of the SDK docs folder. */
+ public static final String FD_DOCS = "docs"; //$NON-NLS-1$
+ /** Name of the doc folder containing API reference doc (javadoc) */
+ public static final String FD_DOCS_REFERENCE = "reference"; //$NON-NLS-1$
+ /** Name of the SDK images folder. */
+ public static final String FD_IMAGES = "images"; //$NON-NLS-1$
+ /** Name of the ABI to support. */
+ public static final String ABI_ARMEABI = "armeabi"; //$NON-NLS-1$
+ public static final String ABI_ARMEABI_V7A = "armeabi-v7a"; //$NON-NLS-1$
+ public static final String ABI_ARM64_V8A = "arm64-v8a"; //$NON-NLS-1$
+ public static final String ABI_INTEL_ATOM = "x86"; //$NON-NLS-1$
+ public static final String ABI_INTEL_ATOM64 = "x86_64"; //$NON-NLS-1$
+ public static final String ABI_MIPS = "mips"; //$NON-NLS-1$
+ public static final String ABI_MIPS64 = "mips64"; //$NON-NLS-1$
+ /** Name of the CPU arch to support. */
+ public static final String CPU_ARCH_ARM = "arm"; //$NON-NLS-1$
+ public static final String CPU_ARCH_ARM64 = "arm64"; //$NON-NLS-1$
+ public static final String CPU_ARCH_INTEL_ATOM = "x86"; //$NON-NLS-1$
+ public static final String CPU_ARCH_INTEL_ATOM64 = "x86_64"; //$NON-NLS-1$
+ public static final String CPU_ARCH_MIPS = "mips"; //$NON-NLS-1$
+ /** TODO double-check this is appropriate value for mips64 */
+ public static final String CPU_ARCH_MIPS64 = "mips64"; //$NON-NLS-1$
+ /** Name of the CPU model to support. */
+ public static final String CPU_MODEL_CORTEX_A8 = "cortex-a8"; //$NON-NLS-1$
+
+ /** Name of the SDK skins folder. */
+ public static final String FD_SKINS = "skins"; //$NON-NLS-1$
+ /** Name of the SDK samples folder. */
+ public static final String FD_SAMPLES = "samples"; //$NON-NLS-1$
+ /** Name of the SDK extras folder. */
+ public static final String FD_EXTRAS = "extras"; //$NON-NLS-1$
+ public static final String FD_M2_REPOSITORY = "m2repository"; //$NON-NLS-1$
+ /**
+ * Name of an extra's sample folder.
+ * Ideally extras should have one {@link #FD_SAMPLES} folder containing
+ * one or more sub-folders (one per sample). However some older extras
+ * might contain a single "sample" folder with directly the samples files
+ * in it. When possible we should encourage extras' owners to move to the
+ * multi-samples format.
+ */
+ public static final String FD_SAMPLE = "sample"; //$NON-NLS-1$
+ /** Name of the SDK templates folder, i.e. "templates" */
+ public static final String FD_TEMPLATES = "templates"; //$NON-NLS-1$
+ /** Name of the SDK Ant folder, i.e. "ant" */
+ public static final String FD_ANT = "ant"; //$NON-NLS-1$
+ /** Name of the SDK data folder, i.e. "data" */
+ public static final String FD_DATA = "data"; //$NON-NLS-1$
+ /** Name of the SDK renderscript folder, i.e. "rs" */
+ public static final String FD_RENDERSCRIPT = "rs"; //$NON-NLS-1$
+ /** Name of the SDK resources folder, i.e. "res" */
+ public static final String FD_RES = "res"; //$NON-NLS-1$
+ /** Name of the SDK font folder, i.e. "fonts" */
+ public static final String FD_FONTS = "fonts"; //$NON-NLS-1$
+ /** Name of the android sources directory and the root of the SDK sources package folder. */
+ public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
+ /** Name of the addon libs folder. */
+ public static final String FD_ADDON_LIBS = "libs"; //$NON-NLS-1$
+
+ /** Name of the cache folder in the $HOME/.android. */
+ public static final String FD_CACHE = "cache"; //$NON-NLS-1$
+
+ /** API codename of a release (non preview) system image or platform. **/
+ public static final String CODENAME_RELEASE = "REL"; //$NON-NLS-1$
+
+ /** Namespace for the resource XML, i.e. "http://schemas.android.com/apk/res/android" */
+ public static final String NS_RESOURCES =
+ "http://schemas.android.com/apk/res/android"; //$NON-NLS-1$
+
+ /**
+ * Namespace pattern for the custom resource XML, i.e. "http://schemas.android.com/apk/res/%s"
+ * <p/>
+ * This string contains a %s. It must be combined with the desired Java package, e.g.:
+ * <pre>
+ * String.format(SdkConstants.NS_CUSTOM_RESOURCES_S, "android");
+ * String.format(SdkConstants.NS_CUSTOM_RESOURCES_S, "com.test.mycustomapp");
+ * </pre>
+ *
+ * Note: if you need an URI specifically for the "android" namespace, consider using
+ * {@link SdkConstants#NS_RESOURCES} instead.
+ */
+ public final static String NS_CUSTOM_RESOURCES_S = "http://schemas.android.com/apk/res/%1$s"; //$NON-NLS-1$
+
+
+ /** The name of the uses-library that provides "android.test.runner" */
+ public static final String ANDROID_TEST_RUNNER_LIB =
+ "android.test.runner"; //$NON-NLS-1$
+
+ /* Folder path relative to the SDK root */
+ /** Path of the documentation directory relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_DOCS_FOLDER = FD_DOCS + File.separator;
+
+ /** Path of the tools directory relative to the sdk folder, or to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_TOOLS_FOLDER = FD_TOOLS + File.separator;
+
+ /** Path of the lib directory relative to the sdk folder, or to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_TOOLS_LIB_FOLDER =
+ OS_SDK_TOOLS_FOLDER + FD_LIB + File.separator;
+
+ /**
+ * Path of the lib directory relative to the sdk folder, or to a platform
+ * folder. This is an OS path, ending with a separator.
+ */
+ public static final String OS_SDK_TOOLS_LIB_EMULATOR_FOLDER = OS_SDK_TOOLS_LIB_FOLDER
+ + "emulator" + File.separator; //$NON-NLS-1$
+
+ /** Path of the platform tools directory relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_PLATFORM_TOOLS_FOLDER = FD_PLATFORM_TOOLS + File.separator;
+
+ /** Path of the build tools directory relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_BUILD_TOOLS_FOLDER = FD_BUILD_TOOLS + File.separator;
+
+ /** Path of the Platform tools Lib directory relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_PLATFORM_TOOLS_LIB_FOLDER =
+ OS_SDK_PLATFORM_TOOLS_FOLDER + FD_LIB + File.separator;
+
+ /** Path of the bin folder of proguard folder relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_TOOLS_PROGUARD_BIN_FOLDER =
+ SdkConstants.OS_SDK_TOOLS_FOLDER +
+ "proguard" + File.separator + //$NON-NLS-1$
+ "bin" + File.separator; //$NON-NLS-1$
+
+ /** Path of the template gradle wrapper folder relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SDK_TOOLS_TEMPLATES_GRADLE_WRAPPER_FOLDER =
+ OS_SDK_TOOLS_FOLDER + FD_TEMPLATES + File.separator + FD_GRADLE_WRAPPER + File.separator;
+
+ /* Folder paths relative to a platform or add-on folder */
+
+ /** Path of the images directory relative to a platform or addon folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_IMAGES_FOLDER = FD_IMAGES + File.separator;
+
+ /** Path of the skin directory relative to a platform or addon folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_SKINS_FOLDER = FD_SKINS + File.separator;
+
+ /* Folder paths relative to a Platform folder */
+
+ /** Path of the data directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_DATA_FOLDER = FD_DATA + File.separator;
+
+ /** Path of the renderscript directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_RENDERSCRIPT_FOLDER = FD_RENDERSCRIPT + File.separator;
+
+
+ /** Path of the samples directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_SAMPLES_FOLDER = FD_SAMPLES + File.separator;
+
+ /** Path of the resources directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_RESOURCES_FOLDER =
+ OS_PLATFORM_DATA_FOLDER + FD_RES + File.separator;
+
+ /** Path of the fonts directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_FONTS_FOLDER =
+ OS_PLATFORM_DATA_FOLDER + FD_FONTS + File.separator;
+
+ /** Path of the android source directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_SOURCES_FOLDER = FD_ANDROID_SOURCES + File.separator;
+
+ /** Path of the android templates directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_TEMPLATES_FOLDER = FD_TEMPLATES + File.separator;
+
+ /** Path of the Ant build rules directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_PLATFORM_ANT_FOLDER = FD_ANT + File.separator;
+
+ /** Path of the attrs.xml file relative to a platform folder. */
+ public static final String OS_PLATFORM_ATTRS_XML =
+ OS_PLATFORM_RESOURCES_FOLDER + SdkConstants.FD_RES_VALUES + File.separator +
+ FN_ATTRS_XML;
+
+ /** Path of the attrs_manifest.xml file relative to a platform folder. */
+ public static final String OS_PLATFORM_ATTRS_MANIFEST_XML =
+ OS_PLATFORM_RESOURCES_FOLDER + SdkConstants.FD_RES_VALUES + File.separator +
+ FN_ATTRS_MANIFEST_XML;
+
+ /** Path of the layoutlib.jar file relative to a platform folder. */
+ public static final String OS_PLATFORM_LAYOUTLIB_JAR =
+ OS_PLATFORM_DATA_FOLDER + FN_LAYOUTLIB_JAR;
+
+ /** Path of the renderscript include folder relative to a platform folder. */
+ public static final String OS_FRAMEWORK_RS =
+ FN_FRAMEWORK_RENDERSCRIPT + File.separator + FN_FRAMEWORK_INCLUDE;
+ /** Path of the renderscript (clang) include folder relative to a platform folder. */
+ public static final String OS_FRAMEWORK_RS_CLANG =
+ FN_FRAMEWORK_RENDERSCRIPT + File.separator + FN_FRAMEWORK_INCLUDE_CLANG;
+
+ /* Folder paths relative to a addon folder */
+ /** Path of the images directory relative to a folder folder.
+ * This is an OS path, ending with a separator. */
+ public static final String OS_ADDON_LIBS_FOLDER = FD_ADDON_LIBS + File.separator;
+
+ /** Skin default **/
+ public static final String SKIN_DEFAULT = "default"; //$NON-NLS-1$
+
+ /** SDK property: ant templates revision */
+ public static final String PROP_SDK_ANT_TEMPLATES_REVISION =
+ "sdk.ant.templates.revision"; //$NON-NLS-1$
+
+ /** SDK property: default skin */
+ public static final String PROP_SDK_DEFAULT_SKIN = "sdk.skin.default"; //$NON-NLS-1$
+
+ /* Android Class Constants */
+ public static final String CLASS_ACTIVITY = "android.app.Activity"; //$NON-NLS-1$
+ public static final String CLASS_APPLICATION = "android.app.Application"; //$NON-NLS-1$
+ public static final String CLASS_SERVICE = "android.app.Service"; //$NON-NLS-1$
+ public static final String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$NON-NLS-1$
+ public static final String CLASS_CONTENTPROVIDER = "android.content.ContentProvider"; //$NON-NLS-1$
+ public static final String CLASS_INSTRUMENTATION = "android.app.Instrumentation"; //$NON-NLS-1$
+ public static final String CLASS_INSTRUMENTATION_RUNNER =
+ "android.test.InstrumentationTestRunner"; //$NON-NLS-1$
+ public static final String CLASS_BUNDLE = "android.os.Bundle"; //$NON-NLS-1$
+ public static final String CLASS_R = "android.R"; //$NON-NLS-1$
+ public static final String CLASS_R_PREFIX = CLASS_R + "."; //$NON-NLS-1$
+ public static final String CLASS_MANIFEST_PERMISSION = "android.Manifest$permission"; //$NON-NLS-1$
+ public static final String CLASS_INTENT = "android.content.Intent"; //$NON-NLS-1$
+ public static final String CLASS_CONTEXT = "android.content.Context"; //$NON-NLS-1$
+ public static final String CLASS_VIEW = "android.view.View"; //$NON-NLS-1$
+ public static final String CLASS_VIEWGROUP = "android.view.ViewGroup"; //$NON-NLS-1$
+ public static final String CLASS_NAME_LAYOUTPARAMS = "LayoutParams"; //$NON-NLS-1$
+ public static final String CLASS_VIEWGROUP_LAYOUTPARAMS =
+ CLASS_VIEWGROUP + "$" + CLASS_NAME_LAYOUTPARAMS; //$NON-NLS-1$
+ public static final String CLASS_NAME_FRAMELAYOUT = "FrameLayout"; //$NON-NLS-1$
+ public static final String CLASS_FRAMELAYOUT =
+ "android.widget." + CLASS_NAME_FRAMELAYOUT; //$NON-NLS-1$
+ public static final String CLASS_PREFERENCE = "android.preference.Preference"; //$NON-NLS-1$
+ public static final String CLASS_NAME_PREFERENCE_SCREEN = "PreferenceScreen"; //$NON-NLS-1$
+ public static final String CLASS_PREFERENCES =
+ "android.preference." + CLASS_NAME_PREFERENCE_SCREEN; //$NON-NLS-1$
+ public static final String CLASS_PREFERENCEGROUP = "android.preference.PreferenceGroup"; //$NON-NLS-1$
+ public static final String CLASS_PARCELABLE = "android.os.Parcelable"; //$NON-NLS-1$
+ public static final String CLASS_FRAGMENT = "android.app.Fragment"; //$NON-NLS-1$
+ public static final String CLASS_V4_FRAGMENT = "android.support.v4.app.Fragment"; //$NON-NLS-1$
+ /** MockView is part of the layoutlib bridge and used to display classes that have
+ * no rendering in the graphical layout editor. */
+ public static final String CLASS_MOCK_VIEW = "com.android.layoutlib.bridge.MockView"; //$NON-NLS-1$
+
+ /** Returns the appropriate name for the 'android' command, which is 'android.exe' for
+ * Windows and 'android' for all other platforms. */
+ public static String androidCmdName() {
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+ String cmd = "android"; //$NON-NLS-1$
+ if (os.startsWith("Windows")) { //$NON-NLS-1$
+ cmd += ".bat"; //$NON-NLS-1$
+ }
+ return cmd;
+ }
+
+ /** Returns the appropriate name for the 'mksdcard' command, which is 'mksdcard.exe' for
+ * Windows and 'mkdsdcard' for all other platforms. */
+ public static String mkSdCardCmdName() {
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+ String cmd = "mksdcard"; //$NON-NLS-1$
+ if (os.startsWith("Windows")) { //$NON-NLS-1$
+ cmd += ".exe"; //$NON-NLS-1$
+ }
+ return cmd;
+ }
+
+ /**
+ * Returns current platform
+ *
+ * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
+ * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
+ */
+ public static int currentPlatform() {
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+ if (os.startsWith("Mac OS")) { //$NON-NLS-1$
+ return PLATFORM_DARWIN;
+ } else if (os.startsWith("Windows")) { //$NON-NLS-1$
+ return PLATFORM_WINDOWS;
+ } else if (os.startsWith("Linux")) { //$NON-NLS-1$
+ return PLATFORM_LINUX;
+ }
+
+ return PLATFORM_UNKNOWN;
+ }
+
+ /**
+ * Returns current platform's UI name
+ *
+ * @return one of "Windows", "Mac OS X", "Linux" or "other".
+ */
+ public static String currentPlatformName() {
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+ if (os.startsWith("Mac OS")) { //$NON-NLS-1$
+ return "Mac OS X"; //$NON-NLS-1$
+ } else if (os.startsWith("Windows")) { //$NON-NLS-1$
+ return "Windows"; //$NON-NLS-1$
+ } else if (os.startsWith("Linux")) { //$NON-NLS-1$
+ return "Linux"; //$NON-NLS-1$
+ }
+
+ return "Other";
+ }
+
+ private static String ext(String windowsExtension, String nonWindowsExtension) {
+ if (CURRENT_PLATFORM == PLATFORM_WINDOWS) {
+ return windowsExtension;
+ } else {
+ return nonWindowsExtension;
+ }
+ }
+
+ /** Default anim resource folder name, i.e. "anim" */
+ public static final String FD_RES_ANIM = "anim"; //$NON-NLS-1$
+ /** Default animator resource folder name, i.e. "animator" */
+ public static final String FD_RES_ANIMATOR = "animator"; //$NON-NLS-1$
+ /** Default color resource folder name, i.e. "color" */
+ public static final String FD_RES_COLOR = "color"; //$NON-NLS-1$
+ /** Default drawable resource folder name, i.e. "drawable" */
+ public static final String FD_RES_DRAWABLE = "drawable"; //$NON-NLS-1$
+ /** Default interpolator resource folder name, i.e. "interpolator" */
+ public static final String FD_RES_INTERPOLATOR = "interpolator"; //$NON-NLS-1$
+ /** Default layout resource folder name, i.e. "layout" */
+ public static final String FD_RES_LAYOUT = "layout"; //$NON-NLS-1$
+ /** Default menu resource folder name, i.e. "menu" */
+ public static final String FD_RES_MENU = "menu"; //$NON-NLS-1$
+ /** Default menu resource folder name, i.e. "mipmap" */
+ public static final String FD_RES_MIPMAP = "mipmap"; //$NON-NLS-1$
+ /** Default values resource folder name, i.e. "values" */
+ public static final String FD_RES_VALUES = "values"; //$NON-NLS-1$
+ /** Default xml resource folder name, i.e. "xml" */
+ public static final String FD_RES_XML = "xml"; //$NON-NLS-1$
+ /** Default raw resource folder name, i.e. "raw" */
+ public static final String FD_RES_RAW = "raw"; //$NON-NLS-1$
+ /** Separator between the resource folder qualifier. */
+ public static final String RES_QUALIFIER_SEP = "-"; //$NON-NLS-1$
+ /** Namespace used in XML files for Android attributes */
+
+ // ---- XML ----
+
+ /** URI of the reserved "xmlns" prefix */
+ public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; //$NON-NLS-1$
+ /** The "xmlns" attribute name */
+ public static final String XMLNS = "xmlns"; //$NON-NLS-1$
+ /** The default prefix used for the {@link #XMLNS_URI} */
+ public static final String XMLNS_PREFIX = "xmlns:"; //$NON-NLS-1$
+ /** Qualified name of the xmlns android declaration element */
+ public static final String XMLNS_ANDROID = "xmlns:android"; //$NON-NLS-1$
+ /** The default prefix used for the {@link #ANDROID_URI} name space */
+ public static final String ANDROID_NS_NAME = "android"; //$NON-NLS-1$
+ /** The default prefix used for the {@link #ANDROID_URI} name space including the colon */
+ public static final String ANDROID_NS_NAME_PREFIX = "android:"; //$NON-NLS-1$
+ public static final int ANDROID_NS_NAME_PREFIX_LEN = ANDROID_NS_NAME_PREFIX.length();
+
+ /** The default prefix used for the app */
+ public static final String APP_PREFIX = "app"; //$NON-NLS-1$
+ /** The entity for the ampersand character */
+ public static final String AMP_ENTITY = "&amp;"; //$NON-NLS-1$
+ /** The entity for the quote character */
+ public static final String QUOT_ENTITY = "&quot;"; //$NON-NLS-1$
+ /** The entity for the apostrophe character */
+ public static final String APOS_ENTITY = "&apos;"; //$NON-NLS-1$
+ /** The entity for the less than character */
+ public static final String LT_ENTITY = "&lt;"; //$NON-NLS-1$
+ /** The entity for the greater than character */
+ public static final String GT_ENTITY = "&gt;"; //$NON-NLS-1$
+
+ // ---- Elements and Attributes ----
+
+ /** Namespace prefix used for all resources */
+ public static final String URI_PREFIX =
+ "http://schemas.android.com/apk/res/"; //$NON-NLS-1$
+ /** Namespace used in XML files for Android attributes */
+ public static final String ANDROID_URI =
+ "http://schemas.android.com/apk/res/android"; //$NON-NLS-1$
+ /** Namespace used in XML files for Android Tooling attributes */
+ public static final String TOOLS_URI =
+ "http://schemas.android.com/tools"; //$NON-NLS-1$
+ /** Namespace used for auto-adjusting namespaces */
+ public static final String AUTO_URI =
+ "http://schemas.android.com/apk/res-auto"; //$NON-NLS-1$
+ /** Default prefix used for tools attributes */
+ public static final String TOOLS_PREFIX = "tools"; //$NON-NLS-1$
+ public static final String R_CLASS = "R"; //$NON-NLS-1$
+ public static final String ANDROID_PKG = "android"; //$NON-NLS-1$
+
+ // Tags: Manifest
+ public static final String TAG_SERVICE = "service"; //$NON-NLS-1$
+ public static final String TAG_PERMISSION = "permission"; //$NON-NLS-1$
+ public static final String TAG_USES_FEATURE = "uses-feature"; //$NON-NLS-1$
+ public static final String TAG_USES_PERMISSION = "uses-permission";//$NON-NLS-1$
+ public static final String TAG_USES_LIBRARY = "uses-library"; //$NON-NLS-1$
+ public static final String TAG_APPLICATION = "application"; //$NON-NLS-1$
+ public static final String TAG_INTENT_FILTER = "intent-filter"; //$NON-NLS-1$
+ public static final String TAG_USES_SDK = "uses-sdk"; //$NON-NLS-1$
+ public static final String TAG_ACTIVITY = "activity"; //$NON-NLS-1$
+ public static final String TAG_RECEIVER = "receiver"; //$NON-NLS-1$
+ public static final String TAG_PROVIDER = "provider"; //$NON-NLS-1$
+ public static final String TAG_GRANT_PERMISSION = "grant-uri-permission"; //$NON-NLS-1$
+ public static final String TAG_PATH_PERMISSION = "path-permission"; //$NON-NLS-1$
+
+ // Tags: Resources
+ public static final String TAG_RESOURCES = "resources"; //$NON-NLS-1$
+ public static final String TAG_STRING = "string"; //$NON-NLS-1$
+ public static final String TAG_ARRAY = "array"; //$NON-NLS-1$
+ public static final String TAG_STYLE = "style"; //$NON-NLS-1$
+ public static final String TAG_ITEM = "item"; //$NON-NLS-1$
+ public static final String TAG_GROUP = "group"; //$NON-NLS-1$
+ public static final String TAG_STRING_ARRAY = "string-array"; //$NON-NLS-1$
+ public static final String TAG_PLURALS = "plurals"; //$NON-NLS-1$
+ public static final String TAG_INTEGER_ARRAY = "integer-array"; //$NON-NLS-1$
+ public static final String TAG_COLOR = "color"; //$NON-NLS-1$
+ public static final String TAG_DIMEN = "dimen"; //$NON-NLS-1$
+ public static final String TAG_DRAWABLE = "drawable"; //$NON-NLS-1$
+ public static final String TAG_MENU = "menu"; //$NON-NLS-1$
+ public static final String TAG_ENUM = "enum"; //$NON-NLS-1$
+ public static final String TAG_FLAG = "flag"; //$NON-NLS-1$
+ public static final String TAG_ATTR = "attr"; //$NON-NLS-1$
+ public static final String TAG_DECLARE_STYLEABLE = "declare-styleable"; //$NON-NLS-1$
+ public static final String TAG_EAT_COMMENT = "eat-comment"; //$NON-NLS-1$
+ public static final String TAG_SKIP = "skip"; //$NON-NLS-1$
+
+ // Tags: XML
+ public static final String TAG_HEADER = "header"; //$NON-NLS-1$
+
+ // Tags: Layouts
+ public static final String VIEW_TAG = "view"; //$NON-NLS-1$
+ public static final String VIEW_INCLUDE = "include"; //$NON-NLS-1$
+ public static final String VIEW_MERGE = "merge"; //$NON-NLS-1$
+ public static final String VIEW_FRAGMENT = "fragment"; //$NON-NLS-1$
+ public static final String REQUEST_FOCUS = "requestFocus"; //$NON-NLS-1$
+ public static final String TAG = "tag"; //$NON-NLS-1$
+
+ public static final String VIEW = "View"; //$NON-NLS-1$
+ public static final String VIEW_GROUP = "ViewGroup"; //$NON-NLS-1$
+ public static final String FRAME_LAYOUT = "FrameLayout"; //$NON-NLS-1$
+ public static final String LINEAR_LAYOUT = "LinearLayout"; //$NON-NLS-1$
+ public static final String RELATIVE_LAYOUT = "RelativeLayout"; //$NON-NLS-1$
+ public static final String GRID_LAYOUT = "GridLayout"; //$NON-NLS-1$
+ public static final String SCROLL_VIEW = "ScrollView"; //$NON-NLS-1$
+ public static final String BUTTON = "Button"; //$NON-NLS-1$
+ public static final String COMPOUND_BUTTON = "CompoundButton"; //$NON-NLS-1$
+ public static final String ADAPTER_VIEW = "AdapterView"; //$NON-NLS-1$
+ public static final String GALLERY = "Gallery"; //$NON-NLS-1$
+ public static final String GRID_VIEW = "GridView"; //$NON-NLS-1$
+ public static final String TAB_HOST = "TabHost"; //$NON-NLS-1$
+ public static final String RADIO_GROUP = "RadioGroup"; //$NON-NLS-1$
+ public static final String RADIO_BUTTON = "RadioButton"; //$NON-NLS-1$
+ public static final String SWITCH = "Switch"; //$NON-NLS-1$
+ public static final String EDIT_TEXT = "EditText"; //$NON-NLS-1$
+ public static final String LIST_VIEW = "ListView"; //$NON-NLS-1$
+ public static final String TEXT_VIEW = "TextView"; //$NON-NLS-1$
+ public static final String CHECKED_TEXT_VIEW = "CheckedTextView"; //$NON-NLS-1$
+ public static final String IMAGE_VIEW = "ImageView"; //$NON-NLS-1$
+ public static final String SURFACE_VIEW = "SurfaceView"; //$NON-NLS-1$
+ public static final String ABSOLUTE_LAYOUT = "AbsoluteLayout"; //$NON-NLS-1$
+ public static final String TABLE_LAYOUT = "TableLayout"; //$NON-NLS-1$
+ public static final String TABLE_ROW = "TableRow"; //$NON-NLS-1$
+ public static final String TAB_WIDGET = "TabWidget"; //$NON-NLS-1$
+ public static final String IMAGE_BUTTON = "ImageButton"; //$NON-NLS-1$
+ public static final String SEEK_BAR = "SeekBar"; //$NON-NLS-1$
+ public static final String VIEW_STUB = "ViewStub"; //$NON-NLS-1$
+ public static final String SPINNER = "Spinner"; //$NON-NLS-1$
+ public static final String WEB_VIEW = "WebView"; //$NON-NLS-1$
+ public static final String TOGGLE_BUTTON = "ToggleButton"; //$NON-NLS-1$
+ public static final String CHECK_BOX = "CheckBox"; //$NON-NLS-1$
+ public static final String ABS_LIST_VIEW = "AbsListView"; //$NON-NLS-1$
+ public static final String PROGRESS_BAR = "ProgressBar"; //$NON-NLS-1$
+ public static final String ABS_SPINNER = "AbsSpinner"; //$NON-NLS-1$
+ public static final String ABS_SEEK_BAR = "AbsSeekBar"; //$NON-NLS-1$
+ public static final String VIEW_ANIMATOR = "ViewAnimator"; //$NON-NLS-1$
+ public static final String VIEW_SWITCHER = "ViewSwitcher"; //$NON-NLS-1$
+ public static final String EXPANDABLE_LIST_VIEW = "ExpandableListView"; //$NON-NLS-1$
+ public static final String HORIZONTAL_SCROLL_VIEW = "HorizontalScrollView"; //$NON-NLS-1$
+ public static final String MULTI_AUTO_COMPLETE_TEXT_VIEW = "MultiAutoCompleteTextView"; //$NON-NLS-1$
+ public static final String AUTO_COMPLETE_TEXT_VIEW = "AutoCompleteTextView"; //$NON-NLS-1$
+ public static final String CHECKABLE = "Checkable"; //$NON-NLS-1$
+
+ // Tags: Drawables
+ public static final String TAG_BITMAP = "bitmap"; //$NON-NLS-1$
+
+ // Attributes: Manifest
+ public static final String ATTR_EXPORTED = "exported"; //$NON-NLS-1$
+ public static final String ATTR_PERMISSION = "permission"; //$NON-NLS-1$
+ public static final String ATTR_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-1$
+ public static final String ATTR_TARGET_SDK_VERSION = "targetSdkVersion"; //$NON-NLS-1$
+ public static final String ATTR_ICON = "icon"; //$NON-NLS-1$
+ public static final String ATTR_PACKAGE = "package"; //$NON-NLS-1$
+ public static final String ATTR_CORE_APP = "coreApp"; //$NON-NLS-1$
+ public static final String ATTR_THEME = "theme"; //$NON-NLS-1$
+ public static final String ATTR_PATH = "path"; //$NON-NLS-1$
+ public static final String ATTR_PATH_PREFIX = "pathPrefix"; //$NON-NLS-1$
+ public static final String ATTR_PATH_PATTERN = "pathPattern"; //$NON-NLS-1$
+ public static final String ATTR_ALLOW_BACKUP = "allowBackup"; //$NON_NLS-1$
+ public static final String ATTR_DEBUGGABLE = "debuggable"; //$NON-NLS-1$
+ public static final String ATTR_READ_PERMISSION = "readPermission"; //$NON_NLS-1$
+ public static final String ATTR_WRITE_PERMISSION = "writePermission"; //$NON_NLS-1$
+ public static final String ATTR_VERSION_CODE = "versionCode"; //$NON_NLS-1$
+ public static final String ATTR_VERSION_NAME = "versionName"; //$NON_NLS-1$
+
+ // Attributes: Resources
+ public static final String ATTR_NAME = "name"; //$NON-NLS-1$
+ public static final String ATTR_FRAGMENT = "fragment"; //$NON-NLS-1$
+ public static final String ATTR_TYPE = "type"; //$NON-NLS-1$
+ public static final String ATTR_PARENT = "parent"; //$NON-NLS-1$
+ public static final String ATTR_TRANSLATABLE = "translatable"; //$NON-NLS-1$
+ public static final String ATTR_COLOR = "color"; //$NON-NLS-1$
+ public static final String ATTR_DRAWABLE = "drawable"; //$NON-NLS-1$
+ public static final String ATTR_VALUE = "value"; //$NON-NLS-1$
+ public static final String ATTR_QUANTITY = "quantity"; //$NON-NLS-1$
+ public static final String ATTR_FORMAT = "format"; //$NON-NLS-1$
+
+ // Attributes: Layout
+ public static final String ATTR_LAYOUT_RESOURCE_PREFIX = "layout_";//$NON-NLS-1$
+ public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+ public static final String ATTR_STYLE = "style"; //$NON-NLS-1$
+ public static final String ATTR_CONTEXT = "context"; //$NON-NLS-1$
+ public static final String ATTR_ID = "id"; //$NON-NLS-1$
+ public static final String ATTR_TEXT = "text"; //$NON-NLS-1$
+ public static final String ATTR_TEXT_SIZE = "textSize"; //$NON-NLS-1$
+ public static final String ATTR_LABEL = "label"; //$NON-NLS-1$
+ public static final String ATTR_HINT = "hint"; //$NON-NLS-1$
+ public static final String ATTR_PROMPT = "prompt"; //$NON-NLS-1$
+ public static final String ATTR_ON_CLICK = "onClick"; //$NON-NLS-1$
+ public static final String ATTR_INPUT_TYPE = "inputType"; //$NON-NLS-1$
+ public static final String ATTR_INPUT_METHOD = "inputMethod"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_GRAVITY = "layout_gravity"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_WIDTH = "layout_width"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_HEIGHT = "layout_height"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_WEIGHT = "layout_weight"; //$NON-NLS-1$
+ public static final String ATTR_PADDING = "padding"; //$NON-NLS-1$
+ public static final String ATTR_PADDING_BOTTOM = "paddingBottom"; //$NON-NLS-1$
+ public static final String ATTR_PADDING_TOP = "paddingTop"; //$NON-NLS-1$
+ public static final String ATTR_PADDING_RIGHT = "paddingRight"; //$NON-NLS-1$
+ public static final String ATTR_PADDING_LEFT = "paddingLeft"; //$NON-NLS-1$
+ public static final String ATTR_PADDING_START = "paddingStart"; //$NON-NLS-1$
+ public static final String ATTR_PADDING_END = "paddingEnd"; //$NON-NLS-1$
+ public static final String ATTR_FOREGROUND = "foreground"; //$NON-NLS-1$
+ public static final String ATTR_BACKGROUND = "background"; //$NON-NLS-1$
+ public static final String ATTR_ORIENTATION = "orientation"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT = "layout"; //$NON-NLS-1$
+ public static final String ATTR_ROW_COUNT = "rowCount"; //$NON-NLS-1$
+ public static final String ATTR_COLUMN_COUNT = "columnCount"; //$NON-NLS-1$
+ public static final String ATTR_LABEL_FOR = "labelFor"; //$NON-NLS-1$
+ public static final String ATTR_BASELINE_ALIGNED = "baselineAligned"; //$NON-NLS-1$
+ public static final String ATTR_CONTENT_DESCRIPTION = "contentDescription"; //$NON-NLS-1$
+ public static final String ATTR_IME_ACTION_LABEL = "imeActionLabel"; //$NON-NLS-1$
+ public static final String ATTR_PRIVATE_IME_OPTIONS = "privateImeOptions"; //$NON-NLS-1$
+ public static final String VALUE_NONE = "none"; //$NON-NLS-1$
+ public static final String VALUE_NO = "no"; //$NON-NLS-1$
+ public static final String ATTR_NUMERIC = "numeric"; //$NON-NLS-1$
+ public static final String ATTR_IME_ACTION_ID = "imeActionId"; //$NON-NLS-1$
+ public static final String ATTR_IME_OPTIONS = "imeOptions"; //$NON-NLS-1$
+ public static final String ATTR_FREEZES_TEXT = "freezesText"; //$NON-NLS-1$
+ public static final String ATTR_EDITOR_EXTRAS = "editorExtras"; //$NON-NLS-1$
+ public static final String ATTR_EDITABLE = "editable"; //$NON-NLS-1$
+ public static final String ATTR_DIGITS = "digits"; //$NON-NLS-1$
+ public static final String ATTR_CURSOR_VISIBLE = "cursorVisible"; //$NON-NLS-1$
+ public static final String ATTR_CAPITALIZE = "capitalize"; //$NON-NLS-1$
+ public static final String ATTR_PHONE_NUMBER = "phoneNumber"; //$NON-NLS-1$
+ public static final String ATTR_PASSWORD = "password"; //$NON-NLS-1$
+ public static final String ATTR_BUFFER_TYPE = "bufferType"; //$NON-NLS-1$
+ public static final String ATTR_AUTO_TEXT = "autoText"; //$NON-NLS-1$
+ public static final String ATTR_ENABLED = "enabled"; //$NON-NLS-1$
+ public static final String ATTR_SINGLE_LINE = "singleLine"; //$NON-NLS-1$
+ public static final String ATTR_SCALE_TYPE = "scaleType"; //$NON-NLS-1$
+ public static final String ATTR_VISIBILITY = "visibility"; //$NON-NLS-1$
+ public static final String ATTR_TEXT_IS_SELECTABLE =
+ "textIsSelectable"; //$NON-NLS-1$
+ public static final String ATTR_IMPORTANT_FOR_ACCESSIBILITY =
+ "importantForAccessibility"; //$NON-NLS-1$
+ public static final String ATTR_LIST_PREFERRED_ITEM_PADDING_LEFT =
+ "listPreferredItemPaddingLeft"; //$NON-NLS-1$
+ public static final String ATTR_LIST_PREFERRED_ITEM_PADDING_RIGHT =
+ "listPreferredItemPaddingRight"; //$NON-NLS-1$
+ public static final String ATTR_LIST_PREFERRED_ITEM_PADDING_START =
+ "listPreferredItemPaddingStart"; //$NON-NLS-1$
+ public static final String ATTR_LIST_PREFERRED_ITEM_PADDING_END =
+ "listPreferredItemPaddingEnd"; //$NON-NLS-1$
+ public static final String ATTR_INDEX = "index"; //$NON-NLS-1$
+
+ // AbsoluteLayout layout params
+ public static final String ATTR_LAYOUT_Y = "layout_y"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_X = "layout_x"; //$NON-NLS-1$
+
+ // GridLayout layout params
+ public static final String ATTR_LAYOUT_ROW = "layout_row"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ROW_SPAN = "layout_rowSpan";//$NON-NLS-1$
+ public static final String ATTR_LAYOUT_COLUMN = "layout_column"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_COLUMN_SPAN = "layout_columnSpan"; //$NON-NLS-1$
+
+ // TableRow
+ public static final String ATTR_LAYOUT_SPAN = "layout_span"; //$NON-NLS-1$
+
+ // RelativeLayout layout params:
+ public static final String ATTR_LAYOUT_ALIGN_LEFT = "layout_alignLeft"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_RIGHT = "layout_alignRight"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_START = "layout_alignStart"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_END = "layout_alignEnd"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_TOP = "layout_alignTop"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_BOTTOM = "layout_alignBottom"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_PARENT_LEFT = "layout_alignParentLeft"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_PARENT_RIGHT = "layout_alignParentRight"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_PARENT_START = "layout_alignParentStart"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_PARENT_END = "layout_alignParentEnd"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_PARENT_TOP = "layout_alignParentTop"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_PARENT_BOTTOM = "layout_alignParentBottom"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_WITH_PARENT_MISSING = "layout_alignWithParentIfMissing"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ALIGN_BASELINE = "layout_alignBaseline"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_CENTER_IN_PARENT = "layout_centerInParent"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_CENTER_VERTICAL = "layout_centerVertical"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_CENTER_HORIZONTAL = "layout_centerHorizontal"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_TO_RIGHT_OF = "layout_toRightOf"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_TO_LEFT_OF = "layout_toLeftOf"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_TO_START_OF = "layout_toStartOf"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_TO_END_OF = "layout_toEndOf"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_BELOW = "layout_below"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_ABOVE = "layout_above"; //$NON-NLS-1$
+
+ // Margins
+ public static final String ATTR_LAYOUT_MARGIN = "layout_margin"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_LEFT = "layout_marginLeft"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_RIGHT = "layout_marginRight"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_START = "layout_marginStart"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_END = "layout_marginEnd"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_TOP = "layout_marginTop"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_BOTTOM = "layout_marginBottom"; //$NON-NLS-1$
+
+ // Attributes: Drawables
+ public static final String ATTR_TILE_MODE = "tileMode"; //$NON-NLS-1$
+
+ // Values: Manifest
+ public static final String VALUE_SPLIT_ACTION_BAR_WHEN_NARROW = "splitActionBarWhenNarrow"; // NON-NLS-$1
+
+ // Values: Layouts
+ public static final String VALUE_FILL_PARENT = "fill_parent"; //$NON-NLS-1$
+ public static final String VALUE_MATCH_PARENT = "match_parent"; //$NON-NLS-1$
+ public static final String VALUE_VERTICAL = "vertical"; //$NON-NLS-1$
+ public static final String VALUE_TRUE = "true"; //$NON-NLS-1$
+ public static final String VALUE_EDITABLE = "editable"; //$NON-NLS-1$
+ public static final String VALUE_AUTO_FIT = "auto_fit"; //$NON-NLS-1$
+ public static final String VALUE_SELECTABLE_ITEM_BACKGROUND =
+ "?android:attr/selectableItemBackground"; //$NON-NLS-1$
+
+
+ // Values: Resources
+ public static final String VALUE_ID = "id"; //$NON-NLS-1$
+
+ // Values: Drawables
+ public static final String VALUE_DISABLED = "disabled"; //$NON-NLS-1$
+ public static final String VALUE_CLAMP = "clamp"; //$NON-NLS-1$
+
+ // Menus
+ public static final String ATTR_SHOW_AS_ACTION = "showAsAction"; //$NON-NLS-1$
+ public static final String ATTR_TITLE = "title"; //$NON-NLS-1$
+ public static final String ATTR_VISIBLE = "visible"; //$NON-NLS-1$
+ public static final String VALUE_IF_ROOM = "ifRoom"; //$NON-NLS-1$
+ public static final String VALUE_ALWAYS = "always"; //$NON-NLS-1$
+
+ // Units
+ public static final String UNIT_DP = "dp"; //$NON-NLS-1$
+ public static final String UNIT_DIP = "dip"; //$NON-NLS-1$
+ public static final String UNIT_SP = "sp"; //$NON-NLS-1$
+ public static final String UNIT_PX = "px"; //$NON-NLS-1$
+ public static final String UNIT_IN = "in"; //$NON-NLS-1$
+ public static final String UNIT_MM = "mm"; //$NON-NLS-1$
+ public static final String UNIT_PT = "pt"; //$NON-NLS-1$
+
+ // Filenames and folder names
+ public static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml"; //$NON-NLS-1$
+ public static final String OLD_PROGUARD_FILE = "proguard.cfg"; //$NON-NLS-1$
+ public static final String CLASS_FOLDER =
+ "bin" + File.separator + "classes"; //$NON-NLS-1$ //$NON-NLS-2$
+ public static final String GEN_FOLDER = "gen"; //$NON-NLS-1$
+ public static final String SRC_FOLDER = "src"; //$NON-NLS-1$
+ public static final String LIBS_FOLDER = "libs"; //$NON-NLS-1$
+ public static final String BIN_FOLDER = "bin"; //$NON-NLS-1$
+
+ public static final String RES_FOLDER = "res"; //$NON-NLS-1$
+ public static final String DOT_XML = ".xml"; //$NON-NLS-1$
+ public static final String DOT_GIF = ".gif"; //$NON-NLS-1$
+ public static final String DOT_JPG = ".jpg"; //$NON-NLS-1$
+ public static final String DOT_JPEG = ".jpeg"; //$NON-NLS-1$
+ public static final String DOT_PNG = ".png"; //$NON-NLS-1$
+ public static final String DOT_9PNG = ".9.png"; //$NON-NLS-1$
+ public static final String DOT_JAVA = ".java"; //$NON-NLS-1$
+ public static final String DOT_CLASS = ".class"; //$NON-NLS-1$
+ public static final String DOT_JAR = ".jar"; //$NON-NLS-1$
+ public static final String DOT_GRADLE = ".gradle"; //$NON-NLS-1$
+ public static final String DOT_PROPERTIES = ".properties"; //$NON-NLS-1$
+
+ /** Extension of the Application package Files, i.e. "apk". */
+ public static final String EXT_ANDROID_PACKAGE = "apk"; //$NON-NLS-1$
+ /** Extension of java files, i.e. "java" */
+ public static final String EXT_JAVA = "java"; //$NON-NLS-1$
+ /** Extension of compiled java files, i.e. "class" */
+ public static final String EXT_CLASS = "class"; //$NON-NLS-1$
+ /** Extension of xml files, i.e. "xml" */
+ public static final String EXT_XML = "xml"; //$NON-NLS-1$
+ /** Extension of gradle files, i.e. "gradle" */
+ public static final String EXT_GRADLE = "gradle"; //$NON-NLS-1$
+ /** Extension of jar files, i.e. "jar" */
+ public static final String EXT_JAR = "jar"; //$NON-NLS-1$
+ /** Extension of ZIP files, i.e. "zip" */
+ public static final String EXT_ZIP = "zip"; //$NON-NLS-1$
+ /** Extension of aidl files, i.e. "aidl" */
+ public static final String EXT_AIDL = "aidl"; //$NON-NLS-1$
+ /** Extension of Renderscript files, i.e. "rs" */
+ public static final String EXT_RS = "rs"; //$NON-NLS-1$
+ /** Extension of Renderscript files, i.e. "rsh" */
+ public static final String EXT_RSH = "rsh"; //$NON-NLS-1$
+ /** Extension of FilterScript files, i.e. "fs" */
+ public static final String EXT_FS = "fs"; //$NON-NLS-1$
+ /** Extension of Renderscript bitcode files, i.e. "bc" */
+ public static final String EXT_BC = "bc"; //$NON-NLS-1$
+ /** Extension of dependency files, i.e. "d" */
+ public static final String EXT_DEP = "d"; //$NON-NLS-1$
+ /** Extension of native libraries, i.e. "so" */
+ public static final String EXT_NATIVE_LIB = "so"; //$NON-NLS-1$
+ /** Extension of dex files, i.e. "dex" */
+ public static final String EXT_DEX = "dex"; //$NON-NLS-1$
+ /** Extension for temporary resource files, ie "ap_ */
+ public static final String EXT_RES = "ap_"; //$NON-NLS-1$
+ /** Extension for pre-processable images. Right now pngs */
+ public static final String EXT_PNG = "png"; //$NON-NLS-1$
+ /** Extension for Android archive files */
+ public static final String EXT_AAR = "aar"; //$NON-NLS-1$
+ /** Extension for Java heap dumps. */
+ public static final String EXT_HPROF = "hprof"; //$NON-NLS-1$
+
+ private static final String DOT = "."; //$NON-NLS-1$
+
+ /** Dot-Extension of the Application package Files, i.e. ".apk". */
+ public static final String DOT_ANDROID_PACKAGE = DOT + EXT_ANDROID_PACKAGE;
+ /** Dot-Extension of aidl files, i.e. ".aidl" */
+ public static final String DOT_AIDL = DOT + EXT_AIDL;
+ /** Dot-Extension of renderscript files, i.e. ".rs" */
+ public static final String DOT_RS = DOT + EXT_RS;
+ /** Dot-Extension of renderscript header files, i.e. ".rsh" */
+ public static final String DOT_RSH = DOT + EXT_RSH;
+ /** Dot-Extension of FilterScript files, i.e. ".fs" */
+ public static final String DOT_FS = DOT + EXT_FS;
+ /** Dot-Extension of renderscript bitcode files, i.e. ".bc" */
+ public static final String DOT_BC = DOT + EXT_BC;
+ /** Dot-Extension of dependency files, i.e. ".d" */
+ public static final String DOT_DEP = DOT + EXT_DEP;
+ /** Dot-Extension of dex files, i.e. ".dex" */
+ public static final String DOT_DEX = DOT + EXT_DEX;
+ /** Dot-Extension for temporary resource files, ie "ap_ */
+ public static final String DOT_RES = DOT + EXT_RES;
+ /** Dot-Extension for BMP files, i.e. ".bmp" */
+ public static final String DOT_BMP = ".bmp"; //$NON-NLS-1$
+ /** Dot-Extension for SVG files, i.e. ".svg" */
+ public static final String DOT_SVG = ".svg"; //$NON-NLS-1$
+ /** Dot-Extension for template files */
+ public static final String DOT_FTL = ".ftl"; //$NON-NLS-1$
+ /** Dot-Extension of text files, i.e. ".txt" */
+ public static final String DOT_TXT = ".txt"; //$NON-NLS-1$
+ /** Dot-Extension for Android archive files */
+ public static final String DOT_AAR = DOT + EXT_AAR; //$NON-NLS-1$
+
+ /** Resource base name for java files and classes */
+ public static final String FN_RESOURCE_BASE = "R"; //$NON-NLS-1$
+ /** Resource java class filename, i.e. "R.java" */
+ public static final String FN_RESOURCE_CLASS = FN_RESOURCE_BASE + DOT_JAVA;
+ /** Resource class file filename, i.e. "R.class" */
+ public static final String FN_COMPILED_RESOURCE_CLASS = FN_RESOURCE_BASE + DOT_CLASS;
+ /** Resource text filename, i.e. "R.txt" */
+ public static final String FN_RESOURCE_TEXT = FN_RESOURCE_BASE + DOT_TXT;
+ /** Generated manifest class name */
+ public static final String FN_MANIFEST_BASE = "Manifest"; //$NON-NLS-1$
+ /** Generated BuildConfig class name */
+ public static final String FN_BUILD_CONFIG_BASE = "BuildConfig"; //$NON-NLS-1$
+ /** Manifest java class filename, i.e. "Manifest.java" */
+ public static final String FN_MANIFEST_CLASS = FN_MANIFEST_BASE + DOT_JAVA;
+ /** BuildConfig java class filename, i.e. "BuildConfig.java" */
+ public static final String FN_BUILD_CONFIG = FN_BUILD_CONFIG_BASE + DOT_JAVA;
+
+ public static final String DRAWABLE_FOLDER = "drawable"; //$NON-NLS-1$
+ public static final String DRAWABLE_XHDPI = "drawable-xhdpi"; //$NON-NLS-1$
+ public static final String DRAWABLE_XXHDPI = "drawable-xxhdpi"; //$NON-NLS-1$
+ public static final String DRAWABLE_HDPI = "drawable-hdpi"; //$NON-NLS-1$
+ public static final String DRAWABLE_MDPI = "drawable-mdpi"; //$NON-NLS-1$
+ public static final String DRAWABLE_LDPI = "drawable-ldpi"; //$NON-NLS-1$
+
+ // Resources
+ public static final String PREFIX_RESOURCE_REF = "@"; //$NON-NLS-1$
+ public static final String PREFIX_THEME_REF = "?"; //$NON-NLS-1$
+ public static final String ANDROID_PREFIX = "@android:"; //$NON-NLS-1$
+ public static final String ANDROID_THEME_PREFIX = "?android:"; //$NON-NLS-1$
+ public static final String LAYOUT_RESOURCE_PREFIX = "@layout/"; //$NON-NLS-1$
+ public static final String STYLE_RESOURCE_PREFIX = "@style/"; //$NON-NLS-1$
+ public static final String COLOR_RESOURCE_PREFIX = "@color/"; //$NON-NLS-1$
+ public static final String NEW_ID_PREFIX = "@+id/"; //$NON-NLS-1$
+ public static final String ID_PREFIX = "@id/"; //$NON-NLS-1$
+ public static final String DRAWABLE_PREFIX = "@drawable/"; //$NON-NLS-1$
+ public static final String STRING_PREFIX = "@string/"; //$NON-NLS-1$
+ public static final String DIMEN_PREFIX = "@dimen/"; //$NON-NLS-1$
+
+ public static final String ANDROID_LAYOUT_RESOURCE_PREFIX = "@android:layout/"; //$NON-NLS-1$
+ public static final String ANDROID_STYLE_RESOURCE_PREFIX = "@android:style/"; //$NON-NLS-1$
+ public static final String ANDROID_NEW_ID_PREFIX = "@android:+id/"; //$NON-NLS-1$
+ public static final String ANDROID_ID_PREFIX = "@android:id/"; //$NON-NLS-1$
+ public static final String ANDROID_DRAWABLE_PREFIX = "@android:drawable/"; //$NON-NLS-1$
+ public static final String ANDROID_STRING_PREFIX = "@android:string/"; //$NON-NLS-1$
+
+ public static final String RESOURCE_CLZ_ID = "id"; //$NON-NLS-1$
+ public static final String RESOURCE_CLZ_COLOR = "color"; //$NON-NLS-1$
+ public static final String RESOURCE_CLZ_ARRAY = "array"; //$NON-NLS-1$
+ public static final String RESOURCE_CLZ_ATTR = "attr"; //$NON-NLS-1$
+ public static final String RESOURCE_CLR_STYLEABLE = "styleable"; //$NON-NLS-1$
+ public static final String NULL_RESOURCE = "@null"; //$NON-NLS-1$
+ public static final String TRANSPARENT_COLOR = "@android:color/transparent"; //$NON-NLS-1$
+ public static final String REFERENCE_STYLE = "style/"; //$NON-NLS-1$
+ public static final String PREFIX_ANDROID = "android:"; //$NON-NLS-1$
+
+ // Resource Types
+ public static final String DRAWABLE_TYPE = "drawable"; //$NON-NLS-1$
+ public static final String MENU_TYPE = "menu"; //$NON-NLS-1$
+
+ // Packages
+ public static final String ANDROID_PKG_PREFIX = "android."; //$NON-NLS-1$
+ public static final String WIDGET_PKG_PREFIX = "android.widget."; //$NON-NLS-1$
+ public static final String VIEW_PKG_PREFIX = "android.view."; //$NON-NLS-1$
+
+ // Project properties
+ public static final String ANDROID_LIBRARY = "android.library"; //$NON-NLS-1$
+ public static final String PROGUARD_CONFIG = "proguard.config"; //$NON-NLS-1$
+ public static final String ANDROID_LIBRARY_REFERENCE_FORMAT = "android.library.reference.%1$d";//$NON-NLS-1$
+ public static final String PROJECT_PROPERTIES = "project.properties";//$NON-NLS-1$
+
+ // Java References
+ public static final String ATTR_REF_PREFIX = "?attr/"; //$NON-NLS-1$
+ public static final String R_PREFIX = "R."; //$NON-NLS-1$
+ public static final String R_ID_PREFIX = "R.id."; //$NON-NLS-1$
+ public static final String R_LAYOUT_RESOURCE_PREFIX = "R.layout."; //$NON-NLS-1$
+ public static final String R_DRAWABLE_PREFIX = "R.drawable."; //$NON-NLS-1$
+ public static final String R_STYLEABLE_PREFIX = "R.styleable."; //$NON-NLS-1$
+ public static final String R_ATTR_PREFIX = "R.attr."; //$NON-NLS-1$
+
+ // Attributes related to tools
+ public static final String ATTR_IGNORE = "ignore"; //$NON-NLS-1$
+ public static final String ATTR_LOCALE = "locale"; //$NON-NLS-1$
+
+ // SuppressLint
+ public static final String SUPPRESS_ALL = "all"; //$NON-NLS-1$
+ public static final String SUPPRESS_LINT = "SuppressLint"; //$NON-NLS-1$
+ public static final String TARGET_API = "TargetApi"; //$NON-NLS-1$
+ public static final String ATTR_TARGET_API = "targetApi"; //$NON-NLS-1$
+ public static final String FQCN_SUPPRESS_LINT = "android.annotation." + SUPPRESS_LINT; //$NON-NLS-1$
+ public static final String FQCN_TARGET_API = "android.annotation." + TARGET_API; //$NON-NLS-1$
+
+ // Class Names
+ public static final String CONSTRUCTOR_NAME = "<init>"; //$NON-NLS-1$
+ public static final String CLASS_CONSTRUCTOR = "<clinit>"; //$NON-NLS-1$
+ public static final String FRAGMENT = "android/app/Fragment"; //$NON-NLS-1$
+ public static final String FRAGMENT_V4 = "android/support/v4/app/Fragment"; //$NON-NLS-1$
+ public static final String ANDROID_APP_ACTIVITY = "android/app/Activity"; //$NON-NLS-1$
+ public static final String ANDROID_APP_SERVICE = "android/app/Service"; //$NON-NLS-1$
+ public static final String ANDROID_CONTENT_CONTENT_PROVIDER =
+ "android/content/ContentProvider"; //$NON-NLS-1$
+ public static final String ANDROID_CONTENT_BROADCAST_RECEIVER =
+ "android/content/BroadcastReceiver"; //$NON-NLS-1$
+ public static final String ANDROID_VIEW_VIEW = "android/view/View"; //$NON-NLS-1$
+
+ // Method Names
+ public static final String FORMAT_METHOD = "format"; //$NON-NLS-1$
+ public static final String GET_STRING_METHOD = "getString"; //$NON-NLS-1$
+
+
+
+
+ public static final String ATTR_TAG = "tag"; //$NON-NLS-1$
+ public static final String ATTR_NUM_COLUMNS = "numColumns"; //$NON-NLS-1$
+
+ // Some common layout element names
+ public static final String CALENDAR_VIEW = "CalendarView"; //$NON-NLS-1$
+ public static final String SPACE = "Space"; //$NON-NLS-1$
+ public static final String GESTURE_OVERLAY_VIEW = "GestureOverlayView";//$NON-NLS-1$
+
+ public static final String ATTR_HANDLE = "handle"; //$NON-NLS-1$
+ public static final String ATTR_CONTENT = "content"; //$NON-NLS-1$
+ public static final String ATTR_CHECKED = "checked"; //$NON-NLS-1$
+
+ // TextView
+ public static final String ATTR_DRAWABLE_RIGHT = "drawableRight"; //$NON-NLS-1$
+ public static final String ATTR_DRAWABLE_LEFT = "drawableLeft"; //$NON-NLS-1$
+ public static final String ATTR_DRAWABLE_START = "drawableStart"; //$NON-NLS-1$
+ public static final String ATTR_DRAWABLE_END = "drawableEnd"; //$NON-NLS-1$
+ public static final String ATTR_DRAWABLE_BOTTOM = "drawableBottom"; //$NON-NLS-1$
+ public static final String ATTR_DRAWABLE_TOP = "drawableTop"; //$NON-NLS-1$
+ public static final String ATTR_DRAWABLE_PADDING = "drawablePadding"; //$NON-NLS-1$
+
+ public static final String ATTR_USE_DEFAULT_MARGINS = "useDefaultMargins"; //$NON-NLS-1$
+ public static final String ATTR_MARGINS_INCLUDED_IN_ALIGNMENT = "marginsIncludedInAlignment"; //$NON-NLS-1$
+
+ public static final String VALUE_WRAP_CONTENT = "wrap_content"; //$NON-NLS-1$
+ public static final String VALUE_FALSE= "false"; //$NON-NLS-1$
+ public static final String VALUE_N_DP = "%ddp"; //$NON-NLS-1$
+ public static final String VALUE_ZERO_DP = "0dp"; //$NON-NLS-1$
+ public static final String VALUE_ONE_DP = "1dp"; //$NON-NLS-1$
+ public static final String VALUE_TOP = "top"; //$NON-NLS-1$
+ public static final String VALUE_BOTTOM = "bottom"; //$NON-NLS-1$
+ public static final String VALUE_CENTER_VERTICAL = "center_vertical"; //$NON-NLS-1$
+ public static final String VALUE_CENTER_HORIZONTAL = "center_horizontal"; //$NON-NLS-1$
+ public static final String VALUE_FILL_HORIZONTAL = "fill_horizontal"; //$NON-NLS-1$
+ public static final String VALUE_FILL_VERTICAL = "fill_vertical"; //$NON-NLS-1$
+ public static final String VALUE_0 = "0"; //$NON-NLS-1$
+ public static final String VALUE_1 = "1"; //$NON-NLS-1$
+
+ // Gravity values. These have the GRAVITY_ prefix in front of value because we already
+ // have VALUE_CENTER_HORIZONTAL defined for layouts, and its definition conflicts
+ // (centerHorizontal versus center_horizontal)
+ public static final String GRAVITY_VALUE_ = "center"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_CENTER = "center"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_LEFT = "left"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_RIGHT = "right"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_START = "start"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_END = "end"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_BOTTOM = "bottom"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_TOP = "top"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_FILL_HORIZONTAL = "fill_horizontal"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_FILL_VERTICAL = "fill_vertical"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_CENTER_HORIZONTAL = "center_horizontal"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_CENTER_VERTICAL = "center_vertical"; //$NON-NLS-1$
+ public static final String GRAVITY_VALUE_FILL = "fill"; //$NON-NLS-1$
+
+ /**
+ * The top level android package as a prefix, "android.".
+ */
+ public static final String ANDROID_SUPPORT_PKG_PREFIX = ANDROID_PKG_PREFIX + "support."; //$NON-NLS-1$
+
+ /** The android.view. package prefix */
+ public static final String ANDROID_VIEW_PKG = ANDROID_PKG_PREFIX + "view."; //$NON-NLS-1$
+
+ /** The android.widget. package prefix */
+ public static final String ANDROID_WIDGET_PREFIX = ANDROID_PKG_PREFIX + "widget."; //$NON-NLS-1$
+
+ /** The android.webkit. package prefix */
+ public static final String ANDROID_WEBKIT_PKG = ANDROID_PKG_PREFIX + "webkit."; //$NON-NLS-1$
+
+ /** The LayoutParams inner-class name suffix, .LayoutParams */
+ public static final String DOT_LAYOUT_PARAMS = ".LayoutParams"; //$NON-NLS-1$
+
+ /** The fully qualified class name of an EditText view */
+ public static final String FQCN_EDIT_TEXT = "android.widget.EditText"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a LinearLayout view */
+ public static final String FQCN_LINEAR_LAYOUT = "android.widget.LinearLayout"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a RelativeLayout view */
+ public static final String FQCN_RELATIVE_LAYOUT = "android.widget.RelativeLayout"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a RelativeLayout view */
+ public static final String FQCN_GRID_LAYOUT = "android.widget.GridLayout"; //$NON-NLS-1$
+ public static final String FQCN_GRID_LAYOUT_V7 = "android.support.v7.widget.GridLayout"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a FrameLayout view */
+ public static final String FQCN_FRAME_LAYOUT = "android.widget.FrameLayout"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a TableRow view */
+ public static final String FQCN_TABLE_ROW = "android.widget.TableRow"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a TableLayout view */
+ public static final String FQCN_TABLE_LAYOUT = "android.widget.TableLayout"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a GridView view */
+ public static final String FQCN_GRID_VIEW = "android.widget.GridView"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a TabWidget view */
+ public static final String FQCN_TAB_WIDGET = "android.widget.TabWidget"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a Button view */
+ public static final String FQCN_BUTTON = "android.widget.Button"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a RadioButton view */
+ public static final String FQCN_RADIO_BUTTON = "android.widget.RadioButton"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a ToggleButton view */
+ public static final String FQCN_TOGGLE_BUTTON = "android.widget.ToggleButton"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a Spinner view */
+ public static final String FQCN_SPINNER = "android.widget.Spinner"; //$NON-NLS-1$
+
+ /** The fully qualified class name of an AdapterView */
+ public static final String FQCN_ADAPTER_VIEW = "android.widget.AdapterView"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a ListView */
+ public static final String FQCN_LIST_VIEW = "android.widget.ListView"; //$NON-NLS-1$
+
+ /** The fully qualified class name of an ExpandableListView */
+ public static final String FQCN_EXPANDABLE_LIST_VIEW = "android.widget.ExpandableListView"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a GestureOverlayView */
+ public static final String FQCN_GESTURE_OVERLAY_VIEW = "android.gesture.GestureOverlayView"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a DatePicker */
+ public static final String FQCN_DATE_PICKER = "android.widget.DatePicker"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a TimePicker */
+ public static final String FQCN_TIME_PICKER = "android.widget.TimePicker"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a RadioGroup */
+ public static final String FQCN_RADIO_GROUP = "android.widgets.RadioGroup"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a Space */
+ public static final String FQCN_SPACE = "android.widget.Space"; //$NON-NLS-1$
+ public static final String FQCN_SPACE_V7 = "android.support.v7.widget.Space"; //$NON-NLS-1$
+
+ /** The fully qualified class name of a TextView view */
+ public static final String FQCN_TEXT_VIEW = "android.widget.TextView"; //$NON-NLS-1$
+
+ /** The fully qualified class name of an ImageView view */
+ public static final String FQCN_IMAGE_VIEW = "android.widget.ImageView"; //$NON-NLS-1$
+
+ public static final String ATTR_SRC = "src"; //$NON-NLS-1$
+
+ public static final String ATTR_GRAVITY = "gravity"; //$NON-NLS-1$
+
+ public static final String ATTR_WEIGHT_SUM = "weightSum"; //$NON-NLS-1$
+ public static final String ATTR_EMS = "ems"; //$NON-NLS-1$
+
+ public static final String VALUE_HORIZONTAL = "horizontal"; //$NON-NLS-1$
+
+ public static final String GRADLE_PLUGIN_NAME = "com.android.tools.build:gradle:";
+ public static final String GRADLE_MINIMUM_VERSION = "1.12";
+ public static final String GRADLE_LATEST_VERSION = "1.12";
+ public static final String GRADLE_PLUGIN_MINIMUM_VERSION = "0.12.0";
+ public static final String GRADLE_PLUGIN_LATEST_VERSION = "0.12.+";
+ public static final String GRADLE_PLUGIN_RECOMMENDED_VERSION = "0.12.2";
+ public static final String MIN_BUILD_TOOLS_VERSION = "19.1.0";
+ public static final String SUPPORT_LIB_ARTIFACT = "com.android.support:support-v4";
+ public static final String APPCOMPAT_LIB_ARTIFACT = "com.android.support:appcompat-v7";
+
+ // Annotations
+ public static final String SUPPORT_ANNOTATIONS_PREFIX = "android.support.annotation.";
+ public static final String INT_DEF_ANNOTATION = SUPPORT_ANNOTATIONS_PREFIX + "IntDef";
+ public static final String STRING_DEF_ANNOTATION = SUPPORT_ANNOTATIONS_PREFIX + "StringDef";
+ public static final String TYPE_DEF_VALUE_ATTRIBUTE = "value";
+ public static final String TYPE_DEF_FLAG_ATTRIBUTE = "flag";
+ public static final String FN_ANNOTATIONS_ZIP = "annotations.zip";
+}
diff --git a/third_party/java/apkbuilder/java/com/android/annotations/NonNull.java b/third_party/java/apkbuilder/java/com/android/annotations/NonNull.java
new file mode 100644
index 0000000000..973ebb654b
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/annotations/NonNull.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that a parameter, field or method return value can never be null.
+ * <p/>
+ * This is a marker annotation and it has no specific attributes.
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({METHOD,PARAMETER,LOCAL_VARIABLE,FIELD})
+public @interface NonNull {
+}
diff --git a/third_party/java/apkbuilder/java/com/android/annotations/Nullable.java b/third_party/java/apkbuilder/java/com/android/annotations/Nullable.java
new file mode 100644
index 0000000000..d9c3861efe
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/annotations/Nullable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that a parameter, field or method return value can be null.
+ * <b>Note</b>: this is the default assumption for most Java APIs and the
+ * default assumption made by most static code checking tools, so usually you
+ * don't need to use this annotation; its primary use is to override a default
+ * wider annotation like {@link NonNullByDefault}.
+ * <p/>
+ * When decorating a method call parameter, this denotes the parameter can
+ * legitimately be null and the method will gracefully deal with it. Typically
+ * used on optional parameters.
+ * <p/>
+ * When decorating a method, this denotes the method might legitimately return
+ * null.
+ * <p/>
+ * This is a marker annotation and it has no specific attributes.
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({METHOD, PARAMETER, LOCAL_VARIABLE, FIELD})
+public @interface Nullable {
+}
diff --git a/third_party/java/apkbuilder/java/com/android/prefs/AndroidLocation.java b/third_party/java/apkbuilder/java/com/android/prefs/AndroidLocation.java
new file mode 100644
index 0000000000..1444cc8279
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/prefs/AndroidLocation.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.prefs;
+
+import com.android.annotations.NonNull;
+
+import java.io.File;
+
+/**
+ * Manages the location of the android files (including emulator files, ddms config, debug keystore)
+ */
+public final class AndroidLocation {
+
+ /**
+ * The name of the .android folder returned by {@link #getFolder()}.
+ */
+ public static final String FOLDER_DOT_ANDROID = ".android";
+
+ /**
+ * Virtual Device folder inside the path returned by {@link #getFolder()}
+ */
+ public static final String FOLDER_AVD = "avd";
+
+ /**
+ * Throw when the location of the android folder couldn't be found.
+ */
+ public static final class AndroidLocationException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public AndroidLocationException(String string) {
+ super(string);
+ }
+ }
+
+ private static String sPrefsLocation = null;
+
+ /**
+ * Enum describing which variables to check and whether they should
+ * be checked via {@link System#getProperty(String)} or {@link System#getenv()} or both.
+ */
+ public enum EnvVar {
+ ANDROID_SDK_HOME("ANDROID_SDK_HOME", true, true), // both sys prop and env var
+ USER_HOME ("user.home", true, false), // sys prop only
+ HOME ("HOME", false, true); // env var only
+
+ final String mName;
+ final boolean mIsSysProp;
+ final boolean mIsEnvVar;
+
+ private EnvVar(String name, boolean isSysProp, boolean isEnvVar) {
+ mName = name;
+ mIsSysProp = isSysProp;
+ mIsEnvVar = isEnvVar;
+ }
+
+ public String getName() {
+ return mName;
+ }
+ }
+
+ /**
+ * Returns the folder used to store android related files.
+ * @return an OS specific path, terminated by a separator.
+ * @throws AndroidLocationException
+ */
+ @NonNull
+ public static final String getFolder() throws AndroidLocationException {
+ if (sPrefsLocation == null) {
+ String home = findValidPath(new EnvVar[] { EnvVar.ANDROID_SDK_HOME,
+ EnvVar.USER_HOME,
+ EnvVar.HOME });
+
+ // if the above failed, we throw an exception.
+ if (home == null) {
+ throw new AndroidLocationException(
+ "Unable to get the Android SDK home directory.\n" +
+ "Make sure the environment variable ANDROID_SDK_HOME is set up.");
+ } else {
+ sPrefsLocation = home;
+ if (!sPrefsLocation.endsWith(File.separator)) {
+ sPrefsLocation += File.separator;
+ }
+ sPrefsLocation += FOLDER_DOT_ANDROID + File.separator;
+ }
+ }
+
+ // make sure the folder exists!
+ File f = new File(sPrefsLocation);
+ if (f.exists() == false) {
+ try {
+ f.mkdir();
+ } catch (SecurityException e) {
+ AndroidLocationException e2 = new AndroidLocationException(String.format(
+ "Unable to create folder '%1$s'. " +
+ "This is the path of preference folder expected by the Android tools.",
+ sPrefsLocation));
+ e2.initCause(e);
+ throw e2;
+ }
+ } else if (f.isFile()) {
+ throw new AndroidLocationException(sPrefsLocation +
+ " is not a directory! " +
+ "This is the path of preference folder expected by the Android tools.");
+ }
+
+ return sPrefsLocation;
+ }
+
+ /**
+ * Resets the folder used to store android related files. For testing.
+ */
+ public static final void resetFolder() {
+ sPrefsLocation = null;
+ }
+
+ /**
+ * Checks a list of system properties and/or system environment variables for validity, and
+ * existing director, and returns the first one.
+ * @param vars The variables to check. Order does matter.
+ * @return the content of the first property/variable that is a valid directory.
+ */
+ private static String findValidPath(EnvVar... vars) {
+ for (EnvVar var : vars) {
+ String path;
+ if (var.mIsSysProp) {
+ path = checkPath(System.getProperty(var.mName));
+ if (path != null) {
+ return path;
+ }
+ }
+
+ if (var.mIsEnvVar) {
+ path = checkPath(System.getenv(var.mName));
+ if (path != null) {
+ return path;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static String checkPath(String path) {
+ if (path != null) {
+ File f = new File(path);
+ if (f.isDirectory()) {
+ return path;
+ }
+ }
+ return null;
+ }
+}
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilder.java b/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilder.java
new file mode 100644
index 0000000000..4a69e2efd1
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilder.java
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.build;
+
+import com.android.SdkConstants;
+import com.android.sdklib.internal.build.DebugKeyProvider;
+import com.android.sdklib.internal.build.DebugKeyProvider.IKeyGenOutput;
+import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException;
+import com.android.sdklib.internal.build.SignedJarBuilder;
+import com.android.sdklib.internal.build.SignedJarBuilder.IZipEntryFilter;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Class making the final apk packaging.
+ * The inputs are:
+ * - packaged resources (output of aapt)
+ * - code file (output of dx)
+ * - Java resources coming from the project, its libraries, and its jar files
+ * - Native libraries from the project or its library.
+ *
+ */
+public final class ApkBuilder implements IArchiveBuilder {
+
+ private static final Pattern PATTERN_NATIVELIB_EXT = Pattern.compile("^.+\\.so$",
+ Pattern.CASE_INSENSITIVE);
+ private static final Pattern PATTERN_BITCODELIB_EXT = Pattern.compile("^.+\\.bc$",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * A No-op zip filter. It's used to detect conflicts.
+ *
+ */
+ private final class NullZipFilter implements IZipEntryFilter {
+ private File mInputFile;
+
+ void reset(File inputFile) {
+ mInputFile = inputFile;
+ }
+
+ @Override
+ public boolean checkEntry(String archivePath) throws ZipAbortException {
+ verbosePrintln("=> %s", archivePath);
+
+ File duplicate = checkFileForDuplicate(archivePath);
+ if (duplicate != null) {
+ throw new DuplicateFileException(archivePath, duplicate, mInputFile);
+ } else {
+ mAddedFiles.put(archivePath, mInputFile);
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Custom {@link IZipEntryFilter} to filter out everything that is not a standard java
+ * resources, and also record whether the zip file contains native libraries.
+ * <p/>Used in {@link SignedJarBuilder#writeZip(java.io.InputStream, IZipEntryFilter)} when
+ * we only want the java resources from external jars.
+ */
+ private final class JavaAndNativeResourceFilter implements IZipEntryFilter {
+ private final List<String> mNativeLibs = new ArrayList<String>();
+ private boolean mNativeLibsConflict = false;
+ private File mInputFile;
+
+ @Override
+ public boolean checkEntry(String archivePath) throws ZipAbortException {
+ // split the path into segments.
+ String[] segments = archivePath.split("/");
+
+ // empty path? skip to next entry.
+ if (segments.length == 0) {
+ return false;
+ }
+
+ // Check each folders to make sure they should be included.
+ // Folders like CVS, .svn, etc.. should already have been excluded from the
+ // jar file, but we need to exclude some other folder (like /META-INF) so
+ // we check anyway.
+ for (int i = 0 ; i < segments.length - 1; i++) {
+ if (!checkFolderForPackaging(segments[i])) {
+ return false;
+ }
+ }
+
+ // get the file name from the path
+ String fileName = segments[segments.length-1];
+
+ boolean check = checkFileForPackaging(fileName);
+
+ // only do additional checks if the file passes the default checks.
+ if (check) {
+ verbosePrintln("=> %s", archivePath);
+
+ File duplicate = checkFileForDuplicate(archivePath);
+ if (duplicate != null) {
+ throw new DuplicateFileException(archivePath, duplicate, mInputFile);
+ } else {
+ mAddedFiles.put(archivePath, mInputFile);
+ }
+
+ if (archivePath.endsWith(".so") || archivePath.endsWith(".bc")) {
+ mNativeLibs.add(archivePath);
+
+ // only .so located in lib/ will interfere with the installation
+ if (archivePath.startsWith(SdkConstants.FD_APK_NATIVE_LIBS + "/")) {
+ mNativeLibsConflict = true;
+ }
+ } else if (archivePath.endsWith(".jnilib")) {
+ mNativeLibs.add(archivePath);
+ }
+ }
+
+ return check;
+ }
+
+ List<String> getNativeLibs() {
+ return mNativeLibs;
+ }
+
+ boolean getNativeLibsConflict() {
+ return mNativeLibsConflict;
+ }
+
+ void reset(File inputFile) {
+ mInputFile = inputFile;
+ mNativeLibs.clear();
+ mNativeLibsConflict = false;
+ }
+ }
+
+ private File mApkFile;
+ private File mResFile;
+ private File mDexFile;
+ private PrintStream mVerboseStream;
+ private SignedJarBuilder mBuilder;
+ private boolean mDebugMode = false;
+ private boolean mIsSealed = false;
+
+ private final NullZipFilter mNullFilter = new NullZipFilter();
+ private final JavaAndNativeResourceFilter mFilter = new JavaAndNativeResourceFilter();
+ private final HashMap<String, File> mAddedFiles = new HashMap<String, File>();
+
+ /**
+ * Status for the addition of a jar file resources into the APK.
+ * This indicates possible issues with native library inside the jar file.
+ */
+ public interface JarStatus {
+ /**
+ * Returns the list of native libraries found in the jar file.
+ */
+ List<String> getNativeLibs();
+
+ /**
+ * Returns whether some of those libraries were located in the location that Android
+ * expects its native libraries.
+ */
+ boolean hasNativeLibsConflicts();
+
+ }
+
+ /** Internal implementation of {@link JarStatus}. */
+ private static final class JarStatusImpl implements JarStatus {
+ public final List<String> mLibs;
+ public final boolean mNativeLibsConflict;
+
+ private JarStatusImpl(List<String> libs, boolean nativeLibsConflict) {
+ mLibs = libs;
+ mNativeLibsConflict = nativeLibsConflict;
+ }
+
+ @Override
+ public List<String> getNativeLibs() {
+ return mLibs;
+ }
+
+ @Override
+ public boolean hasNativeLibsConflicts() {
+ return mNativeLibsConflict;
+ }
+ }
+
+ /**
+ * Signing information.
+ *
+ * Both the {@link PrivateKey} and the {@link X509Certificate} are guaranteed to be non-null.
+ *
+ */
+ public static final class SigningInfo {
+ public final PrivateKey key;
+ public final X509Certificate certificate;
+
+ private SigningInfo(PrivateKey key, X509Certificate certificate) {
+ if (key == null || certificate == null) {
+ throw new IllegalArgumentException("key and certificate cannot be null");
+ }
+ this.key = key;
+ this.certificate = certificate;
+ }
+ }
+
+ /**
+ * Returns the key and certificate from a given debug store.
+ *
+ * It is expected that the store password is 'android' and the key alias and password are
+ * 'androiddebugkey' and 'android' respectively.
+ *
+ * @param storeOsPath the OS path to the debug store.
+ * @param verboseStream an option {@link PrintStream} to display verbose information
+ * @return they key and certificate in a {@link SigningInfo} object or null.
+ * @throws ApkCreationException
+ */
+ public static SigningInfo getDebugKey(String storeOsPath, final PrintStream verboseStream)
+ throws ApkCreationException {
+ try {
+ if (storeOsPath != null) {
+ File storeFile = new File(storeOsPath);
+ try {
+ checkInputFile(storeFile);
+ } catch (FileNotFoundException e) {
+ // ignore these since the debug store can be created on the fly anyway.
+ }
+
+ // get the debug key
+ if (verboseStream != null) {
+ verboseStream.println(String.format("Using keystore: %s", storeOsPath));
+ }
+
+ IKeyGenOutput keygenOutput = null;
+ if (verboseStream != null) {
+ keygenOutput = new IKeyGenOutput() {
+ @Override
+ public void out(String message) {
+ verboseStream.println(message);
+ }
+
+ @Override
+ public void err(String message) {
+ verboseStream.println(message);
+ }
+ };
+ }
+
+ DebugKeyProvider keyProvider = new DebugKeyProvider(
+ storeOsPath, null /*store type*/, keygenOutput);
+
+ PrivateKey key = keyProvider.getDebugKey();
+ X509Certificate certificate = (X509Certificate)keyProvider.getCertificate();
+
+ if (key == null) {
+ throw new ApkCreationException("Unable to get debug signature key");
+ }
+
+ // compare the certificate expiration date
+ if (certificate != null && certificate.getNotAfter().compareTo(new Date()) < 0) {
+ // TODO, regenerate a new one.
+ throw new ApkCreationException("Debug Certificate expired on " +
+ DateFormat.getInstance().format(certificate.getNotAfter()));
+ }
+
+ return new SigningInfo(key, certificate);
+ } else {
+ return null;
+ }
+ } catch (KeytoolException e) {
+ if (e.getJavaHome() == null) {
+ throw new ApkCreationException(e.getMessage() +
+ "\nJAVA_HOME seems undefined, setting it will help locating keytool automatically\n" +
+ "You can also manually execute the following command\n:" +
+ e.getCommandLine(), e);
+ } else {
+ throw new ApkCreationException(e.getMessage() +
+ "\nJAVA_HOME is set to: " + e.getJavaHome() +
+ "\nUpdate it if necessary, or manually execute the following command:\n" +
+ e.getCommandLine(), e);
+ }
+ } catch (ApkCreationException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ApkCreationException(e);
+ }
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * This creates a new builder that will create the specified output file, using the two
+ * mandatory given input files.
+ *
+ * An optional debug keystore can be provided. If set, it is expected that the store password
+ * is 'android' and the key alias and password are 'androiddebugkey' and 'android'.
+ *
+ * An optional {@link PrintStream} can also be provided for verbose output. If null, there will
+ * be no output.
+ *
+ * @param apkOsPath the OS path of the file to create.
+ * @param resOsPath the OS path of the packaged resource file.
+ * @param dexOsPath the OS path of the dex file. This can be null for apk with no code.
+ * @param verboseStream the stream to which verbose output should go. If null, verbose mode
+ * is not enabled.
+ * @throws ApkCreationException
+ */
+ public ApkBuilder(String apkOsPath, String resOsPath, String dexOsPath, String storeOsPath,
+ PrintStream verboseStream) throws ApkCreationException {
+ this(new File(apkOsPath),
+ new File(resOsPath),
+ dexOsPath != null ? new File(dexOsPath) : null,
+ storeOsPath,
+ verboseStream);
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * This creates a new builder that will create the specified output file, using the two
+ * mandatory given input files.
+ *
+ * Optional {@link PrivateKey} and {@link X509Certificate} can be provided to sign the APK.
+ *
+ * An optional {@link PrintStream} can also be provided for verbose output. If null, there will
+ * be no output.
+ *
+ * @param apkOsPath the OS path of the file to create.
+ * @param resOsPath the OS path of the packaged resource file.
+ * @param dexOsPath the OS path of the dex file. This can be null for apk with no code.
+ * @param key the private key used to sign the package. Can be null.
+ * @param certificate the certificate used to sign the package. Can be null.
+ * @param verboseStream the stream to which verbose output should go. If null, verbose mode
+ * is not enabled.
+ * @throws ApkCreationException
+ */
+ public ApkBuilder(String apkOsPath, String resOsPath, String dexOsPath, PrivateKey key,
+ X509Certificate certificate, PrintStream verboseStream) throws ApkCreationException {
+ this(new File(apkOsPath),
+ new File(resOsPath),
+ dexOsPath != null ? new File(dexOsPath) : null,
+ key, certificate,
+ verboseStream);
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * This creates a new builder that will create the specified output file, using the two
+ * mandatory given input files.
+ *
+ * An optional debug keystore can be provided. If set, it is expected that the store password
+ * is 'android' and the key alias and password are 'androiddebugkey' and 'android'.
+ *
+ * An optional {@link PrintStream} can also be provided for verbose output. If null, there will
+ * be no output.
+ *
+ * @param apkFile the file to create
+ * @param resFile the file representing the packaged resource file.
+ * @param dexFile the file representing the dex file. This can be null for apk with no code.
+ * @param debugStoreOsPath the OS path to the debug keystore, if needed or null.
+ * @param verboseStream the stream to which verbose output should go. If null, verbose mode
+ * is not enabled.
+ * @throws ApkCreationException
+ */
+ public ApkBuilder(File apkFile, File resFile, File dexFile, String debugStoreOsPath,
+ final PrintStream verboseStream) throws ApkCreationException {
+
+ SigningInfo info = getDebugKey(debugStoreOsPath, verboseStream);
+ if (info != null) {
+ init(apkFile, resFile, dexFile, info.key, info.certificate, verboseStream);
+ } else {
+ init(apkFile, resFile, dexFile, null /*key*/, null/*certificate*/, verboseStream);
+ }
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * This creates a new builder that will create the specified output file, using the two
+ * mandatory given input files.
+ *
+ * Optional {@link PrivateKey} and {@link X509Certificate} can be provided to sign the APK.
+ *
+ * An optional {@link PrintStream} can also be provided for verbose output. If null, there will
+ * be no output.
+ *
+ * @param apkFile the file to create
+ * @param resFile the file representing the packaged resource file.
+ * @param dexFile the file representing the dex file. This can be null for apk with no code.
+ * @param key the private key used to sign the package. Can be null.
+ * @param certificate the certificate used to sign the package. Can be null.
+ * @param verboseStream the stream to which verbose output should go. If null, verbose mode
+ * is not enabled.
+ * @throws ApkCreationException
+ */
+ public ApkBuilder(File apkFile, File resFile, File dexFile, PrivateKey key,
+ X509Certificate certificate, PrintStream verboseStream) throws ApkCreationException {
+ init(apkFile, resFile, dexFile, key, certificate, verboseStream);
+ }
+
+
+ /**
+ * Constructor init method.
+ *
+ * @see #ApkBuilder(File, File, File, String, PrintStream)
+ * @see #ApkBuilder(String, String, String, String, PrintStream)
+ * @see #ApkBuilder(File, File, File, PrivateKey, X509Certificate, PrintStream)
+ */
+ private void init(File apkFile, File resFile, File dexFile, PrivateKey key,
+ X509Certificate certificate, PrintStream verboseStream) throws ApkCreationException {
+
+ try {
+ checkOutputFile(mApkFile = apkFile);
+ checkInputFile(mResFile = resFile);
+ if (dexFile != null) {
+ checkInputFile(mDexFile = dexFile);
+ } else {
+ mDexFile = null;
+ }
+ mVerboseStream = verboseStream;
+
+ mBuilder = new SignedJarBuilder(
+ new FileOutputStream(mApkFile, false /* append */), key,
+ certificate);
+
+ verbosePrintln("Packaging %s", mApkFile.getName());
+
+ // add the resources
+ addZipFile(mResFile);
+
+ // add the class dex file at the root of the apk
+ if (mDexFile != null) {
+ addFile(mDexFile, SdkConstants.FN_APK_CLASSES_DEX);
+ }
+
+ } catch (ApkCreationException e) {
+ if (mBuilder != null) {
+ mBuilder.cleanUp();
+ }
+ throw e;
+ } catch (Exception e) {
+ if (mBuilder != null) {
+ mBuilder.cleanUp();
+ }
+ throw new ApkCreationException(e);
+ }
+ }
+
+ /**
+ * Sets the debug mode. In debug mode, when native libraries are present, the packaging
+ * will also include one or more copies of gdbserver in the final APK file.
+ *
+ * These are used for debugging native code, to ensure that gdbserver is accessible to the
+ * application.
+ *
+ * There will be one version of gdbserver for each ABI supported by the application.
+ *
+ * the gbdserver files are placed in the libs/abi/ folders automatically by the NDK.
+ *
+ * @param debugMode the debug mode flag.
+ */
+ public void setDebugMode(boolean debugMode) {
+ mDebugMode = debugMode;
+ }
+
+ /**
+ * Adds a file to the APK at a given path
+ * @param file the file to add
+ * @param archivePath the path of the file inside the APK archive.
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
+ */
+ @Override
+ public void addFile(File file, String archivePath) throws ApkCreationException,
+ SealedApkException, DuplicateFileException {
+ if (mIsSealed) {
+ throw new SealedApkException("APK is already sealed");
+ }
+
+ try {
+ doAddFile(file, archivePath);
+ } catch (DuplicateFileException e) {
+ mBuilder.cleanUp();
+ throw e;
+ } catch (Exception e) {
+ mBuilder.cleanUp();
+ throw new ApkCreationException(e, "Failed to add %s", file);
+ }
+ }
+
+ /**
+ * Adds the content from a zip file.
+ * All file keep the same path inside the archive.
+ * @param zipFile the zip File.
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
+ */
+ public void addZipFile(File zipFile) throws ApkCreationException, SealedApkException,
+ DuplicateFileException {
+ if (mIsSealed) {
+ throw new SealedApkException("APK is already sealed");
+ }
+
+ try {
+ verbosePrintln("%s:", zipFile);
+
+ // reset the filter with this input.
+ mNullFilter.reset(zipFile);
+
+ // ask the builder to add the content of the file.
+ FileInputStream fis = new FileInputStream(zipFile);
+ mBuilder.writeZip(fis, mNullFilter);
+ fis.close();
+ } catch (DuplicateFileException e) {
+ mBuilder.cleanUp();
+ throw e;
+ } catch (Exception e) {
+ mBuilder.cleanUp();
+ throw new ApkCreationException(e, "Failed to add %s", zipFile);
+ }
+ }
+
+ /**
+ * Adds the resources from a jar file.
+ * @param jarFile the jar File.
+ * @return a {@link JarStatus} object indicating if native libraries where found in
+ * the jar file.
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
+ */
+ public JarStatus addResourcesFromJar(File jarFile) throws ApkCreationException,
+ SealedApkException, DuplicateFileException {
+ if (mIsSealed) {
+ throw new SealedApkException("APK is already sealed");
+ }
+
+ try {
+ verbosePrintln("%s:", jarFile);
+
+ // reset the filter with this input.
+ mFilter.reset(jarFile);
+
+ // ask the builder to add the content of the file, filtered to only let through
+ // the java resources.
+ FileInputStream fis = new FileInputStream(jarFile);
+ mBuilder.writeZip(fis, mFilter);
+ fis.close();
+
+ // check if native libraries were found in the external library. This should
+ // constitutes an error or warning depending on if they are in lib/
+ return new JarStatusImpl(mFilter.getNativeLibs(), mFilter.getNativeLibsConflict());
+ } catch (DuplicateFileException e) {
+ mBuilder.cleanUp();
+ throw e;
+ } catch (Exception e) {
+ mBuilder.cleanUp();
+ throw new ApkCreationException(e, "Failed to add %s", jarFile);
+ }
+ }
+
+ /**
+ * Adds the resources from a source folder.
+ * @param sourceFolder the source folder.
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
+ */
+ public void addSourceFolder(File sourceFolder) throws ApkCreationException, SealedApkException,
+ DuplicateFileException {
+ if (mIsSealed) {
+ throw new SealedApkException("APK is already sealed");
+ }
+
+ addSourceFolder(this, sourceFolder);
+ }
+
+ /**
+ * Adds the resources from a source folder to a given {@link IArchiveBuilder}
+ * @param sourceFolder the source folder.
+ * @throws ApkCreationException if an error occurred
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
+ */
+ public static void addSourceFolder(IArchiveBuilder builder, File sourceFolder)
+ throws ApkCreationException, DuplicateFileException {
+ if (sourceFolder.isDirectory()) {
+ try {
+ // file is a directory, process its content.
+ File[] files = sourceFolder.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ processFileForResource(builder, file, null);
+ }
+ }
+ } catch (DuplicateFileException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ApkCreationException(e, "Failed to add %s", sourceFolder);
+ }
+ } else {
+ // not a directory? check if it's a file or doesn't exist
+ if (sourceFolder.exists()) {
+ throw new ApkCreationException("%s is not a folder", sourceFolder);
+ } else {
+ throw new ApkCreationException("%s does not exist", sourceFolder);
+ }
+ }
+ }
+
+ /**
+ * Adds the native libraries from the top native folder.
+ * The content of this folder must be the various ABI folders.
+ *
+ * This may or may not copy gdbserver into the apk based on whether the debug mode is set.
+ *
+ * @param nativeFolder the native folder.
+ *
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
+ *
+ * @see #setDebugMode(boolean)
+ */
+ public void addNativeLibraries(File nativeFolder)
+ throws ApkCreationException, SealedApkException, DuplicateFileException {
+ if (mIsSealed) {
+ throw new SealedApkException("APK is already sealed");
+ }
+
+ if (!nativeFolder.isDirectory()) {
+ // not a directory? check if it's a file or doesn't exist
+ if (nativeFolder.exists()) {
+ throw new ApkCreationException("%s is not a folder", nativeFolder);
+ } else {
+ throw new ApkCreationException("%s does not exist", nativeFolder);
+ }
+ }
+
+ File[] abiList = nativeFolder.listFiles();
+
+ verbosePrintln("Native folder: %s", nativeFolder);
+
+ if (abiList != null) {
+ for (File abi : abiList) {
+ if (abi.isDirectory()) { // ignore files
+
+ File[] libs = abi.listFiles();
+ if (libs != null) {
+ for (File lib : libs) {
+ // only consider files that are .so or, if in debug mode, that
+ // are gdbserver executables
+ if (lib.isFile() &&
+ (PATTERN_NATIVELIB_EXT.matcher(lib.getName()).matches() ||
+ PATTERN_BITCODELIB_EXT.matcher(lib.getName()).matches() ||
+ (mDebugMode &&
+ SdkConstants.FN_GDBSERVER.equals(
+ lib.getName())))) {
+ String path =
+ SdkConstants.FD_APK_NATIVE_LIBS + "/" +
+ abi.getName() + "/" + lib.getName();
+
+ try {
+ doAddFile(lib, path);
+ } catch (IOException e) {
+ mBuilder.cleanUp();
+ throw new ApkCreationException(e, "Failed to add %s", lib);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void addNativeLibraries(List<FileEntry> entries) throws SealedApkException,
+ DuplicateFileException, ApkCreationException {
+ if (mIsSealed) {
+ throw new SealedApkException("APK is already sealed");
+ }
+
+ for (FileEntry entry : entries) {
+ try {
+ doAddFile(entry.mFile, entry.mPath);
+ } catch (IOException e) {
+ mBuilder.cleanUp();
+ throw new ApkCreationException(e, "Failed to add %s", entry.mFile);
+ }
+ }
+ }
+
+ public static final class FileEntry {
+ public final File mFile;
+ public final String mPath;
+
+ FileEntry(File file, String path) {
+ mFile = file;
+ mPath = path;
+ }
+ }
+
+ public static List<FileEntry> getNativeFiles(File nativeFolder, boolean debugMode)
+ throws ApkCreationException {
+
+ if (!nativeFolder.isDirectory()) {
+ // not a directory? check if it's a file or doesn't exist
+ if (nativeFolder.exists()) {
+ throw new ApkCreationException("%s is not a folder", nativeFolder);
+ } else {
+ throw new ApkCreationException("%s does not exist", nativeFolder);
+ }
+ }
+
+ List<FileEntry> files = new ArrayList<FileEntry>();
+
+ File[] abiList = nativeFolder.listFiles();
+
+ if (abiList != null) {
+ for (File abi : abiList) {
+ if (abi.isDirectory()) { // ignore files
+
+ File[] libs = abi.listFiles();
+ if (libs != null) {
+ for (File lib : libs) {
+ // only consider files that are .so or, if in debug mode, that
+ // are gdbserver executables
+ if (lib.isFile() &&
+ (PATTERN_NATIVELIB_EXT.matcher(lib.getName()).matches() ||
+ PATTERN_BITCODELIB_EXT.matcher(lib.getName()).matches() ||
+ (debugMode &&
+ SdkConstants.FN_GDBSERVER.equals(
+ lib.getName())))) {
+ String path =
+ SdkConstants.FD_APK_NATIVE_LIBS + "/" +
+ abi.getName() + "/" + lib.getName();
+
+ files.add(new FileEntry(lib, path));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return files;
+ }
+
+
+
+ /**
+ * Seals the APK, and signs it if necessary.
+ * @throws ApkCreationException
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ */
+ public void sealApk() throws ApkCreationException, SealedApkException {
+ if (mIsSealed) {
+ throw new SealedApkException("APK is already sealed");
+ }
+
+ // close and sign the application package.
+ try {
+ mBuilder.close();
+ mIsSealed = true;
+ } catch (Exception e) {
+ throw new ApkCreationException(e, "Failed to seal APK");
+ } finally {
+ mBuilder.cleanUp();
+ }
+ }
+
+ /**
+ * Output a given message if the verbose mode is enabled.
+ * @param format the format string for {@link String#format(String, Object...)}
+ * @param args the string arguments
+ */
+ private void verbosePrintln(String format, Object... args) {
+ if (mVerboseStream != null) {
+ mVerboseStream.println(String.format(format, args));
+ }
+ }
+
+ private void doAddFile(File file, String archivePath) throws DuplicateFileException,
+ IOException {
+ verbosePrintln("%1$s => %2$s", file, archivePath);
+
+ File duplicate = checkFileForDuplicate(archivePath);
+ if (duplicate != null) {
+ throw new DuplicateFileException(archivePath, duplicate, file);
+ }
+
+ mAddedFiles.put(archivePath, file);
+ mBuilder.writeFile(file, archivePath);
+ }
+
+ /**
+ * Processes a {@link File} that could be an APK {@link File}, or a folder containing
+ * java resources.
+ *
+ * @param file the {@link File} to process.
+ * @param path the relative path of this file to the source folder.
+ * Can be <code>null</code> to identify a root file.
+ * @throws IOException
+ * @throws DuplicateFileException if a file conflicts with another already added
+ * to the APK at the same location inside the APK archive.
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws ApkCreationException if an error occurred
+ */
+ private static void processFileForResource(IArchiveBuilder builder, File file, String path)
+ throws IOException, DuplicateFileException, ApkCreationException, SealedApkException {
+ if (file.isDirectory()) {
+ // a directory? we check it
+ if (checkFolderForPackaging(file.getName())) {
+ // if it's valid, we append its name to the current path.
+ if (path == null) {
+ path = file.getName();
+ } else {
+ path = path + "/" + file.getName();
+ }
+
+ // and process its content.
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File contentFile : files) {
+ processFileForResource(builder, contentFile, path);
+ }
+ }
+ }
+ } else {
+ // a file? we check it to make sure it should be added
+ if (checkFileForPackaging(file.getName())) {
+ // we append its name to the current path
+ if (path == null) {
+ path = file.getName();
+ } else {
+ path = path + "/" + file.getName();
+ }
+
+ // and add it to the apk
+ builder.addFile(file, path);
+ }
+ }
+ }
+
+ /**
+ * Checks if the given path in the APK archive has not already been used and if it has been,
+ * then returns a {@link File} object for the source of the duplicate
+ * @param archivePath the archive path to test.
+ * @return A File object of either a file at the same location or an archive that contains a
+ * file that was put at the same location.
+ */
+ private File checkFileForDuplicate(String archivePath) {
+ return mAddedFiles.get(archivePath);
+ }
+
+ /**
+ * Checks an output {@link File} object.
+ * This checks the following:
+ * - the file is not an existing directory.
+ * - if the file exists, that it can be modified.
+ * - if it doesn't exists, that a new file can be created.
+ * @param file the File to check
+ * @throws ApkCreationException If the check fails
+ */
+ private void checkOutputFile(File file) throws ApkCreationException {
+ if (file.isDirectory()) {
+ throw new ApkCreationException("%s is a directory!", file);
+ }
+
+ if (file.exists()) { // will be a file in this case.
+ if (!file.canWrite()) {
+ throw new ApkCreationException("Cannot write %s", file);
+ }
+ } else {
+ try {
+ if (!file.createNewFile()) {
+ throw new ApkCreationException("Failed to create %s", file);
+ }
+ } catch (IOException e) {
+ throw new ApkCreationException(
+ "Failed to create '%1$ss': %2$s", file, e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Checks an input {@link File} object.
+ * This checks the following:
+ * - the file is not an existing directory.
+ * - that the file exists (if <var>throwIfDoesntExist</var> is <code>false</code>) and can
+ * be read.
+ * @param file the File to check
+ * @throws FileNotFoundException if the file is not here.
+ * @throws ApkCreationException If the file is a folder or a file that cannot be read.
+ */
+ private static void checkInputFile(File file) throws FileNotFoundException, ApkCreationException {
+ if (file.isDirectory()) {
+ throw new ApkCreationException("%s is a directory!", file);
+ }
+
+ if (file.exists()) {
+ if (!file.canRead()) {
+ throw new ApkCreationException("Cannot read %s", file);
+ }
+ } else {
+ throw new FileNotFoundException(String.format("%s does not exist", file));
+ }
+ }
+
+ public static String getDebugKeystore() throws ApkCreationException {
+ try {
+ return DebugKeyProvider.getDefaultKeyStoreOsPath();
+ } catch (Exception e) {
+ throw new ApkCreationException(e, e.getMessage());
+ }
+ }
+
+ /**
+ * Checks whether a folder and its content is valid for packaging into the .apk as
+ * standard Java resource.
+ * @param folderName the name of the folder.
+ */
+ public static boolean checkFolderForPackaging(String folderName) {
+ return !folderName.equalsIgnoreCase("CVS") &&
+ !folderName.equalsIgnoreCase(".svn") &&
+ !folderName.equalsIgnoreCase("SCCS") &&
+ !folderName.equalsIgnoreCase("META-INF") &&
+ !folderName.startsWith("_");
+ }
+
+ /**
+ * Checks a file to make sure it should be packaged as standard resources.
+ * @param fileName the name of the file (including extension)
+ * @return true if the file should be packaged as standard java resources.
+ */
+ public static boolean checkFileForPackaging(String fileName) {
+ String[] fileSegments = fileName.split("\\.");
+ String fileExt = "";
+ if (fileSegments.length > 1) {
+ fileExt = fileSegments[fileSegments.length-1];
+ }
+
+ return checkFileForPackaging(fileName, fileExt);
+ }
+
+ /**
+ * Checks a file to make sure it should be packaged as standard resources.
+ * @param fileName the name of the file (including extension)
+ * @param extension the extension of the file (excluding '.')
+ * @return true if the file should be packaged as standard java resources.
+ */
+ public static boolean checkFileForPackaging(String fileName, String extension) {
+ // ignore hidden files and backup files
+ if (fileName.charAt(0) == '.' || fileName.charAt(fileName.length()-1) == '~') {
+ return false;
+ }
+
+ return !"aidl".equalsIgnoreCase(extension) && // Aidl files
+ !"rs".equalsIgnoreCase(extension) && // RenderScript files
+ !"fs".equalsIgnoreCase(extension) && // FilterScript files
+ !"rsh".equalsIgnoreCase(extension) && // RenderScript header files
+ !"d".equalsIgnoreCase(extension) && // Dependency files
+ !"java".equalsIgnoreCase(extension) && // Java files
+ !"scala".equalsIgnoreCase(extension) && // Scala files
+ !"class".equalsIgnoreCase(extension) && // Java class files
+ !"scc".equalsIgnoreCase(extension) && // VisualSourceSafe
+ !"swp".equalsIgnoreCase(extension) && // vi swap file
+ !"thumbs.db".equalsIgnoreCase(fileName) && // image index file
+ !"picasa.ini".equalsIgnoreCase(fileName) && // image index file
+ !"package.html".equalsIgnoreCase(fileName) && // Javadoc
+ !"overview.html".equalsIgnoreCase(fileName); // Javadoc
+ }
+}
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilderMain.java b/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilderMain.java
new file mode 100644
index 0000000000..304385bed6
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkBuilderMain.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.build;
+
+import com.google.devtools.build.singlejar.ZipCombiner;
+import com.google.devtools.build.singlejar.ZipEntryFilter;
+
+import com.android.SdkConstants;
+import com.android.sdklib.build.ApkBuilder.FileEntry;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+
+/**
+ * Command line APK builder with signing support.
+ */
+public final class ApkBuilderMain {
+
+ private final static Pattern PATTERN_JAR_EXT = Pattern.compile("^.+\\.jar$",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Main method. This is meant to be called from the command line through an exec.
+ * <p/>WARNING: this will call {@link System#exit(int)} if anything goes wrong.
+ * @param args command line arguments.
+ */
+ public static void main(String[] args) {
+ if (args.length < 1) {
+ printUsageAndQuit();
+ }
+
+ try {
+ File outApk = new File(args[0]);
+
+ File dexFile = null;
+ ArrayList<File> zipArchives = new ArrayList<File>();
+ ArrayList<File> sourceFolders = new ArrayList<File>();
+ ArrayList<File> jarFiles = new ArrayList<File>();
+ ArrayList<File> nativeFolders = new ArrayList<File>();
+
+ boolean verbose = false;
+ boolean signed = true;
+ boolean debug = false;
+ String keystorePath = null;
+
+ int index = 1;
+ do {
+ String argument = args[index++];
+
+ if ("-v".equals(argument)) {
+ verbose = true;
+
+ } else if ("-d".equals(argument)) {
+ debug = true;
+
+ } else if ("-u".equals(argument)) {
+ signed = false;
+
+ } else if ("-ks".equals(argument)) {
+ // bazel-specific option
+ if (index == args.length) {
+ printAndExit("Missing value for -ks");
+ }
+
+ keystorePath = args[index++];
+ } else if ("-z".equals(argument)) {
+ // quick check on the next argument.
+ if (index == args.length) {
+ printAndExit("Missing value for -z");
+ }
+
+ zipArchives.add(new File(args[index++]));
+ } else if ("-f". equals(argument)) {
+ if (dexFile != null) {
+ // can't have more than one dex file.
+ printAndExit("Can't have more than one dex file (-f)");
+ }
+ // quick check on the next argument.
+ if (index == args.length) {
+ printAndExit("Missing value for -f");
+ }
+
+ dexFile = new File(args[index++]);
+ } else if ("-rf". equals(argument)) {
+ // quick check on the next argument.
+ if (index == args.length) {
+ printAndExit("Missing value for -rf");
+ }
+
+ sourceFolders.add(new File(args[index++]));
+ } else if ("-rj". equals(argument)) {
+ // quick check on the next argument.
+ if (index == args.length) {
+ printAndExit("Missing value for -rj");
+ }
+
+ jarFiles.add(new File(args[index++]));
+ } else if ("-nf".equals(argument)) {
+ // quick check on the next argument.
+ if (index == args.length) {
+ printAndExit("Missing value for -nf");
+ }
+
+ nativeFolders.add(new File(args[index++]));
+ } else if ("-storetype".equals(argument)) {
+ // quick check on the next argument.
+ if (index == args.length) {
+ printAndExit("Missing value for -storetype");
+ }
+
+ // FIXME
+ } else {
+ printAndExit("Unknown argument: " + argument);
+ }
+ } while (index < args.length);
+
+ if (zipArchives.size() == 0) {
+ printAndExit("No zip archive, there must be one for the resources");
+ }
+
+ if (signed && keystorePath == null) {
+ keystorePath = ApkBuilder.getDebugKeystore();
+ }
+
+ // create the builder with the basic files.
+ ApkBuilder builder = new ApkBuilder(outApk, zipArchives.get(0), dexFile,
+ signed ? keystorePath : null,
+ verbose ? System.out : null);
+ builder.setDebugMode(debug);
+
+ // add the rest of the files.
+ // first zip Archive was used in the constructor.
+ for (int i = 1 ; i < zipArchives.size() ; i++) {
+ builder.addZipFile(zipArchives.get(i));
+ }
+
+ for (File sourceFolder : sourceFolders) {
+ builder.addSourceFolder(sourceFolder);
+ }
+
+ for (File jarFile : jarFiles) {
+ if (jarFile.isDirectory()) {
+ String[] filenames = jarFile.list(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return PATTERN_JAR_EXT.matcher(name).matches();
+ }
+ });
+
+ for (String filename : filenames) {
+ builder.addResourcesFromJar(new File(jarFile, filename));
+ }
+ } else {
+ builder.addResourcesFromJar(jarFile);
+ }
+ }
+
+ for (File nativeFolder : nativeFolders) {
+ builder.addNativeLibraries(nativeFolder);
+ }
+
+ // seal the apk
+ builder.sealApk();
+
+ // ensure hermeticity, bazel specific
+ clearTimeStamps(outApk);
+ } catch (ApkCreationException e) {
+ printAndExit(e.getMessage());
+ } catch (DuplicateFileException e) {
+ printAndExit(String.format(
+ "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s",
+ e.getArchivePath(), e.getFile1(), e.getFile2()));
+ } catch (SealedApkException e) {
+ printAndExit(e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void clearTimeStamps(File outApk) throws IOException {
+ File renamed = new File(outApk.getPath() + ".nonhermetic");
+ if (!outApk.renameTo(renamed)) {
+ throw new IOException("could not rename: " + outApk);
+ }
+
+ OutputStream out = new FileOutputStream(outApk);
+ ZipCombiner combiner = new ZipCombiner(
+ new ZipEntryFilter() {
+ @Override
+ public void accept(String filename, StrategyCallback callback)
+ throws IOException {
+ callback.copy(ZipCombiner.DOS_EPOCH);
+ }
+ }, out);
+ combiner.addZip(renamed);
+ combiner.close(); // closes its outstream.
+ renamed.deleteOnExit();
+ }
+
+ private static void printUsageAndQuit() {
+ // 80 cols marker: 01234567890123456789012345678901234567890123456789012345678901234567890123456789
+ System.err.println("A command line tool to package an Android application from various sources.");
+ System.err.println("Usage: apkbuilder <out archive> [-v][-u][-storetype STORE_TYPE] [-z inputzip]");
+ System.err.println(" [-f inputfile] [-rf input-folder] [-rj -input-path]");
+ System.err.println(" [-nf native-folder] [-rj -input-path]");
+ System.err.println("");
+ System.err.println("NOTE: This is a version of the ApkBuilder tool that comes "
+ + "with the Android sdk modified for Bazel.");
+ System.err.println("");
+ System.err.println(" -v Verbose.");
+ System.err.println(" -d Debug Mode: Includes debug files in the APK file.");
+ System.err.println(" -u Creates an unsigned package.");
+ System.err.println(" -storetype Forces the KeyStore type. If ommited the default is used.");
+ System.err.println("");
+ System.err.println(" -z Followed by the path to a zip archive.");
+ System.err.println(" Adds the content of the application package.");
+ System.err.println("");
+ System.err.println(" -f Followed by the path to a file.");
+ System.err.println(" Adds the file to the application package.");
+ System.err.println("");
+ System.err.println(" -rf Followed by the path to a source folder.");
+ System.err.println(" Adds the java resources found in that folder to the application");
+ System.err.println(" package, while keeping their path relative to the source folder.");
+ System.err.println("");
+ System.err.println(" -rj Followed by the path to a jar file or a folder containing");
+ System.err.println(" jar files.");
+ System.err.println(" Adds the java resources found in the jar file(s) to the application");
+ System.err.println(" package.");
+ System.err.println("");
+ System.err.println(" -nf Followed by the root folder containing native libraries to");
+ System.err.println(" include in the application package.");
+
+ System.exit(1);
+ }
+
+ private static void printAndExit(String... messages) {
+ for (String message : messages) {
+ System.err.println(message);
+ }
+ System.exit(1);
+ }
+
+ private ApkBuilderMain() {
+ }
+}
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkCreationException.java b/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkCreationException.java
new file mode 100644
index 0000000000..2379915dc8
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/build/ApkCreationException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.build;
+
+/**
+ * An exception thrown during packaging of an APK file.
+ */
+public final class ApkCreationException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public ApkCreationException(String format, Object... args) {
+ super(String.format(format, args));
+ }
+
+ public ApkCreationException(Throwable cause, String format, Object... args) {
+ super(String.format(format, args), cause);
+ }
+
+ public ApkCreationException(Throwable cause) {
+ super(cause);
+ }
+} \ No newline at end of file
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/build/DuplicateFileException.java b/third_party/java/apkbuilder/java/com/android/sdklib/build/DuplicateFileException.java
new file mode 100644
index 0000000000..ba53ba37ce
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/build/DuplicateFileException.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.build;
+
+import com.android.sdklib.internal.build.SignedJarBuilder.IZipEntryFilter.ZipAbortException;
+
+import java.io.File;
+
+/**
+ * An exception thrown during packaging of an APK file.
+ */
+public final class DuplicateFileException extends ZipAbortException {
+ private static final long serialVersionUID = 1L;
+ private final String mArchivePath;
+ private final File mFile1;
+ private final File mFile2;
+
+ public DuplicateFileException(String archivePath, File file1, File file2) {
+ super();
+ mArchivePath = archivePath;
+ mFile1 = file1;
+ mFile2 = file2;
+ }
+
+ public String getArchivePath() {
+ return mArchivePath;
+ }
+
+ public File getFile1() {
+ return mFile1;
+ }
+
+ public File getFile2() {
+ return mFile2;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Duplicate files at the same path inside the APK";
+ }
+} \ No newline at end of file
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/build/IArchiveBuilder.java b/third_party/java/apkbuilder/java/com/android/sdklib/build/IArchiveBuilder.java
new file mode 100644
index 0000000000..e2230e9ee7
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/build/IArchiveBuilder.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.build;
+
+import java.io.File;
+
+public interface IArchiveBuilder {
+
+ /**
+ * Adds a file to the archive at a given path
+ * @param file the file to add
+ * @param archivePath the path of the file inside the APK archive.
+ * @throws ApkCreationException if an error occurred
+ * @throws SealedApkException if the APK is already sealed.
+ * @throws DuplicateFileException if a file conflicts with another already added to the APK
+ * at the same location inside the APK archive.
+ */
+ void addFile(File file, String archivePath) throws ApkCreationException,
+ SealedApkException, DuplicateFileException;
+
+}
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/build/SealedApkException.java b/third_party/java/apkbuilder/java/com/android/sdklib/build/SealedApkException.java
new file mode 100644
index 0000000000..97f03bdece
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/build/SealedApkException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.build;
+
+/**
+ * An exception thrown when trying to add files to a sealed APK.
+ */
+public final class SealedApkException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public SealedApkException(String format, Object... args) {
+ super(String.format(format, args));
+ }
+
+ public SealedApkException(Throwable cause, String format, Object... args) {
+ super(String.format(format, args), cause);
+ }
+
+ public SealedApkException(Throwable cause) {
+ super(cause);
+ }
+} \ No newline at end of file
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/DebugKeyProvider.java b/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/DebugKeyProvider.java
new file mode 100644
index 0000000000..8d4ba37aa3
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/DebugKeyProvider.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.internal.build;
+
+import com.android.prefs.AndroidLocation;
+import com.android.prefs.AndroidLocation.AndroidLocationException;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+
+/**
+ * A provider of a dummy key to sign Android application for debugging purpose.
+ * <p/>This provider uses a custom keystore to create and store a key with a known password.
+ *
+ * @deprecated Use Android-Builder instead
+ */
+@Deprecated
+public class DebugKeyProvider {
+
+ public interface IKeyGenOutput {
+ public void out(String message);
+ public void err(String message);
+ }
+
+ private static final String PASSWORD_STRING = "android";
+ private static final char[] PASSWORD_CHAR = PASSWORD_STRING.toCharArray();
+ private static final String DEBUG_ALIAS = "AndroidDebugKey";
+
+ // Certificate CN value. This is a hard-coded value for the debug key.
+ // Android Market checks against this value in order to refuse applications signed with
+ // debug keys.
+ private static final String CERTIFICATE_DESC = "CN=Android Debug,O=Android,C=US";
+
+ private KeyStore.PrivateKeyEntry mEntry;
+
+ public static class KeytoolException extends Exception {
+ /** default serial uid */
+ private static final long serialVersionUID = 1L;
+ private String mJavaHome = null;
+ private String mCommandLine = null;
+
+ KeytoolException(String message) {
+ super(message);
+ }
+
+ KeytoolException(String message, String javaHome, String commandLine) {
+ super(message);
+
+ mJavaHome = javaHome;
+ mCommandLine = commandLine;
+ }
+
+ public String getJavaHome() {
+ return mJavaHome;
+ }
+
+ public String getCommandLine() {
+ return mCommandLine;
+ }
+ }
+
+ /**
+ * Creates a provider using a keystore at the given location.
+ * <p/>The keystore, and a new random android debug key are created if they do not yet exist.
+ * <p/>Password for the store/key is <code>android</code>, and the key alias is
+ * <code>AndroidDebugKey</code>.
+ * @param osKeyStorePath the OS path to the keystore, or <code>null</code> if the default one
+ * is to be used.
+ * @param storeType an optional keystore type, or <code>null</code> if the default is to
+ * be used.
+ * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
+ * of the keytool process call.
+ * @throws KeytoolException If the creation of the debug key failed.
+ * @throws AndroidLocationException
+ */
+ public DebugKeyProvider(String osKeyStorePath, String storeType, IKeyGenOutput output)
+ throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
+ UnrecoverableEntryException, IOException, KeytoolException, AndroidLocationException {
+
+ if (osKeyStorePath == null) {
+ osKeyStorePath = getDefaultKeyStoreOsPath();
+ }
+
+ if (loadKeyEntry(osKeyStorePath, storeType) == false) {
+ // create the store with the key
+ createNewStore(osKeyStorePath, storeType, output);
+ }
+ }
+
+ /**
+ * Returns the OS path to the default debug keystore.
+ *
+ * @return The OS path to the default debug keystore.
+ * @throws KeytoolException
+ * @throws AndroidLocationException
+ */
+ public static String getDefaultKeyStoreOsPath()
+ throws KeytoolException, AndroidLocationException {
+ String folder = AndroidLocation.getFolder();
+ if (folder == null) {
+ throw new KeytoolException("Failed to get HOME directory!\n");
+ }
+ String osKeyStorePath = folder + "debug.keystore";
+
+ return osKeyStorePath;
+ }
+
+ /**
+ * Returns the debug {@link PrivateKey} to use to sign applications for debug purpose.
+ * @return the private key or <code>null</code> if its creation failed.
+ */
+ @SuppressWarnings("unused") // the thrown Exceptions are not actually thrown
+ public PrivateKey getDebugKey() throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException, UnrecoverableEntryException {
+ if (mEntry != null) {
+ return mEntry.getPrivateKey();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the debug {@link Certificate} to use to sign applications for debug purpose.
+ * @return the certificate or <code>null</code> if its creation failed.
+ */
+ @SuppressWarnings("unused") // the thrown Exceptions are not actually thrown
+ public Certificate getCertificate() throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException, UnrecoverableEntryException {
+ if (mEntry != null) {
+ return mEntry.getCertificate();
+ }
+
+ return null;
+ }
+
+ /**
+ * Loads the debug key from the keystore.
+ * @param osKeyStorePath the OS path to the keystore.
+ * @param storeType an optional keystore type, or <code>null</code> if the default is to
+ * be used.
+ * @return <code>true</code> if success, <code>false</code> if the keystore does not exist.
+ */
+ private boolean loadKeyEntry(String osKeyStorePath, String storeType) throws KeyStoreException,
+ NoSuchAlgorithmException, CertificateException, IOException,
+ UnrecoverableEntryException {
+ FileInputStream fis = null;
+ try {
+ KeyStore keyStore = KeyStore.getInstance(
+ storeType != null ? storeType : KeyStore.getDefaultType());
+ fis = new FileInputStream(osKeyStorePath);
+ keyStore.load(fis, PASSWORD_CHAR);
+ mEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(
+ DEBUG_ALIAS, new KeyStore.PasswordProtection(PASSWORD_CHAR));
+ } catch (FileNotFoundException e) {
+ return false;
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ // pass
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Creates a new store
+ * @param osKeyStorePath the location of the store
+ * @param storeType an optional keystore type, or <code>null</code> if the default is to
+ * be used.
+ * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
+ * of the keytool process call.
+ * @throws KeyStoreException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ * @throws UnrecoverableEntryException
+ * @throws IOException
+ * @throws KeytoolException
+ */
+ private void createNewStore(String osKeyStorePath, String storeType, IKeyGenOutput output)
+ throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
+ UnrecoverableEntryException, IOException, KeytoolException {
+
+ if (KeystoreHelper.createNewStore(osKeyStorePath, storeType, PASSWORD_STRING, DEBUG_ALIAS,
+ PASSWORD_STRING, CERTIFICATE_DESC, 30 /* validity*/, output)) {
+ loadKeyEntry(osKeyStorePath, storeType);
+ }
+ }
+}
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/KeystoreHelper.java b/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/KeystoreHelper.java
new file mode 100644
index 0000000000..d339ea52af
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/KeystoreHelper.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.internal.build;
+
+import com.android.annotations.Nullable;
+import com.android.sdklib.internal.build.DebugKeyProvider.IKeyGenOutput;
+import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException;
+import com.android.utils.GrabProcessOutput;
+import com.android.utils.GrabProcessOutput.IProcessOutput;
+import com.android.utils.GrabProcessOutput.Wait;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+
+/**
+ * A Helper to create new keystore/key.
+ *
+ * @deprecated Use Android-Builder instead
+ */
+@Deprecated
+public final class KeystoreHelper {
+
+ /**
+ * Creates a new store
+ * @param osKeyStorePath the location of the store
+ * @param storeType an optional keystore type, or <code>null</code> if the default is to
+ * be used.
+ * @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
+ * of the keytool process call.
+ * @throws KeyStoreException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ * @throws UnrecoverableEntryException
+ * @throws IOException
+ * @throws KeytoolException
+ */
+ public static boolean createNewStore(
+ String osKeyStorePath,
+ String storeType,
+ String storePassword,
+ String alias,
+ String keyPassword,
+ String description,
+ int validityYears,
+ final IKeyGenOutput output)
+ throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
+ UnrecoverableEntryException, IOException, KeytoolException {
+
+ // get the executable name of keytool depending on the platform.
+ String os = System.getProperty("os.name");
+
+ String keytoolCommand;
+ if (os.startsWith("Windows")) {
+ keytoolCommand = "keytool.exe";
+ } else {
+ keytoolCommand = "keytool";
+ }
+
+ String javaHome = System.getProperty("java.home");
+
+ if (javaHome != null && javaHome.length() > 0) {
+ keytoolCommand = javaHome + File.separator + "bin" + File.separator + keytoolCommand;
+ }
+
+ // create the command line to call key tool to build the key with no user input.
+ ArrayList<String> commandList = new ArrayList<String>();
+ commandList.add(keytoolCommand);
+ commandList.add("-genkey");
+ commandList.add("-alias");
+ commandList.add(alias);
+ commandList.add("-keyalg");
+ commandList.add("RSA");
+ commandList.add("-dname");
+ commandList.add(description);
+ commandList.add("-validity");
+ commandList.add(Integer.toString(validityYears * 365));
+ commandList.add("-keypass");
+ commandList.add(keyPassword);
+ commandList.add("-keystore");
+ commandList.add(osKeyStorePath);
+ commandList.add("-storepass");
+ commandList.add(storePassword);
+ if (storeType != null) {
+ commandList.add("-storetype");
+ commandList.add(storeType);
+ }
+
+ String[] commandArray = commandList.toArray(new String[commandList.size()]);
+
+ // launch the command line process
+ int result = 0;
+ try {
+ Process process = Runtime.getRuntime().exec(commandArray);
+ result = GrabProcessOutput.grabProcessOutput(
+ process,
+ Wait.WAIT_FOR_READERS,
+ new IProcessOutput() {
+ @Override
+ public void out(@Nullable String line) {
+ if (line != null) {
+ if (output != null) {
+ output.out(line);
+ } else {
+ System.out.println(line);
+ }
+ }
+ }
+
+ @Override
+ public void err(@Nullable String line) {
+ if (line != null) {
+ if (output != null) {
+ output.err(line);
+ } else {
+ System.err.println(line);
+ }
+ }
+ }
+ });
+ } catch (Exception e) {
+ // create the command line as one string for debugging purposes
+ StringBuilder builder = new StringBuilder();
+ boolean firstArg = true;
+ for (String arg : commandArray) {
+ boolean hasSpace = arg.indexOf(' ') != -1;
+
+ if (firstArg == true) {
+ firstArg = false;
+ } else {
+ builder.append(' ');
+ }
+
+ if (hasSpace) {
+ builder.append('"');
+ }
+
+ builder.append(arg);
+
+ if (hasSpace) {
+ builder.append('"');
+ }
+ }
+
+ throw new KeytoolException("Failed to create key: " + e.getMessage(),
+ javaHome, builder.toString());
+ }
+
+ if (result != 0) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/SignedJarBuilder.java b/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/SignedJarBuilder.java
new file mode 100644
index 0000000000..2faba6ae02
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/sdklib/internal/build/SignedJarBuilder.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.internal.build;
+
+import com.android.SdkConstants;
+import com.android.sdklib.internal.build.SignedJarBuilder.IZipEntryFilter.ZipAbortException;
+
+import sun.misc.BASE64Encoder;
+import sun.security.pkcs.ContentInfo;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.X500Name;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.security.DigestOutputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * A Jar file builder with signature support.
+ *
+ * @deprecated Use Android-Builder instead
+ */
+@Deprecated
+public class SignedJarBuilder {
+ private static final String DIGEST_ALGORITHM = "SHA1";
+ private static final String DIGEST_ATTR = "SHA1-Digest";
+ private static final String DIGEST_MANIFEST_ATTR = "SHA1-Digest-Manifest";
+
+ /** Write to another stream and also feed it to the Signature object. */
+ private static class SignatureOutputStream extends FilterOutputStream {
+ private Signature mSignature;
+ private int mCount = 0;
+
+ public SignatureOutputStream(OutputStream out, Signature sig) {
+ super(out);
+ mSignature = sig;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ try {
+ mSignature.update((byte) b);
+ } catch (SignatureException e) {
+ throw new IOException("SignatureException: " + e);
+ }
+ super.write(b);
+ mCount++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ try {
+ mSignature.update(b, off, len);
+ } catch (SignatureException e) {
+ throw new IOException("SignatureException: " + e);
+ }
+ super.write(b, off, len);
+ mCount += len;
+ }
+
+ public int size() {
+ return mCount;
+ }
+ }
+
+ private JarOutputStream mOutputJar;
+ private PrivateKey mKey;
+ private X509Certificate mCertificate;
+ private Manifest mManifest;
+ private BASE64Encoder mBase64Encoder;
+ private MessageDigest mMessageDigest;
+
+ private byte[] mBuffer = new byte[4096];
+
+ /**
+ * Classes which implement this interface provides a method to check whether a file should
+ * be added to a Jar file.
+ */
+ public interface IZipEntryFilter {
+
+ /**
+ * An exception thrown during packaging of a zip file into APK file.
+ * This is typically thrown by implementations of
+ * {@link IZipEntryFilter#checkEntry(String)}.
+ */
+ public static class ZipAbortException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public ZipAbortException() {
+ super();
+ }
+
+ public ZipAbortException(String format, Object... args) {
+ super(String.format(format, args));
+ }
+
+ public ZipAbortException(Throwable cause, String format, Object... args) {
+ super(String.format(format, args), cause);
+ }
+
+ public ZipAbortException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+
+ /**
+ * Checks a file for inclusion in a Jar archive.
+ * @param archivePath the archive file path of the entry
+ * @return <code>true</code> if the file should be included.
+ * @throws ZipAbortException if writing the file should be aborted.
+ */
+ public boolean checkEntry(String archivePath) throws ZipAbortException;
+ }
+
+ /**
+ * Creates a {@link SignedJarBuilder} with a given output stream, and signing information.
+ * <p/>If either <code>key</code> or <code>certificate</code> is <code>null</code> then
+ * the archive will not be signed.
+ * @param out the {@link OutputStream} where to write the Jar archive.
+ * @param key the {@link PrivateKey} used to sign the archive, or <code>null</code>.
+ * @param certificate the {@link X509Certificate} used to sign the archive, or
+ * <code>null</code>.
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ */
+ public SignedJarBuilder(OutputStream out, PrivateKey key, X509Certificate certificate)
+ throws IOException, NoSuchAlgorithmException {
+ mOutputJar = new JarOutputStream(new BufferedOutputStream(out));
+ mOutputJar.setLevel(9);
+ mKey = key;
+ mCertificate = certificate;
+
+ if (mKey != null && mCertificate != null) {
+ mManifest = new Manifest();
+ Attributes main = mManifest.getMainAttributes();
+ main.putValue("Manifest-Version", "1.0");
+ main.putValue("Created-By", "1.0 (Android)");
+
+ mBase64Encoder = new BASE64Encoder();
+ mMessageDigest = MessageDigest.getInstance(DIGEST_ALGORITHM);
+ }
+ }
+
+ /**
+ * Writes a new {@link File} into the archive.
+ * @param inputFile the {@link File} to write.
+ * @param jarPath the filepath inside the archive.
+ * @throws IOException
+ */
+ public void writeFile(File inputFile, String jarPath) throws IOException {
+ // Get an input stream on the file.
+ FileInputStream fis = new FileInputStream(inputFile);
+ try {
+
+ // create the zip entry
+ JarEntry entry = new JarEntry(jarPath);
+ entry.setTime(inputFile.lastModified());
+
+ writeEntry(fis, entry);
+ } finally {
+ // close the file stream used to read the file
+ fis.close();
+ }
+ }
+
+ /**
+ * Copies the content of a Jar/Zip archive into the receiver archive.
+ * <p/>An optional {@link IZipEntryFilter} allows to selectively choose which files
+ * to copy over.
+ * @param input the {@link InputStream} for the Jar/Zip to copy.
+ * @param filter the filter or <code>null</code>
+ * @throws IOException
+ * @throws ZipAbortException if the {@link IZipEntryFilter} filter indicated that the write
+ * must be aborted.
+ */
+ public void writeZip(InputStream input, IZipEntryFilter filter)
+ throws IOException, ZipAbortException {
+ ZipInputStream zis = new ZipInputStream(input);
+
+ try {
+ // loop on the entries of the intermediary package and put them in the final package.
+ ZipEntry entry;
+ while ((entry = zis.getNextEntry()) != null) {
+ String name = entry.getName();
+
+ // do not take directories or anything inside a potential META-INF folder.
+ if (entry.isDirectory() || name.startsWith("META-INF/")) {
+ continue;
+ }
+
+ // if we have a filter, we check the entry against it
+ if (filter != null && filter.checkEntry(name) == false) {
+ continue;
+ }
+
+ JarEntry newEntry;
+
+ // Preserve the STORED method of the input entry.
+ if (entry.getMethod() == JarEntry.STORED) {
+ newEntry = new JarEntry(entry);
+ } else {
+ // Create a new entry so that the compressed len is recomputed.
+ newEntry = new JarEntry(name);
+ }
+
+ writeEntry(zis, newEntry);
+
+ zis.closeEntry();
+ }
+ } finally {
+ zis.close();
+ }
+ }
+
+ /**
+ * Closes the Jar archive by creating the manifest, and signing the archive.
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ public void close() throws IOException, GeneralSecurityException {
+ if (mManifest != null) {
+ // write the manifest to the jar file
+ mOutputJar.putNextEntry(new JarEntry(JarFile.MANIFEST_NAME));
+ mManifest.write(mOutputJar);
+
+ // CERT.SF
+ Signature signature = Signature.getInstance("SHA1with" + mKey.getAlgorithm());
+ signature.initSign(mKey);
+ mOutputJar.putNextEntry(new JarEntry("META-INF/CERT.SF"));
+ SignatureOutputStream out = new SignatureOutputStream(mOutputJar, signature);
+ writeSignatureFile(out);
+
+ // CERT.*
+ mOutputJar.putNextEntry(new JarEntry("META-INF/CERT." + mKey.getAlgorithm()));
+ writeSignatureBlock(signature, mCertificate, mKey);
+
+ // close out at the end because it can also close mOutputJar.
+ // (there's some timing issue here I think, because it's worked before with out
+ // being closed after writing CERT.SF).
+ out.close();
+ }
+
+ mOutputJar.close();
+ mOutputJar = null;
+ }
+
+ /**
+ * Clean up of the builder for interrupted workflow.
+ * This does nothing if {@link #close()} was called successfully.
+ */
+ public void cleanUp() {
+ if (mOutputJar != null) {
+ try {
+ mOutputJar.close();
+ } catch (IOException e) {
+ // pass
+ }
+ }
+ }
+
+ /**
+ * Adds an entry to the output jar, and write its content from the {@link InputStream}
+ * @param input The input stream from where to write the entry content.
+ * @param entry the entry to write in the jar.
+ * @throws IOException
+ */
+ private void writeEntry(InputStream input, JarEntry entry) throws IOException {
+ // add the entry to the jar archive
+ mOutputJar.putNextEntry(entry);
+
+ // read the content of the entry from the input stream, and write it into the archive.
+ int count;
+ while ((count = input.read(mBuffer)) != -1) {
+ mOutputJar.write(mBuffer, 0, count);
+
+ // update the digest
+ if (mMessageDigest != null) {
+ mMessageDigest.update(mBuffer, 0, count);
+ }
+ }
+
+ // close the entry for this file
+ mOutputJar.closeEntry();
+
+ if (mManifest != null) {
+ // update the manifest for this entry.
+ Attributes attr = mManifest.getAttributes(entry.getName());
+ if (attr == null) {
+ attr = new Attributes();
+ mManifest.getEntries().put(entry.getName(), attr);
+ }
+ attr.putValue(DIGEST_ATTR, mBase64Encoder.encode(mMessageDigest.digest()));
+ }
+ }
+
+ /** Writes a .SF file with a digest to the manifest. */
+ private void writeSignatureFile(SignatureOutputStream out)
+ throws IOException, GeneralSecurityException {
+ Manifest sf = new Manifest();
+ Attributes main = sf.getMainAttributes();
+ main.putValue("Signature-Version", "1.0");
+ main.putValue("Created-By", "1.0 (Android)");
+
+ BASE64Encoder base64 = new BASE64Encoder();
+ MessageDigest md = MessageDigest.getInstance(DIGEST_ALGORITHM);
+ PrintStream print = new PrintStream(
+ new DigestOutputStream(new ByteArrayOutputStream(), md),
+ true, SdkConstants.UTF_8);
+
+ // Digest of the entire manifest
+ mManifest.write(print);
+ print.flush();
+ main.putValue(DIGEST_MANIFEST_ATTR, base64.encode(md.digest()));
+
+ Map<String, Attributes> entries = mManifest.getEntries();
+ for (Map.Entry<String, Attributes> entry : entries.entrySet()) {
+ // Digest of the manifest stanza for this entry.
+ print.print("Name: " + entry.getKey() + "\r\n");
+ for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {
+ print.print(att.getKey() + ": " + att.getValue() + "\r\n");
+ }
+ print.print("\r\n");
+ print.flush();
+
+ Attributes sfAttr = new Attributes();
+ sfAttr.putValue(DIGEST_ATTR, base64.encode(md.digest()));
+ sf.getEntries().put(entry.getKey(), sfAttr);
+ }
+
+ sf.write(out);
+
+ // A bug in the java.util.jar implementation of Android platforms
+ // up to version 1.6 will cause a spurious IOException to be thrown
+ // if the length of the signature file is a multiple of 1024 bytes.
+ // As a workaround, add an extra CRLF in this case.
+ if ((out.size() % 1024) == 0) {
+ out.write('\r');
+ out.write('\n');
+ }
+ }
+
+ /** Write the certificate file with a digital signature. */
+ private void writeSignatureBlock(Signature signature, X509Certificate publicKey,
+ PrivateKey privateKey)
+ throws IOException, GeneralSecurityException {
+ SignerInfo signerInfo = new SignerInfo(
+ new X500Name(publicKey.getIssuerX500Principal().getName()),
+ publicKey.getSerialNumber(),
+ AlgorithmId.get(DIGEST_ALGORITHM),
+ AlgorithmId.get(privateKey.getAlgorithm()),
+ signature.sign());
+
+ PKCS7 pkcs7 = new PKCS7(
+ new AlgorithmId[] { AlgorithmId.get(DIGEST_ALGORITHM) },
+ new ContentInfo(ContentInfo.DATA_OID, null),
+ new X509Certificate[] { publicKey },
+ new SignerInfo[] { signerInfo });
+
+ pkcs7.encodeSignedData(mOutputJar);
+ }
+}
diff --git a/third_party/java/apkbuilder/java/com/android/utils/GrabProcessOutput.java b/third_party/java/apkbuilder/java/com/android/utils/GrabProcessOutput.java
new file mode 100644
index 0000000000..d5cd78b4ad
--- /dev/null
+++ b/third_party/java/apkbuilder/java/com/android/utils/GrabProcessOutput.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.utils;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.google.common.io.Closeables;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class GrabProcessOutput {
+
+ public enum Wait {
+ /**
+ * Doesn't wait for the exec to complete.
+ * This still monitors the output but does not wait for the process to finish.
+ * In this mode the process return code is unknown and always 0.
+ */
+ ASYNC,
+ /**
+ * This waits for the process to finish.
+ * In this mode, {@link GrabProcessOutput#grabProcessOutput} returns the
+ * error code from the process.
+ * In some rare cases and depending on the OS, the process might not have
+ * finished dumping data into stdout/stderr.
+ * <p/>
+ * Use this when you don't particularly care for the output but instead
+ * care for the return code of the executed process.
+ */
+ WAIT_FOR_PROCESS,
+ /**
+ * This waits for the process to finish <em>and</em> for the stdout/stderr
+ * threads to complete.
+ * In this mode, {@link GrabProcessOutput#grabProcessOutput} returns the
+ * error code from the process.
+ * <p/>
+ * Use this one when capturing all the output from the process is important.
+ */
+ WAIT_FOR_READERS,
+ }
+
+ public interface IProcessOutput {
+ /**
+ * Processes an stdout message line.
+ * @param line The stdout message line. Null when the reader reached the end of stdout.
+ */
+ public void out(@Nullable String line);
+ /**
+ * Processes an stderr message line.
+ * @param line The stderr message line. Null when the reader reached the end of stderr.
+ */
+ public void err(@Nullable String line);
+ }
+
+ /**
+ * Get the stderr/stdout outputs of a process and return when the process is done.
+ * Both <b>must</b> be read or the process will block on windows.
+ *
+ * @param process The process to get the output from.
+ * @param output Optional object to capture stdout/stderr.
+ * Note that on Windows capturing the output is not optional. If output is null
+ * the stdout/stderr will be captured and discarded.
+ * @param waitMode Whether to wait for the process and/or the readers to finish.
+ * @return the process return code.
+ * @throws InterruptedException if {@link Process#waitFor()} was interrupted.
+ */
+ public static int grabProcessOutput(
+ @NonNull final Process process,
+ Wait waitMode,
+ @Nullable final IProcessOutput output) throws InterruptedException {
+ // read the lines as they come. if null is returned, it's
+ // because the process finished
+ Thread threadErr = new Thread("stderr") {
+ @Override
+ public void run() {
+ // create a buffer to read the stderr output
+ InputStream is = process.getErrorStream();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader errReader = new BufferedReader(isr);
+
+ try {
+ while (true) {
+ String line = errReader.readLine();
+ if (output != null) {
+ output.err(line);
+ }
+ if (line == null) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ // do nothing.
+ } finally {
+ try {
+ Closeables.close(is, true /* swallowIOException */);
+ } catch (IOException e) {
+ // cannot happen
+ }
+ try {
+ Closeables.close(isr, true /* swallowIOException */);
+ } catch (IOException e) {
+ // cannot happen
+ }
+ try {
+ Closeables.close(errReader, true /* swallowIOException */);
+ } catch (IOException e) {
+ // cannot happen
+ }
+ }
+ }
+ };
+
+ Thread threadOut = new Thread("stdout") {
+ @Override
+ public void run() {
+ InputStream is = process.getInputStream();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader outReader = new BufferedReader(isr);
+
+ try {
+ while (true) {
+ String line = outReader.readLine();
+ if (output != null) {
+ output.out(line);
+ }
+ if (line == null) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ // do nothing.
+ } finally {
+ try {
+ Closeables.close(is, true /* swallowIOException */);
+ } catch (IOException e) {
+ // cannot happen
+ }
+ try {
+ Closeables.close(isr, true /* swallowIOException */);
+ } catch (IOException e) {
+ // cannot happen
+ }
+ try {
+ Closeables.close(outReader, true /* swallowIOException */);
+ } catch (IOException e) {
+ // cannot happen
+ }
+ }
+ }
+ };
+
+ threadErr.start();
+ threadOut.start();
+
+ if (waitMode == Wait.ASYNC) {
+ return 0;
+ }
+
+ // it looks like on windows process#waitFor() can return
+ // before the thread have filled the arrays, so we wait for both threads and the
+ // process itself.
+ if (waitMode == Wait.WAIT_FOR_READERS) {
+ try {
+ threadErr.join();
+ } catch (InterruptedException e) {
+ }
+ try {
+ threadOut.join();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ // get the return code from the process
+ return process.waitFor();
+ }
+}