Merge branch 'cupcake'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
2
pdk/doxygen_config/footer.html
Normal file
2
pdk/doxygen_config/footer.html
Normal file
@@ -0,0 +1,2 @@
|
||||
</body>
|
||||
</html>
|
||||
15
pdk/doxygen_config/header.html
Normal file
15
pdk/doxygen_config/header.html
Normal file
@@ -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>
|
||||
@@ -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:
|
||||
// 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:
|
||||
/**
|
||||
* 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) {
|
||||
if (mCandidateView != null) {
|
||||
mCandidateView.setSuggestions(suggestions, completions, typedWordValid);
|
||||
if (suggestions != null && suggestions.size() > 0) {
|
||||
setCandidatesViewShown(true);
|
||||
} else if (isFullscreenMode()) {
|
||||
setCandidatesViewShown(true);
|
||||
} else {
|
||||
setCandidatesViewShown(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 onRelease(int primaryCode) { }
|
||||
public void onPress(int primaryCode) {
|
||||
}
|
||||
|
||||
public void onRelease(int primaryCode) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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 "$@"
|
||||
@@ -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 %*
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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\\";
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<name>adt</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
<project>SdkLib</project>
|
||||
<project>SdkUiLib</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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$
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 */);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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$
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<name>adt-tests</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
<project>SdkLib</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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 #"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.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.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,16 +219,27 @@ 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(),
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 + ")";
|
||||
}
|
||||
|
||||
stdout(" -%1$s %2$-10s %3$s%4$s",
|
||||
String required = arg.isMandatory() ? " [required]" : "";
|
||||
|
||||
stdout(" -%1$s %2$-10s %3$s%4$s%5$s",
|
||||
arg.getShortArg(),
|
||||
"--" + arg.getLongArg(),
|
||||
arg.getDescription(),
|
||||
value == null ? "" : " (" + value + ")");
|
||||
value,
|
||||
required);
|
||||
numOptions++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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_NEW_PROJECT, "n", KEY_NAME,
|
||||
"Project 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, 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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,6 +134,8 @@ 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.
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -219,6 +266,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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@ public final class ProjectProperties {
|
||||
mFilename = filename;
|
||||
mHeader = header;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return mFilename;
|
||||
}
|
||||
}
|
||||
|
||||
private final static String LOCAL_HEADER =
|
||||
|
||||
@@ -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;
|
||||
@@ -49,6 +52,8 @@ public final class VmManager {
|
||||
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 {
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user