diff options
Diffstat (limited to 'common/src/main/java/com')
21 files changed, 4141 insertions, 0 deletions
diff --git a/common/src/main/java/com/android/SdkConstants.java b/common/src/main/java/com/android/SdkConstants.java new file mode 100644 index 0000000..48cecc1 --- /dev/null +++ b/common/src/main/java/com/android/SdkConstants.java @@ -0,0 +1,1162 @@ +/* + * 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(); + + /** + * Charset for the ini file handled by the SDK. + */ + public static final String INI_CHARSET = "UTF-8"; //$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$ + + /** 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$ + + /** 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$ + + /** 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$ + + /** 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$ + + /** + * filename for gdbserver. + */ + public static final String FN_GDBSERVER = "gdbserver"; //$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 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$ + + /* 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 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_INTEL_ATOM = "x86"; //$NON-NLS-1$ + public static final String ABI_MIPS = "mips"; //$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_INTEL_ATOM = "x86"; //$NON-NLS-1$ + public static final String CPU_ARCH_MIPS = "mips"; //$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$ + /** + * 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 */ + 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 for the device schema, i.e. "http://schemas.android.com/sdk/devices/1" */ + public static final String NS_DEVICES_XSD = + "http://schemas.android.com/sdk/devices/1"; //$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 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$ + + /* 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_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$ + /** 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 = "&"; //$NON-NLS-1$ + /** The entity for the quote character */ + public static final String QUOT_ENTITY = """; //$NON-NLS-1$ + /** The entity for the apostrophe character */ + public static final String APOS_ENTITY = "'"; //$NON-NLS-1$ + /** The entity for the less than character */ + public static final String LT_ENTITY = "<"; //$NON-NLS-1$ + /** The entity for the greater than character */ + public static final String GT_ENTITY = ">"; //$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_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_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$ + + // 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 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$ + + // Attributes: Resources + public static final String ATTR_NAME = "name"; //$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$ + + // 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_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$ + + // 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_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_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_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_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_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_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: 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$ + + + /** 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 jar files, i.e. "jar" */ + public static final String EXT_JAR = "jar"; //$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 FilterScript files, i.e. "fs" */ + public static final String EXT_FS = "fs"; //$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$ + + private final static 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 FilterScript files, i.e. ".fs" */ + public static final String DOT_FS = DOT + EXT_FS; + /** 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$ + + /** 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; + /** Manifest java class filename, i.e. "Manifest.java" */ + public static final String FN_MANIFEST_CLASS = "Manifest.java"; //$NON-NLS-1$ + + 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_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 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 ANDROID_STRING_PREFIX = "@android:string/"; //$NON-NLS-1$ + public static final String ANDROID_LAYOUT_RESOURCE_PREFIX = "@android:layout/"; //$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 ANDROID_STYLE_RESOURCE_PREFIX = "@android:style/"; //$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_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$ + + // 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_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_LEFT = "left"; //$NON-NLS-1$ + public static final String VALUE_RIGHT = "right"; //$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_RIGHT = "right"; //$NON-NLS-1$ + public static final String GRAVITY_VALUE_LEFT = "left"; //$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$ + + /** + * The highest known API level. Note that the tools may also look at the + * installed platforms to see if they can find more recently released + * platforms, e.g. when the tools have not yet been updated for a new + * release. This number is used as a baseline and any more recent platforms + * found can be used to increase the highest known number. + */ + public static final int HIGHEST_KNOWN_API = 17; +} diff --git a/common/src/main/java/com/android/annotations/NonNull.java b/common/src/main/java/com/android/annotations/NonNull.java new file mode 100644 index 0000000..973ebb6 --- /dev/null +++ b/common/src/main/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/common/src/main/java/com/android/annotations/NonNullByDefault.java b/common/src/main/java/com/android/annotations/NonNullByDefault.java new file mode 100644 index 0000000..3db891c --- /dev/null +++ b/common/src/main/java/com/android/annotations/NonNullByDefault.java @@ -0,0 +1,47 @@ +/* + * 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.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Denotes that all parameters, fields or methods within a class or method by + * default can not be null. This can be overridden by adding specific + * {@link com.android.annotations.Nullable} annotations on fields, parameters or + * methods that should not use the default. + * <p/> + * NOTE: Eclipse does not yet handle defaults well (in particular, if + * you add this on a class which implements Comparable, then it will insist + * that your compare method is changing the nullness of the compare parameter, + * so you'll need to add @Nullable on it, which also is not right (since + * the method should have implied @NonNull and you do not need to check + * the parameter.). For now, it's best to individually annotate methods, + * parameters and fields. + * <p/> + * This is a marker annotation and it has no specific attributes. + */ +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({PACKAGE, TYPE}) +public @interface NonNullByDefault { +} diff --git a/common/src/main/java/com/android/annotations/Nullable.java b/common/src/main/java/com/android/annotations/Nullable.java new file mode 100755 index 0000000..d9c3861 --- /dev/null +++ b/common/src/main/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/common/src/main/java/com/android/annotations/VisibleForTesting.java b/common/src/main/java/com/android/annotations/VisibleForTesting.java new file mode 100755 index 0000000..7f41d70 --- /dev/null +++ b/common/src/main/java/com/android/annotations/VisibleForTesting.java @@ -0,0 +1,50 @@ +/* + * 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 java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Denotes that the class, method or field has its visibility relaxed so + * that unit tests can access it. + * <p/> + * The <code>visibility</code> argument can be used to specific what the original + * visibility should have been if it had not been made public or package-private for testing. + * The default is to consider the element private. + */ +@Retention(RetentionPolicy.SOURCE) +public @interface VisibleForTesting { + /** + * Intended visibility if the element had not been made public or package-private for + * testing. + */ + enum Visibility { + /** The element should be considered protected. */ + PROTECTED, + /** The element should be considered package-private. */ + PACKAGE, + /** The element should be considered private. */ + PRIVATE + } + + /** + * Intended visibility if the element had not been made public or package-private for testing. + * If not specified, one should assume the element originally intended to be private. + */ + Visibility visibility() default Visibility.PRIVATE; +} diff --git a/common/src/main/java/com/android/io/FileWrapper.java b/common/src/main/java/com/android/io/FileWrapper.java new file mode 100644 index 0000000..8be7859 --- /dev/null +++ b/common/src/main/java/com/android/io/FileWrapper.java @@ -0,0 +1,158 @@ +/* + * 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.io; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; + +/** + * An implementation of {@link IAbstractFile} extending {@link File}. + */ +public class FileWrapper extends File implements IAbstractFile { + private static final long serialVersionUID = 1L; + + /** + * Creates a new File instance matching a given {@link File} object. + * @param file the file to match + */ + public FileWrapper(File file) { + super(file.getAbsolutePath()); + } + + /** + * Creates a new File instance from a parent abstract pathname and a child pathname string. + * @param parent the parent pathname + * @param child the child name + * + * @see File#File(File, String) + */ + public FileWrapper(File parent, String child) { + super(parent, child); + } + + /** + * Creates a new File instance by converting the given pathname string into an abstract + * pathname. + * @param osPathname the OS pathname + * + * @see File#File(String) + */ + public FileWrapper(String osPathname) { + super(osPathname); + } + + /** + * Creates a new File instance from a parent abstract pathname and a child pathname string. + * @param parent the parent pathname + * @param child the child name + * + * @see File#File(String, String) + */ + public FileWrapper(String parent, String child) { + super(parent, child); + } + + /** + * Creates a new File instance by converting the given <code>file:</code> URI into an + * abstract pathname. + * @param uri An absolute, hierarchical URI with a scheme equal to "file", a non-empty path + * component, and undefined authority, query, and fragment components + * + * @see File#File(URI) + */ + public FileWrapper(URI uri) { + super(uri); + } + + @Override + public InputStream getContents() throws StreamException { + try { + return new FileInputStream(this); + } catch (FileNotFoundException e) { + throw new StreamException(e, this, StreamException.Error.FILENOTFOUND); + } + } + + @Override + public void setContents(InputStream source) throws StreamException { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(this); + + byte[] buffer = new byte[1024]; + int count = 0; + while ((count = source.read(buffer)) != -1) { + fos.write(buffer, 0, count); + } + } catch (IOException e) { + throw new StreamException(e, this); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + throw new StreamException(e, this); + } + } + } + } + + @Override + public OutputStream getOutputStream() throws StreamException { + try { + return new FileOutputStream(this); + } catch (FileNotFoundException e) { + throw new StreamException(e, this); + } + } + + @Override + public PreferredWriteMode getPreferredWriteMode() { + return PreferredWriteMode.OUTPUTSTREAM; + } + + @Override + public String getOsLocation() { + return getAbsolutePath(); + } + + @Override + public boolean exists() { + return isFile(); + } + + @Override + public long getModificationStamp() { + return lastModified(); + } + + @Override + public IAbstractFolder getParentFolder() { + String p = this.getParent(); + if (p == null) { + return null; + } + return new FolderWrapper(p); + } +} diff --git a/common/src/main/java/com/android/io/FolderWrapper.java b/common/src/main/java/com/android/io/FolderWrapper.java new file mode 100644 index 0000000..c29c934 --- /dev/null +++ b/common/src/main/java/com/android/io/FolderWrapper.java @@ -0,0 +1,162 @@ +/* + * 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.io; + + +import java.io.File; +import java.net.URI; +import java.util.ArrayList; + +/** + * An implementation of {@link IAbstractFolder} extending {@link File}. + */ +public class FolderWrapper extends File implements IAbstractFolder { + + private static final long serialVersionUID = 1L; + + /** + * Creates a new File instance from a parent abstract pathname and a child pathname string. + * @param parent the parent pathname + * @param child the child name + * + * @see File#File(File, String) + */ + public FolderWrapper(File parent, String child) { + super(parent, child); + } + + /** + * Creates a new File instance by converting the given pathname string into an abstract + * pathname. + * @param pathname the pathname + * + * @see File#File(String) + */ + public FolderWrapper(String pathname) { + super(pathname); + } + + /** + * Creates a new File instance from a parent abstract pathname and a child pathname string. + * @param parent the parent pathname + * @param child the child name + * + * @see File#File(String, String) + */ + public FolderWrapper(String parent, String child) { + super(parent, child); + } + + /** + * Creates a new File instance by converting the given <code>file:</code> URI into an + * abstract pathname. + * @param uri An absolute, hierarchical URI with a scheme equal to "file", a non-empty path + * component, and undefined authority, query, and fragment components + * + * @see File#File(URI) + */ + public FolderWrapper(URI uri) { + super(uri); + } + + /** + * Creates a new File instance matching a give {@link File} object. + * @param file the file to match + */ + public FolderWrapper(File file) { + super(file.getAbsolutePath()); + } + + @Override + public IAbstractResource[] listMembers() { + File[] files = listFiles(); + final int count = files == null ? 0 : files.length; + IAbstractResource[] afiles = new IAbstractResource[count]; + + if (files != null) { + for (int i = 0 ; i < count ; i++) { + File f = files[i]; + if (f.isFile()) { + afiles[i] = new FileWrapper(f); + } else if (f.isDirectory()) { + afiles[i] = new FolderWrapper(f); + } + } + } + + return afiles; + } + + @Override + public boolean hasFile(final String name) { + String[] match = list(new FilenameFilter() { + @Override + public boolean accept(IAbstractFolder dir, String filename) { + return name.equals(filename); + } + }); + + return match.length > 0; + } + + @Override + public IAbstractFile getFile(String name) { + return new FileWrapper(this, name); + } + + @Override + public IAbstractFolder getFolder(String name) { + return new FolderWrapper(this, name); + } + + @Override + public IAbstractFolder getParentFolder() { + String p = this.getParent(); + if (p == null) { + return null; + } + return new FolderWrapper(p); + } + + @Override + public String getOsLocation() { + return getAbsolutePath(); + } + + @Override + public boolean exists() { + return isDirectory(); + } + + @Override + public String[] list(FilenameFilter filter) { + File[] files = listFiles(); + if (files != null && files.length > 0) { + ArrayList<String> list = new ArrayList<String>(); + + for (File file : files) { + if (filter.accept(this, file.getName())) { + list.add(file.getName()); + } + } + + return list.toArray(new String[list.size()]); + } + + return new String[0]; + } +} diff --git a/common/src/main/java/com/android/io/IAbstractFile.java b/common/src/main/java/com/android/io/IAbstractFile.java new file mode 100644 index 0000000..6dfc8d8 --- /dev/null +++ b/common/src/main/java/com/android/io/IAbstractFile.java @@ -0,0 +1,58 @@ +/* + * 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.io; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * A file. + */ +public interface IAbstractFile extends IAbstractResource { + public static enum PreferredWriteMode { + INPUTSTREAM, OUTPUTSTREAM; + } + + /** + * Returns an {@link InputStream} object on the file content. + * @throws StreamException + */ + InputStream getContents() throws StreamException; + + /** + * Sets the content of the file. + * @param source the content + * @throws StreamException + */ + void setContents(InputStream source) throws StreamException; + + /** + * Returns an {@link OutputStream} to write into the file. + * @throws StreamException + */ + OutputStream getOutputStream() throws StreamException; + + /** + * Returns the preferred mode to write into the file. + */ + PreferredWriteMode getPreferredWriteMode(); + + /** + * Returns the last modification timestamp + */ + long getModificationStamp(); +} diff --git a/common/src/main/java/com/android/io/IAbstractFolder.java b/common/src/main/java/com/android/io/IAbstractFolder.java new file mode 100644 index 0000000..8335ef9 --- /dev/null +++ b/common/src/main/java/com/android/io/IAbstractFolder.java @@ -0,0 +1,77 @@ +/* + * 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.io; + +import java.io.File; + +/** + * A folder. + */ +public interface IAbstractFolder extends IAbstractResource { + /** + * Instances of classes that implement this interface are used to + * filter filenames. + */ + public interface FilenameFilter { + /** + * Tests if a specified file should be included in a file list. + * + * @param dir the directory in which the file was found. + * @param name the name of the file. + * @return <code>true</code> if and only if the name should be + * included in the file list; <code>false</code> otherwise. + */ + boolean accept(IAbstractFolder dir, String name); + } + + /** + * Returns true if the receiver contains a file with a given name + * @param name the name of the file. This is the name without the path leading to the + * parent folder. + */ + boolean hasFile(String name); + + /** + * Returns an {@link IAbstractFile} representing a child of the current folder with the + * given name. The file may not actually exist. + * @param name the name of the file. + */ + IAbstractFile getFile(String name); + + /** + * Returns an {@link IAbstractFolder} representing a child of the current folder with the + * given name. The folder may not actually exist. + * @param name the name of the folder. + */ + IAbstractFolder getFolder(String name); + + /** + * Returns a list of all existing file and directory members in this folder. + * The returned array can be empty but is never null. + */ + IAbstractResource[] listMembers(); + + /** + * Returns a list of all existing file and directory members in this folder + * that satisfy the specified filter. + * + * @param filter A filename filter instance. Must not be null. + * @return An array of file names (generated using {@link File#getName()}). + * The array can be empty but is never null. + */ + String[] list(FilenameFilter filter); +} diff --git a/common/src/main/java/com/android/io/IAbstractResource.java b/common/src/main/java/com/android/io/IAbstractResource.java new file mode 100644 index 0000000..e6358ec --- /dev/null +++ b/common/src/main/java/com/android/io/IAbstractResource.java @@ -0,0 +1,50 @@ +/* + * 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.io; + +/** + * Base representation of a file system resource.<p/> + * This somewhat limited interface is designed to let classes use file-system resources, without + * having the manually handle either the standard Java file or the Eclipse file API.. + */ +public interface IAbstractResource { + + /** + * Returns the name of the resource. + */ + String getName(); + + /** + * Returns the OS path of the folder location. + */ + String getOsLocation(); + + /** + * Returns whether the resource actually exists. + */ + boolean exists(); + + /** + * Returns the parent folder or null if there is no parent. + */ + IAbstractFolder getParentFolder(); + + /** + * Deletes the resource. + */ + boolean delete(); +} diff --git a/common/src/main/java/com/android/io/StreamException.java b/common/src/main/java/com/android/io/StreamException.java new file mode 100644 index 0000000..9f632f4 --- /dev/null +++ b/common/src/main/java/com/android/io/StreamException.java @@ -0,0 +1,50 @@ +/* + * 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.io; + + +/** + * Exception thrown when {@link IAbstractFile#getContents()} fails. + */ +public class StreamException extends Exception { + private static final long serialVersionUID = 1L; + + public static enum Error { + DEFAULT, OUTOFSYNC, FILENOTFOUND; + } + + private final Error mError; + private final IAbstractFile mFile; + + public StreamException(Exception e, IAbstractFile file) { + this(e, file, Error.DEFAULT); + } + + public StreamException(Exception e, IAbstractFile file, Error error) { + super(e); + mFile = file; + mError = error; + } + + public Error getError() { + return mError; + } + + public IAbstractFile getFile() { + return mFile; + } +} diff --git a/common/src/main/java/com/android/prefs/AndroidLocation.java b/common/src/main/java/com/android/prefs/AndroidLocation.java new file mode 100644 index 0000000..6af8e9b --- /dev/null +++ b/common/src/main/java/com/android/prefs/AndroidLocation.java @@ -0,0 +1,128 @@ +/* + * 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; + + /** + * Returns the folder used to store android related files. + * @return an OS specific path, terminated by a separator. + * @throws AndroidLocationException + */ + @NonNull public final static String getFolder() throws AndroidLocationException { + if (sPrefsLocation == null) { + String home = findValidPath("ANDROID_SDK_HOME", "user.home", "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 final static 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 names + * @return the content of the first property/variable. + */ + private static String findValidPath(String... names) { + for (String name : names) { + String path; + if (name.indexOf('.') != -1) { + path = System.getProperty(name); + } else { + path = System.getenv(name); + } + + if (path != null) { + File f = new File(path); + if (f.isDirectory()) { + return path; + } + } + } + + return null; + } +} diff --git a/common/src/main/java/com/android/utils/ILogger.java b/common/src/main/java/com/android/utils/ILogger.java new file mode 100644 index 0000000..7df5d10 --- /dev/null +++ b/common/src/main/java/com/android/utils/ILogger.java @@ -0,0 +1,77 @@ +/* + * 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 java.util.Formatter; + +/** + * Interface used to display warnings/errors while parsing the SDK content. + * <p/> + * There are a few default implementations available: + * <ul> + * <li> {@link NullLogger} is an implementation that does <em>nothing</em> with the log. + * Useful for limited cases where you need to call a class that requires a non-null logging + * yet the calling code does not have any mean of reporting logs itself. It can be + * acceptable for use as a temporary implementation but most of the time that means the caller + * code needs to be reworked to take a logger object from its own caller. + * </li> + * <li> {@link StdLogger} is an implementation that dumps the log to {@link System#out} or + * {@link System#err}. This is useful for unit tests or code that does not have any GUI. + * GUI based apps based should not use it and should provide a better way to report to the user. + * </li> + * </ul> + */ +public interface ILogger { + + /** + * Prints an error message. + * + * @param t is an optional {@link Throwable} or {@link Exception}. If non-null, its + * message will be printed out. + * @param msgFormat is an optional error format. If non-null, it will be printed + * using a {@link Formatter} with the provided arguments. + * @param args provides the arguments for errorFormat. + */ + void error(Throwable t, String msgFormat, Object... args); + + /** + * Prints a warning message. + * + * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null. + * @param args provides the arguments for warningFormat. + */ + void warning(@NonNull String msgFormat, Object... args); + + /** + * Prints an information message. + * + * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null. + * @param args provides the arguments for msgFormat. + */ + void info(@NonNull String msgFormat, Object... args); + + /** + * Prints a verbose message. + * + * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null. + * @param args provides the arguments for msgFormat. + */ + void verbose(@NonNull String msgFormat, Object... args); + +} diff --git a/common/src/main/java/com/android/utils/NullLogger.java b/common/src/main/java/com/android/utils/NullLogger.java new file mode 100644 index 0000000..8b1a3d9 --- /dev/null +++ b/common/src/main/java/com/android/utils/NullLogger.java @@ -0,0 +1,54 @@ +/* + * 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; + +/** + * Dummy implementation of an {@link ILogger}. + * <p/> + * Use {@link #getLogger()} to get a default instance of this {@link NullLogger}. + */ +public class NullLogger implements ILogger { + + private static final ILogger sThis = new NullLogger(); + + public static ILogger getLogger() { + return sThis; + } + + @Override + public void error(Throwable t, String errorFormat, Object... args) { + // ignore + } + + @Override + public void warning(@NonNull String warningFormat, Object... args) { + // ignore + } + + @Override + public void info(@NonNull String msgFormat, Object... args) { + // ignore + } + + @Override + public void verbose(@NonNull String msgFormat, Object... args) { + // ignore + } + +} diff --git a/common/src/main/java/com/android/utils/Pair.java b/common/src/main/java/com/android/utils/Pair.java new file mode 100644 index 0000000..63694de --- /dev/null +++ b/common/src/main/java/com/android/utils/Pair.java @@ -0,0 +1,107 @@ +/* + * 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.utils; + +/** + * A Pair class is simply a 2-tuple for use in this package. We might want to + * think about adding something like this to a more central utility place, or + * replace it by a common tuple class if one exists, or even rewrite the layout + * classes using this Pair by a more dedicated data structure (so we don't have + * to pass around generic signatures as is currently done, though at least the + * construction is helped a bit by the {@link #of} factory method. + * + * @param <S> The type of the first value + * @param <T> The type of the second value + */ +public class Pair<S,T> { + private final S mFirst; + private final T mSecond; + + // Use {@link Pair#of} factory instead since it infers generic types + private Pair(S first, T second) { + this.mFirst = first; + this.mSecond = second; + } + + /** + * Return the first item in the pair + * + * @return the first item in the pair + */ + public S getFirst() { + return mFirst; + } + + /** + * Return the second item in the pair + * + * @return the second item in the pair + */ + public T getSecond() { + return mSecond; + } + + /** + * Constructs a new pair of the given two objects, inferring generic types. + * + * @param first the first item to store in the pair + * @param second the second item to store in the pair + * @param <S> the type of the first item + * @param <T> the type of the second item + * @return a new pair wrapping the two items + */ + public static <S,T> Pair<S,T> of(S first, T second) { + return new Pair<S,T>(first,second); + } + + @Override + public String toString() { + return "Pair [first=" + mFirst + ", second=" + mSecond + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mFirst == null) ? 0 : mFirst.hashCode()); + result = prime * result + ((mSecond == null) ? 0 : mSecond.hashCode()); + return result; + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Pair other = (Pair) obj; + if (mFirst == null) { + if (other.mFirst != null) + return false; + } else if (!mFirst.equals(other.mFirst)) + return false; + if (mSecond == null) { + if (other.mSecond != null) + return false; + } else if (!mSecond.equals(other.mSecond)) + return false; + return true; + } +} diff --git a/common/src/main/java/com/android/utils/PositionXmlParser.java b/common/src/main/java/com/android/utils/PositionXmlParser.java new file mode 100644 index 0000000..73574d5 --- /dev/null +++ b/common/src/main/java/com/android/utils/PositionXmlParser.java @@ -0,0 +1,729 @@ +/* + * 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.utils; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +/** + * A simple DOM XML parser which can retrieve exact beginning and end offsets + * (and line and column numbers) for element nodes as well as attribute nodes. + */ +public class PositionXmlParser { + private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$ + private static final String UTF_16 = "UTF_16"; //$NON-NLS-1$ + private static final String UTF_16LE = "UTF_16LE"; //$NON-NLS-1$ + private static final String CONTENT_KEY = "contents"; //$NON-NLS-1$ + private final static String POS_KEY = "offsets"; //$NON-NLS-1$ + private static final String NAMESPACE_PREFIX_FEATURE = + "http://xml.org/sax/features/namespace-prefixes"; //$NON-NLS-1$ + private static final String NAMESPACE_FEATURE = + "http://xml.org/sax/features/namespaces"; //$NON-NLS-1$ + /** See http://www.w3.org/TR/REC-xml/#NT-EncodingDecl */ + private static final Pattern ENCODING_PATTERN = + Pattern.compile("encoding=['\"](\\S*)['\"]");//$NON-NLS-1$ + + /** + * Parses the XML content from the given input stream. + * + * @param input the input stream containing the XML to be parsed + * @return the corresponding document + * @throws ParserConfigurationException if a SAX parser is not available + * @throws SAXException if the document contains a parsing error + * @throws IOException if something is seriously wrong. This should not + * happen since the input source is known to be constructed from + * a string. + */ + @Nullable + public Document parse(@NonNull InputStream input) + throws ParserConfigurationException, SAXException, IOException { + // Read in all the data + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + while (true) { + int r = input.read(buf); + if (r == -1) { + break; + } + out.write(buf, 0, r); + } + input.close(); + return parse(out.toByteArray()); + } + + /** + * Parses the XML content from the given byte array + * + * @param data the raw XML data (with unknown encoding) + * @return the corresponding document + * @throws ParserConfigurationException if a SAX parser is not available + * @throws SAXException if the document contains a parsing error + * @throws IOException if something is seriously wrong. This should not + * happen since the input source is known to be constructed from + * a string. + */ + @Nullable + public Document parse(@NonNull byte[] data) + throws ParserConfigurationException, SAXException, IOException { + String xml = getXmlString(data); + return parse(xml, new InputSource(new StringReader(xml)), true); + } + + /** + * Parses the given XML content. + * + * @param xml the XML string to be parsed. This must be in the correct + * encoding already. + * @return the corresponding document + * @throws ParserConfigurationException if a SAX parser is not available + * @throws SAXException if the document contains a parsing error + * @throws IOException if something is seriously wrong. This should not + * happen since the input source is known to be constructed from + * a string. + */ + @Nullable + public Document parse(@NonNull String xml) + throws ParserConfigurationException, SAXException, IOException { + return parse(xml, new InputSource(new StringReader(xml)), true); + } + + @NonNull + private Document parse(@NonNull String xml, @NonNull InputSource input, boolean checkBom) + throws ParserConfigurationException, SAXException, IOException { + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setFeature(NAMESPACE_FEATURE, true); + factory.setFeature(NAMESPACE_PREFIX_FEATURE, true); + SAXParser parser = factory.newSAXParser(); + DomBuilder handler = new DomBuilder(xml); + parser.parse(input, handler); + return handler.getDocument(); + } catch (SAXException e) { + if (checkBom && e.getMessage().contains("Content is not allowed in prolog")) { + // Byte order mark in the string? Skip it. There are many markers + // (see http://en.wikipedia.org/wiki/Byte_order_mark) so here we'll + // just skip those up to the XML prolog beginning character, < + xml = xml.replaceFirst("^([\\W]+)<","<"); //$NON-NLS-1$ //$NON-NLS-2$ + return parse(xml, new InputSource(new StringReader(xml)), false); + } + throw e; + } + } + + /** + * Returns the String corresponding to the given byte array of XML data + * (with unknown encoding). This method attempts to guess the encoding based + * on the XML prologue. + * @param data the XML data to be decoded into a string + * @return a string corresponding to the XML data + */ + public static String getXmlString(byte[] data) { + int offset = 0; + + String defaultCharset = UTF_8; + String charset = null; + // Look for the byte order mark, to see if we need to remove bytes from + // the input stream (and to determine whether files are big endian or little endian) etc + // for files which do not specify the encoding. + // See http://unicode.org/faq/utf_bom.html#BOM for more. + if (data.length > 4) { + if (data[0] == (byte)0xef && data[1] == (byte)0xbb && data[2] == (byte)0xbf) { + // UTF-8 + defaultCharset = charset = UTF_8; + offset += 3; + } else if (data[0] == (byte)0xfe && data[1] == (byte)0xff) { + // UTF-16, big-endian + defaultCharset = charset = UTF_16; + offset += 2; + } else if (data[0] == (byte)0x0 && data[1] == (byte)0x0 + && data[2] == (byte)0xfe && data[3] == (byte)0xff) { + // UTF-32, big-endian + defaultCharset = charset = "UTF_32"; //$NON-NLS-1$ + offset += 4; + } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe + && data[2] == (byte)0x0 && data[3] == (byte)0x0) { + // UTF-32, little-endian. We must check for this *before* looking for + // UTF_16LE since UTF_32LE has the same prefix! + defaultCharset = charset = "UTF_32LE"; //$NON-NLS-1$ + offset += 4; + } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe) { + // UTF-16, little-endian + defaultCharset = charset = UTF_16LE; + offset += 2; + } + } + int length = data.length - offset; + + // Guess encoding by searching for an encoding= entry in the first line. + // The prologue, and the encoding names, will always be in ASCII - which means + // we don't need to worry about strange character encodings for the prologue characters. + // However, one wrinkle is that the whole file may be encoded in something like UTF-16 + // where there are two bytes per character, so we can't just look for + // ['e','n','c','o','d','i','n','g'] etc in the byte array since there could be + // multiple bytes for each character. However, since again the prologue is in ASCII, + // we can just drop the zeroes. + boolean seenOddZero = false; + boolean seenEvenZero = false; + int prologueStart = -1; + for (int lineEnd = offset; lineEnd < data.length; lineEnd++) { + if (data[lineEnd] == 0) { + if ((lineEnd - offset) % 2 == 0) { + seenEvenZero = true; + } else { + seenOddZero = true; + } + } else if (data[lineEnd] == '\n' || data[lineEnd] == '\r') { + break; + } else if (data[lineEnd] == '<') { + prologueStart = lineEnd; + } else if (data[lineEnd] == '>') { + // End of prologue. Quick check to see if this is a utf-8 file since that's + // common + for (int i = lineEnd - 4; i >= 0; i--) { + if ((data[i] == 'u' || data[i] == 'U') + && (data[i + 1] == 't' || data[i + 1] == 'T') + && (data[i + 2] == 'f' || data[i + 2] == 'F') + && (data[i + 3] == '-' || data[i + 3] == '_') + && (data[i + 4] == '8') + ) { + charset = UTF_8; + break; + } + } + + if (charset == null) { + StringBuilder sb = new StringBuilder(); + for (int i = prologueStart; i <= lineEnd; i++) { + if (data[i] != 0) { + sb.append((char) data[i]); + } + } + String prologue = sb.toString(); + int encodingIndex = prologue.indexOf("encoding"); //$NON-NLS-1$ + if (encodingIndex != -1) { + Matcher matcher = ENCODING_PATTERN.matcher(prologue); + if (matcher.find(encodingIndex)) { + charset = matcher.group(1); + } + } + } + + break; + } + } + + // No prologue on the first line, and no byte order mark: Assume UTF-8/16 + if (charset == null) { + charset = seenOddZero ? UTF_16LE : seenEvenZero ? UTF_16 : UTF_8; + } + + String xml = null; + try { + xml = new String(data, offset, length, charset); + } catch (UnsupportedEncodingException e) { + try { + if (charset != defaultCharset) { + xml = new String(data, offset, length, defaultCharset); + } + } catch (UnsupportedEncodingException u) { + // Just use the default encoding below + } + } + if (xml == null) { + xml = new String(data, offset, length); + } + return xml; + } + + /** + * Returns the position for the given node. This is the start position. The + * end position can be obtained via {@link Position#getEnd()}. + * + * @param node the node to look up position for + * @return the position, or null if the node type is not supported for + * position info + */ + @Nullable + public Position getPosition(@NonNull Node node) { + return getPosition(node, -1, -1); + } + + /** + * Returns the position for the given node. This is the start position. The + * end position can be obtained via {@link Position#getEnd()}. A specific + * range within the node can be specified with the {@code start} and + * {@code end} parameters. + * + * @param node the node to look up position for + * @param start the relative offset within the node range to use as the + * starting position, inclusive, or -1 to not limit the range + * @param end the relative offset within the node range to use as the ending + * position, or -1 to not limit the range + * @return the position, or null if the node type is not supported for + * position info + */ + @Nullable + public Position getPosition(@NonNull Node node, int start, int end) { + // Look up the position information stored while parsing for the given node. + // Note however that we only store position information for elements (because + // there is no SAX callback for individual attributes). + // Therefore, this method special cases this: + // -- First, it looks at the owner element and uses its position + // information as a first approximation. + // -- Second, it uses that, as well as the original XML text, to search + // within the node range for an exact text match on the attribute name + // and if found uses that as the exact node offsets instead. + if (node instanceof Attr) { + Attr attr = (Attr) node; + Position pos = (Position) attr.getOwnerElement().getUserData(POS_KEY); + if (pos != null) { + int startOffset = pos.getOffset(); + int endOffset = pos.getEnd().getOffset(); + if (start != -1) { + startOffset += start; + if (end != -1) { + endOffset = start + end; + } + } + + // Find attribute in the text + String contents = (String) node.getOwnerDocument().getUserData(CONTENT_KEY); + if (contents == null) { + return null; + } + + // Locate the name=value attribute in the source text + // Fast string check first for the common occurrence + String name = attr.getName(); + Pattern pattern = Pattern.compile( + String.format("%1$s\\s*=\\s*[\"'].*[\"']", name)); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(contents); + if (matcher.find(startOffset) && matcher.start() <= endOffset) { + int index = matcher.start(); + // Adjust the line and column to this new offset + int line = pos.getLine(); + int column = pos.getColumn(); + for (int offset = pos.getOffset(); offset < index; offset++) { + char t = contents.charAt(offset); + if (t == '\n') { + line++; + column = 0; + } else { + column++; + } + } + + Position attributePosition = createPosition(line, column, index); + // Also set end range for retrieval in getLocation + attributePosition.setEnd(createPosition(line, column + matcher.end() - index, + matcher.end())); + return attributePosition; + } else { + // No regexp match either: just fall back to element position + return pos; + } + } + } else if (node instanceof Text) { + // Position of parent element, if any + Position pos = null; + if (node.getPreviousSibling() != null) { + pos = (Position) node.getPreviousSibling().getUserData(POS_KEY); + } + if (pos == null) { + pos = (Position) node.getParentNode().getUserData(POS_KEY); + } + if (pos != null) { + // Attempt to point forward to the actual text node + int startOffset = pos.getOffset(); + int endOffset = pos.getEnd().getOffset(); + int line = pos.getLine(); + int column = pos.getColumn(); + + // Find attribute in the text + String contents = (String) node.getOwnerDocument().getUserData(CONTENT_KEY); + if (contents == null || contents.length() < endOffset) { + return null; + } + + boolean inAttribute = false; + for (int offset = startOffset; offset <= endOffset; offset++) { + char c = contents.charAt(offset); + if (c == '>' && !inAttribute) { + // Found the end of the element open tag: this is where the + // text begins. + + // Skip > + offset++; + column++; + + String text = node.getNodeValue(); + int textIndex = 0; + int textLength = text.length(); + int newLine = line; + int newColumn = column; + if (start != -1) { + textLength = Math.min(textLength, start); + for (; textIndex < textLength; textIndex++) { + char t = text.charAt(textIndex); + if (t == '\n') { + newLine++; + newColumn = 0; + } else { + newColumn++; + } + } + } else { + // Skip text whitespace prefix, if the text node contains + // non-whitespace characters + for (; textIndex < textLength; textIndex++) { + char t = text.charAt(textIndex); + if (t == '\n') { + newLine++; + newColumn = 0; + } else if (!Character.isWhitespace(t)) { + break; + } else { + newColumn++; + } + } + } + if (textIndex == text.length()) { + textIndex = 0; // Whitespace node + } else { + line = newLine; + column = newColumn; + } + + Position attributePosition = createPosition(line, column, + offset + textIndex); + // Also set end range for retrieval in getLocation + if (end != -1) { + attributePosition.setEnd(createPosition(line, column, + offset + end)); + } else { + attributePosition.setEnd(createPosition(line, column, + offset + textLength)); + } + return attributePosition; + } else if (c == '"') { + inAttribute = !inAttribute; + } else if (c == '\n') { + line++; + column = -1; // pre-subtract column added below + } + column++; + } + + return pos; + } + } + + return (Position) node.getUserData(POS_KEY); + } + + /** + * SAX parser handler which incrementally builds up a DOM document as we go + * along, and updates position information along the way. Position + * information is attached to the DOM nodes by setting user data with the + * {@link POS_KEY} key. + */ + private final class DomBuilder extends DefaultHandler { + private final String mXml; + private final Document mDocument; + private Locator mLocator; + private int mCurrentLine = 0; + private int mCurrentOffset; + private int mCurrentColumn; + private final List<Element> mStack = new ArrayList<Element>(); + private final StringBuilder mPendingText = new StringBuilder(); + + private DomBuilder(String xml) throws ParserConfigurationException { + mXml = xml; + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setValidating(false); + DocumentBuilder docBuilder = factory.newDocumentBuilder(); + mDocument = docBuilder.newDocument(); + mDocument.setUserData(CONTENT_KEY, xml, null); + } + + /** Returns the document parsed by the handler */ + Document getDocument() { + return mDocument; + } + + @Override + public void setDocumentLocator(Locator locator) { + this.mLocator = locator; + } + + @Override + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException { + try { + flushText(); + Element element = mDocument.createElement(qName); + for (int i = 0; i < attributes.getLength(); i++) { + if (attributes.getURI(i) != null && attributes.getURI(i).length() > 0) { + Attr attr = mDocument.createAttributeNS(attributes.getURI(i), + attributes.getQName(i)); + attr.setValue(attributes.getValue(i)); + element.setAttributeNodeNS(attr); + assert attr.getOwnerElement() == element; + } else { + Attr attr = mDocument.createAttribute(attributes.getQName(i)); + attr.setValue(attributes.getValue(i)); + element.setAttributeNode(attr); + assert attr.getOwnerElement() == element; + } + } + + Position pos = getCurrentPosition(); + + // The starting position reported to us by SAX is really the END of the + // open tag in an element, when all the attributes have been processed. + // We have to scan backwards to find the real beginning. We'll do that + // by scanning backwards. + // -1: Make sure that when we have <foo></foo> we don't consider </foo> + // the beginning since pos.offset will typically point to the first character + // AFTER the element open tag, which could be a closing tag or a child open + // tag + + for (int offset = pos.getOffset() - 1; offset >= 0; offset--) { + char c = mXml.charAt(offset); + // < cannot appear in attribute values or anywhere else within + // an element open tag, so we know the first occurrence is the real + // element start + if (c == '<') { + // Adjust line position + int line = pos.getLine(); + for (int i = offset, n = pos.getOffset(); i < n; i++) { + if (mXml.charAt(i) == '\n') { + line--; + } + } + + // Compute new column position + int column = 0; + for (int i = offset - 1; i >= 0; i--, column++) { + if (mXml.charAt(i) == '\n') { + break; + } + } + + pos = createPosition(line, column, offset); + break; + } + } + + element.setUserData(POS_KEY, pos, null); + mStack.add(element); + } catch (Exception t) { + throw new SAXException(t); + } + } + + @Override + public void endElement(String uri, String localName, String qName) { + flushText(); + Element element = mStack.remove(mStack.size() - 1); + + Position pos = (Position) element.getUserData(POS_KEY); + assert pos != null; + pos.setEnd(getCurrentPosition()); + + if (mStack.isEmpty()) { + mDocument.appendChild(element); + } else { + Element parent = mStack.get(mStack.size() - 1); + parent.appendChild(element); + } + } + + /** + * Returns a position holder for the current position. The most + * important part of this function is to incrementally compute the + * offset as well, by counting forwards until it reaches the new line + * number and column position of the XML parser, counting characters as + * it goes along. + */ + private Position getCurrentPosition() { + int line = mLocator.getLineNumber() - 1; + int column = mLocator.getColumnNumber() - 1; + + // Compute offset incrementally now that we have the new line and column + // numbers + int xmlLength = mXml.length(); + while (mCurrentLine < line && mCurrentOffset < xmlLength) { + char c = mXml.charAt(mCurrentOffset); + if (c == '\r' && mCurrentOffset < xmlLength - 1) { + if (mXml.charAt(mCurrentOffset + 1) != '\n') { + mCurrentLine++; + mCurrentColumn = 0; + } + } else if (c == '\n') { + mCurrentLine++; + mCurrentColumn = 0; + } else { + mCurrentColumn++; + } + mCurrentOffset++; + } + + mCurrentOffset += column - mCurrentColumn; + if (mCurrentOffset >= xmlLength) { + // The parser sometimes passes wrong column numbers at the + // end of the file: Ensure that the offset remains valid. + mCurrentOffset = xmlLength; + } + mCurrentColumn = column; + + return createPosition(mCurrentLine, mCurrentColumn, mCurrentOffset); + } + + @Override + public void characters(char c[], int start, int length) throws SAXException { + mPendingText.append(c, start, length); + } + + private void flushText() { + if (mPendingText.length() > 0 && !mStack.isEmpty()) { + Element element = mStack.get(mStack.size() - 1); + Node textNode = mDocument.createTextNode(mPendingText.toString()); + element.appendChild(textNode); + mPendingText.setLength(0); + } + } + } + + /** + * Creates a position while constructing the DOM document. This method + * allows a subclass to create a custom implementation of the position + * class. + * + * @param line the line number for the position + * @param column the column number for the position + * @param offset the character offset + * @return a new position + */ + @NonNull + protected Position createPosition(int line, int column, int offset) { + return new DefaultPosition(line, column, offset); + } + + protected interface Position { + /** + * Linked position: for a begin position this will point to the + * corresponding end position. For an end position this will be null. + * + * @return the end position, or null + */ + @Nullable + public Position getEnd(); + + /** + * Linked position: for a begin position this will point to the + * corresponding end position. For an end position this will be null. + * + * @param end the end position + */ + public void setEnd(@NonNull Position end); + + /** @return the line number, 0-based */ + public int getLine(); + + /** @return the offset number, 0-based */ + public int getOffset(); + + /** @return the column number, 0-based, and -1 if the column number if not known */ + public int getColumn(); + } + + protected static class DefaultPosition implements Position { + /** The line number (0-based where the first line is line 0) */ + private final int mLine; + private final int mColumn; + private final int mOffset; + private Position mEnd; + + /** + * Creates a new {@link Position} + * + * @param line the 0-based line number, or -1 if unknown + * @param column the 0-based column number, or -1 if unknown + * @param offset the offset, or -1 if unknown + */ + public DefaultPosition(int line, int column, int offset) { + this.mLine = line; + this.mColumn = column; + this.mOffset = offset; + } + + @Override + public int getLine() { + return mLine; + } + + @Override + public int getOffset() { + return mOffset; + } + + @Override + public int getColumn() { + return mColumn; + } + + @Override + public Position getEnd() { + return mEnd; + } + + @Override + public void setEnd(@NonNull Position end) { + mEnd = end; + } + } +} diff --git a/common/src/main/java/com/android/utils/SdkUtils.java b/common/src/main/java/com/android/utils/SdkUtils.java new file mode 100644 index 0000000..160f95d --- /dev/null +++ b/common/src/main/java/com/android/utils/SdkUtils.java @@ -0,0 +1,216 @@ +/* + * 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; + +/** Miscellaneous utilities used by the Android SDK tools */ +public class SdkUtils { + /** + * Returns true if the given string ends with the given suffix, using a + * case-insensitive comparison. + * + * @param string the full string to be checked + * @param suffix the suffix to be checked for + * @return true if the string case-insensitively ends with the given suffix + */ + public static boolean endsWithIgnoreCase(String string, String suffix) { + return string.regionMatches(true /* ignoreCase */, string.length() - suffix.length(), + suffix, 0, suffix.length()); + } + + /** + * Returns true if the given sequence ends with the given suffix (case + * sensitive). + * + * @param sequence the character sequence to be checked + * @param suffix the suffix to look for + * @return true if the given sequence ends with the given suffix + */ + public static boolean endsWith(CharSequence sequence, CharSequence suffix) { + return endsWith(sequence, sequence.length(), suffix); + } + + /** + * Returns true if the given sequence ends at the given offset with the given suffix (case + * sensitive) + * + * @param sequence the character sequence to be checked + * @param endOffset the offset at which the sequence is considered to end + * @param suffix the suffix to look for + * @return true if the given sequence ends with the given suffix + */ + public static boolean endsWith(CharSequence sequence, int endOffset, CharSequence suffix) { + if (endOffset < suffix.length()) { + return false; + } + + for (int i = endOffset - 1, j = suffix.length() - 1; j >= 0; i--, j--) { + if (sequence.charAt(i) != suffix.charAt(j)) { + return false; + } + } + + return true; + } + + /** + * Returns true if the given string starts with the given prefix, using a + * case-insensitive comparison. + * + * @param string the full string to be checked + * @param prefix the prefix to be checked for + * @return true if the string case-insensitively starts with the given prefix + */ + public static boolean startsWithIgnoreCase(String string, String prefix) { + return string.regionMatches(true /* ignoreCase */, 0, prefix, 0, prefix.length()); + } + + /** + * Returns true if the given string starts at the given offset with the + * given prefix, case insensitively. + * + * @param string the full string to be checked + * @param offset the offset in the string to start looking + * @param prefix the prefix to be checked for + * @return true if the string case-insensitively starts at the given offset + * with the given prefix + */ + public static boolean startsWith(String string, int offset, String prefix) { + return string.regionMatches(true /* ignoreCase */, offset, prefix, 0, prefix.length()); + } + + /** + * Strips the whitespace from the given string + * + * @param string the string to be cleaned up + * @return the string, without whitespace + */ + public static String stripWhitespace(String string) { + StringBuilder sb = new StringBuilder(string.length()); + for (int i = 0, n = string.length(); i < n; i++) { + char c = string.charAt(i); + if (!Character.isWhitespace(c)) { + sb.append(c); + } + } + + return sb.toString(); + } + + /** + * Returns true if the given string has an upper case character. + * + * @param s the string to check + * @return true if it contains uppercase characters + */ + public static boolean hasUpperCaseCharacter(String s) { + for (int i = 0; i < s.length(); i++) { + if (Character.isUpperCase(s.charAt(i))) { + return true; + } + } + + return false; + } + + /** For use by {@link #getLineSeparator()} */ + private static String sLineSeparator; + + /** + * Returns the default line separator to use. + * <p> + * NOTE: If you have an associated IDocument (Eclipse), it is better to call + * TextUtilities#getDefaultLineDelimiter(IDocument) since that will + * allow (for example) editing a \r\n-delimited document on a \n-delimited + * platform and keep a consistent usage of delimiters in the file. + * + * @return the delimiter string to use + */ + @NonNull + public static String getLineSeparator() { + if (sLineSeparator == null) { + // This is guaranteed to exist: + sLineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$ + } + + return sLineSeparator; + } + + /** + * Wraps the given text at the given line width, with an optional hanging + * indent. + * + * @param text the text to be wrapped + * @param lineWidth the number of characters to wrap the text to + * @param hangingIndent the hanging indent (to be used for the second and + * subsequent lines in each paragraph, or null if not known + * @return the string, wrapped + */ + @NonNull + public static String wrap( + @NonNull String text, + int lineWidth, + @Nullable String hangingIndent) { + if (hangingIndent == null) { + hangingIndent = ""; + } + int explanationLength = text.length(); + StringBuilder sb = new StringBuilder(explanationLength * 2); + int index = 0; + + while (index < explanationLength) { + int lineEnd = text.indexOf('\n', index); + int next; + + if (lineEnd != -1 && (lineEnd - index) < lineWidth) { + next = lineEnd + 1; + } else { + // Line is longer than available width; grab as much as we can + lineEnd = Math.min(index + lineWidth, explanationLength); + if (lineEnd - index < lineWidth) { + next = explanationLength; + } else { + // then back up to the last space + int lastSpace = text.lastIndexOf(' ', lineEnd); + if (lastSpace > index) { + lineEnd = lastSpace; + next = lastSpace + 1; + } else { + // No space anywhere on the line: it contains something wider than + // can fit (like a long URL) so just hard break it + next = lineEnd + 1; + } + } + } + + if (sb.length() > 0) { + sb.append(hangingIndent); + } else { + lineWidth -= hangingIndent.length(); + } + + sb.append(text.substring(index, lineEnd)); + sb.append('\n'); + index = next; + } + + return sb.toString(); + } + +} diff --git a/common/src/main/java/com/android/utils/StdLogger.java b/common/src/main/java/com/android/utils/StdLogger.java new file mode 100644 index 0000000..05eb456 --- /dev/null +++ b/common/src/main/java/com/android/utils/StdLogger.java @@ -0,0 +1,177 @@ +/* + * 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.SdkConstants; +import com.android.annotations.NonNull; + +import java.io.PrintStream; +import java.util.Formatter; + + +/** + * An implementation of {@link ILogger} that prints to {@link System#out} and {@link System#err}. + * <p/> + * + */ +public class StdLogger implements ILogger { + + private final Level mLevel; + + public enum Level { + VERBOSE(0), + INFO(1), + WARNING(2), + ERROR(3); + + private final int mLevel; + + Level(int level) { + mLevel = level; + } + } + + /** + * Creates the {@link StdLogger} with a given log {@link Level}. + * @param level the log Level. + */ + public StdLogger(@NonNull Level level) { + if (level == null) { + throw new IllegalArgumentException("level cannot be null"); + } + + mLevel = level; + } + + /** + * Returns the logger's log {@link Level}. + * @return the log level. + */ + public Level getLevel() { + return mLevel; + } + + /** + * Prints an error message. + * <p/> + * The message will be tagged with "Error" on the output so the caller does not + * need to put such a prefix in the format string. + * <p/> + * The output is done on {@link System#err}. + * <p/> + * This is always displayed, independent of the logging {@link Level}. + * + * @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's + * message will be printed out. + * @param errorFormat is an optional error format. If non-null, it will be printed + * using a {@link Formatter} with the provided arguments. + * @param args provides the arguments for errorFormat. + */ + @Override + public void error(Throwable t, String errorFormat, Object... args) { + if (errorFormat != null) { + String msg = String.format("Error: " + errorFormat, args); + + printMessage(msg, System.err); + } + if (t != null) { + System.err.println(String.format("Error: %1$s", t.getMessage())); + } + } + + /** + * Prints a warning message. + * <p/> + * The message will be tagged with "Warning" on the output so the caller does not + * need to put such a prefix in the format string. + * <p/> + * The output is done on {@link System#out}. + * <p/> + * This is displayed only if the logging {@link Level} is {@link Level#WARNING} or higher. + * + * @param warningFormat is a string format to be used with a {@link Formatter}. Cannot be null. + * @param args provides the arguments for warningFormat. + */ + @Override + public void warning(@NonNull String warningFormat, Object... args) { + if (mLevel.mLevel > Level.WARNING.mLevel) { + return; + } + + String msg = String.format("Warning: " + warningFormat, args); + + printMessage(msg, System.out); + } + + /** + * Prints an info message. + * <p/> + * The output is done on {@link System#out}. + * <p/> + * This is displayed only if the logging {@link Level} is {@link Level#INFO} or higher. + * + * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null. + * @param args provides the arguments for msgFormat. + */ + @Override + public void info(@NonNull String msgFormat, Object... args) { + if (mLevel.mLevel > Level.INFO.mLevel) { + return; + } + + String msg = String.format(msgFormat, args); + + printMessage(msg, System.out); + } + + /** + * Prints a verbose message. + * <p/> + * The output is done on {@link System#out}. + * <p/> + * This is displayed only if the logging {@link Level} is {@link Level#VERBOSE} or higher. + * + * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null. + * @param args provides the arguments for msgFormat. + */ + @Override + public void verbose(@NonNull String msgFormat, Object... args) { + if (mLevel.mLevel > Level.VERBOSE.mLevel) { + return; + } + + String msg = String.format(msgFormat, args); + + printMessage(msg, System.out); + } + + private void printMessage(String msg, PrintStream stream) { + if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS && + !msg.endsWith("\r\n") && + msg.endsWith("\n")) { + // remove last \n so that println can use \r\n as needed. + msg = msg.substring(0, msg.length() - 1); + } + + stream.print(msg); + + if (!msg.endsWith("\n")) { + stream.println(); + } + } + +} diff --git a/common/src/main/java/com/android/utils/XmlUtils.java b/common/src/main/java/com/android/utils/XmlUtils.java new file mode 100644 index 0000000..0969eb1 --- /dev/null +++ b/common/src/main/java/com/android/utils/XmlUtils.java @@ -0,0 +1,278 @@ +/* + * 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 static com.android.SdkConstants.AMP_ENTITY; +import static com.android.SdkConstants.ANDROID_NS_NAME; +import static com.android.SdkConstants.ANDROID_URI; +import static com.android.SdkConstants.APOS_ENTITY; +import static com.android.SdkConstants.APP_PREFIX; +import static com.android.SdkConstants.LT_ENTITY; +import static com.android.SdkConstants.QUOT_ENTITY; +import static com.android.SdkConstants.XMLNS; +import static com.android.SdkConstants.XMLNS_PREFIX; +import static com.android.SdkConstants.XMLNS_URI; + +import com.android.SdkConstants; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +import java.util.HashSet; + +/** XML Utilities */ +public class XmlUtils { + /** + * Returns the namespace prefix matching the requested namespace URI. + * If no such declaration is found, returns the default "android" prefix for + * the Android URI, and "app" for other URI's. By default the app namespace + * will be created. If this is not desirable, call + * {@link #lookupNamespacePrefix(Node, String, boolean)} instead. + * + * @param node The current node. Must not be null. + * @param nsUri The namespace URI of which the prefix is to be found, + * e.g. {@link SdkConstants#ANDROID_URI} + * @return The first prefix declared or the default "android" prefix + * (or "app" for non-Android URIs) + */ + @NonNull + public static String lookupNamespacePrefix(@NonNull Node node, @NonNull String nsUri) { + String defaultPrefix = ANDROID_URI.equals(nsUri) ? ANDROID_NS_NAME : APP_PREFIX; + return lookupNamespacePrefix(node, nsUri, defaultPrefix, true /*create*/); + } + + /** + * Returns the namespace prefix matching the requested namespace URI. If no + * such declaration is found, returns the default "android" prefix for the + * Android URI, and "app" for other URI's. + * + * @param node The current node. Must not be null. + * @param nsUri The namespace URI of which the prefix is to be found, e.g. + * {@link SdkConstants#ANDROID_URI} + * @param create whether the namespace declaration should be created, if + * necessary + * @return The first prefix declared or the default "android" prefix (or + * "app" for non-Android URIs) + */ + @NonNull + public static String lookupNamespacePrefix(@NonNull Node node, @NonNull String nsUri, + boolean create) { + String defaultPrefix = ANDROID_URI.equals(nsUri) ? ANDROID_NS_NAME : APP_PREFIX; + return lookupNamespacePrefix(node, nsUri, defaultPrefix, create); + } + + /** + * Returns the namespace prefix matching the requested namespace URI. If no + * such declaration is found, returns the default "android" prefix. + * + * @param node The current node. Must not be null. + * @param nsUri The namespace URI of which the prefix is to be found, e.g. + * {@link SdkConstants#ANDROID_URI} + * @param defaultPrefix The default prefix (root) to use if the namespace is + * not found. If null, do not create a new namespace if this URI + * is not defined for the document. + * @param create whether the namespace declaration should be created, if + * necessary + * @return The first prefix declared or the provided prefix (possibly with a + * number appended to avoid conflicts with existing prefixes. + */ + public static String lookupNamespacePrefix( + @Nullable Node node, @Nullable String nsUri, @Nullable String defaultPrefix, + boolean create) { + // Note: Node.lookupPrefix is not implemented in wst/xml/core NodeImpl.java + // The following code emulates this simple call: + // String prefix = node.lookupPrefix(NS_RESOURCES); + + // if the requested URI is null, it denotes an attribute with no namespace. + if (nsUri == null) { + return null; + } + + // per XML specification, the "xmlns" URI is reserved + if (XMLNS_URI.equals(nsUri)) { + return XMLNS; + } + + HashSet<String> visited = new HashSet<String>(); + Document doc = node == null ? null : node.getOwnerDocument(); + + // Ask the document about it. This method may not be implemented by the Document. + String nsPrefix = null; + try { + nsPrefix = doc != null ? doc.lookupPrefix(nsUri) : null; + if (nsPrefix != null) { + return nsPrefix; + } + } catch (Throwable t) { + // ignore + } + + // If that failed, try to look it up manually. + // This also gathers prefixed in use in the case we want to generate a new one below. + for (; node != null && node.getNodeType() == Node.ELEMENT_NODE; + node = node.getParentNode()) { + NamedNodeMap attrs = node.getAttributes(); + for (int n = attrs.getLength() - 1; n >= 0; --n) { + Node attr = attrs.item(n); + if (XMLNS.equals(attr.getPrefix())) { + String uri = attr.getNodeValue(); + nsPrefix = attr.getLocalName(); + // Is this the URI we are looking for? If yes, we found its prefix. + if (nsUri.equals(uri)) { + return nsPrefix; + } + visited.add(nsPrefix); + } + } + } + + // Failed the find a prefix. Generate a new sensible default prefix, unless + // defaultPrefix was null in which case the caller does not want the document + // modified. + if (defaultPrefix == null) { + return null; + } + + // + // We need to make sure the prefix is not one that was declared in the scope + // visited above. Pick a unique prefix from the provided default prefix. + String prefix = defaultPrefix; + String base = prefix; + for (int i = 1; visited.contains(prefix); i++) { + prefix = base + Integer.toString(i); + } + // Also create & define this prefix/URI in the XML document as an attribute in the + // first element of the document. + if (doc != null) { + node = doc.getFirstChild(); + while (node != null && node.getNodeType() != Node.ELEMENT_NODE) { + node = node.getNextSibling(); + } + if (node != null && create) { + // This doesn't work: + //Attr attr = doc.createAttributeNS(XMLNS_URI, prefix); + //attr.setPrefix(XMLNS); + // + // Xerces throws + //org.w3c.dom.DOMException: NAMESPACE_ERR: An attempt is made to create or + // change an object in a way which is incorrect with regard to namespaces. + // + // Instead pass in the concatenated prefix. (This is covered by + // the UiElementNodeTest#testCreateNameSpace() test.) + Attr attr = doc.createAttributeNS(XMLNS_URI, XMLNS_PREFIX + prefix); + attr.setValue(nsUri); + node.getAttributes().setNamedItemNS(attr); + } + } + + return prefix; + } + + /** + * Converts the given attribute value to an XML-attribute-safe value, meaning that + * single and double quotes are replaced with their corresponding XML entities. + * + * @param attrValue the value to be escaped + * @return the escaped value + */ + @NonNull + public static String toXmlAttributeValue(@NonNull String attrValue) { + for (int i = 0, n = attrValue.length(); i < n; i++) { + char c = attrValue.charAt(i); + if (c == '"' || c == '\'' || c == '<' || c == '&') { + StringBuilder sb = new StringBuilder(2 * attrValue.length()); + appendXmlAttributeValue(sb, attrValue); + return sb.toString(); + } + } + + return attrValue; + } + + /** + * Converts the given attribute value to an XML-text-safe value, meaning that + * less than and ampersand characters are escaped. + * + * @param textValue the text value to be escaped + * @return the escaped value + */ + @NonNull + public static String toXmlTextValue(@NonNull String textValue) { + for (int i = 0, n = textValue.length(); i < n; i++) { + char c = textValue.charAt(i); + if (c == '<' || c == '&') { + StringBuilder sb = new StringBuilder(2 * textValue.length()); + appendXmlTextValue(sb, textValue); + return sb.toString(); + } + } + + return textValue; + } + + /** + * Appends text to the given {@link StringBuilder} and escapes it as required for a + * DOM attribute node. + * + * @param sb the string builder + * @param attrValue the attribute value to be appended and escaped + */ + public static void appendXmlAttributeValue(@NonNull StringBuilder sb, + @NonNull String attrValue) { + int n = attrValue.length(); + // &, ", ' and < are illegal in attributes; see http://www.w3.org/TR/REC-xml/#NT-AttValue + // (' legal in a " string and " is legal in a ' string but here we'll stay on the safe + // side) + for (int i = 0; i < n; i++) { + char c = attrValue.charAt(i); + if (c == '"') { + sb.append(QUOT_ENTITY); + } else if (c == '<') { + sb.append(LT_ENTITY); + } else if (c == '\'') { + sb.append(APOS_ENTITY); + } else if (c == '&') { + sb.append(AMP_ENTITY); + } else { + sb.append(c); + } + } + } + + /** + * Appends text to the given {@link StringBuilder} and escapes it as required for a + * DOM text node. + * + * @param sb the string builder + * @param textValue the text value to be appended and escaped + */ + public static void appendXmlTextValue(@NonNull StringBuilder sb, @NonNull String textValue) { + for (int i = 0, n = textValue.length(); i < n; i++) { + char c = textValue.charAt(i); + if (c == '<') { + sb.append(LT_ENTITY); + } else if (c == '&') { + sb.append(AMP_ENTITY); + } else { + sb.append(c); + } + } + } +} diff --git a/common/src/main/java/com/android/xml/AndroidManifest.java b/common/src/main/java/com/android/xml/AndroidManifest.java new file mode 100644 index 0000000..306471e --- /dev/null +++ b/common/src/main/java/com/android/xml/AndroidManifest.java @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2009 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.xml; + +import com.android.SdkConstants; +import com.android.io.IAbstractFile; +import com.android.io.IAbstractFolder; +import com.android.io.StreamException; + +import org.w3c.dom.Node; +import org.xml.sax.InputSource; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; + +/** + * Helper and Constants for the AndroidManifest.xml file. + * + */ +public final class AndroidManifest { + + public static final String NODE_MANIFEST = "manifest"; + public static final String NODE_APPLICATION = "application"; + public static final String NODE_ACTIVITY = "activity"; + public static final String NODE_ACTIVITY_ALIAS = "activity-alias"; + public static final String NODE_SERVICE = "service"; + public static final String NODE_RECEIVER = "receiver"; + public static final String NODE_PROVIDER = "provider"; + public static final String NODE_INTENT = "intent-filter"; + public static final String NODE_ACTION = "action"; + public static final String NODE_CATEGORY = "category"; + public static final String NODE_USES_SDK = "uses-sdk"; + public static final String NODE_INSTRUMENTATION = "instrumentation"; + public static final String NODE_USES_LIBRARY = "uses-library"; + public static final String NODE_SUPPORTS_SCREENS = "supports-screens"; + public static final String NODE_USES_CONFIGURATION = "uses-configuration"; + public static final String NODE_USES_FEATURE = "uses-feature"; + + public static final String ATTRIBUTE_PACKAGE = "package"; + public static final String ATTRIBUTE_VERSIONCODE = "versionCode"; + public static final String ATTRIBUTE_NAME = "name"; + public static final String ATTRIBUTE_REQUIRED = "required"; + public static final String ATTRIBUTE_GLESVERSION = "glEsVersion"; + public static final String ATTRIBUTE_PROCESS = "process"; + public static final String ATTRIBUTE_DEBUGGABLE = "debuggable"; + public static final String ATTRIBUTE_LABEL = "label"; + public static final String ATTRIBUTE_ICON = "icon"; + public static final String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; + public static final String ATTRIBUTE_TARGET_SDK_VERSION = "targetSdkVersion"; + public static final String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; + public static final String ATTRIBUTE_TARGET_ACTIVITY = "targetActivity"; + public static final String ATTRIBUTE_MANAGE_SPACE_ACTIVITY = "manageSpaceActivity"; + public static final String ATTRIBUTE_EXPORTED = "exported"; + public static final String ATTRIBUTE_RESIZEABLE = "resizeable"; + public static final String ATTRIBUTE_ANYDENSITY = "anyDensity"; + public static final String ATTRIBUTE_SMALLSCREENS = "smallScreens"; + public static final String ATTRIBUTE_NORMALSCREENS = "normalScreens"; + public static final String ATTRIBUTE_LARGESCREENS = "largeScreens"; + public static final String ATTRIBUTE_REQ_5WAYNAV = "reqFiveWayNav"; + public static final String ATTRIBUTE_REQ_NAVIGATION = "reqNavigation"; + public static final String ATTRIBUTE_REQ_HARDKEYBOARD = "reqHardKeyboard"; + public static final String ATTRIBUTE_REQ_KEYBOARDTYPE = "reqKeyboardType"; + public static final String ATTRIBUTE_REQ_TOUCHSCREEN = "reqTouchScreen"; + public static final String ATTRIBUTE_THEME = "theme"; + public static final String ATTRIBUTE_BACKUP_AGENT = "backupAgent"; + public static final String ATTRIBUTE_PARENT_ACTIVITY_NAME = "parentActivityName"; + + /** + * Returns an {@link IAbstractFile} object representing the manifest for the given project. + * + * @param projectFolder The project containing the manifest file. + * @return An IAbstractFile object pointing to the manifest or null if the manifest + * is missing. + */ + public static IAbstractFile getManifest(IAbstractFolder projectFolder) { + IAbstractFile file = projectFolder.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); + if (file.exists()) { + return file; + } + + return null; + } + + /** + * Returns the package for a given project. + * @param projectFolder the folder of the project. + * @return the package info or null (or empty) if not found. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static String getPackage(IAbstractFolder projectFolder) + throws XPathExpressionException, StreamException { + IAbstractFile file = getManifest(projectFolder); + if (file != null) { + return getPackage(file); + } + + return null; + } + + /** + * Returns the package for a given manifest. + * @param manifestFile the manifest to parse. + * @return the package info or null (or empty) if not found. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static String getPackage(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + return xPath.evaluate( + "/" + NODE_MANIFEST + + "/@" + ATTRIBUTE_PACKAGE, + new InputSource(manifestFile.getContents())); + } + + /** + * Returns whether the manifest is set to make the application debuggable. + * + * If the give manifest does not contain the debuggable attribute then the application + * is considered to not be debuggable. + * + * @param manifestFile the manifest to parse. + * @return true if the application is debuggable. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static boolean getDebuggable(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + String value = xPath.evaluate( + "/" + NODE_MANIFEST + + "/" + NODE_APPLICATION + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + ATTRIBUTE_DEBUGGABLE, + new InputSource(manifestFile.getContents())); + + // default is not debuggable, which is the same behavior as parseBoolean + return Boolean.parseBoolean(value); + } + + /** + * Returns the value of the versionCode attribute or -1 if the value is not set. + * @param manifestFile the manifest file to read the attribute from. + * @return the integer value or -1 if not set. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static int getVersionCode(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + String result = xPath.evaluate( + "/" + NODE_MANIFEST + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + ATTRIBUTE_VERSIONCODE, + new InputSource(manifestFile.getContents())); + + try { + return Integer.parseInt(result); + } catch (NumberFormatException e) { + return -1; + } + } + + /** + * Returns whether the version Code attribute is set in a given manifest. + * @param manifestFile the manifest to check + * @return true if the versionCode attribute is present and its value is not empty. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static boolean hasVersionCode(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + Object result = xPath.evaluate( + "/" + NODE_MANIFEST + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + ATTRIBUTE_VERSIONCODE, + new InputSource(manifestFile.getContents()), + XPathConstants.NODE); + + if (result != null) { + Node node = (Node)result; + if (node.getNodeValue().length() > 0) { + return true; + } + } + + return false; + } + + /** + * Returns the value of the minSdkVersion attribute. + * <p/> + * If the attribute is set with an int value, the method returns an Integer object. + * <p/> + * If the attribute is set with a codename, it returns the codename as a String object. + * <p/> + * If the attribute is not set, it returns null. + * + * @param manifestFile the manifest file to read the attribute from. + * @return the attribute value. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static Object getMinSdkVersion(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + String result = xPath.evaluate( + "/" + NODE_MANIFEST + + "/" + NODE_USES_SDK + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + ATTRIBUTE_MIN_SDK_VERSION, + new InputSource(manifestFile.getContents())); + + try { + return Integer.valueOf(result); + } catch (NumberFormatException e) { + return result.length() > 0 ? result : null; + } + } + + /** + * Returns the value of the targetSdkVersion attribute (defaults to 1 if the attribute is + * not set), or -1 if the value is a codename. + * @param manifestFile the manifest file to read the attribute from. + * @return the integer value or -1 if not set. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static Integer getTargetSdkVersion(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + String result = xPath.evaluate( + "/" + NODE_MANIFEST + + "/" + NODE_USES_SDK + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + ATTRIBUTE_TARGET_SDK_VERSION, + new InputSource(manifestFile.getContents())); + + try { + return Integer.valueOf(result); + } catch (NumberFormatException e) { + return result.length() > 0 ? -1 : null; + } + } + + /** + * Returns the application icon for a given manifest. + * @param manifestFile the manifest to parse. + * @return the icon or null (or empty) if not found. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static String getApplicationIcon(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + return xPath.evaluate( + "/" + NODE_MANIFEST + + "/" + NODE_APPLICATION + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + ATTRIBUTE_ICON, + new InputSource(manifestFile.getContents())); + } + + /** + * Returns the application label for a given manifest. + * @param manifestFile the manifest to parse. + * @return the label or null (or empty) if not found. + * @throws XPathExpressionException + * @throws StreamException If any error happens when reading the manifest. + */ + public static String getApplicationLabel(IAbstractFile manifestFile) + throws XPathExpressionException, StreamException { + XPath xPath = AndroidXPathFactory.newXPath(); + + return xPath.evaluate( + "/" + NODE_MANIFEST + + "/" + NODE_APPLICATION + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + ATTRIBUTE_LABEL, + new InputSource(manifestFile.getContents())); + } + + /** + * Combines a java package, with a class value from the manifest to make a fully qualified + * class name + * @param javaPackage the java package from the manifest. + * @param className the class name from the manifest. + * @return the fully qualified class name. + */ + public static String combinePackageAndClassName(String javaPackage, String className) { + if (className == null || className.length() == 0) { + return javaPackage; + } + if (javaPackage == null || javaPackage.length() == 0) { + return className; + } + + // the class name can be a subpackage (starts with a '.' + // char), a simple class name (no dot), or a full java package + boolean startWithDot = (className.charAt(0) == '.'); + boolean hasDot = (className.indexOf('.') != -1); + if (startWithDot || hasDot == false) { + + // add the concatenation of the package and class name + if (startWithDot) { + return javaPackage + className; + } else { + return javaPackage + '.' + className; + } + } else { + // just add the class as it should be a fully qualified java name. + return className; + } + } + + /** + * Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project + * package base name (e.g. com.foo), returns the relative activity name that would be used + * the "name" attribute of an "activity" element. + * + * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass" + * @param packageName The project base package name, e.g. "com.foo" + * @return The relative activity name if it can be computed or the original fullActivityName. + */ + public static String extractActivityName(String fullActivityName, String packageName) { + if (packageName != null && fullActivityName != null) { + if (packageName.length() > 0 && fullActivityName.startsWith(packageName)) { + String name = fullActivityName.substring(packageName.length()); + if (name.length() > 0 && name.charAt(0) == '.') { + return name; + } + } + } + + return fullActivityName; + } +} diff --git a/common/src/main/java/com/android/xml/AndroidXPathFactory.java b/common/src/main/java/com/android/xml/AndroidXPathFactory.java new file mode 100644 index 0000000..ee5b87b --- /dev/null +++ b/common/src/main/java/com/android/xml/AndroidXPathFactory.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009 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.xml; + +import com.android.SdkConstants; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; + +/** + * XPath factory with automatic support for the android name space. + */ +public class AndroidXPathFactory { + /** Default prefix for android name space: 'android' */ + public final static String DEFAULT_NS_PREFIX = "android"; //$NON-NLS-1$ + + private final static XPathFactory sFactory = XPathFactory.newInstance(); + + /** Name space context for Android resource XML files. */ + private static class AndroidNamespaceContext implements NamespaceContext { + private final static AndroidNamespaceContext sThis = new AndroidNamespaceContext( + DEFAULT_NS_PREFIX); + + private final String mAndroidPrefix; + private final List<String> mAndroidPrefixes; + + /** + * Returns the default {@link AndroidNamespaceContext}. + */ + private static AndroidNamespaceContext getDefault() { + return sThis; + } + + /** + * Construct the context with the prefix associated with the android namespace. + * @param androidPrefix the Prefix + */ + public AndroidNamespaceContext(String androidPrefix) { + mAndroidPrefix = androidPrefix; + mAndroidPrefixes = Collections.singletonList(mAndroidPrefix); + } + + @Override + public String getNamespaceURI(String prefix) { + if (prefix != null) { + if (prefix.equals(mAndroidPrefix)) { + return SdkConstants.NS_RESOURCES; + } + } + + return XMLConstants.NULL_NS_URI; + } + + @Override + public String getPrefix(String namespaceURI) { + if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) { + return mAndroidPrefix; + } + + return null; + } + + @Override + public Iterator<?> getPrefixes(String namespaceURI) { + if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) { + return mAndroidPrefixes.iterator(); + } + + return null; + } + } + + /** + * Creates a new XPath object, specifying which prefix in the query is used for the + * android namespace. + * @param androidPrefix The namespace prefix. + */ + public static XPath newXPath(String androidPrefix) { + XPath xpath = sFactory.newXPath(); + xpath.setNamespaceContext(new AndroidNamespaceContext(androidPrefix)); + return xpath; + } + + /** + * Creates a new XPath object using the default prefix for the android namespace. + * @see #DEFAULT_NS_PREFIX + */ + public static XPath newXPath() { + XPath xpath = sFactory.newXPath(); + xpath.setNamespaceContext(AndroidNamespaceContext.getDefault()); + return xpath; + } +} |