diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-20 14:05:23 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-20 14:05:23 -0800 |
| commit | 2d6668aaf09b01a045954c824183d53482fadafe (patch) | |
| tree | e045a54a6979ee399dd7931576d6a0b13d9b9c98 | |
| parent | db1b7a2e17ba200c36b7ab73920a76b28a43974c (diff) | |
| parent | 7b53e3937797ee1eea71c6291bdcd58cb9dedf7a (diff) | |
| download | android_development-2d6668aaf09b01a045954c824183d53482fadafe.tar.gz android_development-2d6668aaf09b01a045954c824183d53482fadafe.tar.bz2 android_development-2d6668aaf09b01a045954c824183d53482fadafe.zip | |
Merge branch 'cupcake'
57 files changed, 1011 insertions, 1271 deletions
diff --git a/build/sdk.atree b/build/sdk.atree index f12a30c0b..b9126d4a2 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -112,9 +112,7 @@ framework/swing-worker-1.1.jar tools/lib/swing-worker-1.1.jar bin/traceview tools/traceview framework/traceview.jar tools/lib/traceview.jar -# activitycreator -bin/activitycreator tools/activitycreator -framework/activitycreator.jar tools/lib/activitycreator.jar +# custom ant tasks framework/anttasks.jar tools/lib/anttasks.jar # sdkmanager diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh index 4f3cee815..bf52679ac 100755 --- a/build/tools/make_windows_sdk.sh +++ b/build/tools/make_windows_sdk.sh @@ -87,7 +87,7 @@ function package() { # Remove obsolete stuff from tools TOOLS="$DEST/tools" LIB="$DEST/tools/lib" - rm -v "$TOOLS"/{aapt,aidl,adb,emulator,traceview,draw9patch,hierarchyviewer,dx,dexdump,apkbuilder,ddms,dmtracedump,mksdcard,sqlite3,activitycreator,android} + rm -v "$TOOLS"/{aapt,aidl,adb,emulator,traceview,draw9patch,hierarchyviewer,dx,dexdump,apkbuilder,ddms,dmtracedump,mksdcard,sqlite3,android} rm -v --force "$LIB"/*.so "$LIB"/*.jnilib # Copy all the new stuff in tools @@ -108,7 +108,6 @@ function package() { cp -v development/tools/traceview/etc/traceview.bat "$TOOLS" cp -v development/tools/hierarchyviewer/etc/hierarchyviewer.bat "$TOOLS" cp -v development/tools/draw9patch/etc/draw9patch.bat "$TOOLS" - cp -v development/tools/activitycreator/etc/activitycreator.bat "$TOOLS" cp -v development/tools/sdkmanager/app/etc/android.bat "$TOOLS" # Fix EOL chars to make window users happy - fix all files at the top level only diff --git a/host/windows/prebuilt/usb/driver_amd_64/androidusb.sys b/host/windows/prebuilt/usb/driver_amd_64/androidusb.sys Binary files differindex 70ce24fd1..e610ebea0 100644 --- a/host/windows/prebuilt/usb/driver_amd_64/androidusb.sys +++ b/host/windows/prebuilt/usb/driver_amd_64/androidusb.sys diff --git a/host/windows/prebuilt/usb/driver_amd_64/androidusba64.cat b/host/windows/prebuilt/usb/driver_amd_64/androidusba64.cat Binary files differindex 9d5db5d1f..cabb288b4 100644 --- a/host/windows/prebuilt/usb/driver_amd_64/androidusba64.cat +++ b/host/windows/prebuilt/usb/driver_amd_64/androidusba64.cat diff --git a/pdk/Pdk.mk b/pdk/Pdk.mk index 88fedf572..319c5ae3d 100644 --- a/pdk/Pdk.mk +++ b/pdk/Pdk.mk @@ -48,7 +48,7 @@ pdk_docs_intermediates := $(call intermediates-dir-for,PACKAGING,pdkdocs) pdk_templates_dir := development/pdk/docs pdk_config_dir := development/pdk/doxygen_config pdk_docsfile_dir := $(pdk_config_dir)/docsfiles -pdk_hardware_dir := hardware/libhardware/include/hardware +pdk_legacy_hardware_dir := hardware/libhardware_legacy/include/hardware_legacy pdk_camera_dir := frameworks/base/include/ui # Destination directory for docs (templates + doxygenated headers) @@ -74,9 +74,10 @@ doxygen_version = doxygen # Header files to doxygenize. # Add new header files to document here, also adjust the templates to have # descriptions for the new headers and point to the new doxygen created html. -pdk_headers := $(pdk_hardware_dir)/AudioHardwareInterface.h \ - $(pdk_hardware_dir)/gps.h \ - $(pdk_hardware_dir)/wifi.h \ +pdk_headers := \ + $(pdk_legacy_hardware_dir)/AudioHardwareInterface.h \ + $(pdk_legacy_hardware_dir)/gps.h \ + $(pdk_legacy_hardware_dir)/wifi.h \ $(pdk_camera_dir)/CameraHardwareInterface.h # Create a rule to copy the list of PDK headers to be doxyginated. diff --git a/pdk/README b/pdk/README index ab923becf..29f46d41a 100644 --- a/pdk/README +++ b/pdk/README @@ -66,3 +66,7 @@ The build target 'pdk' brings in the pdk/ndk make files into the build system. pdk_docs - which builds the pdk documentation ndk - which builds the native development kit (native compiler, linker, etc.) pdk_all - which builds the above two targets + +for doxygen version changing you can pass in the variable: +doxygen_version='<path/name_of_doxygen_executable>' +on the make line. diff --git a/pdk/doxygen_config/footer.html b/pdk/doxygen_config/footer.html new file mode 100644 index 000000000..691287b6e --- /dev/null +++ b/pdk/doxygen_config/footer.html @@ -0,0 +1,2 @@ +</body> +</html>
\ No newline at end of file diff --git a/pdk/doxygen_config/header.html b/pdk/doxygen_config/header.html new file mode 100644 index 000000000..b26c3030a --- /dev/null +++ b/pdk/doxygen_config/header.html @@ -0,0 +1,15 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> +<title>Doxygen-Generated Content</title> +<link href="doxygen.css" rel="stylesheet" type="text/css" /> +<style type="text/css"> +<!-- +.navigation { + display: none; +} +--> +</style> +</head> +<body>
\ No newline at end of file diff --git a/samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java b/samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java index c6e572923..36d4233ff 100644 --- a/samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java +++ b/samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java @@ -16,7 +16,6 @@ package com.example.android.softkeyboard; -import android.content.Context; import android.inputmethodservice.InputMethodService; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; @@ -25,7 +24,6 @@ import android.util.Log; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.View; -import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; @@ -44,6 +42,16 @@ public class SoftKeyboard extends InputMethodService implements KeyboardView.OnKeyboardActionListener { static final boolean DEBUG = false; + /** + * This boolean indicates the optional example code for performing + * processing of hard keys in addition to regular text generation + * from on-screen interaction. It would be used for input methods that + * perform language translations (such as converting text entered on + * a QWERTY keyboard to Chinese), but may not be used for input methods + * that are primarily intended to be used for on-screen text entry. + */ + static final boolean PROCESS_HARD_KEYS = true; + private KeyboardView mInputView; private CandidateView mCandidateView; private CompletionInfo[] mCompletions; @@ -62,13 +70,17 @@ public class SoftKeyboard extends InputMethodService private String mWordSeparators; + /** + * Helper function to generate the various keyboard layouts used by the + * input method. Takes care of regenerating the layouts if the width + * of the input method changes. + */ private void makeKeyboards() { - // Configuration change is coming after the keyboard gets recreated. So don't rely on that. - // If keyboards have already been made, check if we have a screen width change and - // create the keyboard layouts again at the correct orientation if (mQwertyKeyboard != null) { - WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); - int displayWidth = wm.getDefaultDisplay().getWidth(); + // Configuration changes can happen after the keyboard gets recreated, + // so we need to be able to re-build the keyboards if the available + // space has changed. + int displayWidth = getMaxWidth(); if (displayWidth == mLastDisplayWidth) return; mLastDisplayWidth = displayWidth; } @@ -77,14 +89,25 @@ public class SoftKeyboard extends InputMethodService mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift); } + /** + * Main initialization of the input method component. Be sure to call + * to super class. + */ @Override public void onCreate() { super.onCreate(); makeKeyboards(); mWordSeparators = getResources().getString(R.string.word_separators); } - @Override - public View onCreateInputView() { + /** + * Called by the framework when your view for creating input needs to + * be generated. This will be called the first time your input method + * is displayed, and every time it needs to be re-created such as due to + * a configuration change. + */ + @Override public View onCreateInputView() { + // We call makeKeyboards() here to regenerate them if needed due to + // a configuration change. makeKeyboards(); mInputView = (KeyboardView) getLayoutInflater().inflate( R.layout.input, null); @@ -93,15 +116,27 @@ public class SoftKeyboard extends InputMethodService return mInputView; } - @Override - public View onCreateCandidatesView() { + /** + * Called by the framework when your view for showing candidates needs to + * be generated, like {@link #onCreateInputView}. + */ + @Override public View onCreateCandidatesView() { mCandidateView = new CandidateView(this); mCandidateView.setService(this); return mCandidateView; } - @Override - public void onStartInputView(EditorInfo attribute, boolean restarting) { + /** + * This is the main point where we do our initialization of the input method + * to begin operating on an application. At this point we have been + * bound to the client, and are now receiving all of the detailed information + * about the target of our edits. + */ + @Override public void onStartInputView(EditorInfo attribute, boolean restarting) { + super.onStartInputView(attribute, restarting); + + // Reset our state. We want to do this even if restarting, because + // the underlying state of the text editor could have changed in any way. mComposing.setLength(0); updateCandidates(); @@ -114,57 +149,105 @@ public class SoftKeyboard extends InputMethodService mCompletionOn = false; mCompletions = null; Keyboard keyboard; + + // We are now going to initialize our state based on the type of + // text being edited. switch (attribute.inputType&EditorInfo.TYPE_MASK_CLASS) { case EditorInfo.TYPE_CLASS_NUMBER: case EditorInfo.TYPE_CLASS_DATETIME: + // Numbers and dates default to the symbols keyboard, with + // no extra features. keyboard = mSymbolsKeyboard; break; + case EditorInfo.TYPE_CLASS_PHONE: + // Phones will also default to the symbols keyboard, though + // often you will want to have a dedicated phone keyboard. keyboard = mSymbolsKeyboard; break; - default: + + case EditorInfo.TYPE_CLASS_TEXT: + // This is general text editing. We will default to the + // normal alphabetic keyboard, and assume that we should + // be doing predictive text (showing candidates as the + // user types). keyboard = mQwertyKeyboard; mPredictionOn = true; - // Make sure that passwords are not displayed in candidate view + + // We now look for a few special variations of text that will + // modify our behavior. int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION; if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD) { + // Do not display predictions / what the user is typing + // when they are entering a password. mPredictionOn = false; } + if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS || variation == EditorInfo.TYPE_TEXT_VARIATION_URI) { + // Our predictions are not useful for e-mail addresses + // or URIs. mPredictionOn = false; } + if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { + // If this is an auto-complete text view, then our predictions + // will not be shown and instead we will allow the editor + // to supply their own. We only show the editor's + // candidates when in fullscreen mode, otherwise relying + // own it displaying its own UI. mPredictionOn = false; mCompletionOn = isFullscreenMode(); } + + // We also want to look at the current state of the editor + // to decide whether our alphabetic keyboard should start out + // shifted. updateShiftKeyState(attribute); break; + + default: + // For all unknown input types, default to the alphabetic + // keyboard with no special features. + keyboard = mQwertyKeyboard; } + // Apply the selected keyboard to the input view. if (mInputView != null) { mInputView.setKeyboard(keyboard); mInputView.closing(); } - - mComposing.setLength(0); - setSuggestions(null, false, false); } - @Override - public void onFinishInput() { + /** + * This is called when the user is done editing a field. We can use + * this to reset our state. + */ + @Override public void onFinishInput() { super.onFinishInput(); + + // Clear current composing text and candidates. mComposing.setLength(0); updateCandidates(); + + // We only hide the candidates window when finishing input on + // a particular editor, to avoid popping the underlying application + // up and down if the user is entering text into the bottom of + // its window. + setCandidatesViewShown(false); + if (mInputView != null) { mInputView.closing(); } } - @Override - public void onUpdateSelection(int oldSelStart, int oldSelEnd, + /** + * Deal with the editor reporting movement of its cursor. + */ + @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) { + // If the current selection in the text view changes, we should // clear whatever candidate text we have. if (mComposing.length() > 0 && (newSelStart != candidatesEnd @@ -178,8 +261,13 @@ public class SoftKeyboard extends InputMethodService } } - @Override - public void onDisplayCompletions(CompletionInfo[] completions) { + /** + * This tells us about completions that the editor has determined based + * on the current text in it. We want to use this in fullscreen mode + * to show the completions ourself, since the editor can not be seen + * in that situation. + */ + @Override public void onDisplayCompletions(CompletionInfo[] completions) { if (mCompletionOn) { mCompletions = completions; if (completions == null) { @@ -196,6 +284,11 @@ public class SoftKeyboard extends InputMethodService } } + /** + * This translates incoming hard key events in to edit operations on an + * InputConnection. It is only needed when using the + * PROCESS_HARD_KEYS option. + */ private boolean translateKeyDown(int keyCode, KeyEvent event) { mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState, keyCode, event); @@ -228,55 +321,71 @@ public class SoftKeyboard extends InputMethodService return true; } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { + /** + * Use this to monitor key events being delivered to the application. + * We get first crack at them, and can either resume them or let them + * continue to the app. + */ + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: + // The InputMethodService already takes care of the back + // key for us, to dismiss the input method if it is shown. + // However, our keyboard could be showing a pop-up window + // that back should dismiss, so we first allow it to do that. if (event.getRepeatCount() == 0 && mInputView != null) { if (mInputView.handleBack()) { return true; } } break; + case KeyEvent.KEYCODE_DEL: + // Special handling of the delete key: if we currently are + // composing text for the user, we want to modify that instead + // of let the application to the delete itself. if (mComposing.length() > 0) { onKey(Keyboard.KEYCODE_DELETE, null); return true; } break; + default: - if (mPredictionOn && translateKeyDown(keyCode, event)) { - return true; + // For all other keys, if we want to do transformations on + // text being entered with a hard keyboard, we need to process + // it and do the appropriate action. + if (PROCESS_HARD_KEYS) { + if (mPredictionOn && translateKeyDown(keyCode, event)) { + return true; + } } } + return super.onKeyDown(keyCode, event); } - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: - // Enable shift key and DPAD to do selections - if (mInputView != null && mInputView.isShown() && mInputView.isShifted()) { - event = new KeyEvent(event.getDownTime(), event.getEventTime(), - event.getAction(), event.getKeyCode(), event.getRepeatCount(), - KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON); - getCurrentInputConnection().sendKeyEvent(event); - return true; - } - break; - default: - if (mPredictionOn) { - mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState, - keyCode, event); - } + /** + * Use this to monitor key events being delivered to the application. + * We get first crack at them, and can either resume them or let them + * continue to the app. + */ + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { + // If we want to do transformations on text being entered with a hard + // keyboard, we need to process the up events to update the meta key + // state we are tracking. + if (PROCESS_HARD_KEYS) { + if (mPredictionOn) { + mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState, + keyCode, event); + } } + return super.onKeyUp(keyCode, event); } + /** + * Helper function to commit any text being composed in to the editor. + */ private void commitTyped(InputConnection inputConnection) { if (mComposing.length() > 0) { inputConnection.commitText(mComposing, mComposing.length()); @@ -285,7 +394,11 @@ public class SoftKeyboard extends InputMethodService } } - public void updateShiftKeyState(EditorInfo attr) { + /** + * Helper to update the shift state of our keyboard based on the initial + * editor state. + */ + private void updateShiftKeyState(EditorInfo attr) { if (attr != null && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) { int caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType); @@ -293,6 +406,9 @@ public class SoftKeyboard extends InputMethodService } } + /** + * Helper to determine if a given character code is alphabetic. + */ private boolean isAlphabet(int code) { if (Character.isLetter(code)) { return true; @@ -301,6 +417,9 @@ public class SoftKeyboard extends InputMethodService } } + /** + * Helper to send a key down / key up pair to the current editor. + */ private void keyDownUp(int keyEventCode) { getCurrentInputConnection().sendKeyEvent( new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode)); @@ -308,6 +427,9 @@ public class SoftKeyboard extends InputMethodService new KeyEvent(KeyEvent.ACTION_UP, keyEventCode)); } + /** + * Helper to send a character to the editor as raw key events. + */ private void sendKey(int keyCode) { switch (keyCode) { case '\n': @@ -378,13 +500,13 @@ public class SoftKeyboard extends InputMethodService public void setSuggestions(List<String> suggestions, boolean completions, boolean typedWordValid) { - mCandidateView.setSuggestions(suggestions, completions, typedWordValid); - if (suggestions != null && suggestions.size() > 0) { - setCandidatesViewShown(true); - } else if (isFullscreenMode()) { - setCandidatesViewShown(true); - } else { - setCandidatesViewShown(false); + if (mCandidateView != null) { + mCandidateView.setSuggestions(suggestions, completions, typedWordValid); + if (suggestions != null && suggestions.size() > 0) { + setCandidatesViewShown(true); + } else if (isFullscreenMode()) { + setCandidatesViewShown(true); + } } } @@ -399,7 +521,6 @@ public class SoftKeyboard extends InputMethodService getCurrentInputConnection().commitText("", 0); updateCandidates(); } else { - //getCurrentInputConnection().deleteSurroundingText(1, 0); keyDownUp(KeyEvent.KEYCODE_DEL); } updateShiftKeyState(getCurrentInputEditorInfo()); @@ -439,7 +560,7 @@ public class SoftKeyboard extends InputMethodService updateCandidates(); } else { getCurrentInputConnection().commitText( - String.valueOf((char) primaryCode), 0); + String.valueOf((char) primaryCode), 1); } } @@ -459,7 +580,7 @@ public class SoftKeyboard extends InputMethodService } } - protected String getWordSeparators() { + private String getWordSeparators() { return mWordSeparators; } @@ -504,10 +625,11 @@ public class SoftKeyboard extends InputMethodService } public void swipeUp() { - // ? } - public void onPress(int primaryCode) { } + public void onPress(int primaryCode) { + } - public void onRelease(int primaryCode) { } + public void onRelease(int primaryCode) { + } } diff --git a/tools/activitycreator/.classpath b/tools/activitycreator/.classpath deleted file mode 100644 index fb5011632..000000000 --- a/tools/activitycreator/.classpath +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<classpath> - <classpathentry kind="src" path="src"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="output" path="bin"/> -</classpath> diff --git a/tools/activitycreator/.project b/tools/activitycreator/.project deleted file mode 100644 index b81a8871d..000000000 --- a/tools/activitycreator/.project +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>ActivityCreator</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - <buildCommand> - <name>org.eclipse.jdt.core.javabuilder</name> - <arguments> - </arguments> - </buildCommand> - </buildSpec> - <natures> - <nature>org.eclipse.jdt.core.javanature</nature> - </natures> -</projectDescription> diff --git a/tools/activitycreator/Android.mk b/tools/activitycreator/Android.mk deleted file mode 100644 index 924c9b6c4..000000000 --- a/tools/activitycreator/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -# 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. - -ACTIVITY_CREATOR_LOCAL_DIR := $(call my-dir) -include $(ACTIVITY_CREATOR_LOCAL_DIR)/etc/Android.mk -include $(ACTIVITY_CREATOR_LOCAL_DIR)/src/Android.mk diff --git a/tools/activitycreator/MODULE_LICENSE_APACHE2 b/tools/activitycreator/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29bb..000000000 --- a/tools/activitycreator/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/tools/activitycreator/etc/Android.mk b/tools/activitycreator/etc/Android.mk deleted file mode 100644 index 9128d8838..000000000 --- a/tools/activitycreator/etc/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -# 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. - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_PREBUILT_EXECUTABLES := activitycreator -include $(BUILD_HOST_PREBUILT) - diff --git a/tools/activitycreator/etc/activitycreator b/tools/activitycreator/etc/activitycreator deleted file mode 100755 index f387d171c..000000000 --- a/tools/activitycreator/etc/activitycreator +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# 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. - -TOOLS_DIR=`dirname $0` -AC_JARFILE=$TOOLS_DIR/lib/activitycreator.jar - -java -Dcom.android.activitycreator.toolsdir=$TOOLS_DIR -cp $AC_JARFILE com.android.activitycreator.ActivityCreator "$@" diff --git a/tools/activitycreator/etc/activitycreator.bat b/tools/activitycreator/etc/activitycreator.bat deleted file mode 100755 index 1cf1847fc..000000000 --- a/tools/activitycreator/etc/activitycreator.bat +++ /dev/null @@ -1,22 +0,0 @@ -@echo off -rem Copyright (C) 2007 The Android Open Source Project -rem -rem Licensed under the Apache License, Version 2.0 (the "License"); -rem you may not use this file except in compliance with the License. -rem You may obtain a copy of the License at -rem -rem http://www.apache.org/licenses/LICENSE-2.0 -rem -rem Unless required by applicable law or agreed to in writing, software -rem distributed under the License is distributed on an "AS IS" BASIS, -rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -rem See the License for the specific language governing permissions and -rem limitations under the License. - -rem don't modify the caller's environmeny -setlocal - -set toolsdir=%~dp0\ -set acjarfile=%toolsdir%/lib/activitycreator.jar - -call java -Dcom.android.activitycreator.toolsdir="%toolsdir%" -cp "%acjarfile%" com.android.activitycreator.ActivityCreator %* diff --git a/tools/activitycreator/src/Android.mk b/tools/activitycreator/src/Android.mk deleted file mode 100644 index eea427a0d..000000000 --- a/tools/activitycreator/src/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -# 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. - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_MODULE := activitycreator - -include $(BUILD_HOST_JAVA_LIBRARY) - diff --git a/tools/activitycreator/src/com/android/activitycreator/ActivityCreator.java b/tools/activitycreator/src/com/android/activitycreator/ActivityCreator.java deleted file mode 100644 index f7db7df6d..000000000 --- a/tools/activitycreator/src/com/android/activitycreator/ActivityCreator.java +++ /dev/null @@ -1,881 +0,0 @@ -/* - * 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.activitycreator; - -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -/** - * Creates the basic files needed to get an Android project up and running. Also - * allows creation of IntelliJ project files. - * - * @hide - */ -public class ActivityCreator { - // FIXME: target platform must be provided by the user - private final String mTargetPlatform = "android-1.1"; - - /** Whether we are in silent mode (i.e.: don't print any non-error messages) */ - private boolean mSilent; - - /** Path to tools */ - private String mToolsDir; - - /** Path to SDK */ - private String mSdkDir; - - /** Path to target platform's template folder */ - private String mTemplateDir; - - /** Path to tools/lib for the build templates */ - private String mLibDir; - - /** Path to output */ - private String mOutDir; - - /** IDE to generate for */ - private String mIde; - - /** Data used for the "alias" mode */ - private String mAliasData; - - /** Application label used in the "alias" mode */ - private String mApplicationLabel; - - /** Package of Activity */ - private String mPackageFull; - - /** - * Constructs object. - * @param args arguments passed to the program - */ - public ActivityCreator(String[] args) { - mSilent = false; - - mIde = ""; - - initPathVars(); - parseArgs(args); - - if (isAliasProject()) { - setupAliasProject(); - } else { - setupProject(); - } - } - - /** - * Initializes the path variables based on location of this class. - */ - private void initPathVars() { - /* We get passed a property for the tools dir */ - String toolsDirProp = System.getProperty("com.android.activitycreator.toolsdir"); - if (toolsDirProp == null) { - // for debugging, it's easier to override using the process environment - toolsDirProp = System.getenv("com.android.activitycreator.toolsdir"); - } - if (toolsDirProp == null) { - printHelpAndExit("ERROR: The tools directory property is not set, please make sure you are executing activitycreator or activitycreator.bat"); - } - - /* Absolute path */ - File toolsDir = new File(toolsDirProp); - try { - mToolsDir = toolsDir.getCanonicalPath(); - } catch (IOException e) { - printHelpAndExit("ERROR: Could not determine the tools directory."); - } - toolsDir = new File(mToolsDir); - - mSdkDir = toolsDir.getParent(); - mLibDir = mToolsDir + File.separator + "lib"; - mTemplateDir = mSdkDir + File.separator + "platforms" + File.separator + - mTargetPlatform + File.separator + "templates"; - try { - mOutDir = new File("").getCanonicalPath(); - } catch (IOException e) { - printHelpAndExit("ERROR: Could not determine the current directory."); - } - - if (!toolsDir.exists()) { - printHelpAndExit("ERROR: Tools directory does not exist."); - } - - if (!(new File(mSdkDir).exists())) { - printHelpAndExit("ERROR: SDK directory does not exist."); - } - - if (!(new File(mTemplateDir).exists())) { - printHelpAndExit("ERROR: Target platform templates directory does not exist."); - } - - if (!(new File(mLibDir).exists())) { - printHelpAndExit("ERROR: Library directory does not exist."); - } - } - - /** - * Parses command-line arguments, or prints help/usage and exits if error. - * @param args arguments passed to the program - */ - private void parseArgs(String[] args) { - final int numArgs = args.length; - - try { - int argPos = 0; - for (; argPos < numArgs; argPos++) { - final String arg = args[argPos]; - if (arg.equals("-o") || arg.equals("-out") || arg.equals("--out")) { - argPos++; - mOutDir = args[argPos]; - } else if (arg.equals("-d") || arg.equals("-data") || arg.equals("--data")) { - argPos++; - mAliasData = args[argPos]; - } else if (arg.equals("-l") || arg.equals("-label") || arg.equals("--label")) { - argPos++; - mApplicationLabel = args[argPos]; - } else if (arg.equals("-i") || arg.equals("-ide") || arg.equals("--ide")) { - argPos++; - mIde = args[argPos].toLowerCase(); - } else if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")) { - printHelpAndExit(null); - } else if (arg.equals("-s") || arg.equals("-silent") || arg.equals("--silent")) { - mSilent = true; - } else { - if (mPackageFull == null) { - mPackageFull = extractPackageFromManifest(args[argPos]); - if (mPackageFull == null) { - mPackageFull = args[argPos]; - } - } else { - /* Package has already been set, so this is an extra argument */ - printHelpAndExit("ERROR: Too many arguments: %1$s", args[argPos]); - } - } - } - } catch (ArrayIndexOutOfBoundsException e) { - /* Any OOB triggers help */ - printHelpAndExit("ERROR: Not enough arguments."); - } - - if (isStringEmpty(mPackageFull)) { - printHelpAndExit("ERROR: Please enter a package."); - } - - if (isStringEmpty(mOutDir)) { - printHelpAndExit("ERROR: Please enter an output directory."); - } - - // we need both application label and url for the "alias" mode - if (isStringEmpty(mAliasData) ^ isStringEmpty(mApplicationLabel)) { - printHelpAndExit("ERROR: Alias projects require both --data and --label."); - } - - if (mIde.equals("eclipse")) { - printHelpAndExit("ERROR: For Eclipse support, please install the Eclipse ADT plugin and use its New Project Wizard."); - } - } - - /** - * Prints the help/usage and exits. - * @param errorFormat Optional error message to print prior to usage using String.format - * @param args Arguments for String.format - */ - private void printHelpAndExit(String errorFormat, Object... args) { - if (errorFormat != null) { - System.err.println(String.format(errorFormat, args)); - } - - /* - * usage should fit in 80 columns - * 12345678901234567890123456789012345678901234567890123456789012345678901234567890 - */ - final String usage = "\n" + - "Activity Creator Script.\n" + - "\n" + - "Usage:\n" + - " activitycreator --out outdir [--ide intellij] your.package.name.ActivityName\n" + - " activitycreator --out outdir [--ide intellij] path/to/AndroidManifest.xml\n" + - " activitycreator --out outdir --data data --label app_label your.package.name\n" + - "\n" + - "With both the --data and --label options, ActivityCreator creates the structure\n" + - "of an 'alias' Android application.\n" + - " An Alias project is an application with no code that simply launches an\n" + - " android.intent.action.VIEW intent with the provided data.\n" + - " The following will be created (existing files will not be modified):\n" + - " - AndroidManifest.xml: The application manifest file.\n" + - " - build.xml: An Ant script to build/package the application.\n" + - " - res/values/strings.xml: an XML file defining the application label\n" + - " string resource.\n" + - " - res/xml/alias.xml: an XML file defining the VIEW intent and its data.\n " + - "\n" + - "Without --data and --label, ActivityCreator creates the structure of a minimal\n" + - "Android application.\n" + - " The following will be created (existing files will not be modified):\n" + - " - AndroidManifest.xml: The application manifest file.\n" + - " - build.xml: An Ant script to build/package the application.\n" + - " - res : The resource directory.\n" + - " - src : The source directory.\n" + - " - src/your/package/name/ActivityName.java the Activity java class.\n" + - " packageName is a fully qualified java Package in the format\n" + - " <package1>.<package2>... (with at least two components).\n" + - " - bin : The output folder for the build script.\n" + - "\n" + - "Options:\n" + - " -o <folder>, --out <folder>\n" + - " Specifies where to create the files/folders.\n" + - " -i intellij, --ide intellij\n" + - " Creates project files for IntelliJ (non alias application only)\n" + - " -d <data-string>, --data <data-string>\n" + - " The data passed to the VIEW intent. For instance, this can be a url,\n" + - " such as http://www.android.com\n" + - " -l <app-label>, --label <app-label>\n" + - " The name the alias application will have in the HOME screen.\n" + - " -h, --help\n" + - " Display this help.\n" + - " -s, --silent\n" + - " Silent mode.\n" + - "\n" + - "For Eclipse support, please use the ADT plugin.\n"; - - println(usage); - System.exit(1); - } - - /** - * Installs a destination file that is based on a code template file at the source. - * For each match of each key in keywords will be replaced with its - * corresponding value in the destination file. - * - * Invokes {@link #installProjectTemplate(String, String, Map, boolean, String)} with - * the main project output directory (#mOutDir) as the last argument. - * - * @param source the name of to the source template file - * @param dest the path to the destination file - * @param keywords in the destination file, the keys will be replaced by their values - * @param force True to force writing the file even if it already exists - * - * @see #installProjectTemplate(String, String, Map, boolean, String) - */ - private void installProjectTemplate(String source, String dest, - Map<String, String> keywords, boolean force) { - installProjectTemplate(source, dest, keywords, force, mOutDir); - } - - /** - * Installs a destination file that is based on a code template file at the source. - * For each match of each key in keywords will be replaced with its - * corresponding value in the destination file. - * - * @param source the name of to the source template file - * @param dest the path to the destination file - * @param keywords in the destination file, the keys will be replaced by their values - * @param force True to force writing the file even if it already exists - * @param outDir the output directory to copy the template file to - */ - private void installProjectTemplate(String source, String dest, - Map<String, String> keywords, boolean force, String outDir) { - final String sourcePath = mTemplateDir + File.separator + source; - final String destPath = outDir + File.separator + dest; - - installFullPathTemplate(sourcePath, destPath, keywords, force); - } - - /** - * Installs a destination file that is based on a build template file at the source. - * For each match of each key in keywords will be replaced with its - * corresponding value in the destination file. - * - * Invokes {@link #installBuildTemplate(String, String, Map, boolean, String)} with - * the main project output directory (#mOutDir) as the last argument. - * - * @param source the name of to the source template file - * @param dest the path to the destination file - * @param keywords in the destination file, the keys will be replaced by their values - * @param force True to force writing the file even if it already exists - * - * @see #installBuildTemplate(String, String, Map, boolean, String) - */ - private void installBuildTemplate(String source, String dest, - Map<String, String> keywords, boolean force) { - installBuildTemplate(source, dest, keywords, force, mOutDir); - } - - /** - * Installs a destination file that is based on a build template file at the source. - * For each match of each key in keywords will be replaced with its - * corresponding value in the destination file. - * - * @param source the name of to the source template file - * @param dest the path to the destination file - * @param keywords in the destination file, the keys will be replaced by their values - * @param force True to force writing the file even if it already exists - * @param outDir the output directory to copy the template file to - */ - private void installBuildTemplate(String source, String dest, - Map<String, String> keywords, boolean force, String outDir) { - final String sourcePath = mLibDir + File.separator + source; - final String destPath = outDir + File.separator + dest; - - installFullPathTemplate(sourcePath, destPath, keywords, force); - } - - /** - * Installs a destination file that is based on the template file at source. - * For each match of each key in keywords will be replaced with its - * corresponding value in the destination file. - * - * @param sourcePath the full path to the source template file - * @param destPath the full path to the destination file - * @param keywords in the destination file, the keys will be replaced by their values - * @param force True to force writing the file even if it already exists - */ - private void installFullPathTemplate(String sourcePath, String destPath, - Map<String, String> keywords, boolean force) { - final File destPathFile = new File(destPath); - if (!force && destPathFile.exists()) { - println("WARNING! The file %1$s already exists and will not be overwritten!\n", - destPathFile.getName()); - return; - } - - try { - BufferedWriter out = new BufferedWriter(new FileWriter(destPathFile)); - BufferedReader in = new BufferedReader(new FileReader(sourcePath)); - String line; - - while ((line = in.readLine()) != null) { - for (String key : keywords.keySet()) { - line = line.replace(key, keywords.get(key)); - } - - out.write(line); - out.newLine(); - } - - out.close(); - in.close(); - } catch (Exception e) { - printHelpAndExit("ERROR: Could not access %1$s: %2$s", destPath, e.getMessage()); - } - - println("Added file %1$s", destPath); - } - - /** - * Set up the Android-related files - */ - private void setupProject() { - String packageName = null; - String activityName = null; - String activityTestName = null; - try { - /* Grab package and Activity names */ - int lastPeriod = mPackageFull.lastIndexOf('.'); - packageName = mPackageFull.substring(0, lastPeriod); - if (lastPeriod < mPackageFull.length() - 1) { - activityName = mPackageFull.substring(lastPeriod+1); - activityTestName = activityName + "Test"; - } - - if (packageName.indexOf('.') == -1) { - printHelpAndExit("ERROR: Package name must be composed of at least two java identifiers."); - } - } catch (RuntimeException e) { - printHelpAndExit("ERROR: Invalid package or activity name."); - } - - println("Package: %1$s", packageName); - println("Output directory: %1$s", mOutDir); - String testsOutDir = mOutDir + File.separator + "tests"; - println("Tests directory: %1$s", testsOutDir); - - if (activityName != null) { - println("Activity name: %1$s", activityName); - } - if (activityTestName != null) { - println("ActivityTest name: %1$s", activityTestName); - } - - final HashMap<String, String> keywords = createBaseKeywordMap(); - - addTargetKeywords(keywords); - - keywords.put("PACKAGE", packageName); - if (activityName != null) { - keywords.put("ACTIVITY_NAME", activityName); - } - - final String packagePath = - stripString(packageName.replace(".", File.separator), - File.separatorChar); - keywords.put("PACKAGE_PATH", packagePath); - - /* Other files that are always created */ - - /* Make Activity java file */ - final String srcDir = "src" + File.separator + packagePath; - createDirs(srcDir); - if (isDirEmpty(srcDir, "Java") && activityName != null) { - installProjectTemplate("java_file.template", srcDir + File.separator - + activityName + ".java", keywords, false /*force*/); - } - createDirs("bin"); - createDirs("libs"); - createDirs("res"); - - /* Make ActivityTest java file */ - createDirs(srcDir, testsOutDir); - if (isDirEmpty(srcDir, "Java", testsOutDir) && activityTestName != null) { - installProjectTemplate("java_tests_file.template", srcDir + File.separator - + activityTestName + ".java", keywords, false, testsOutDir); - } - createDirs("bin", testsOutDir); - createDirs("libs", testsOutDir); - createDirs("res", testsOutDir); - - /* Make res files */ - final String valuesDir = "res" + File.separator + "values"; - createDirs(valuesDir); - if (isDirEmpty(valuesDir, "Resource Values")) { - installProjectTemplate("strings.template", valuesDir + File.separator - + "strings.xml", keywords, false /*force*/); - } - - final String layoutDir = "res" + File.separator + "layout"; - createDirs(layoutDir); - if (isDirEmpty(layoutDir, "Resource Layout")) { - installProjectTemplate("layout.template", layoutDir + File.separator - + "main.xml", keywords, false /*force*/); - } - - /* Make AndroidManifest.xml and build.xml files */ - installProjectTemplate("AndroidManifest.template", "AndroidManifest.xml", - keywords, false /*force*/); - - installBuildTemplate("build.template", "build.xml", keywords, false /*force*/); - installBuildTemplate("default.properties.template", "default.properties", keywords, - true /*force*/); - - /* Make AndroidManifest.xml and build.xml files for tests */ - installProjectTemplate("AndroidManifest.tests.template", "AndroidManifest.xml", - keywords, false /*force*/, testsOutDir); - - installBuildTemplate("build.template", "build.xml", keywords, false /*force*/, testsOutDir); - installBuildTemplate("default.properties.template", "default.properties", keywords, - true /*force*/, testsOutDir); - - if (mIde.equals("intellij")) { - /* IntelliJ files */ - if (activityName != null) { - installProjectTemplate("iml.template", activityName + ".iml", keywords, - false /*force*/); - installProjectTemplate("ipr.template", activityName + ".ipr", keywords, - false /*force*/); - installProjectTemplate("iws.template", activityName + ".iws", keywords, - false /*force*/); - } - } else if (!isStringEmpty(mIde)) { - println("WARNING: Unknown IDE option \"%1$s\". No IDE files generated.", - mIde); - } - } - - - /** - * Sets up the files for an alias project. - */ - private void setupAliasProject() { - println("Package: %1$s", mPackageFull); - println("Output directory: %1$s", mOutDir); - println("URL: %1$s", mAliasData); - println("Application label: %1$s", mApplicationLabel); - - if (mIde != null) { - println("Alias project: ignoring --ide option."); - } - - final HashMap<String, String> keywords = createBaseKeywordMap(); - keywords.put("PACKAGE", mPackageFull); - keywords.put("ALIASDATA", mAliasData); - - // since strings.xml uses ACTIVITY_NAME for the application label we use it as well. - // since we'll use a different AndroidManifest template this is not a problem. - keywords.put("ACTIVITY_NAME", mApplicationLabel); - - /* Make res files */ - final String xmlDir = "res" + File.separator + "xml"; - createDirs(xmlDir); - if (isDirEmpty(xmlDir, "Resource Xml")) { - installProjectTemplate("alias.template", xmlDir + File.separator + "alias.xml", - keywords, false /*force*/); - } - - final String valuesDir = "res" + File.separator + "values"; - createDirs(valuesDir); - if (isDirEmpty(valuesDir, "Resource Values")) { - installProjectTemplate("strings.template", valuesDir + File.separator - + "strings.xml", keywords, false /*force*/); - } - - - /* Make AndroidManifest.xml and build.xml files */ - installProjectTemplate("AndroidManifest.alias.template", "AndroidManifest.xml", keywords, - false /*force*/); - - installBuildTemplate("build.alias.template", "build.xml", keywords, false /*force*/); - installBuildTemplate("default.properties.template", "default.properties", keywords, true /*force*/); - } - - - private HashMap<String, String> createBaseKeywordMap() { - final HashMap<String, String> keywords = new HashMap<String, String>(); - - // When the tools & sdk folder on Windows get written to a properties file, - // we need to transform \ in /, otherwise it gets interpreted as an escape character. - // This is OK since ant can understand / as a separator even under Windows. - // References: - // - http://ant.apache.org/manual/CoreTasks/property.html - // - http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream) - keywords.put("ANDROID_SDK_TOOLS", mToolsDir.replace('\\', '/')); - keywords.put("ANDROID_SDK_FOLDER", mSdkDir.replace('\\', '/')); - - return keywords; - } - - private void addTargetKeywords(HashMap<String, String> keywords) { - // FIXME: get this from the target selection - keywords.put("TARGET_MODE", "platform"); - keywords.put("TARGET_API", "1"); // this is potentially wrong but since it's only used - // when editing a project config, this is ok for now. - keywords.put("TARGET_NAME", "android"); // this is only used in add-on mode. - keywords.put("TARGET_FOLDER", mTargetPlatform); - keywords.put("TARGET_MODE", "platform"); - } - - - /** - * Called first. - * @param args arguments passed to the program - */ - public static void main(String[] args) { - new ActivityCreator(args); - } - - /** - * Prints a message unless silence is enabled. - * @param format Format for String.format - * @param args Arguments for String.format - */ - public void println(String format, Object... args) { - if (!mSilent) { - System.out.println(String.format(format, args)); - } - } - - /** - * Checks whether a string is "empty" (null or trimmed length == 0) - * @param s the string to check - * @return true if empty - */ - public static boolean isStringEmpty(String s) { - return (s == null) || (s.trim().length() == 0); - } - - /** - * Creates the path in the output directory along with any parent paths - * that don't exist. - * - * Invokes ActivityCreator#createDirs(String, String) with - * the main project output directory (#mOutDir) as the last argument. - * - * @param path the directory out/path that is created. - * - * @see com.android.activitycreator.ActivityCreator#createDirs(String, String) - */ - public void createDirs(String path) { - createDirs(path, mOutDir); - } - - /** - * Creates the path in the output directory along with any parent paths - * that don't exist. - * - * @param path the directory out/path that is created. - * @param dir the directory in which the path to be created - */ - public void createDirs(String path, String dir) { - final File pathFile = new File(dir + File.separator + path); - boolean existedBefore = true; - - if (!pathFile.exists()) { - if (!pathFile.mkdirs()) { - printHelpAndExit("ERROR: Could not create directory: %1$s", pathFile); - } - existedBefore = false; - } - - if (pathFile.isDirectory()) { - if (!pathFile.canWrite()) { - printHelpAndExit("ERROR: Path is not writable: %1$s", pathFile); - } - } else { - printHelpAndExit("ERROR: Path is not a directory: %1$s", pathFile); - } - - if (!existedBefore) { - try { - println("Created directory %1$s", pathFile.getCanonicalPath()); - } catch (IOException e) { - printHelpAndExit("ERROR: Could not determine canonical path of created directory"); - } - } - } - - /** - * Checks whether the path in the output directory is empty - * - * Invokes ActivityCreator#isDirEmpty(String, String, String) with - * the main project output directory (#mOutDir) as the last argument. - * - * @param path the out/path directory that is checked - * @param message the logical name for what this path points to (used in - * warning message) - * @return whether the directory is empty - * @see com.android.activitycreator.ActivityCreator#isDirEmpty(String, String, String) - */ - public boolean isDirEmpty(String path, String message) { - return isDirEmpty(path, message, mOutDir); - } - - /** - * Checks whether the path in the output directory is empty - * - * @param path the out/path directory that is checked - * @param message the logical name for what this path points to (used in - * warning message) - * @param outDir the output director to check - * @return whether the directory is empty - */ - public boolean isDirEmpty(String path, String message, String outDir) { - File pathFile = new File(outDir + File.separator + path); - - String[] pathListing = pathFile.list(); - if ((pathListing != null) && (pathListing.length > 0)) { - println("WARNING: There are already some %1$s files present. None will be created!", - message); - return false; - } - - return true; - } - - /** - * Strips the string of beginning and trailing characters (multiple - * characters will be stripped, example stripString("..test...", '.') - * results in "test"; - * - * @param s the string to strip - * @param strip the character to strip from beginning and end - * @return the stripped string or the empty string if everything is stripped. - */ - public static String stripString(String s, char strip) { - final int sLen = s.length(); - int newStart = 0, newEnd = sLen - 1; - - while (newStart < sLen && s.charAt(newStart) == strip) { - newStart++; - } - while (newEnd >= 0 && s.charAt(newEnd) == strip) { - newEnd--; - } - - /* - * newEnd contains a char we want, and substring takes end as being - * exclusive - */ - newEnd++; - - if (newStart >= sLen || newEnd < 0) { - return ""; - } - - return s.substring(newStart, newEnd); - } - - /** - * Returns true if the project is an alias project. - * <p/> - * Alias projects require both the --url and the --label options. - * @return boolean true if the project requested is an alias project - */ - private boolean isAliasProject() { - return (!isStringEmpty(mAliasData) && !isStringEmpty(mApplicationLabel)); - } - - /** - * Extracts a "full" package & activity name from an AndroidManifest.xml. - * @param osManifestPath The OS path to the AndroidManifest.xml - * @return A full "package.ActivtyName" if this is a valid manifest, - * or "package." (with a dot at the end) if there's no activity, - * or null if there's no valid package namespace. - */ - private String extractPackageFromManifest(String osManifestPath) { - File f = new File(osManifestPath); - if (!f.isFile()) { - return null; - } - - try { - final String nsPrefix = "android"; - final String nsURI = "http://schemas.android.com/apk/res/android"; - - XPath xpath = XPathFactory.newInstance().newXPath(); - - xpath.setNamespaceContext(new NamespaceContext() { - public String getNamespaceURI(String prefix) { - if (nsPrefix.equals(prefix)) { - return nsURI; - } - return XMLConstants.NULL_NS_URI; - } - - public String getPrefix(String namespaceURI) { - if (nsURI.equals(namespaceURI)) { - return nsPrefix; - } - return null; - } - - @SuppressWarnings("unchecked") - public Iterator getPrefixes(String namespaceURI) { - if (nsURI.equals(namespaceURI)) { - ArrayList<String> list = new ArrayList<String>(); - list.add(nsPrefix); - return list.iterator(); - } - return null; - } - - }); - - InputSource source = new InputSource(new FileReader(osManifestPath)); - String packageName = xpath.evaluate("/manifest/@package", source); - - source = new InputSource(new FileReader(osManifestPath)); - - // Select the "android:name" attribute of all <activity> nodes but only if they - // contain a sub-node <intent-filter><action> with an "android:name" attribute which - // is 'android.intent.action.MAIN' and an <intent-filter><category> with an - // "android:name" attribute which is 'android.intent.category.LAUNCHER' - String expression = String.format("/manifest/application/activity" + - "[intent-filter/action/@%1$s:name='android.intent.action.MAIN' and " + - "intent-filter/category/@%1$s:name='android.intent.category.LAUNCHER']" + - "/@%1$s:name", nsPrefix); - - NodeList activityNames = (NodeList) xpath.evaluate(expression, source, - XPathConstants.NODESET); - - // If we get here, both XPath expressions were valid so we're most likely dealing - // with an actual AndroidManifest.xml file. The nodes may not have the requested - // attributes though, if which case we should warn. - - if (packageName == null || packageName.length() == 0) { - printHelpAndExit("ERROR: missing <manifest package=\"...\"> in '%1$s'", - osManifestPath); - } - - // Get the first activity that matched earlier. If there is no activity, - // activityName is set to an empty string and the generated "combined" name - // will be in the form "package." (with a dot at the end). - String activityName = ""; - if (activityNames.getLength() > 0) { - activityName = activityNames.item(0).getNodeValue(); - } - - if (!mSilent && activityNames.getLength() > 1) { - println("WARNING: There is more than one activity defined in '%1$s'.\n" + - "Only the first one will be used. If this is not appropriate, you need\n" + - "to specify one of these values manually instead:", - osManifestPath); - - for (int i = 0; i < activityNames.getLength(); i++) { - String name = activityNames.item(i).getNodeValue(); - name = combinePackageActivityNames(packageName, name); - println("- %1$s", name); - } - } - - if (!mSilent && activityName.length() == 0) { - println("WARNING: missing <activity %1$s:name=\"...\"> in '%2$s'.\n" + - "No activity will be generated.", - nsPrefix, osManifestPath); - } - - return combinePackageActivityNames(packageName, activityName); - - } catch (IOException e) { - printHelpAndExit("ERROR: failed to read '%1$s', %2$s", osManifestPath, e.getMessage()); - } catch (XPathExpressionException e) { - Throwable t = e.getCause(); - printHelpAndExit("ERROR: failed to parse '%1$s', %2$s", osManifestPath, - t == null ? e.getMessage() : t.getMessage()); - } - - return null; - } - - private String combinePackageActivityNames(String packageName, - String activityName) { - // Activity Name can have 3 forms: - // - ".Name" means this is a class name in the given package name. - // The full FQCN is thus packageName + ".Name" - // - "Name" is an older variant of the former. Full FQCN is packageName + "." + "Name" - // - "com.blah.Name" is a full FQCN. Ignore packageName and use activityName as-is. - // To be valid, the package name should have at least two components. This is checked - // later during the creation of the build.xml file, so we just need to detect there's - // a dot but not at pos==0. - - int pos = activityName.indexOf('.'); - if (pos == 0) { - return packageName + activityName; - } else if (pos > 0) { - return activityName; - } else { - return packageName + "." + activityName; - } - } - -} diff --git a/tools/androidprefs/src/com/android/prefs/AndroidLocation.java b/tools/androidprefs/src/com/android/prefs/AndroidLocation.java index 3530f2dd1..a7ceb76a4 100644 --- a/tools/androidprefs/src/com/android/prefs/AndroidLocation.java +++ b/tools/androidprefs/src/com/android/prefs/AndroidLocation.java @@ -56,47 +56,15 @@ public final class AndroidLocation { */ public final static String getFolder() throws AndroidLocationException { if (sPrefsLocation == null) { - String osName = System.getProperty("os.name"); - - // First we check for unknown or non windows OS. - if (osName == null || osName.startsWith("Windows") == false) { - String home = findValidPath("user.home", "HOME"); - - if (home != null) { - sPrefsLocation = home + File.separator + ".android" + File.separator; - } - } else { - String localAppData = findValidPath("LOCALAPPDATA"); - if (localAppData == null) { - localAppData = findValidPath("USERPROFILE"); - if (localAppData != null) { - localAppData = localAppData + "\\Local Settings\\Application Data"; - - // check that this directory exists. - File f = new File(localAppData); - if (f.isDirectory() == false) { - localAppData = null; - } - } - - // ok if nothing worked, revert to HOME - if (localAppData == null) { - localAppData = findValidPath("HOME", "user.home"); - } - } - - if (localAppData != null) { - sPrefsLocation = localAppData + "\\Android\\"; - } - } + String home = findValidPath("user.home", "HOME"); - // if all the above failed, try to create a temporary file to get its parent and - // use that as the folder - if (sPrefsLocation == null) { - // no home dir? + // if the above failed, we throw an exception. + if (home == null) { throw new AndroidLocationException( "Unable to get the home directory. Make sure the user.home property is set up"); } else { + sPrefsLocation = home + File.separator + ".android" + File.separator; + // make sure the folder exists! File f = new File(sPrefsLocation); if (f.exists() == false) { @@ -107,7 +75,7 @@ public final class AndroidLocation { } } } - + return sPrefsLocation; } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/.project b/tools/eclipse/plugins/com.android.ide.eclipse.adt/.project index 6689a1f9b..c7b1ad476 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/.project +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/.project @@ -3,6 +3,8 @@ <name>adt</name> <comment></comment> <projects> + <project>SdkLib</project> + <project>SdkUiLib</project> </projects> <buildSpec> <buildCommand> diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java index a0a3603fb..172b4ae34 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java @@ -82,9 +82,11 @@ public class Sdk { logMessages.add(throwable.getMessage()); } } + public void warning(String warningFormat, Object... arg) { logMessages.add(String.format(warningFormat, arg)); } + public void printf(String msgFormat, Object... arg) { logMessages.add(String.format(msgFormat, arg)); } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java index 0e780a982..65817c306 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java @@ -158,9 +158,6 @@ public class AndroidConstants { /** Regexp for aidl extension, i.e. "\.aidl$" */ public final static String RE_AIDL_EXT = "\\.aidl$"; //$NON-NLS-1$ - /** Namespace for the resource XML, i.e. "http://schemas.android.com/apk/res/android" */ - public final static String NS_RESOURCES = "http://schemas.android.com/apk/res/android"; //$NON-NLS-1$ - /** Namespace pattern for the custom resource XML, i.e. "http://schemas.android.com/apk/res/%s" */ public final static String NS_CUSTOM_RESOURCES = "http://schemas.android.com/apk/res/%1$s"; //$NON-NLS-1$ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java index 2866ce21f..850c59d71 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.common.project; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.XmlErrorHandler.XmlErrorListener; +import com.android.sdklib.SdkConstants; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; @@ -442,7 +443,7 @@ public class AndroidManifestParser { * @param attributeName the name of the attribute to look for. * @param hasNamespace Indicates whether the attribute has an android namespace. * @return a String with the value or null if the attribute was not found. - * @see AndroidConstants#NS_RESOURCES + * @see SdkConstants#NS_RESOURCES */ private String getAttributeValue(Attributes attributes, String attributeName, boolean hasNamespace) { @@ -450,7 +451,7 @@ public class AndroidManifestParser { for (int i = 0 ; i < count ; i++) { if (attributeName.equals(attributes.getLocalName(i)) && ((hasNamespace && - AndroidConstants.NS_RESOURCES.equals(attributes.getURI(i))) || + SdkConstants.NS_RESOURCES.equals(attributes.getURI(i))) || (hasNamespace == false && attributes.getURI(i).length() == 0))) { return attributes.getValue(i); } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java index 8544b25ff..0f1e25574 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java @@ -16,7 +16,7 @@ package com.android.ide.eclipse.common.project; -import com.android.ide.eclipse.common.AndroidConstants; +import com.android.sdklib.SdkConstants; import java.util.Iterator; @@ -48,7 +48,7 @@ public class AndroidXPathFactory { public String getNamespaceURI(String prefix) { if (prefix != null) { if (prefix.equals(mAndroidPrefix)) { - return AndroidConstants.NS_RESOURCES; + return SdkConstants.NS_RESOURCES; } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java index 50d3d2856..a325ccbf6 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java @@ -17,7 +17,6 @@ package com.android.ide.eclipse.editors; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; @@ -29,6 +28,7 @@ import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; import com.android.ide.eclipse.editors.uimodel.UiFlagAttributeNode; +import com.android.sdklib.SdkConstants; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -199,13 +199,13 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { * * @param node The current node. Must not be null. * @param nsUri The namespace URI of which the prefix is to be found, - * e.g. AndroidConstants.NS_RESOURCES + * e.g. {@link SdkConstants#NS_RESOURCES} * @return The first prefix declared or the default "android" prefix. */ private String lookupNamespacePrefix(Node node, String nsUri) { // Note: Node.lookupPrefix is not implemented in wst/xml/core NodeImpl.java // The following emulates this: - // String prefix = node.lookupPrefix(AndroidConstants.NS_RESOURCES); + // String prefix = node.lookupPrefix(SdkConstants.NS_RESOURCES); if (XmlnsAttributeDescriptor.XMLNS_URI.equals(nsUri)) { return "xmlns"; //$NON-NLS-1$ @@ -223,7 +223,7 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { Node attr = attrs.item(n); if ("xmlns".equals(attr.getPrefix())) { //$NON-NLS-1$ String uri = attr.getNodeValue(); - if (AndroidConstants.NS_RESOURCES.equals(uri)) { + if (SdkConstants.NS_RESOURCES.equals(uri)) { return attr.getLocalName(); } visited.add(uri); @@ -234,7 +234,7 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { // Use a sensible default prefix if we can't find one. // We need to make sure the prefix is not one that was declared in the scope // visited above. - prefix = AndroidConstants.NS_RESOURCES.equals(nsUri) ? "android" : "ns"; //$NON-NLS-1$ //$NON-NLS-2$ + prefix = SdkConstants.NS_RESOURCES.equals(nsUri) ? "android" : "ns"; //$NON-NLS-1$ //$NON-NLS-2$ String base = prefix; for (int i = 1; visited.contains(prefix); i++) { prefix = base + Integer.toString(i); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java index 70d03a19b..e0ec86bfb 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java @@ -17,10 +17,10 @@ package com.android.ide.eclipse.editors.descriptors; import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.IconFactory; import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; +import com.android.sdklib.SdkConstants; import org.eclipse.swt.graphics.Image; @@ -45,7 +45,7 @@ public abstract class AttributeDescriptor { * * @param xmlLocalName The XML name of the attribute (case sensitive) * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. */ public AttributeDescriptor(String xmlLocalName, String nsUri) { mXmlLocalName = xmlLocalName; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java index 09f147833..cc923bf54 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java @@ -23,6 +23,7 @@ import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeIn import com.android.ide.eclipse.editors.layout.LayoutConstants; import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; +import com.android.sdklib.SdkConstants; import org.eclipse.swt.graphics.Image; @@ -75,7 +76,7 @@ public final class DescriptorsUtils { * @param xmlName The XML attribute name. * @param uiName The UI attribute name. * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param tooltip An optional tooltip. * @return A new {@link TextAttributeDescriptor} (or derived) instance. */ @@ -90,7 +91,7 @@ public final class DescriptorsUtils { * @param elementXmlName Optional XML local name of the element to which attributes are * being added. When not null, this is used to filter overrides. * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param infos The array of {@link AttributeInfo} to read and append to attributes * @param requiredAttributes An optional set of attributes to mark as "required" (i.e. append * a "*" to their UI name as a hint for the user.) If not null, must contains @@ -125,7 +126,7 @@ public final class DescriptorsUtils { * being added. When not null, this is used to filter overrides. * @param info The {@link AttributeInfo} to append to attributes * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param required True if the attribute is to be marked as "required" (i.e. append * a "*" to its UI name as a hint for the user.) * @param overrides A map [attribute name => TextAttributeDescriptor creator]. A creator diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ElementDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ElementDescriptor.java index 7d7b1c9be..555015537 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ElementDescriptor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ElementDescriptor.java @@ -17,9 +17,9 @@ package com.android.ide.eclipse.editors.descriptors; import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.IconFactory; import com.android.ide.eclipse.editors.uimodel.UiElementNode; +import com.android.sdklib.SdkConstants; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.graphics.Image; @@ -147,7 +147,7 @@ public class ElementDescriptor { public final String getNamespace() { // For now we hard-code the prefix as being "android" if (mXmlName.startsWith("android:")) { //$NON-NLs-1$ - return AndroidConstants.NS_RESOURCES; + return SdkConstants.NS_RESOURCES; } return ""; //$NON-NLs-1$ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ReferenceAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ReferenceAttributeDescriptor.java index 3d3ff2901..336dfe2b3 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ReferenceAttributeDescriptor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ReferenceAttributeDescriptor.java @@ -16,12 +16,12 @@ package com.android.ide.eclipse.editors.descriptors; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.resources.ResourceType; import com.android.ide.eclipse.editors.ui.ResourceValueCellEditor; import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; import com.android.ide.eclipse.editors.uimodel.UiResourceAttributeNode; +import com.android.sdklib.SdkConstants; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.swt.widgets.Composite; @@ -39,7 +39,7 @@ public final class ReferenceAttributeDescriptor extends TextAttributeDescriptor * @param xmlLocalName The XML name of the attribute (case sensitive) * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param tooltip A non-empty tooltip string or null */ public ReferenceAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, @@ -55,7 +55,7 @@ public final class ReferenceAttributeDescriptor extends TextAttributeDescriptor * @param xmlLocalName The XML name of the attribute (case sensitive) * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param tooltip A non-empty tooltip string or null */ public ReferenceAttributeDescriptor(ResourceType resourceType, diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java index a9d2b2e65..77fc0678d 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java @@ -16,11 +16,11 @@ package com.android.ide.eclipse.editors.descriptors; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.ui.TextValueCellEditor; import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; import com.android.ide.eclipse.editors.uimodel.UiTextAttributeNode; +import com.android.sdklib.SdkConstants; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ILabelProvider; @@ -47,7 +47,7 @@ public class TextAttributeDescriptor extends AttributeDescriptor implements IPro * @param xmlLocalName The XML name of the attribute (case sensitive) * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param tooltip A non-empty tooltip string or null */ public TextAttributeDescriptor(String xmlLocalName, String uiName, diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/WidgetPullParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/WidgetPullParser.java index 75d10eda0..e62ab6951 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/WidgetPullParser.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/WidgetPullParser.java @@ -19,6 +19,7 @@ package com.android.ide.eclipse.editors.layout; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; import com.android.layoutlib.api.IXmlPullParser; +import com.android.sdklib.SdkConstants; import org.xmlpull.v1.XmlPullParserException; @@ -61,7 +62,7 @@ public class WidgetPullParser extends BasePullParser { } public String getAttributeNamespace(int index) { - return AndroidConstants.NS_RESOURCES; + return SdkConstants.NS_RESOURCES; } public String getAttributePrefix(int index) { @@ -78,7 +79,7 @@ public class WidgetPullParser extends BasePullParser { } public String getAttributeValue(String ns, String name) { - if (AndroidConstants.NS_RESOURCES.equals(ns)) { + if (SdkConstants.NS_RESOURCES.equals(ns)) { for (String[] attribute : mAttributes) { if (name.equals(attribute[0])) { return attribute[1]; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java index cad9ccf60..7caa50f12 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java @@ -26,6 +26,7 @@ import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; +import com.android.sdklib.SdkConstants; import java.util.ArrayList; import java.util.Collections; @@ -134,7 +135,7 @@ public final class LayoutDescriptors implements IDescriptorProvider { ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>(); DescriptorsUtils.appendAttributes(attributes, null, // elementName - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, info.getAttributes(), null, // requiredAttributes null /* overrides */); @@ -148,7 +149,7 @@ public final class LayoutDescriptors implements IDescriptorProvider { String.format("Attributes from %1$s", link.getShortClassName()))); DescriptorsUtils.appendAttributes(attributes, null, // elementName - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, attrList, null, // requiredAttributes null /* overrides */); @@ -163,7 +164,7 @@ public final class LayoutDescriptors implements IDescriptorProvider { boolean need_separator = true; for (AttributeInfo attr_info : layoutParams.getAttributes()) { if (DescriptorsUtils.containsAttribute(layoutAttributes, - AndroidConstants.NS_RESOURCES, attr_info)) { + SdkConstants.NS_RESOURCES, attr_info)) { continue; } if (need_separator) { @@ -182,7 +183,7 @@ public final class LayoutDescriptors implements IDescriptorProvider { } DescriptorsUtils.appendAttribute(layoutAttributes, null, // elementName - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, attr_info, false, // required null /* overrides */); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementEditPart.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementEditPart.java index d873005ce..a2e05c7fa 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementEditPart.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementEditPart.java @@ -16,10 +16,10 @@ package com.android.ide.eclipse.editors.layout.parts; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener; import com.android.ide.eclipse.editors.uimodel.UiElementNode; +import com.android.sdklib.SdkConstants; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; @@ -177,7 +177,7 @@ public abstract class UiElementEditPart extends AbstractGraphicalEditPart NamedNodeMap nodeAttributes = xmlNode.getAttributes(); if (nodeAttributes != null) { Node attr = nodeAttributes.getNamedItemNS( - AndroidConstants.NS_RESOURCES, attrName); + SdkConstants.NS_RESOURCES, attrName); if (attr != null) { return attr.getNodeValue(); } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/uimodel/UiViewElementNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/uimodel/UiViewElementNode.java index 45cbc7760..1bf5d5abf 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/uimodel/UiViewElementNode.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/uimodel/UiViewElementNode.java @@ -26,6 +26,7 @@ import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.SdkConstants; import org.eclipse.core.resources.IProject; @@ -109,7 +110,7 @@ public class UiViewElementNode extends UiElementNode { if (need_xmlns) { AttributeDescriptor desc = new XmlnsAttributeDescriptor( "android", //$NON-NLS-1$ - AndroidConstants.NS_RESOURCES); + SdkConstants.NS_RESOURCES); mCachedAttributeDescriptors[direct_attrs.length + layout_attrs.length] = desc; } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java index a0b30ecab..61b73a279 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java @@ -28,6 +28,7 @@ import com.android.ide.eclipse.editors.descriptors.ListAttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.ReferenceAttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; +import com.android.sdklib.SdkConstants; import org.eclipse.core.runtime.IStatus; @@ -166,7 +167,7 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider { XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor( "android", //$NON-NLS-1$ - AndroidConstants.NS_RESOURCES); + SdkConstants.NS_RESOURCES); // -- setup the required attributes overrides -- @@ -355,7 +356,7 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider { ArrayList<AttributeDescriptor> attrDescs = new ArrayList<AttributeDescriptor>(); DescriptorsUtils.appendAttributes(attrDescs, elemDesc.getXmlLocalName(), - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, style.getAttributes(), requiredAttributes, overrides); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java index 1144006d2..abaf438d6 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java @@ -44,7 +44,7 @@ public class ClassAttributeDescriptor extends TextAttributeDescriptor { * @param xmlLocalName The XML name of the attribute (case sensitive, with android: prefix). * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param tooltip A non-empty tooltip string or null. * @param mandatory indicates if the class attribute is mandatory. */ @@ -64,7 +64,7 @@ public class ClassAttributeDescriptor extends TextAttributeDescriptor { * @param xmlLocalName The XML local name of the attribute (case sensitive). * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. + * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param tooltip A non-empty tooltip string or null. * @param mandatory indicates if the class attribute is mandatory. */ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiManifestElementNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiManifestElementNode.java index 79295a817..fb8f2115d 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiManifestElementNode.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiManifestElementNode.java @@ -16,12 +16,12 @@ package com.android.ide.eclipse.editors.manifest.model; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; import com.android.ide.eclipse.editors.manifest.descriptors.ManifestElementDescriptor; import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; +import com.android.sdklib.SdkConstants; import org.w3c.dom.Element; @@ -74,10 +74,10 @@ public final class UiManifestElementNode extends UiElementNode { if (desc != manifestDescriptors.getManifestElement() && desc != manifestDescriptors.getApplicationElement()) { Element elem = (Element) getXmlNode(); - String attr = elem.getAttributeNS(AndroidConstants.NS_RESOURCES, + String attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, AndroidManifestDescriptors.ANDROID_NAME_ATTR); if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(AndroidConstants.NS_RESOURCES, + attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, AndroidManifestDescriptors.ANDROID_LABEL_ATTR); } if (attr != null && attr.length() > 0) { diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/descriptors/MenuDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/descriptors/MenuDescriptors.java index 34c7bb275..40a8f16db 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/descriptors/MenuDescriptors.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/descriptors/MenuDescriptors.java @@ -16,13 +16,13 @@ package com.android.ide.eclipse.editors.menu.descriptors; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.resources.DeclareStyleableInfo; import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; +import com.android.sdklib.SdkConstants; import java.util.ArrayList; import java.util.Map; @@ -121,7 +121,7 @@ public final class MenuDescriptors implements IDescriptorProvider { false /* mandatory */); XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor("android", //$NON-NLS-1$ - AndroidConstants.NS_RESOURCES); + SdkConstants.NS_RESOURCES); updateElement(mDescriptor, styleMap, "Menu", xmlns); //$NON-NLS-1$ mDescriptor.setChildren(new ElementDescriptor[] { top_item, top_group }); @@ -159,7 +159,7 @@ public final class MenuDescriptors implements IDescriptorProvider { if (style != null) { DescriptorsUtils.appendAttributes(descs, null, // elementName - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, style.getAttributes(), null, // requiredAttributes null); // overrides diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiElementNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiElementNode.java index e0e9a4051..3728886b5 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiElementNode.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiElementNode.java @@ -18,7 +18,6 @@ package com.android.ide.eclipse.editors.uimodel; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.AndroidEditor; import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; @@ -31,6 +30,7 @@ import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescr import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener.UiUpdateState; import com.android.ide.eclipse.editors.xml.descriptors.XmlDescriptors; +import com.android.sdklib.SdkConstants; import org.eclipse.core.runtime.IStatus; import org.eclipse.ui.IEditorInput; @@ -201,21 +201,21 @@ public class UiElementNode implements IPropertySource { // just using the UI name below. Element elem = (Element) mXmlNode; - String attr = elem.getAttributeNS(AndroidConstants.NS_RESOURCES, + String attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, AndroidManifestDescriptors.ANDROID_NAME_ATTR); if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(AndroidConstants.NS_RESOURCES, + attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, AndroidManifestDescriptors.ANDROID_LABEL_ATTR); } if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(AndroidConstants.NS_RESOURCES, + attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, XmlDescriptors.PREF_KEY_ATTR); } if (attr == null || attr.length() == 0) { attr = elem.getAttribute(ResourcesDescriptors.NAME_ATTR); } if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(AndroidConstants.NS_RESOURCES, + attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, LayoutDescriptors.ID_ATTR); if (attr != null && attr.length() > 0) { @@ -1205,13 +1205,13 @@ public class UiElementNode implements IPropertySource { * * @param node The current node. Must not be null. * @param nsUri The namespace URI of which the prefix is to be found, - * e.g. AndroidConstants.NS_RESOURCES + * e.g. SdkConstants.NS_RESOURCES * @return The first prefix declared or the default "android" prefix. */ private String lookupNamespacePrefix(Node node, String nsUri) { // Note: Node.lookupPrefix is not implemented in wst/xml/core NodeImpl.java // The following code emulates this simple call: - // String prefix = node.lookupPrefix(AndroidConstants.NS_RESOURCES); + // String prefix = node.lookupPrefix(SdkConstants.NS_RESOURCES); // if the requested URI is null, it denotes an attribute with no namespace. if (nsUri == null) { @@ -1234,7 +1234,7 @@ public class UiElementNode implements IPropertySource { if ("xmlns".equals(attr.getPrefix())) { //$NON-NLS-1$ String uri = attr.getNodeValue(); String nsPrefix = attr.getLocalName(); - if (AndroidConstants.NS_RESOURCES.equals(uri)) { + if (SdkConstants.NS_RESOURCES.equals(uri)) { return nsPrefix; } visited.add(nsPrefix); @@ -1245,7 +1245,7 @@ public class UiElementNode implements IPropertySource { // Use a sensible default prefix if we can't find one. // We need to make sure the prefix is not one that was declared in the scope // visited above. - String prefix = AndroidConstants.NS_RESOURCES.equals(nsUri) ? "android" : "ns"; //$NON-NLS-1$ //$NON-NLS-2$ + String prefix = SdkConstants.NS_RESOURCES.equals(nsUri) ? "android" : "ns"; //$NON-NLS-1$ //$NON-NLS-2$ String base = prefix; for (int i = 1; visited.contains(prefix); i++) { prefix = base + Integer.toString(i); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiListAttributeNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiListAttributeNode.java index aaad0ce72..c5c10aa11 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiListAttributeNode.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiListAttributeNode.java @@ -18,7 +18,6 @@ package com.android.ide.eclipse.editors.uimodel; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.AndroidEditor; import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; @@ -26,6 +25,7 @@ import com.android.ide.eclipse.editors.descriptors.ListAttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; import com.android.ide.eclipse.editors.ui.SectionHelper; +import com.android.sdklib.SdkConstants; import org.eclipse.core.runtime.IStatus; import org.eclipse.swt.SWT; @@ -135,7 +135,7 @@ public class UiListAttributeNode extends UiAbstractTextAttributeNode { // FrameworkResourceManager expects a specific prefix for the attribute. String prefix = ""; - if (AndroidConstants.NS_RESOURCES.equals(descriptor.getNamespaceUri())) { + if (SdkConstants.NS_RESOURCES.equals(descriptor.getNamespaceUri())) { prefix = "android:"; //$NON-NLS-1$ } else if (XmlnsAttributeDescriptor.XMLNS_URI.equals(descriptor.getNamespaceUri())) { prefix = "xmlns:"; //$NON-NLS-1$ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java index cc643be49..4d171762c 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java @@ -163,7 +163,7 @@ class NewXmlFileCreationPage extends WizardPage { /** * If the generated resource XML file requires an "android" XMLNS, this should be set - * to {@link AndroidConstants#NS_RESOURCES}. When it is null, no XMLNS is generated. + * to {@link SdkConstants#NS_RESOURCES}. When it is null, no XMLNS is generated. */ String getXmlns() { return mXmlns; @@ -188,7 +188,7 @@ class NewXmlFileCreationPage extends WizardPage { ResourceFolderType.LAYOUT, // folder type AndroidTargetData.DESCRIPTOR_LAYOUT, // root seed "LinearLayout", // default root - AndroidConstants.NS_RESOURCES, // xmlns + SdkConstants.NS_RESOURCES, // xmlns "android:layout_width=\"wrap_content\"\n" + // default attributes "android:layout_height=\"wrap_content\"" ), @@ -205,7 +205,7 @@ class NewXmlFileCreationPage extends WizardPage { ResourceFolderType.MENU, // folder type MenuDescriptors.MENU_ROOT_ELEMENT, // root seed null, // default root - AndroidConstants.NS_RESOURCES, // xmlns + SdkConstants.NS_RESOURCES, // xmlns null // default attributes ), new TypeInfo("Preference", // UI name @@ -213,7 +213,7 @@ class NewXmlFileCreationPage extends WizardPage { ResourceFolderType.XML, // folder type AndroidTargetData.DESCRIPTOR_PREFERENCES, // root seed AndroidConstants.CLASS_PREFERENCE_SCREEN, // default root - AndroidConstants.NS_RESOURCES, // xmlns + SdkConstants.NS_RESOURCES, // xmlns null // default attributes ), new TypeInfo("Searchable", // UI name @@ -221,7 +221,7 @@ class NewXmlFileCreationPage extends WizardPage { ResourceFolderType.XML, // folder type AndroidTargetData.DESCRIPTOR_SEARCHABLE, // root seed null, // default root - AndroidConstants.NS_RESOURCES, // xmlns + SdkConstants.NS_RESOURCES, // xmlns null // default attributes ), new TypeInfo("Animation", // UI name diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlEditor.java index b1900ae41..d7f611949 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlEditor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlEditor.java @@ -26,6 +26,7 @@ import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.SdkConstants; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; @@ -80,7 +81,7 @@ public class XmlEditor extends AndroidEditor { FirstElementParser.Result result = FirstElementParser.parse( file.getLocation().toOSString(), - AndroidConstants.NS_RESOURCES); + SdkConstants.NS_RESOURCES); if (result != null) { String name = result.getElement(); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java index 31b4c617a..fa1370f31 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java @@ -25,9 +25,10 @@ import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; +import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; +import com.android.sdklib.SdkConstants; import java.util.ArrayList; import java.util.Map; @@ -111,7 +112,7 @@ public final class XmlDescriptors implements IDescriptorProvider { XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor( "android", //$NON-NLS-1$ - AndroidConstants.NS_RESOURCES); + SdkConstants.NS_RESOURCES); ElementDescriptor searchable = createSearchable(searchableStyleMap, xmlns); ElementDescriptor preferences = createPreference(prefs, prefGroups, xmlns); @@ -191,7 +192,7 @@ public final class XmlDescriptors implements IDescriptorProvider { if (style != null) { DescriptorsUtils.appendAttributes(descs, null, // elementName - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, style.getAttributes(), null, // requiredAttributes null); // overrides @@ -280,7 +281,7 @@ public final class XmlDescriptors implements IDescriptorProvider { ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>(); DescriptorsUtils.appendAttributes(attributes, null, // elementName - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, info.getAttributes(), null, // requiredAttributes null); // overrides @@ -294,7 +295,7 @@ public final class XmlDescriptors implements IDescriptorProvider { String.format("Attributes from %1$s", link.getShortClassName()))); DescriptorsUtils.appendAttributes(attributes, null, // elementName - AndroidConstants.NS_RESOURCES, + SdkConstants.NS_RESOURCES, attrList, null, // requiredAttributes null); // overrides diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/.classpath b/tools/eclipse/plugins/com.android.ide.eclipse.tests/.classpath index 1cc51e994..40886832d 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/.classpath +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/.classpath @@ -5,5 +5,6 @@ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="lib" path="kxml2-2.3.0.jar"/> + <classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/.project b/tools/eclipse/plugins/com.android.ide.eclipse.tests/.project index 094260254..99e496486 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/.project +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/.project @@ -3,6 +3,7 @@ <name>adt-tests</name> <comment></comment> <projects> + <project>SdkLib</project> </projects> <buildSpec> <buildCommand> diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/layout/UiElementPullParserTest.java b/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/layout/UiElementPullParserTest.java index 1427eeea0..b0deda0ad 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/layout/UiElementPullParserTest.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/layout/UiElementPullParserTest.java @@ -16,18 +16,17 @@ package com.android.ide.eclipse.editors.layout; -import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; import com.android.ide.eclipse.editors.mock.MockXmlNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; +import com.android.sdklib.SdkConstants; import org.w3c.dom.Node; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import java.io.IOException; import java.util.HashMap; import junit.framework.TestCase; @@ -47,22 +46,22 @@ public class UiElementPullParserTest extends TestCase { // Also add some dummy attributes. ElementDescriptor buttonDescriptor = new ElementDescriptor("Button", "Button", "", "", new AttributeDescriptor[] { - new TextAttributeDescriptor("name", "name", AndroidConstants.NS_RESOURCES, ""), - new TextAttributeDescriptor("text", "text", AndroidConstants.NS_RESOURCES, ""), + new TextAttributeDescriptor("name", "name", SdkConstants.NS_RESOURCES, ""), + new TextAttributeDescriptor("text", "text", SdkConstants.NS_RESOURCES, ""), }, new ElementDescriptor[] {}, false); ElementDescriptor textDescriptor = new ElementDescriptor("TextView", "TextView", "", "", new AttributeDescriptor[] { - new TextAttributeDescriptor("name", "name", AndroidConstants.NS_RESOURCES, ""), - new TextAttributeDescriptor("text", "text", AndroidConstants.NS_RESOURCES, ""), }, + new TextAttributeDescriptor("name", "name", SdkConstants.NS_RESOURCES, ""), + new TextAttributeDescriptor("text", "text", SdkConstants.NS_RESOURCES, ""), }, new ElementDescriptor[] {}, false); ElementDescriptor linearDescriptor = new ElementDescriptor("LinearLayout", "Linear Layout", "", "", new AttributeDescriptor[] { new TextAttributeDescriptor("orientation", "orientation", - AndroidConstants.NS_RESOURCES, ""), + SdkConstants.NS_RESOURCES, ""), }, new ElementDescriptor[] { }, false); @@ -70,7 +69,7 @@ public class UiElementPullParserTest extends TestCase { "Relative Layout", "", "", new AttributeDescriptor[] { new TextAttributeDescriptor("orientation", "orientation", - AndroidConstants.NS_RESOURCES, ""), + SdkConstants.NS_RESOURCES, ""), }, new ElementDescriptor[] { }, false); @@ -99,8 +98,8 @@ public class UiElementPullParserTest extends TestCase { */ MockXmlNode button1 = new MockXmlNode(null /* namespace */, "Button", Node.ELEMENT_NODE, null); - button1.addAttributes(AndroidConstants.NS_RESOURCES, "name", "button1"); - button1.addAttributes(AndroidConstants.NS_RESOURCES, "text", "button1text"); + button1.addAttributes(SdkConstants.NS_RESOURCES, "name", "button1"); + button1.addAttributes(SdkConstants.NS_RESOURCES, "text", "button1text"); // create a map of the attributes we add to the multi-attribute nodes so that // we can more easily test the values when we parse the XML. @@ -112,8 +111,8 @@ public class UiElementPullParserTest extends TestCase { MockXmlNode button2 = new MockXmlNode(null /* namespace */, "Button", Node.ELEMENT_NODE, null); - button2.addAttributes(AndroidConstants.NS_RESOURCES, "name", "button2"); - button2.addAttributes(AndroidConstants.NS_RESOURCES, "text", "button2text"); + button2.addAttributes(SdkConstants.NS_RESOURCES, "name", "button2"); + button2.addAttributes(SdkConstants.NS_RESOURCES, "text", "button2text"); button2Map = new HashMap<String, String>(); button2Map.put("name", "button2"); @@ -121,8 +120,8 @@ public class UiElementPullParserTest extends TestCase { MockXmlNode text = new MockXmlNode(null /* namespace */, "TextView", Node.ELEMENT_NODE, null); - text.addAttributes(AndroidConstants.NS_RESOURCES, "name", "text1"); - text.addAttributes(AndroidConstants.NS_RESOURCES, "text", "text1text"); + text.addAttributes(SdkConstants.NS_RESOURCES, "name", "text1"); + text.addAttributes(SdkConstants.NS_RESOURCES, "text", "text1text"); textMap = new HashMap<String, String>(); textMap.put("name", "text1"); @@ -130,17 +129,17 @@ public class UiElementPullParserTest extends TestCase { MockXmlNode relative = new MockXmlNode(null /* namespace */, "RelativeLayout", Node.ELEMENT_NODE, new MockXmlNode[] { button2, text }); - relative.addAttributes(AndroidConstants.NS_RESOURCES, "orientation", "toto"); + relative.addAttributes(SdkConstants.NS_RESOURCES, "orientation", "toto"); MockXmlNode linear = new MockXmlNode(null /* namespace */, "LinearLayout", Node.ELEMENT_NODE, new MockXmlNode[] { button1, relative }); - linear.addAttributes(AndroidConstants.NS_RESOURCES, "orientation", "vertical"); + linear.addAttributes(SdkConstants.NS_RESOURCES, "orientation", "vertical"); MockXmlNode root = new MockXmlNode(null /* namespace */, "root", Node.ELEMENT_NODE, new MockXmlNode[] { linear }); // put the namespace/prefix in place - root.setPrefix(AndroidConstants.NS_RESOURCES, "android"); + root.setPrefix(SdkConstants.NS_RESOURCES, "android"); // load the xml into the UiElementNode ui.loadFromXmlNode(root); @@ -165,7 +164,7 @@ public class UiElementPullParserTest extends TestCase { assertEquals("LinearLayout", parser.getName()); assertEquals(1, parser.getAttributeCount()); assertEquals("orientation", parser.getAttributeName(0)); - assertEquals(AndroidConstants.NS_RESOURCES, parser.getAttributeNamespace(0)); + assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(0)); assertEquals("android", parser.getAttributePrefix(0)); assertEquals("vertical", parser.getAttributeValue(0)); @@ -183,7 +182,7 @@ public class UiElementPullParserTest extends TestCase { assertEquals("RelativeLayout", parser.getName()); assertEquals(1, parser.getAttributeCount()); assertEquals("orientation", parser.getAttributeName(0)); - assertEquals(AndroidConstants.NS_RESOURCES, parser.getAttributeNamespace(0)); + assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(0)); assertEquals("android", parser.getAttributePrefix(0)); assertEquals("toto", parser.getAttributeValue(0)); @@ -234,7 +233,7 @@ public class UiElementPullParserTest extends TestCase { assertNotNull(referenceValue); assertEquals(referenceValue, value); - assertEquals(AndroidConstants.NS_RESOURCES, parser.getAttributeNamespace(i)); + assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(i)); assertEquals("android", parser.getAttributePrefix(i)); } diff --git a/tools/runtest b/tools/runtest index 989f8a493..9978504d9 100755 --- a/tools/runtest +++ b/tools/runtest @@ -114,7 +114,7 @@ knownTests=( # system-wide tests "framework frameworks/base/tests/FrameworkTest # com.android.frameworktest.AllTests com.android.frameworktest.tests #" "android frameworks/base/tests/AndroidTests com.android.unit_tests AndroidTests # #" - "smoke tests/SmokeTest com.android.smoketest # com.android.smoketest.tests #" + "smoke frameworks/base/tests/SmokeTest com.android.smoketest # com.android.smoketest.tests #" "core frameworks/base/tests/CoreTests # android.core.CoreTests android.core #" "libcore frameworks/base/tests/CoreTests # android.core.JavaTests android.core #" "apidemos samples/ApiDemos com.example.android.apis # com.example.android.apis.tests #" diff --git a/tools/scripts/build.alias.template b/tools/scripts/build.alias.template index b85887e8c..f7de2e889 100644 --- a/tools/scripts/build.alias.template +++ b/tools/scripts/build.alias.template @@ -1,5 +1,5 @@ <?xml version="1.0" ?> -<project name="ACTIVITY_NAME" default="package"> +<project name="PROJECT_NAME" default="package"> <!-- The build.properties file can be created by you and is never touched by activitycreator. If you want to manually set properties, this is diff --git a/tools/scripts/build.template b/tools/scripts/build.template index 8923428a0..350d0f417 100644 --- a/tools/scripts/build.template +++ b/tools/scripts/build.template @@ -1,5 +1,5 @@ <?xml version="1.0" ?> -<project name="ACTIVITY_NAME" default="help"> +<project name="PROJECT_NAME" default="help"> <!-- The local.properties file is created and updated by the 'android' tool. It contain the path to the SDK. It should *NOT* be checked in in Version diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java index d63272df4..2db668ef5 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java @@ -45,6 +45,8 @@ public class CommandLineProcessor { public static final String KEY_HELP = "help"; /** The global verbose flag. */ public static final String KEY_VERBOSE = "verbose"; + /** The global silent flag. */ + public static final String KEY_SILENT = "silent"; /** The internal action flag. */ public static final String KEY_ACTION = "action"; @@ -65,10 +67,18 @@ public class CommandLineProcessor { mLog = logger; mActions = actions; - define(MODE.STRING, false, INTERNAL_FLAG, null, KEY_ACTION, "Selected Action", null); - - define(MODE.BOOLEAN, false, GLOBAL_FLAG, "v", KEY_VERBOSE, "Verbose mode", false); - define(MODE.BOOLEAN, false, GLOBAL_FLAG, "h", KEY_HELP, "This help", false); + define(MODE.STRING, false, INTERNAL_FLAG, null, KEY_ACTION, + "Selected Action", null); + + define(MODE.BOOLEAN, false, GLOBAL_FLAG, "v", KEY_VERBOSE, + "Verbose mode: errors, warnings and informational messages are printed.", + false); + define(MODE.BOOLEAN, false, GLOBAL_FLAG, "s", KEY_SILENT, + "Silent mode: only errors are printed out.", + false); + define(MODE.BOOLEAN, false, GLOBAL_FLAG, "h", KEY_HELP, + "This help.", + false); } //------------------ @@ -79,6 +89,11 @@ public class CommandLineProcessor { return ((Boolean) getValue(GLOBAL_FLAG, KEY_VERBOSE)).booleanValue(); } + /** Helper that returns true if --silent was requested. */ + public boolean isSilent() { + return ((Boolean) getValue(GLOBAL_FLAG, KEY_SILENT)).booleanValue(); + } + /** Helper that returns true if --help was requested. */ public boolean isHelpRequested() { return ((Boolean) getValue(GLOBAL_FLAG, KEY_HELP)).booleanValue(); @@ -204,18 +219,29 @@ public class CommandLineProcessor { needsHelp = "Missing action name."; } else { // Validate that all mandatory arguments are non-null for this action + String missing = null; + boolean plural = false; for (Entry<String, Arg> entry : mArguments.entrySet()) { Arg arg = entry.getValue(); if (arg.getAction().equals(action)) { if (arg.isMandatory() && arg.getCurrentValue() == null) { - needsHelp = String.format("The parameter --%1$s must be defined for action '%2$s'", - arg.getLongArg(), - action); - break; + if (missing == null) { + missing = "--" + arg.getLongArg(); + } else { + missing += ", --" + arg.getLongArg(); + plural = true; + } } } } - + + if (missing != null) { + needsHelp = String.format("The %1$s %2$s must be defined for action '%3$s'", + plural ? "parameters" : "parameter", + missing, + action); + } + setValue(INTERNAL_FLAG, KEY_ACTION, action); } } @@ -324,24 +350,29 @@ public class CommandLineProcessor { Arg arg = entry.getValue(); if (arg.getAction().equals(action)) { - String value = null; + String value = ""; if (arg.getDefaultValue() instanceof String[]) { - value = ""; for (String v : (String[]) arg.getDefaultValue()) { if (value.length() > 0) { - value += "|"; + value += ", "; } value += v; } } else if (arg.getDefaultValue() != null) { value = arg.getDefaultValue().toString(); } + if (value.length() > 0) { + value = " (" + value + ")"; + } + + String required = arg.isMandatory() ? " [required]" : ""; - stdout(" -%1$s %2$-10s %3$s%4$s", + stdout(" -%1$s %2$-10s %3$s%4$s%5$s", arg.getShortArg(), "--" + arg.getLongArg(), arg.getDescription(), - value == null ? "" : " (" + value + ")"); + value, + required); numOptions++; } } diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java index b50b113dd..1544f5bff 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -144,7 +144,7 @@ class Main { if (mSdkFolder == null) { errorAndExit("The tools directory property is not set, please make sure you are executing %1$s", - SdkConstants.AndroidCmdName()); + SdkConstants.androidCmdName()); } // We might get passed a property for the working directory @@ -203,19 +203,48 @@ class Main { IAndroidTarget[] targets = mSdkManager.getTargets(); if (targetId < 1 || targetId > targets.length) { errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.", - SdkConstants.AndroidCmdName()); + SdkConstants.androidCmdName()); } IAndroidTarget target = targets[targetId - 1]; ProjectCreator creator = new ProjectCreator(mSdkFolder, - mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE : OutputLevel.NORMAL, + mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE : + mSdkCommandLine.isSilent() ? OutputLevel.SILENT : + OutputLevel.NORMAL, mSdkLog); String projectDir = getProjectLocation(mSdkCommandLine.getNewProjectLocation()); creator.createProject(projectDir, - mSdkCommandLine.getNewProjectName(), mSdkCommandLine.getNewProjectPackage(), - mSdkCommandLine.getNewProjectActivity(), target, false /* isTestProject*/); + mSdkCommandLine.getNewProjectName(), + mSdkCommandLine.getNewProjectPackage(), + mSdkCommandLine.getNewProjectActivity(), + target, + false /* isTestProject*/); + } else if (SdkCommandLine.ACTION_UPDATE_PROJECT.equals(action)) { + // get the target and try to resolve it. + IAndroidTarget target = null; + int targetId = mSdkCommandLine.getUpdateProjectTargetId(); + if (targetId >= 0) { + IAndroidTarget[] targets = mSdkManager.getTargets(); + if (targetId < 1 || targetId > targets.length) { + errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.", + SdkConstants.androidCmdName()); + } + target = targets[targetId - 1]; + } + + ProjectCreator creator = new ProjectCreator(mSdkFolder, + mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE : + mSdkCommandLine.isSilent() ? OutputLevel.SILENT : + OutputLevel.NORMAL, + mSdkLog); + + String projectDir = getProjectLocation(mSdkCommandLine.getUpdateProjectLocation()); + + creator.updateProject(projectDir, + target, + mSdkCommandLine.getUpdateProjectName()); } else { mSdkCommandLine.printHelpAndExit(null); } @@ -355,7 +384,7 @@ class Main { target = mSdkManager.getTargets()[targetId-1]; // target it is 1-based } else { errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.", - SdkConstants.AndroidCmdName()); + SdkConstants.androidCmdName()); } try { @@ -384,8 +413,7 @@ class Main { mSdkCommandLine.getNewVmName(), target, mSdkCommandLine.getNewVmSkin(), - null /*sdcardPath*/, - 0 /*sdcardSize*/, + mSdkCommandLine.getNewVmSdCard(), hardwareConfig, mSdkLog); } diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java index 39c80b195..08626a833 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java @@ -31,7 +31,6 @@ public class SdkCommandLine extends CommandLineProcessor { public static final String ARG_TARGET = "target"; public static final String ARG_ALL = "all"; - public static final String KEY_IN = "in"; public static final String KEY_ACTIVITY = ARG_ACTIVITY; public static final String KEY_PACKAGE = "package"; public static final String KEY_MODE = "mode"; @@ -40,7 +39,7 @@ public class SdkCommandLine extends CommandLineProcessor { public static final String KEY_OUT = "out"; public static final String KEY_FILTER = "filter"; public static final String KEY_SKIN = "skin"; - public static final String KEY_SDCARD_PATH = "sdcard"; + public static final String KEY_SDCARD = "sdcard"; public final static String ACTION_LIST = "list"; public final static String ACTION_NEW_VM = ARG_VM; @@ -72,26 +71,28 @@ public class SdkCommandLine extends CommandLineProcessor { "Target id of the new VM", null); define(MODE.STRING, true, ACTION_NEW_VM, "s", KEY_SKIN, "Skin of the new VM", null); - define(MODE.STRING, true, ACTION_NEW_VM, "p", KEY_SDCARD_PATH, - "Path to a shared SD card image for the new VM", null); + define(MODE.STRING, false, ACTION_NEW_VM, "c", KEY_SDCARD, + "Path to a shared SD card image, or size of a new sdcard for the new VM", null); define(MODE.ENUM, true, ACTION_NEW_PROJECT, "m", KEY_MODE, "Project mode", new String[] { ARG_ACTIVITY, ARG_ALIAS }); - define(MODE.STRING, false, ACTION_NEW_PROJECT, "o", KEY_OUT, + define(MODE.STRING, true, ACTION_NEW_PROJECT, "o", KEY_OUT, "Location path of new project", null); - define(MODE.STRING, true, ACTION_NEW_PROJECT, "n", KEY_NAME, - "Name of the new project", null); define(MODE.INTEGER, true, ACTION_NEW_PROJECT, "t", KEY_TARGET_ID, "Target id of the new project", null); define(MODE.STRING, true, ACTION_NEW_PROJECT, "p", KEY_PACKAGE, "Package name", null); define(MODE.STRING, true, ACTION_NEW_PROJECT, "a", KEY_ACTIVITY, "Activity name", null); - - define(MODE.STRING, false, ACTION_UPDATE_PROJECT, "i", KEY_IN, - "Directory location of the project", null); - define(MODE.STRING, true, ACTION_UPDATE_PROJECT, "t", KEY_TARGET_ID, - "Target id to set for the project", null); + define(MODE.STRING, false, ACTION_NEW_PROJECT, "n", KEY_NAME, + "Project name", null); + + define(MODE.STRING, true, ACTION_UPDATE_PROJECT, "o", KEY_OUT, + "Location path of the project", null); + define(MODE.INTEGER, true, ACTION_UPDATE_PROJECT, "t", KEY_TARGET_ID, + "Target id to set for the project", -1); + define(MODE.STRING, false, ACTION_UPDATE_PROJECT, "n", KEY_NAME, + "Project name", null); } // -- some helpers for list action flags @@ -123,9 +124,9 @@ public class SdkCommandLine extends CommandLineProcessor { return ((String) getValue(ACTION_NEW_VM, KEY_SKIN)); } - /** Helper to retrieve the --sdcard name for the new vm action. */ + /** Helper to retrieve the --sdcard data for the new vm action. */ public String getNewVmSdCard() { - return ((String) getValue(ACTION_NEW_VM, KEY_SDCARD_PATH)); + return ((String) getValue(ACTION_NEW_VM, KEY_SDCARD)); } @@ -167,4 +168,9 @@ public class SdkCommandLine extends CommandLineProcessor { public int getUpdateProjectTargetId() { return ((Integer) getValue(ACTION_UPDATE_PROJECT, KEY_TARGET_ID)).intValue(); } + + /** Helper to retrieve the --name for the update project action. */ + public String getUpdateProjectName() { + return ((String) getValue(ACTION_UPDATE_PROJECT, KEY_NAME)); + } } diff --git a/tools/sdkmanager/app/tests/com/android/sdkmanager/MockStdLogger.java b/tools/sdkmanager/app/tests/com/android/sdkmanager/MockStdLogger.java new file mode 100644 index 000000000..961e88dae --- /dev/null +++ b/tools/sdkmanager/app/tests/com/android/sdkmanager/MockStdLogger.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.sdkmanager; + +import com.android.sdklib.ISdkLog; + +/** + * + */ +public class MockStdLogger implements ISdkLog { + + public void error(Throwable t, String errorFormat, Object... args) { + if (errorFormat != null) { + System.err.printf("Error: " + errorFormat, args); + if (!errorFormat.endsWith("\n")) { + System.err.printf("\n"); + } + } + if (t != null) { + System.err.printf("Error: %s\n", t.getMessage()); + } + } + + public void warning(String warningFormat, Object... args) { + System.out.printf("Warning: " + warningFormat, args); + if (!warningFormat.endsWith("\n")) { + System.out.printf("\n"); + } + } + + public void printf(String msgFormat, Object... args) { + System.out.printf(msgFormat, args); + } +} diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java index a2de8fc17..b79dedbe3 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java @@ -31,6 +31,11 @@ import java.io.File; */ public final class SdkConstants { + /** An SDK Project's AndroidManifest.xml file */ + public static final String FN_ANDROID_MANIFEST_XML= "AndroidManifest.xml"; + /** An SDK Project's build.xml file */ + public final static String FN_BUILD_XML = "build.xml"; + /** Name of the framework library, i.e. "android.jar" */ public static final String FN_FRAMEWORK_LIBRARY = "android.jar"; /** Name of the layout attributes, i.e. "attrs.xml" */ @@ -129,7 +134,9 @@ public final class SdkConstants { /** Name of the addon libs folder. */ public final static String FD_ADDON_LIBS = "libs"; - + /** Namespace for the resource XML, i.e. "http://schemas.android.com/apk/res/android" */ + public final static String NS_RESOURCES = "http://schemas.android.com/apk/res/android"; + /* 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. */ @@ -206,7 +213,7 @@ public final class SdkConstants { /** Returns the appropriate name for the 'android' command, which is 'android.bat' for * Windows and 'android' for all other platforms. */ - public static String AndroidCmdName() { + public static String androidCmdName() { String os = System.getProperty("os.name"); String cmd = "android"; if (os.startsWith("Windows")) { @@ -215,4 +222,15 @@ public final class SdkConstants { 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"); + String cmd = "mksdcard"; + if (os.startsWith("Windows")) { + cmd += ".exe"; + } + return cmd; + } + } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java index 4cf224d40..1cff43c88 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java @@ -21,14 +21,27 @@ import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; import com.android.sdklib.project.ProjectProperties.PropertyType; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import java.util.regex.Pattern; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; /** * Creates the basic files needed to get an Android project up and running. Also @@ -38,16 +51,31 @@ import java.util.Map; */ public class ProjectCreator { + /** Package path substitution string used in template files, i.e. "PACKAGE_PATH" */ private final static String PH_JAVA_FOLDER = "PACKAGE_PATH"; + /** Package name substitution string used in template files, i.e. "PACKAGE" */ private final static String PH_PACKAGE = "PACKAGE"; + /** Activity name substitution string used in template files, i.e. "ACTIVITY_NAME". */ private final static String PH_ACTIVITY_NAME = "ACTIVITY_NAME"; + /** Project name substitution string used in template files, i.e. "PROJECT_NAME". */ + private final static String PH_PROJECT_NAME = "PROJECT_NAME"; private final static String FOLDER_TESTS = "tests"; public enum OutputLevel { - SILENT, NORMAL, VERBOSE; + /** Silent mode. Project creation will only display errors. */ + SILENT, + /** Normal mode. Project creation will display what's being done, display + * error but not warnings. */ + NORMAL, + /** Verbose mode. Project creation will display what's being done, errors and warnings. */ + VERBOSE; } + /** + * Exception thrown when a project creation fails, typically because a template + * file cannot be written. + */ private static class ProjectCreateException extends Exception { /** default UID. This will not be serialized anyway. */ private static final long serialVersionUID = 1L; @@ -78,7 +106,8 @@ public class ProjectCreator { /** * Creates a new project. - * @param folderPath the folder of the project to create. This folder must exist. + * + * @param folderPath the folder of the project to create. * @param projectName the name of the project. * @param packageName the package of the project. * @param activityName the activity of the project as it will appear in the manifest. @@ -113,16 +142,16 @@ public class ProjectCreator { try { String[] content = projectFolder.list(); if (content == null) { - error = "Project directory %1$s is not a directory."; + error = "Project folder '%1$s' is not a directory."; } else if (content.length != 0) { - error = "Project directory %1$s is not empty. Please consider using '%2$s update' instead."; + error = "Project folder '%1$s' is not empty. Please consider using '%2$s update' instead."; } } catch (Exception e1) { e = e1; } if (e != null || error != null) { - mLog.error(e, error, projectFolder, SdkConstants.AndroidCmdName()); + mLog.error(e, error, projectFolder, SdkConstants.androidCmdName()); } } @@ -164,6 +193,21 @@ public class ProjectCreator { keywords.put(PH_ACTIVITY_NAME, activityName); } + // Take the project name from the command line if there's one + if (projectName != null) { + keywords.put(PH_PROJECT_NAME, projectName); + } else { + if (activityName != null) { + // Use the activity as project name + keywords.put(PH_PROJECT_NAME, activityName); + } else { + // We need a project name. Just pick up the basename of the project + // directory. + projectName = projectFolder.getName(); + keywords.put(PH_PROJECT_NAME, projectName); + } + } + // create the source folder and the java package folders. final String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath; File sourceFolder = createDirs(projectFolder, srcFolderPath); @@ -198,10 +242,13 @@ public class ProjectCreator { manifestTemplate = "AndroidManifest.tests.template"; } - installTemplate(manifestTemplate, new File(projectFolder, "AndroidManifest.xml"), + installTemplate(manifestTemplate, + new File(projectFolder, SdkConstants.FN_ANDROID_MANIFEST_XML), keywords, target); - installTemplate("build.template", new File(projectFolder, "build.xml"), keywords); + installTemplate("build.template", + new File(projectFolder, SdkConstants.FN_BUILD_XML), + keywords); // if this is not a test project, then we create one. if (isTestProject == false) { @@ -220,6 +267,293 @@ public class ProjectCreator { } /** + * Updates an existing project. + * <p/> + * Workflow: + * <ul> + * <li> Check AndroidManifest.xml is present (required) + * <li> Check there's a default.properties with a target *or* --target was specified + * <li> Update default.prop if --target was specified + * <li> Refresh/create "sdk" in local.properties + * <li> Build.xml: create if not present or no <androidinit(\w|/>) in it + * </ul> + * + * @param folderPath the folder of the project to update. This folder must exist. + * @param target the project target. Can be null. + * @param projectName The project name from --name. Can be null. + */ + public void updateProject(String folderPath, IAndroidTarget target, String projectName ) { + // project folder must exist and be a directory, since this is an update + File projectFolder = new File(folderPath); + if (!projectFolder.isDirectory()) { + mLog.error(null, "Project folder '%1$s' is not a valid directory, this is not an Android project you can update.", + projectFolder); + return; + } + + // Check AndroidManifest.xml is present + File androidManifest = new File(projectFolder, SdkConstants.FN_ANDROID_MANIFEST_XML); + if (!androidManifest.isFile()) { + mLog.error(null, + "%1$s not found in '%2$s', this is not an Android project you can update.", + SdkConstants.FN_ANDROID_MANIFEST_XML, + folderPath); + return; + } + + // Check there's a default.properties with a target *or* --target was specified + ProjectProperties props = ProjectProperties.load(folderPath, PropertyType.DEFAULT); + if (props == null || props.getProperty(ProjectProperties.PROPERTY_TARGET) == null) { + if (target == null) { + mLog.error(null, + "There is no %1$s file in '%2$s'. Please provide a --target to the '%3$s update' command.", + PropertyType.DEFAULT.getFilename(), + folderPath, + SdkConstants.androidCmdName()); + return; + } + } + + // Update default.prop iif --target was specified + if (target != null) { + props = ProjectProperties.create(folderPath, PropertyType.DEFAULT); + props.setAndroidTarget(target); + try { + props.save(); + println("Updated %1$s", PropertyType.DEFAULT.getFilename()); + } catch (IOException e) { + mLog.error(e, "Failed to write %1$s file in '%2$s'", + PropertyType.DEFAULT.getFilename(), + folderPath); + return; + } + } + + // Refresh/create "sdk" in local.properties + props = ProjectProperties.create(folderPath, PropertyType.LOCAL); + props.setProperty(ProjectProperties.PROPERTY_SDK, mSdkFolder); + try { + props.save(); + println("Updated %1$s", PropertyType.LOCAL.getFilename()); + } catch (IOException e) { + mLog.error(e, "Failed to write %1$s file in '%2$s'", + PropertyType.LOCAL.getFilename(), + folderPath); + return; + } + + // Build.xml: create if not present or no <androidinit/> in it + File buildXml = new File(projectFolder, SdkConstants.FN_BUILD_XML); + boolean needsBuildXml = projectName != null || !buildXml.exists(); + if (!needsBuildXml) { + // Note that "<androidinit" must be followed by either a whitespace, a "/" (for the + // XML /> closing tag) or an end-of-line. This way we know the XML tag is really this + // one and later we will be able to use an "androidinit2" tag or such as necessary. + needsBuildXml = !checkFileContainsRegexp(buildXml, "<androidinit(?:\\s|/|$)"); + if (needsBuildXml) { + println("File %1$s is too old and needs to be updated.", SdkConstants.FN_BUILD_XML); + } + } + + if (needsBuildXml) { + // create the map for place-holders of values to replace in the templates + final HashMap<String, String> keywords = new HashMap<String, String>(); + + // Take the project name from the command line if there's one + if (projectName != null) { + keywords.put(PH_PROJECT_NAME, projectName); + } else { + extractPackageFromManifest(androidManifest, keywords); + if (keywords.containsKey(PH_ACTIVITY_NAME)) { + // Use the activity as project name + keywords.put(PH_PROJECT_NAME, keywords.get(PH_ACTIVITY_NAME)); + } else { + // We need a project name. Just pick up the basename of the project + // directory. + projectName = projectFolder.getName(); + keywords.put(PH_PROJECT_NAME, projectName); + } + } + + if (mLevel == OutputLevel.VERBOSE) { + println("Regenerating %1$s with project name %2$s", + SdkConstants.FN_BUILD_XML, + keywords.get(PH_PROJECT_NAME)); + } + + try { + installTemplate("build.template", + new File(projectFolder, SdkConstants.FN_BUILD_XML), + keywords); + } catch (ProjectCreateException e) { + mLog.error(e, null); + } + } + } + + /** + * Returns true if any line of the input file contains the requested regexp. + */ + private boolean checkFileContainsRegexp(File file, String regexp) { + Pattern p = Pattern.compile(regexp); + + try { + BufferedReader in = new BufferedReader(new FileReader(file)); + String line; + + while ((line = in.readLine()) != null) { + if (p.matcher(line).find()) { + return true; + } + } + + in.close(); + } catch (Exception e) { + // ignore + } + + return false; + } + + /** + * Extracts a "full" package & activity name from an AndroidManifest.xml. + * <p/> + * The keywords dictionary is always filed the package name under the key {@link #PH_PACKAGE}. + * If an activity name can be found, it is filed under the key {@link #PH_ACTIVITY_NAME}. + * When no activity is found, this key is not created. + * + * @param manifestFile The AndroidManifest.xml file + * @param outKeywords Place where to put the out parameters: package and activity names. + * @return True if the package/activity was parsed and updated in the keyword dictionary. + */ + private boolean extractPackageFromManifest(File manifestFile, + Map<String, String> outKeywords) { + try { + final String nsPrefix = "android"; + final String nsURI = SdkConstants.NS_RESOURCES; + + XPath xpath = XPathFactory.newInstance().newXPath(); + + xpath.setNamespaceContext(new NamespaceContext() { + public String getNamespaceURI(String prefix) { + if (nsPrefix.equals(prefix)) { + return nsURI; + } + return XMLConstants.NULL_NS_URI; + } + + public String getPrefix(String namespaceURI) { + if (nsURI.equals(namespaceURI)) { + return nsPrefix; + } + return null; + } + + @SuppressWarnings("unchecked") + public Iterator getPrefixes(String namespaceURI) { + if (nsURI.equals(namespaceURI)) { + ArrayList<String> list = new ArrayList<String>(); + list.add(nsPrefix); + return list.iterator(); + } + return null; + } + + }); + + InputSource source = new InputSource(new FileReader(manifestFile)); + String packageName = xpath.evaluate("/manifest/@package", source); + + source = new InputSource(new FileReader(manifestFile)); + + // Select the "android:name" attribute of all <activity> nodes but only if they + // contain a sub-node <intent-filter><action> with an "android:name" attribute which + // is 'android.intent.action.MAIN' and an <intent-filter><category> with an + // "android:name" attribute which is 'android.intent.category.LAUNCHER' + String expression = String.format("/manifest/application/activity" + + "[intent-filter/action/@%1$s:name='android.intent.action.MAIN' and " + + "intent-filter/category/@%1$s:name='android.intent.category.LAUNCHER']" + + "/@%1$s:name", nsPrefix); + + NodeList activityNames = (NodeList) xpath.evaluate(expression, source, + XPathConstants.NODESET); + + // If we get here, both XPath expressions were valid so we're most likely dealing + // with an actual AndroidManifest.xml file. The nodes may not have the requested + // attributes though, if which case we should warn. + + if (packageName == null || packageName.length() == 0) { + mLog.error(null, + "Missing <manifest package=\"...\"> in '%1$s'", + manifestFile.getName()); + return false; + } + + // Get the first activity that matched earlier. If there is no activity, + // activityName is set to an empty string and the generated "combined" name + // will be in the form "package." (with a dot at the end). + String activityName = ""; + if (activityNames.getLength() > 0) { + activityName = activityNames.item(0).getNodeValue(); + } + + if (mLevel == OutputLevel.VERBOSE && activityNames.getLength() > 1) { + println("WARNING: There is more than one activity defined in '%1$s'.\n" + + "Only the first one will be used. If this is not appropriate, you need\n" + + "to specify one of these values manually instead:", + manifestFile.getName()); + + for (int i = 0; i < activityNames.getLength(); i++) { + String name = activityNames.item(i).getNodeValue(); + name = combinePackageActivityNames(packageName, name); + println("- %1$s", name); + } + } + + if (activityName.length() == 0) { + mLog.warning("Missing <activity %1$s:name=\"...\"> in '%2$s'.\n" + + "No activity will be generated.", + nsPrefix, manifestFile.getName()); + } else { + outKeywords.put(PH_ACTIVITY_NAME, activityName); + } + + outKeywords.put(PH_PACKAGE, packageName); + return true; + + } catch (IOException e) { + mLog.error(e, "Failed to read %1$s", manifestFile.getName()); + } catch (XPathExpressionException e) { + Throwable t = e.getCause(); + mLog.error(t == null ? e : t, + "Failed to parse %1$s", + manifestFile.getName()); + } + + return false; + } + + private String combinePackageActivityNames(String packageName, String activityName) { + // Activity Name can have 3 forms: + // - ".Name" means this is a class name in the given package name. + // The full FQCN is thus packageName + ".Name" + // - "Name" is an older variant of the former. Full FQCN is packageName + "." + "Name" + // - "com.blah.Name" is a full FQCN. Ignore packageName and use activityName as-is. + // To be valid, the package name should have at least two components. This is checked + // later during the creation of the build.xml file, so we just need to detect there's + // a dot but not at pos==0. + + int pos = activityName.indexOf('.'); + if (pos == 0) { + return packageName + activityName; + } else if (pos > 0) { + return activityName; + } else { + return packageName + "." + activityName; + } + } + + /** * Installs a new file that is based on a template file provided by a given target. * Each match of each key from the place-holder map in the template will be replaced with its * corresponding value in the created file. @@ -272,6 +606,9 @@ public class ProjectCreator { */ private void installFullPathTemplate(String sourcePath, File destFile, Map<String, String> placeholderMap) throws ProjectCreateException { + + boolean existed = destFile.exists(); + try { BufferedWriter out = new BufferedWriter(new FileWriter(destFile)); BufferedReader in = new BufferedReader(new FileReader(sourcePath)); @@ -293,17 +630,26 @@ public class ProjectCreator { destFile, e.getMessage()); } - println("Added file %1$s", destFile); + println("%1$s file %2$s", + existed ? "Updated" : "Added", + destFile); } /** * Prints a message unless silence is enabled. + * <p/> + * This is just a convenience wrapper around {@link ISdkLog#printf(String, Object...)} from + * {@link #mLog} after testing if ouput level is {@link OutputLevel#VERBOSE}. + * * @param format Format for String.format * @param args Arguments for String.format */ private void println(String format, Object... args) { - if (mLevel == OutputLevel.VERBOSE) { - System.out.println(String.format(format, args)); + if (mLevel != OutputLevel.SILENT) { + if (!format.endsWith("\n")) { + format += "\n"; + } + mLog.printf(format, args); } } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java index 938f89d9a..4e1c27ff0 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java @@ -47,6 +47,10 @@ public final class ProjectProperties { mFilename = filename; mHeader = header; } + + public String getFilename() { + return mFilename; + } } private final static String LOCAL_HEADER = diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java index 1edd8b2f8..39316d2b0 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java @@ -20,14 +20,17 @@ import com.android.prefs.AndroidLocation; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.ISdkLog; +import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkManager; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -42,13 +45,15 @@ public final class VmManager { private final static String VM_INFO_PATH = "path"; private final static String VM_INFO_TARGET = "target"; - + private final static String IMAGE_USERDATA = "userdata.img"; private final static String CONFIG_INI = "config.ini"; - + private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\.ini$", Pattern.CASE_INSENSITIVE); + private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]?"); + public static final class VmInfo { String name; String path; @@ -69,10 +74,12 @@ public final class VmManager { private final ArrayList<VmInfo> mVmList = new ArrayList<VmInfo>(); private ISdkLog mSdkLog; + private final SdkManager mSdk; public VmManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException { + mSdk = sdk; mSdkLog = sdkLog; - buildVmList(sdk); + buildVmList(); } /** @@ -104,12 +111,12 @@ public final class VmManager { * @param name the name of the VM * @param target the target of the VM * @param skinName the name of the skin. Can be null. - * @param sdcardPath the path to the sdCard. Can be null. - * @param sdcardSize the size of a local sdcard to create. Can be 0 for no local sdcard. + * @param sdcard the parameter value for the sdCard. Can be null. This is either a path to + * an existing sdcard image or a sdcard size (\d+, \d+K, \dM). * @param hardwareConfig the hardware setup for the VM */ public VmInfo createVm(String parentFolder, String name, IAndroidTarget target, - String skinName, String sdcardPath, int sdcardSize, Map<String,String> hardwareConfig, + String skinName, String sdcard, Map<String,String> hardwareConfig, ISdkLog log) { try { @@ -128,7 +135,7 @@ public final class VmManager { } return null; } - + // create the vm folder. vmFolder.mkdir(); @@ -177,15 +184,40 @@ public final class VmManager { } } - if (sdcardPath != null) { - File sdcard = new File(sdcardPath); - if (sdcard.isFile()) { - values.put("sdcard", sdcardPath); - } else if (log != null) { - log.warning("sdcarad image '%1$s' does not exists.", sdcardPath); + if (sdcard != null) { + File sdcardFile = new File(sdcard); + if (sdcardFile.isFile()) { + values.put("sdcard", sdcard); + } else { + // check that it matches the pattern for sdcard size + Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard); + if (m.matches()) { + // create the sdcard. + sdcardFile = new File(vmFolder, "sdcard.img"); + String path = sdcardFile.getAbsolutePath(); + + // execute mksdcard with the proper parameters. + File toolsFolder = new File(mSdk.getLocation(), SdkConstants.FD_TOOLS); + File mkSdCard = new File(toolsFolder, SdkConstants.mkSdCardCmdName()); + + if (mkSdCard.isFile() == false) { + log.error(null, "'%1$s' is missing from the SDK tools folder.", + mkSdCard.getName()); + return null; + } + + if (createSdCard(mkSdCard.getAbsolutePath(), sdcard, path, log) == false) { + return null; // mksdcard output has already been displayed, no need to + // output anything else. + } + + // add its path to the values. + values.put("sdcard", path); + } else { + log.error(null, "'%1$s' is not recognized as a valid sdcard value", sdcard); + return null; + } } - } else if (sdcardSize != 0) { - // TODO: create sdcard image. } if (hardwareConfig != null) { @@ -227,7 +259,7 @@ public final class VmManager { return null; } - private void buildVmList(SdkManager sdk) throws AndroidLocationException { + private void buildVmList() throws AndroidLocationException { // get the Android prefs location. String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS; @@ -253,14 +285,14 @@ public final class VmManager { }); for (File vm : vms) { - VmInfo info = parseVmInfo(vm, sdk); + VmInfo info = parseVmInfo(vm); if (info != null) { mVmList.add(info); } } } - private VmInfo parseVmInfo(File path, SdkManager sdk) { + private VmInfo parseVmInfo(File path) { Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog); String vmPath = map.get(VM_INFO_PATH); @@ -273,7 +305,7 @@ public final class VmManager { return null; } - IAndroidTarget target = sdk.getTargetFromHashString(targetHash); + IAndroidTarget target = mSdk.getTargetFromHashString(targetHash); if (target == null) { return null; } @@ -301,4 +333,118 @@ public final class VmManager { writer.close(); } + + private boolean createSdCard(String toolLocation, String size, String location, ISdkLog log) { + try { + String[] command = new String[3]; + command[0] = toolLocation; + command[1] = size; + command[2] = location; + Process process = Runtime.getRuntime().exec(command); + + ArrayList<String> errorOutput = new ArrayList<String>(); + ArrayList<String> stdOutput = new ArrayList<String>(); + int status = grabProcessOutput(process, errorOutput, stdOutput, + true /* waitForReaders */); + + if (status != 0) { + log.error(null, "Failed to create the SD card."); + for (String error : errorOutput) { + log.error(null, error); + } + + return false; + } + + return true; + } catch (InterruptedException e) { + log.error(null, "Failed to create the SD card."); + } catch (IOException e) { + log.error(null, "Failed to create the SD card."); + } + + return false; + } + + /** + * Gets the stderr/stdout outputs of a process and returns when the process is done. + * Both <b>must</b> be read or the process will block on windows. + * @param process The process to get the ouput from + * @param errorOutput The array to store the stderr output. cannot be null. + * @param stdOutput The array to store the stdout output. cannot be null. + * @param waitforReaders if true, this will wait for the reader threads. + * @return the process return code. + * @throws InterruptedException + */ + private int grabProcessOutput(final Process process, final ArrayList<String> errorOutput, + final ArrayList<String> stdOutput, boolean waitforReaders) + throws InterruptedException { + assert errorOutput != null; + assert stdOutput != null; + // read the lines as they come. if null is returned, it's + // because the process finished + Thread t1 = new Thread("") { //$NON-NLS-1$ + @Override + public void run() { + // create a buffer to read the stderr output + InputStreamReader is = new InputStreamReader(process.getErrorStream()); + BufferedReader errReader = new BufferedReader(is); + + try { + while (true) { + String line = errReader.readLine(); + if (line != null) { + errorOutput.add(line); + } else { + break; + } + } + } catch (IOException e) { + // do nothing. + } + } + }; + + Thread t2 = new Thread("") { //$NON-NLS-1$ + @Override + public void run() { + InputStreamReader is = new InputStreamReader(process.getInputStream()); + BufferedReader outReader = new BufferedReader(is); + + try { + while (true) { + String line = outReader.readLine(); + if (line != null) { + stdOutput.add(line); + } else { + break; + } + } + } catch (IOException e) { + // do nothing. + } + } + }; + + t1.start(); + t2.start(); + + // it looks like on windows process#waitFor() can return + // before the thread have filled the arrays, so we wait for both threads and the + // process itself. + if (waitforReaders) { + try { + t1.join(); + } catch (InterruptedException e) { + } + try { + t2.join(); + } catch (InterruptedException e) { + } + } + + // get the return code from the process + return process.waitFor(); + } + } |
