auto import from //branches/cupcake/...@130745
This commit is contained in:
21
apps/Fallback/res/values-ko/strings.xml
Normal file
21
apps/Fallback/res/values-ko/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="appTitle">"Fallback"</string>
|
||||||
|
<string name="title">"지원되지 않는 작업"</string>
|
||||||
|
<string name="error">"이 작업은 현재 지원되지 않습니다."</string>
|
||||||
|
</resources>
|
||||||
21
apps/Fallback/res/values-nb/strings.xml
Normal file
21
apps/Fallback/res/values-nb/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="appTitle">"Fallback"</string>
|
||||||
|
<string name="title">"Ustøttet handling"</string>
|
||||||
|
<string name="error">"Denne handlingen er ikke støttet nå."</string>
|
||||||
|
</resources>
|
||||||
@@ -30,6 +30,10 @@
|
|||||||
<string name="summary_transition_animations">Speed of animations moving between screens</string>
|
<string name="summary_transition_animations">Speed of animations moving between screens</string>
|
||||||
<string name="dialog_title_transition_animations">Select transition speed</string>
|
<string name="dialog_title_transition_animations">Select transition speed</string>
|
||||||
|
|
||||||
|
<string name="title_fancy_ime_animations">Fancy input animations</string>
|
||||||
|
<string name="summary_on_fancy_ime_animations">Use fancier animations for input method windows</string>
|
||||||
|
<string name="summary_off_fancy_ime_animations">Use normal animations for input method windows</string>
|
||||||
|
|
||||||
<string name="title_font_size">Font size</string>
|
<string name="title_font_size">Font size</string>
|
||||||
<string name="summary_font_size">Overall size of fonts</string>
|
<string name="summary_font_size">Overall size of fonts</string>
|
||||||
<string name="dialog_title_font_size">Select font size</string>
|
<string name="dialog_title_font_size">Select font size</string>
|
||||||
|
|||||||
@@ -37,6 +37,12 @@
|
|||||||
android:entryValues="@array/entryvalues_animations"
|
android:entryValues="@array/entryvalues_animations"
|
||||||
android:dialogTitle="@string/dialog_title_transition_animations" />
|
android:dialogTitle="@string/dialog_title_transition_animations" />
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="fancy_ime_animations"
|
||||||
|
android:title="@string/title_fancy_ime_animations"
|
||||||
|
android:summaryOn="@string/summary_on_fancy_ime_animations"
|
||||||
|
android:summaryOff="@string/summary_off_fancy_ime_animations"/>
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="font_size"
|
android:key="font_size"
|
||||||
android:title="@string/title_font_size"
|
android:title="@string/title_font_size"
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public class SpareParts extends PreferenceActivity
|
|||||||
|
|
||||||
private static final String WINDOW_ANIMATIONS_PREF = "window_animations";
|
private static final String WINDOW_ANIMATIONS_PREF = "window_animations";
|
||||||
private static final String TRANSITION_ANIMATIONS_PREF = "transition_animations";
|
private static final String TRANSITION_ANIMATIONS_PREF = "transition_animations";
|
||||||
|
private static final String FANCY_IME_ANIMATIONS_PREF = "fancy_ime_animations";
|
||||||
private static final String FONT_SIZE_PREF = "font_size";
|
private static final String FONT_SIZE_PREF = "font_size";
|
||||||
private static final String END_BUTTON_PREF = "end_button";
|
private static final String END_BUTTON_PREF = "end_button";
|
||||||
private static final String ACCELEROMETER_PREF = "accelerometer";
|
private static final String ACCELEROMETER_PREF = "accelerometer";
|
||||||
@@ -51,6 +52,7 @@ public class SpareParts extends PreferenceActivity
|
|||||||
|
|
||||||
private ListPreference mWindowAnimationsPref;
|
private ListPreference mWindowAnimationsPref;
|
||||||
private ListPreference mTransitionAnimationsPref;
|
private ListPreference mTransitionAnimationsPref;
|
||||||
|
private CheckBoxPreference mFancyImeAnimationsPref;
|
||||||
private ListPreference mFontSizePref;
|
private ListPreference mFontSizePref;
|
||||||
private ListPreference mEndButtonPref;
|
private ListPreference mEndButtonPref;
|
||||||
private CheckBoxPreference mAccelerometerPref;
|
private CheckBoxPreference mAccelerometerPref;
|
||||||
@@ -69,6 +71,7 @@ public class SpareParts extends PreferenceActivity
|
|||||||
mWindowAnimationsPref.setOnPreferenceChangeListener(this);
|
mWindowAnimationsPref.setOnPreferenceChangeListener(this);
|
||||||
mTransitionAnimationsPref = (ListPreference) prefSet.findPreference(TRANSITION_ANIMATIONS_PREF);
|
mTransitionAnimationsPref = (ListPreference) prefSet.findPreference(TRANSITION_ANIMATIONS_PREF);
|
||||||
mTransitionAnimationsPref.setOnPreferenceChangeListener(this);
|
mTransitionAnimationsPref.setOnPreferenceChangeListener(this);
|
||||||
|
mFancyImeAnimationsPref = (CheckBoxPreference) prefSet.findPreference(FANCY_IME_ANIMATIONS_PREF);
|
||||||
mFontSizePref = (ListPreference) prefSet.findPreference(FONT_SIZE_PREF);
|
mFontSizePref = (ListPreference) prefSet.findPreference(FONT_SIZE_PREF);
|
||||||
mFontSizePref.setOnPreferenceChangeListener(this);
|
mFontSizePref.setOnPreferenceChangeListener(this);
|
||||||
mEndButtonPref = (ListPreference) prefSet.findPreference(END_BUTTON_PREF);
|
mEndButtonPref = (ListPreference) prefSet.findPreference(END_BUTTON_PREF);
|
||||||
@@ -83,6 +86,9 @@ public class SpareParts extends PreferenceActivity
|
|||||||
|
|
||||||
private void updateToggles() {
|
private void updateToggles() {
|
||||||
try {
|
try {
|
||||||
|
mFancyImeAnimationsPref.setChecked(Settings.System.getInt(
|
||||||
|
getContentResolver(),
|
||||||
|
Settings.System.FANCY_IME_ANIMATIONS, 0) != 0);
|
||||||
mAccelerometerPref.setChecked(Settings.System.getInt(
|
mAccelerometerPref.setChecked(Settings.System.getInt(
|
||||||
getContentResolver(),
|
getContentResolver(),
|
||||||
Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
|
Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
|
||||||
@@ -181,6 +187,10 @@ public class SpareParts extends PreferenceActivity
|
|||||||
Settings.System.putInt(getContentResolver(),
|
Settings.System.putInt(getContentResolver(),
|
||||||
Settings.System.ACCELEROMETER_ROTATION,
|
Settings.System.ACCELEROMETER_ROTATION,
|
||||||
mAccelerometerPref.isChecked() ? 1 : 0);
|
mAccelerometerPref.isChecked() ? 1 : 0);
|
||||||
|
} else if (FANCY_IME_ANIMATIONS_PREF.equals(key)) {
|
||||||
|
Settings.System.putInt(getContentResolver(),
|
||||||
|
Settings.System.FANCY_IME_ANIMATIONS,
|
||||||
|
mFancyImeAnimationsPref.isChecked() ? 1 : 0);
|
||||||
} else if (MAPS_COMPASS_PREF.equals(key)) {
|
} else if (MAPS_COMPASS_PREF.equals(key)) {
|
||||||
try {
|
try {
|
||||||
Context c = createPackageContext("com.google.android.apps.maps", 0);
|
Context c = createPackageContext("com.google.android.apps.maps", 0);
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
<activity android:name="Term"
|
<activity android:name="Term"
|
||||||
android:theme="@style/Theme"
|
android:theme="@style/Theme"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation">
|
android:configChanges="keyboard|keyboardHidden|orientation"
|
||||||
|
android:windowSoftInputMode="adjustResize|stateVisible">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.TEST" />
|
<category android:name="android.intent.category.TEST" />
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ import android.view.Menu;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.inputmethod.CompletionInfo;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.view.inputmethod.ExtractedText;
|
||||||
|
import android.view.inputmethod.ExtractedTextRequest;
|
||||||
|
import android.view.inputmethod.InputConnection;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -177,6 +183,9 @@ public class Term extends Activity {
|
|||||||
|
|
||||||
mKeyListener = new TermKeyListener();
|
mKeyListener = new TermKeyListener();
|
||||||
|
|
||||||
|
mEmulatorView.setFocusable(true);
|
||||||
|
mEmulatorView.requestFocus();
|
||||||
|
|
||||||
updatePrefs();
|
updatePrefs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2583,7 +2592,6 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener {
|
|||||||
private FileOutputStream mTermOut;
|
private FileOutputStream mTermOut;
|
||||||
|
|
||||||
private ByteQueue mByteQueue;
|
private ByteQueue mByteQueue;
|
||||||
private final static int MAX_BYTES_PER_UPDATE = 4 * 1024;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to temporarily hold data received from the remote process. Allocated
|
* Used to temporarily hold data received from the remote process. Allocated
|
||||||
@@ -2643,6 +2651,117 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener {
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCheckIsTextEditor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||||
|
return new InputConnection(){
|
||||||
|
|
||||||
|
public boolean beginBatchEdit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean clearMetaKeyStates(int states) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean commitCompletion(CompletionInfo text) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||||
|
sendText(text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteSurroundingText(int leftLength, int rightLength) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean endBatchEdit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean finishComposingText() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCursorCapsMode(int reqModes) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtractedText getExtractedText(ExtractedTextRequest request,
|
||||||
|
int flags) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getTextAfterCursor(int n, int flags) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getTextBeforeCursor(int n, int flags) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hideStatusIcon() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean performContextMenuAction(int id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean performPrivateCommand(String action, Bundle data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean sendKeyEvent(KeyEvent event) {
|
||||||
|
switch(event.getKeyCode()) {
|
||||||
|
case KeyEvent.KEYCODE_ENTER:
|
||||||
|
sendChar('\r');
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_DEL:
|
||||||
|
sendChar(127);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setSelection(int start, int end) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean showStatusIcon(String packageName, int resId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendChar(int c) {
|
||||||
|
try {
|
||||||
|
mTermOut.write(c);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void sendText(CharSequence text) {
|
||||||
|
int n = text.length();
|
||||||
|
try {
|
||||||
|
for(int i = 0; i < n; i++) {
|
||||||
|
char c = text.charAt(i);
|
||||||
|
mTermOut.write(c);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public boolean getKeypadApplicationMode() {
|
public boolean getKeypadApplicationMode() {
|
||||||
return mEmulator.getKeypadApplicationMode();
|
return mEmulator.getKeypadApplicationMode();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ system.img platforms/${PLATFORM_NAME}/images/system.img
|
|||||||
ramdisk.img platforms/${PLATFORM_NAME}/images/ramdisk.img
|
ramdisk.img platforms/${PLATFORM_NAME}/images/ramdisk.img
|
||||||
userdata.img platforms/${PLATFORM_NAME}/images/userdata.img
|
userdata.img platforms/${PLATFORM_NAME}/images/userdata.img
|
||||||
prebuilt/android-arm/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/kernel-qemu
|
prebuilt/android-arm/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/kernel-qemu
|
||||||
external/qemu/android/vm/hardware-properties.ini tools/lib/hardware-properties.ini
|
external/qemu/android/avd/hardware-properties.ini tools/lib/hardware-properties.ini
|
||||||
|
|
||||||
# emulator skins
|
# emulator skins
|
||||||
development/emulator/skins/HVGA platforms/${PLATFORM_NAME}/skins/HVGA
|
development/emulator/skins/HVGA platforms/${PLATFORM_NAME}/skins/HVGA
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,7 @@ Signature="$WINDOWS NT$"
|
|||||||
Class=USB
|
Class=USB
|
||||||
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
|
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
|
||||||
Provider=%GOOG%
|
Provider=%GOOG%
|
||||||
DriverVer=12/11/2008,1.0.0009.00000
|
DriverVer=1/29/2009,1.0.0010.00000
|
||||||
CatalogFile.NTx86=androidusb86.cat
|
CatalogFile.NTx86=androidusb86.cat
|
||||||
CatalogFile.NTamd64=androidusba64.cat
|
CatalogFile.NTamd64=androidusba64.cat
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
; For XP and later
|
; For XP and later
|
||||||
[Google.NTx86]
|
[Google.NTx86]
|
||||||
@@ -46,6 +47,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
; For AMD64 and later
|
; For AMD64 and later
|
||||||
[Google.NTamd64]
|
[Google.NTamd64]
|
||||||
@@ -54,6 +56,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
[androidusb.Dev.NT]
|
[androidusb.Dev.NT]
|
||||||
CopyFiles=androidusb.Files.Ext
|
CopyFiles=androidusb.Files.Ext
|
||||||
@@ -120,3 +123,4 @@ ClassName = "ADB Interface"
|
|||||||
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
|
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
|
||||||
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
|
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
|
||||||
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
|
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
|
||||||
|
USB\VID_0BB4&PID_0FFF.DeviceDescRelease="HTC Bootloader"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Signature="$WINDOWS NT$"
|
|||||||
Class=USB
|
Class=USB
|
||||||
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
|
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
|
||||||
Provider=%GOOG%
|
Provider=%GOOG%
|
||||||
DriverVer=12/11/2008,1.0.0009.00000
|
DriverVer=1/29/2009,1.0.0010.00000
|
||||||
CatalogFile.NTx86=androidusb86.cat
|
CatalogFile.NTx86=androidusb86.cat
|
||||||
CatalogFile.NTamd64=androidusba64.cat
|
CatalogFile.NTamd64=androidusba64.cat
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
; For XP and later
|
; For XP and later
|
||||||
[Google.NTx86]
|
[Google.NTx86]
|
||||||
@@ -46,6 +47,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
; For AMD64 and later
|
; For AMD64 and later
|
||||||
[Google.NTamd64]
|
[Google.NTamd64]
|
||||||
@@ -54,6 +56,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
[androidusb.Dev.NT]
|
[androidusb.Dev.NT]
|
||||||
CopyFiles=androidusb.Files.Ext
|
CopyFiles=androidusb.Files.Ext
|
||||||
@@ -120,3 +123,4 @@ ClassName = "ADB Interface"
|
|||||||
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
|
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
|
||||||
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
|
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
|
||||||
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
|
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
|
||||||
|
USB\VID_0BB4&PID_0FFF.DeviceDescRelease="HTC Bootloader"
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ bool AdbInterfaceObject::GetSerialNumber(void* buffer,
|
|||||||
|
|
||||||
// Open USB device for this intefface
|
// Open USB device for this intefface
|
||||||
HANDLE usb_device_handle = CreateFile(interface_name().c_str(),
|
HANDLE usb_device_handle = CreateFile(interface_name().c_str(),
|
||||||
FILE_READ_ATTRIBUTES | FILE_READ_EA,
|
GENERIC_READ,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
NULL,
|
NULL,
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
@@ -208,7 +208,7 @@ bool AdbInterfaceObject::GetEndpointInformation(UCHAR endpoint_index,
|
|||||||
|
|
||||||
// Open USB device for this intefface
|
// Open USB device for this intefface
|
||||||
HANDLE usb_device_handle = CreateFile(interface_name().c_str(),
|
HANDLE usb_device_handle = CreateFile(interface_name().c_str(),
|
||||||
FILE_READ_ATTRIBUTES | FILE_READ_EA,
|
GENERIC_READ,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
NULL,
|
NULL,
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Signature="$WINDOWS NT$"
|
|||||||
Class=USB
|
Class=USB
|
||||||
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
|
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
|
||||||
Provider=%GOOG%
|
Provider=%GOOG%
|
||||||
DriverVer=12/11/2008,1.0.0009.00000
|
DriverVer=1/29/2009,1.0.0010.00000
|
||||||
CatalogFile.NTx86=androidusb86.cat
|
CatalogFile.NTx86=androidusb86.cat
|
||||||
CatalogFile.NTamd64=androidusba64.cat
|
CatalogFile.NTamd64=androidusba64.cat
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
; For XP and later
|
; For XP and later
|
||||||
[Google.NTx86]
|
[Google.NTx86]
|
||||||
@@ -46,6 +47,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
; For AMD64 and later
|
; For AMD64 and later
|
||||||
[Google.NTamd64]
|
[Google.NTamd64]
|
||||||
@@ -54,6 +56,7 @@ DefaultDestDir = 12
|
|||||||
; HTC Dream
|
; HTC Dream
|
||||||
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
|
||||||
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
|
||||||
|
%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF
|
||||||
|
|
||||||
[androidusb.Dev.NT]
|
[androidusb.Dev.NT]
|
||||||
CopyFiles=androidusb.Files.Ext
|
CopyFiles=androidusb.Files.Ext
|
||||||
@@ -120,3 +123,4 @@ ClassName = "ADB Interface"
|
|||||||
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
|
USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
|
||||||
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
|
USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
|
||||||
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
|
USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
|
||||||
|
USB\VID_0BB4&PID_0FFF.DeviceDescRelease="HTC Bootloader"
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
<classpathentry kind="src" path="packages/apps/Settings/src"/>
|
<classpathentry kind="src" path="packages/apps/Settings/src"/>
|
||||||
<classpathentry kind="src" path="packages/apps/SoundRecorder/src"/>
|
<classpathentry kind="src" path="packages/apps/SoundRecorder/src"/>
|
||||||
<classpathentry kind="src" path="packages/apps/Stk/src"/>
|
<classpathentry kind="src" path="packages/apps/Stk/src"/>
|
||||||
<classpathentry kind="src" path="packages/apps/Sync/src"/>
|
|
||||||
<classpathentry kind="src" path="packages/apps/Updater/src"/>
|
<classpathentry kind="src" path="packages/apps/Updater/src"/>
|
||||||
<classpathentry kind="src" path="packages/apps/VoiceDialer/src"/>
|
<classpathentry kind="src" path="packages/apps/VoiceDialer/src"/>
|
||||||
<classpathentry kind="src" path="packages/providers/CalendarProvider/src"/>
|
<classpathentry kind="src" path="packages/providers/CalendarProvider/src"/>
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ h1,h2,h3 {
|
|||||||
<a href="#androidTestingLocationFiles">Location of Files</a><br/>
|
<a href="#androidTestingLocationFiles">Location of Files</a><br/>
|
||||||
<a href="#androidTestingContentMakefile">Contents of makefile</a><br/>
|
<a href="#androidTestingContentMakefile">Contents of makefile</a><br/>
|
||||||
<a href="#androidTestingContentManifest">Content of Manifest</a><br/>
|
<a href="#androidTestingContentManifest">Content of Manifest</a><br/>
|
||||||
<a href="#androidInstrumentationTestingCreatingTestRunner">New Instrumentation TestRunner</a><br/>
|
<a href="#androidInstrumentationTestingCreatingTestRunner">New InstrumentationTestRunner</a><br/>
|
||||||
<a href="#androidInstrumentationTestingCreatingTestCase">New InstrumentationTestCase</a><br/>
|
<a href="#androidInstrumentationTestingCreatingTestCase">New InstrumentationTestCase</a><br/>
|
||||||
<a href="#androidInstrumentationFrameworkTestCase">Exploring a Test Case</a><br/>
|
<a href="#androidInstrumentationFrameworkTestCase">Exploring a Test Case</a><br/>
|
||||||
<a href="#androidTestingKindsofTests">Deciding Kinds of Tests to Write</a><br/></div>
|
<a href="#androidTestingKindsofTests">Deciding Kinds of Tests to Write</a><br/></div>
|
||||||
@@ -493,22 +493,27 @@ include $(BUILD_PACKAGE)
|
|||||||
|
|
||||||
<a name="androidTestingContentManifest"></a><h3>Content of Manifest</h3>
|
<a name="androidTestingContentManifest"></a><h3>Content of Manifest</h3>
|
||||||
|
|
||||||
<p>Use the following example to create an <code>AndroidManifest.xml</code> file that declares the instrumentation. Specify that the framework supplied Instrumentation TestRunner targest the package of your application, allowing the tests that are run with the instrumentation to get access to all of the classes of your application without having to build the source into the test app. The name of the test application is typically the same as your target application with <code>.tests</code> appended. </p>
|
<p>Use the following example to create an <code>AndroidManifest.xml</code> file that declares the instrumentation. Specify that the framework supplied InstrumentationTestRunner targets the package of your application, allowing the tests that are run with the instrumentation to get access to all of the classes of your application without having to build the source into the test app. The name of the test application is typically the same as your target application with <code>.tests</code> appended. </p>
|
||||||
<pre>
|
<pre>
|
||||||
# Add appropriate copyright banner here
|
# Add appropriate copyright banner here
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.android.samples.tests">
|
package="com.example.android.apis.tests">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
|
<!-- We add an application tag here just so that we can indicate that
|
||||||
|
this package needs to link against the android.test library,
|
||||||
|
which is needed when building test cases. -->
|
||||||
|
<application>
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
</application>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This declares that this app uses the instrumentation test runner targeting
|
This declares that this app uses the instrumentation test runner targeting
|
||||||
the package of com.android.samples. To run the tests use the command:
|
the package of com.example.android.apis. To run the tests use the command:
|
||||||
"adb shell am instrument -w com.android.samples.tests/android.test.InstrumentationTestRunner"
|
"adb shell am instrument -w com.example.android.apis.tests/android.test.InstrumentationTestRunner"
|
||||||
-->
|
-->
|
||||||
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
||||||
android:targetPackage="com.android.samples"
|
android:targetPackage="com.example.android.apis"
|
||||||
android:label="Tests for Api Demos."/>
|
android:label="Tests for Api Demos."/>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
</pre>
|
</pre>
|
||||||
@@ -520,7 +525,7 @@ $ adb shell am instrument -w \
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<a name="androidInstrumentationTestingCreatingTestRunner"></a><h3>New Instrumentation TestRunner</h3>
|
<a name="androidInstrumentationTestingCreatingTestRunner"></a><h3>New InstrumentationTestRunner</h3>
|
||||||
|
|
||||||
<p>Create a class that derives from this class. You must override two abstract methods; one that returns the class loader of the target package, and another that defines all of the tests within the package. For example, the snippet below displays the test runner for the framework tests.</p>
|
<p>Create a class that derives from this class. You must override two abstract methods; one that returns the class loader of the target package, and another that defines all of the tests within the package. For example, the snippet below displays the test runner for the framework tests.</p>
|
||||||
<pre class="prettify">
|
<pre class="prettify">
|
||||||
@@ -544,8 +549,6 @@ public class FrameworkInstrumentationTestRunner extends InstrumentationTestRunne
|
|||||||
</pre>
|
</pre>
|
||||||
<p> Next, in an appropriate <code>AndroidManifest.xml</code>, define the instrumentation for the derived class with the appropriate <code>android:targetPackage</code> set. For example, the snippet below defines the instrumentation runner for the framework tests.</p>
|
<p> Next, in an appropriate <code>AndroidManifest.xml</code>, define the instrumentation for the derived class with the appropriate <code>android:targetPackage</code> set. For example, the snippet below defines the instrumentation runner for the framework tests.</p>
|
||||||
<pre class="prettify">
|
<pre class="prettify">
|
||||||
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
|
|
||||||
|
|
||||||
<instrumentation android:name="android.tests.FrameworkInstrumentationTestRunner"
|
<instrumentation android:name="android.tests.FrameworkInstrumentationTestRunner"
|
||||||
android:targetPackage="com.google.android.frameworktest"
|
android:targetPackage="com.google.android.frameworktest"
|
||||||
android:label="framework instrumentation test runner" />
|
android:label="framework instrumentation test runner" />
|
||||||
|
|||||||
741
pdk/ndk/Android_NDK_README.html
Normal file
741
pdk/ndk/Android_NDK_README.html
Normal file
@@ -0,0 +1,741 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||||
|
|
||||||
|
<html>
|
||||||
|
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
|
||||||
|
<base target="_top">
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
|
||||||
|
/* default css */
|
||||||
|
|
||||||
|
table {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tr {
|
||||||
|
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div, address, ol, ul, li, option, select {
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 6px;
|
||||||
|
padding: 0px;
|
||||||
|
font-family: Verdana, sans-serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
img {
|
||||||
|
-moz-force-broken-image-icon: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen {
|
||||||
|
html.pageview {
|
||||||
|
background-color: #f3f3f3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 1100px;
|
||||||
|
|
||||||
|
counter-reset: __goog_page__;
|
||||||
|
}
|
||||||
|
* html body {
|
||||||
|
height: 1100px;
|
||||||
|
}
|
||||||
|
.pageview body {
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
border-left: 1px solid #ccc;
|
||||||
|
border-right: 2px solid #bbb;
|
||||||
|
border-bottom: 2px solid #bbb;
|
||||||
|
width: 648px !important;
|
||||||
|
margin: 15px auto 25px;
|
||||||
|
padding: 40px 50px;
|
||||||
|
}
|
||||||
|
/* IE6 */
|
||||||
|
* html {
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
* html.pageview body {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
/* Prevent repaint errors when scrolling in Safari. This "Star-7" css hack
|
||||||
|
targets Safari 3.1, but not WebKit nightlies and presumably Safari 4.
|
||||||
|
That's OK because this bug is fixed in WebKit nightlies/Safari 4 :-). */
|
||||||
|
html*#wys_frame::before {
|
||||||
|
content: '\A0';
|
||||||
|
position: fixed;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.writely-callout-data {
|
||||||
|
display: none;
|
||||||
|
*display: inline-block;
|
||||||
|
*width: 0;
|
||||||
|
*height: 0;
|
||||||
|
*overflow: hidden;
|
||||||
|
}
|
||||||
|
.writely-footnote-marker {
|
||||||
|
background-image: url('MISSING');
|
||||||
|
background-color: transparent;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 7px;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 16px;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
.editor .writely-footnote-marker {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
.writely-footnote-marker-highlight {
|
||||||
|
background-position: -15px 0;
|
||||||
|
-moz-user-select: text;
|
||||||
|
}
|
||||||
|
.writely-footnote-hide-selection ::-moz-selection, .writely-footnote-hide-selection::-moz-selection {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.writely-footnote-hide-selection ::selection, .writely-footnote-hide-selection::selection {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.writely-footnote-hide-selection {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.editor .writely-comment-yellow {
|
||||||
|
background-color: #FF9;
|
||||||
|
background-position: -240px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-yellow-hover {
|
||||||
|
background-color: #FF0;
|
||||||
|
background-position: -224px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-blue {
|
||||||
|
background-color: #C0D3FF;
|
||||||
|
background-position: -16px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-blue-hover {
|
||||||
|
background-color: #6292FE;
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-orange {
|
||||||
|
background-color: #FFDEAD;
|
||||||
|
background-position: -80px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-orange-hover {
|
||||||
|
background-color: #F90;
|
||||||
|
background-position: -64px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-green {
|
||||||
|
background-color: #99FBB3;
|
||||||
|
background-position: -48px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-green-hover {
|
||||||
|
background-color: #00F442;
|
||||||
|
background-position: -32px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-cyan {
|
||||||
|
background-color: #CFF;
|
||||||
|
background-position: -208px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-cyan-hover {
|
||||||
|
background-color: #0FF;
|
||||||
|
background-position: -192px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-purple {
|
||||||
|
background-color: #EBCCFF;
|
||||||
|
background-position: -144px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-purple-hover {
|
||||||
|
background-color: #90F;
|
||||||
|
background-position: -128px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-magenta {
|
||||||
|
background-color: #FCF;
|
||||||
|
background-position: -112px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-magenta-hover {
|
||||||
|
background-color: #F0F;
|
||||||
|
background-position: -96px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-red {
|
||||||
|
background-color: #FFCACA;
|
||||||
|
background-position: -176px 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-red-hover {
|
||||||
|
background-color: #FF7A7A;
|
||||||
|
background-position: -160px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor .writely-comment-marker {
|
||||||
|
background-image: url('MISSING');
|
||||||
|
background-color: transparent;
|
||||||
|
padding-right: 11px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor .writely-comment-hidden {
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-marker-hidden {
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-none {
|
||||||
|
opacity: .2;
|
||||||
|
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
|
||||||
|
-moz-opacity: .2;
|
||||||
|
}
|
||||||
|
.editor .writely-comment-none-hover {
|
||||||
|
opacity: .2;
|
||||||
|
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
|
||||||
|
-moz-opacity: .2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.br_fix br:not(:-moz-last-node):not(:-moz-first-node) {
|
||||||
|
|
||||||
|
position:relative;
|
||||||
|
|
||||||
|
left: -1ex
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.br_fix br+br {
|
||||||
|
position: static !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 { font-size: 8pt }
|
||||||
|
h5 { font-size: 8pt }
|
||||||
|
h4 { font-size: 10pt }
|
||||||
|
h3 { font-size: 12pt }
|
||||||
|
h2 { font-size: 14pt }
|
||||||
|
h1 { font-size: 18pt }
|
||||||
|
|
||||||
|
blockquote {padding: 10px; border: 1px #DDD dashed }
|
||||||
|
|
||||||
|
a img {border: 0}
|
||||||
|
|
||||||
|
.pb {
|
||||||
|
border-width: 0;
|
||||||
|
page-break-after: always;
|
||||||
|
/* We don't want this to be resizeable, so enforce a width and height
|
||||||
|
using !important */
|
||||||
|
height: 1px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor .pb {
|
||||||
|
border-top: 1px dashed #C0C0C0;
|
||||||
|
border-bottom: 1px dashed #C0C0C0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.google_header, div.google_footer {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Table of contents */
|
||||||
|
.editor div.writely-toc {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.writely-toc > ol {
|
||||||
|
padding-left: 3em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
ol.writely-toc-subheading {
|
||||||
|
padding-left: 1em;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
/* IE6 only */
|
||||||
|
* html writely-toc ol {
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
.writely-toc-none {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
.writely-toc-decimal {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
.writely-toc-upper-alpha {
|
||||||
|
list-style-type: upper-alpha;
|
||||||
|
}
|
||||||
|
.writely-toc-lower-alpha {
|
||||||
|
list-style-type: lower-alpha;
|
||||||
|
}
|
||||||
|
.writely-toc-upper-roman {
|
||||||
|
list-style-type: upper-roman;
|
||||||
|
}
|
||||||
|
.writely-toc-lower-roman {
|
||||||
|
list-style-type: lower-roman;
|
||||||
|
}
|
||||||
|
.writely-toc-disc {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end default css */
|
||||||
|
|
||||||
|
|
||||||
|
/* default print css */
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.google_header, div.google_footer {
|
||||||
|
display: block;
|
||||||
|
min-height: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.google_header {
|
||||||
|
flow: static(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used to insert page numbers */
|
||||||
|
div.google_header::before, div.google_footer::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.google_footer {
|
||||||
|
flow: static(footer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* always consider this element at the start of the doc */
|
||||||
|
div#google_footer {
|
||||||
|
flow: static(footer, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.google_pagenumber {
|
||||||
|
content: counter(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.google_pagecount {
|
||||||
|
content: counter(pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
callout.google_footnote {
|
||||||
|
|
||||||
|
display: prince-footnote;
|
||||||
|
footnote-style-position: inside;
|
||||||
|
/* These styles keep the footnote from taking on the style of the text
|
||||||
|
surrounding the footnote marker. They can be overridden in the
|
||||||
|
document CSS. */
|
||||||
|
color: #000;
|
||||||
|
font-family: Verdana;
|
||||||
|
font-size: 10.0pt;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table of contents */
|
||||||
|
#WritelyTableOfContents a::after {
|
||||||
|
content: leader('.') target-counter(attr(href), page);
|
||||||
|
}
|
||||||
|
|
||||||
|
#WritelyTableOfContents a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
@top {
|
||||||
|
content: flow(header);
|
||||||
|
}
|
||||||
|
@bottom {
|
||||||
|
content: flow(footer);
|
||||||
|
}
|
||||||
|
@footnotes {
|
||||||
|
border-top: solid black thin;
|
||||||
|
padding-top: 8pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* end default print css */
|
||||||
|
|
||||||
|
|
||||||
|
/* custom css */
|
||||||
|
|
||||||
|
|
||||||
|
/* end custom css */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ui edited css */
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Verdana;
|
||||||
|
|
||||||
|
font-size: 10.0pt;
|
||||||
|
line-height: normal;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
/* end ui edited css */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* editor CSS */
|
||||||
|
.editor a:visited {color: #551A8B}
|
||||||
|
.editor table.zeroBorder {border: 1px dotted gray}
|
||||||
|
.editor table.zeroBorder td {border: 1px dotted gray}
|
||||||
|
.editor table.zeroBorder th {border: 1px dotted gray}
|
||||||
|
|
||||||
|
|
||||||
|
.editor div.google_header, .editor div.google_footer {
|
||||||
|
border: 2px #DDDDDD dashed;
|
||||||
|
position: static;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor .misspell {background-color: yellow}
|
||||||
|
|
||||||
|
.editor .writely-comment {
|
||||||
|
font-size: 9pt;
|
||||||
|
line-height: 1.4;
|
||||||
|
padding: 1px;
|
||||||
|
border: 1px dashed #C0C0C0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* end editor CSS */
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="DoPageLoad();"
|
||||||
|
|
||||||
|
revision="cfnx2f69_111dp3jzfgb:107">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Using the Android Native Development Kit (NDK)
|
||||||
|
</h1>
|
||||||
|
version 1.3<br>
|
||||||
|
<br>
|
||||||
|
<h2>
|
||||||
|
Introduction
|
||||||
|
</h2>
|
||||||
|
The Android Native Development Kit enables developers to write shared libraries
|
||||||
|
in C or C++ and call them from Java code. The native shared libraries can be
|
||||||
|
packaged into apk files along with a normal Android application written in Java,
|
||||||
|
so that the resulting Android application can be downloaded and installed on an
|
||||||
|
Android phone.<br>
|
||||||
|
<br>
|
||||||
|
The Native Development Kit consists of:<br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
C/C++ headers for native APIs<br>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
C/C++ libraries for native APIs<br>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Documentation
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Sample Code
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
The Native Development Kit is designed to be used with the Android SDK:<br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The NDK is used to create a shared library containing native code.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The SDK is used to create an Android application written in Java that calls
|
||||||
|
into the native code shared library.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h1>
|
||||||
|
</h1>
|
||||||
|
<h2>
|
||||||
|
Setting up your machine<br>
|
||||||
|
</h2>
|
||||||
|
The Native Development Kit may be installed on either Linux or OS X. Developing
|
||||||
|
under Windows is not yet supported.<br>
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
Linux Installation
|
||||||
|
</h3>
|
||||||
|
The
|
||||||
|
Android build is routinely tested on recent versions of Ubuntu (6.06 and later), but
|
||||||
|
may work on other distributions as well.<br>
|
||||||
|
<h4>
|
||||||
|
<a name=TOC-Ubuntu-Linux-i386-></a><span style=FONT-FAMILY:Verdana>Ubuntu
|
||||||
|
Linux (i386)</span>
|
||||||
|
</h4>
|
||||||
|
<div style=FONT-FAMILY:Verdana>
|
||||||
|
To set up your Linux development environment, make sure you have the
|
||||||
|
following:<span style="WORD-SPACING:0px; FONT-STYLE:normal; FONT-VARIANT:normal; FONT-WEIGHT:normal; font-size-adjust:none; font-stretch:normal; TEXT-TRANSFORM:none; COLOR:#000000; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate"><font size=2>
|
||||||
|
</font></span>
|
||||||
|
</div>
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
|
||||||
|
<ul style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
|
||||||
|
<li style="MARGIN-TOP:8px; MARGIN-BOTTOM:8px">
|
||||||
|
Git 1.5.4 or
|
||||||
|
newer<span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal"><font size=2>. </font></span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<blockquote style="BORDER:medium none ; MARGIN:0pt 0pt 0pt 40px; PADDING:0px">
|
||||||
|
<span style=FONT-FAMILY:arial><span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal"><span style="FONT-FAMILY:courier new,monospace">$
|
||||||
|
</span></span><span style="FONT-FAMILY:courier new,monospace">sudo apt-get
|
||||||
|
install git-core<br>
|
||||||
|
</span></span>
|
||||||
|
</blockquote>
|
||||||
|
<div>
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:arial,sans-serif">
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px">
|
||||||
|
<h4>
|
||||||
|
<a name=TOC-Ubuntu-Linux-amd64-></a><span style=FONT-FAMILY:Verdana>Ubuntu
|
||||||
|
Linux (amd64)</span>
|
||||||
|
</h4>
|
||||||
|
<span style=FONT-FAMILY:Verdana>This has not been as well
|
||||||
|
tested.</span>
|
||||||
|
</div>
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
|
||||||
|
The Android build requires a 32-bit build environment:
|
||||||
|
</div>
|
||||||
|
<div style="MARGIN-TOP:0px; MARGIN-BOTTOM:0px; FONT-FAMILY:Verdana">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Get the packages as listed above in the i386
|
||||||
|
instructions:<span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal"> </span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<blockquote style="BORDER:medium none ; MARGIN:0pt 0pt 0pt 40px; PADDING:0px">
|
||||||
|
<span style=FONT-FAMILY:arial><span style="FONT-WEIGHT:normal; WORD-SPACING:0px; TEXT-TRANSFORM:none; COLOR:#000000; FONT-STYLE:normal; WHITE-SPACE:normal; LETTER-SPACING:normal; border-collapse:separate; FONT-VARIANT:normal"><span style="FONT-FAMILY:courier new,monospace">$ </span></span><span style="FONT-FAMILY:courier new,monospace">sudo
|
||||||
|
apt-get install git-core<br>
|
||||||
|
</span></span>
|
||||||
|
</blockquote>
|
||||||
|
<h4>
|
||||||
|
<a name=TOC-Other-Linux></a>Other Linux
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
There's
|
||||||
|
no reason why Android cannot be built on non-Ubuntu systems<span style=FONT-WEIGHT:normal><font size=2>. In general you will need:</font></span>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Git 1.5.4 or newer. You can find it at <a href=http://git.or.cz/ rel=nofollow>http://git.or.cz/</a><span style=FONT-FAMILY:arial></span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
Mac OS Installation
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span style=FONT-FAMILY:arial,sans-serif>To build the Android files in a
|
||||||
|
Mac OS environment, you need an Intel/x86 machine. The Android build
|
||||||
|
system and tools do not support the older PowerPC architecture.</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span style=FONT-FAMILY:arial,sans-serif>Android must be built on a
|
||||||
|
case-sensitive file system.<br>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
We recommend that you build Android on a partition that has been
|
||||||
|
formatted with the "Case-sensitive Journaled HFS+" file system:
|
||||||
|
</li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
A case-sensitive file system is required because the sources contain
|
||||||
|
files that differ only in case.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Journaled systems are more robust. (This is optional, but
|
||||||
|
recommended.)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
HFS+ is required to successfully build Mac OS applications such as
|
||||||
|
the Android Emulator for OS X.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<li>
|
||||||
|
If you want to avoid partitioning/formatting your hard drive, you can
|
||||||
|
use a case-sensitive disk image instead.
|
||||||
|
</li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
To create the image:<br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
launch /Applications/Utilities/Disk Utility
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
select "New Image"
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
size: 8 GB (this will work, but you can choose more if you want
|
||||||
|
to)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
volume format: case sensitive, journaled
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
This will create a .dmg file which, once mounted, acts as a drive
|
||||||
|
with the required formatting for Android development. For a disk
|
||||||
|
image named "android.dmg" stored in your home directory, you can add
|
||||||
|
the following to your ~/.bash_profile to mount the image when you
|
||||||
|
execute "mountAndroid":<br>
|
||||||
|
<br>
|
||||||
|
<div style=MARGIN-LEFT:40px>
|
||||||
|
<span style="FONT-FAMILY:courier new,monospace"># command to mount
|
||||||
|
the android file
|
||||||
|
image</span><br style="FONT-FAMILY:courier new,monospace">
|
||||||
|
<span style="FONT-FAMILY:courier new,monospace">function
|
||||||
|
mountAndroid { hdiutil attach ~/android.dmg
|
||||||
|
-mountpoint /Volumes/android; }</span><br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
Once mounted, you'll do all your work in the "android" volume. You
|
||||||
|
can eject it (unmount it) just like you would with an external
|
||||||
|
drive.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<div>
|
||||||
|
<br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Install git 1.5.4 or newer. You can find it at
|
||||||
|
<a href=http://git.or.cz/ rel=nofollow>http://git.or.cz/</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h2>
|
||||||
|
Installing the Android SDK
|
||||||
|
</h2>
|
||||||
|
The Android NDK uses the Android SDK. You can find the Android SDK at
|
||||||
|
<a href=http://code.google.com/android/download.html id=a.-o title=http://code.google.com/android/download.html>http://code.google.com/android/download.html</a><br>
|
||||||
|
This version of the Android NDK requires the Cupcake version of the
|
||||||
|
Android SDK.<br>
|
||||||
|
<br>
|
||||||
|
<h2>
|
||||||
|
Installing the Prebuilt Native Toolchain<br>
|
||||||
|
</h2>
|
||||||
|
The NDK uses the prebuilt native toolchain from the Android Open Source
|
||||||
|
git repository.<br>
|
||||||
|
<br>
|
||||||
|
To download the prebuilt native toolchain to your working directory,
|
||||||
|
execute the following commands:<br>
|
||||||
|
<br>
|
||||||
|
<span style="FONT-FAMILY:Courier New"></span>
|
||||||
|
<div style=MARGIN-LEFT:40px>
|
||||||
|
<span style="FONT-FAMILY:Courier New">git clone
|
||||||
|
git://android.git.kernel.org/platform/prebuilt.git</span><br>
|
||||||
|
<span style="FONT-FAMILY:Courier New">cd prebuilt</span><br>
|
||||||
|
<span style="FONT-FAMILY:Courier New">git checkout -b cupcake -t
|
||||||
|
origin/cupcake</span><br>
|
||||||
|
</div>
|
||||||
|
<div style=MARGIN-LEFT:40px>
|
||||||
|
<span style="FONT-FAMILY:Courier New"></span>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<h2>
|
||||||
|
Setting Environment Variables
|
||||||
|
</h2>
|
||||||
|
The NDK requires that you set two environment variables:<br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
PREBUILT must be set to the directory that contains the prebuilt
|
||||||
|
toolchain. Include the "prebuilt" directory in the path. Example:
|
||||||
|
/Volumes/android/prebuilt<br>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
ANDROID_SDK_BASE must be set to the directory that contains the
|
||||||
|
Android SDK. Example: ~/AndroidSDK<br>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<h2>
|
||||||
|
<span style=FONT-FAMILY:Verdana>Unpacking the NDK</span>
|
||||||
|
</h2>
|
||||||
|
Unpack the android_ndk.tar.gz into your working directory<br>
|
||||||
|
<br>
|
||||||
|
<div style=MARGIN-LEFT:40px>
|
||||||
|
<span style="FONT-FAMILY:Courier New">tar -zxvf
|
||||||
|
android_ndk.tar.gz</span><br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
This will create a directory called ndk. It should contain a README.html
|
||||||
|
file (this file) and the following directories: config, include, lib, and
|
||||||
|
sample.<br>
|
||||||
|
<br>
|
||||||
|
Look in the "samples" directory for samples showing how to use the NDK.<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<br></body>
|
||||||
|
</html>
|
||||||
@@ -100,7 +100,7 @@ ndk_src_dest_dir := $(ndk_src_tree)/ndk
|
|||||||
bionic_src_dest_dir := $(ndk_src_dest_dir)/include/bionic
|
bionic_src_dest_dir := $(ndk_src_dest_dir)/include/bionic
|
||||||
|
|
||||||
# Destinations of all common files (not picked up by tree rules below)
|
# Destinations of all common files (not picked up by tree rules below)
|
||||||
ndk_common_dest_files := $(ndk_common_dest_dir)/README \
|
ndk_common_dest_files := $(ndk_common_dest_dir)/Android_NDK_README.html \
|
||||||
$(ndk_common_dest_dir)/config/armelf.x \
|
$(ndk_common_dest_dir)/config/armelf.x \
|
||||||
$(ndk_common_dest_dir)/config/armelflib.x \
|
$(ndk_common_dest_dir)/config/armelflib.x \
|
||||||
$(ndk_common_dest_dir)/lib/crtbegin_dynamic.o \
|
$(ndk_common_dest_dir)/lib/crtbegin_dynamic.o \
|
||||||
@@ -114,8 +114,8 @@ ndk_common_full_dest_files := \
|
|||||||
$(ndk_common_full_dest_dir)/lib/libstdc++.so
|
$(ndk_common_full_dest_dir)/lib/libstdc++.so
|
||||||
|
|
||||||
# Install common files outside common trees
|
# Install common files outside common trees
|
||||||
$(ndk_common_dest_dir)/README: $(LOCAL_PATH)/README | $(ACP)
|
$(ndk_common_dest_dir)/Android_NDK_README.html: $(LOCAL_PATH)/Android_NDK_README.html | $(ACP)
|
||||||
@echo "NDK README: from $? to $@"
|
@echo "NDK Android_NDK_README.html: from $? to $@"
|
||||||
$(copy-file-to-target)
|
$(copy-file-to-target)
|
||||||
|
|
||||||
$(ndk_common_dest_dir)/config/armelf.x: $(BUILD_SYSTEM)/armelf.x | $(ACP)
|
$(ndk_common_dest_dir)/config/armelf.x: $(BUILD_SYSTEM)/armelf.x | $(ACP)
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
Using the Native Development Kit (NDK)
|
|
||||||
version 1.2
|
|
||||||
|
|
||||||
PRECONDITIONS
|
|
||||||
|
|
||||||
The Native Development Kit may be installed on either Linux or OS X.
|
|
||||||
|
|
||||||
The NDK must be installed on a case-sensitive file system. Linux
|
|
||||||
file systems are always case-sensitive, but the default OS X file
|
|
||||||
system is case-insenstive. A case-sensitive file sytem can be
|
|
||||||
created either by partitioning your drive to include a case-sensitive
|
|
||||||
partition or by creating a disk image that is case-sensitive.
|
|
||||||
|
|
||||||
STEP 1
|
|
||||||
Installing arm-eabi-gcc
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
1) Untar the android_ndk.tar.gz:
|
|
||||||
|
|
||||||
tar -zxvf android_ndk.tar.gz
|
|
||||||
|
|
||||||
This will create a directory called ndk. It should include a README file (this
|
|
||||||
file) and the following directories: config, include, lib, sample and toolchain.
|
|
||||||
|
|
||||||
|
|
||||||
STEP 2
|
|
||||||
Samples
|
|
||||||
-------
|
|
||||||
|
|
||||||
Look in the "samples" directory for samples of how to use the NDK.
|
|
||||||
@@ -152,6 +152,18 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name=".app.ReorderOnLaunch"
|
||||||
|
android:label="@string/activity_reorder">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name=".app.ReorderTwo" />
|
||||||
|
<activity android:name=".app.ReorderThree" />
|
||||||
|
<activity android:name=".app.ReorderFour" />
|
||||||
|
|
||||||
<!-- Intent Samples -->
|
<!-- Intent Samples -->
|
||||||
|
|
||||||
<activity android:name=".app.Intents" android:label="@string/activity_intents">
|
<activity android:name=".app.Intents" android:label="@string/activity_intents">
|
||||||
|
|||||||
38
samples/ApiDemos/res/layout/reorder_four.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_four.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
|
||||||
|
See corresponding Java code com.example.android.apis.app.ReorderOnLaunch.java. -->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="4dip"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:paddingBottom="4dip"
|
||||||
|
android:text="@string/reorder_four_text"/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/reorder_second_to_front"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reorder_second_to_front">
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
38
samples/ApiDemos/res/layout/reorder_on_launch.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_on_launch.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
|
||||||
|
See corresponding Java code com.android.sdk.app.ReorderOnLaunch.java. -->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="4dip"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:paddingBottom="4dip"
|
||||||
|
android:text="@string/reorder_on_launch"/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/reorder_launch_two"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reorder_launch_two">
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
38
samples/ApiDemos/res/layout/reorder_three.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_three.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
|
||||||
|
See corresponding Java code com.example.android.apis.app.ReorderOnLaunch.java. -->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="4dip"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:paddingBottom="4dip"
|
||||||
|
android:text="@string/reorder_three_text"/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/reorder_launch_four"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reorder_launch_four">
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
38
samples/ApiDemos/res/layout/reorder_two.xml
Normal file
38
samples/ApiDemos/res/layout/reorder_two.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Demonstrates using Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
|
||||||
|
See corresponding Java code com.example.android.apis.app.ReorderOnLaunch.java. -->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="4dip"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:paddingBottom="4dip"
|
||||||
|
android:text="@string/reorder_two_text"/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/reorder_launch_three"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reorder_launch_three">
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -185,11 +185,21 @@
|
|||||||
<string name="custom_title_left_button">Change Left</string>
|
<string name="custom_title_left_button">Change Left</string>
|
||||||
<string name="custom_title_right_button">Change Right</string>
|
<string name="custom_title_right_button">Change Right</string>
|
||||||
|
|
||||||
|
<string name="activity_reorder">App/Activity/Reorder Activities</string>
|
||||||
|
<string name="reorder_on_launch">This is the first of a sequence of four Activities. A button on the fourth will use the Intent.FLAG_ACTIVITY_REORDER_TO_FRONT flag to bring the second of the activities to the front of the history stack. After that, proceeding back through the history should begin with the newly-frontmost second reorder activity, then the fourth, the third, and finally the first.</string>
|
||||||
|
<string name="reorder_launch_two">Go to the second</string>
|
||||||
|
<string name="reorder_two_text">This is the second in a sequence of four Activities.</string>
|
||||||
|
<string name="reorder_launch_three">Go to the third</string>
|
||||||
|
<string name="reorder_three_text">This is the third of a sequence of four Activities.</string>
|
||||||
|
<string name="reorder_launch_four">Go to the fourth</string>
|
||||||
|
<string name="reorder_four_text">This is the last in a sequence of four Activities.</string>
|
||||||
|
<string name="reorder_second_to_front">Bring the second in front</string>
|
||||||
|
|
||||||
<string name="menu_from_xml_title">App/Menu/Inflate from XML</string>
|
<string name="menu_from_xml_title">App/Menu/Inflate from XML</string>
|
||||||
<string name="menu_from_xml_instructions_press_menu">Select a menu resource and press the menu key.</string>
|
<string name="menu_from_xml_instructions_press_menu">Select a menu resource and press the menu key.</string>
|
||||||
<string name="menu_from_xml_instructions_go_back">If you want to choose another menu resource, go back and re-run this activity.</string>
|
<string name="menu_from_xml_instructions_go_back">If you want to choose another menu resource, go back and re-run this activity.</string>
|
||||||
|
|
||||||
<string name="voice_recognition">App/Voice Recognition</string>
|
<string name="voice_recognition">App/Voice Recognition</string>
|
||||||
|
|
||||||
<!-- ============================== -->
|
<!-- ============================== -->
|
||||||
<!-- app/content examples strings -->
|
<!-- app/content examples strings -->
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
android:hint="@string/search_hint"
|
android:hint="@string/search_hint"
|
||||||
android:searchMode="showSearchLabelAsBadge"
|
android:searchMode="showSearchLabelAsBadge"
|
||||||
|
|
||||||
|
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"
|
||||||
|
android:voiceLanguageModel="free_form"
|
||||||
|
android:voicePromptText="@string/search_invoke"
|
||||||
|
|
||||||
android:searchSuggestAuthority="com.example.android.apis.SuggestionProvider"
|
android:searchSuggestAuthority="com.example.android.apis.SuggestionProvider"
|
||||||
android:searchSuggestSelection=" ? "
|
android:searchSuggestSelection=" ? "
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example.android.apis.app;
|
||||||
|
|
||||||
|
import com.example.android.apis.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
public class ReorderFour extends Activity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedState) {
|
||||||
|
super.onCreate(savedState);
|
||||||
|
|
||||||
|
setContentView(R.layout.reorder_four);
|
||||||
|
|
||||||
|
Button twoButton = (Button) findViewById(R.id.reorder_second_to_front);
|
||||||
|
twoButton.setOnClickListener(mClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final OnClickListener mClickListener = new OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = new Intent(ReorderFour.this, ReorderTwo.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example.android.apis.app;
|
||||||
|
|
||||||
|
import com.example.android.apis.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
public class ReorderOnLaunch extends Activity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedState) {
|
||||||
|
super.onCreate(savedState);
|
||||||
|
|
||||||
|
setContentView(R.layout.reorder_on_launch);
|
||||||
|
|
||||||
|
Button twoButton = (Button) findViewById(R.id.reorder_launch_two);
|
||||||
|
twoButton.setOnClickListener(mClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final OnClickListener mClickListener = new OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
startActivity(new Intent(ReorderOnLaunch.this, ReorderTwo.class));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example.android.apis.app;
|
||||||
|
|
||||||
|
import com.example.android.apis.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
public class ReorderThree extends Activity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedState) {
|
||||||
|
super.onCreate(savedState);
|
||||||
|
|
||||||
|
setContentView(R.layout.reorder_three);
|
||||||
|
|
||||||
|
Button twoButton = (Button) findViewById(R.id.reorder_launch_four);
|
||||||
|
twoButton.setOnClickListener(mClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final OnClickListener mClickListener = new OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
startActivity(new Intent(ReorderThree.this, ReorderFour.class));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example.android.apis.app;
|
||||||
|
|
||||||
|
import com.example.android.apis.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
public class ReorderTwo extends Activity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedState) {
|
||||||
|
super.onCreate(savedState);
|
||||||
|
|
||||||
|
setContentView(R.layout.reorder_two);
|
||||||
|
|
||||||
|
Button twoButton = (Button) findViewById(R.id.reorder_launch_three);
|
||||||
|
twoButton.setOnClickListener(mClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final OnClickListener mClickListener = new OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
startActivity(new Intent(ReorderTwo.this, ReorderThree.class));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.samples.app;
|
package com.example.android.apis.app;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable;
|
|||||||
public class ProxyDrawable extends Drawable {
|
public class ProxyDrawable extends Drawable {
|
||||||
|
|
||||||
private Drawable mProxy;
|
private Drawable mProxy;
|
||||||
|
private boolean mMutated;
|
||||||
|
|
||||||
public ProxyDrawable(Drawable target) {
|
public ProxyDrawable(Drawable target) {
|
||||||
mProxy = target;
|
mProxy = target;
|
||||||
@@ -88,5 +89,14 @@ public class ProxyDrawable extends Drawable {
|
|||||||
mProxy.setAlpha(alpha);
|
mProxy.setAlpha(alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Drawable mutate() {
|
||||||
|
if (mProxy != null && !mMutated && super.mutate() == this) {
|
||||||
|
mProxy.mutate();
|
||||||
|
mMutated = true;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -223,14 +223,18 @@ class GTView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
private float mMotionStartTiltAngle;
|
private float mMotionStartTiltAngle;
|
||||||
private int mMotionDirection;
|
private int mMotionDirection;
|
||||||
|
|
||||||
|
private boolean mPaused = true;
|
||||||
|
private boolean mHaveSurface = false;
|
||||||
|
private boolean mStartAnimating = false;
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
EGL10 egl = (EGL10)EGLContext.getEGL();
|
mHaveSurface = true;
|
||||||
mEGLSurface = egl.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, this, null);
|
startEGL();
|
||||||
egl.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
// nothing to do
|
mHaveSurface = false;
|
||||||
|
stopEGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
||||||
@@ -249,59 +253,114 @@ class GTView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
getHolder().addCallback(this);
|
getHolder().addCallback(this);
|
||||||
getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||||
|
|
||||||
AssetManager am = context.getAssets();
|
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
EGL10 egl = (EGL10)EGLContext.getEGL();
|
|
||||||
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
|
||||||
int[] version = new int[2];
|
|
||||||
egl.eglInitialize(dpy, version);
|
|
||||||
int[] configSpec = {
|
|
||||||
EGL10.EGL_DEPTH_SIZE, 16,
|
|
||||||
EGL10.EGL_NONE
|
|
||||||
};
|
|
||||||
EGLConfig[] configs = new EGLConfig[1];
|
|
||||||
int[] num_config = new int[1];
|
|
||||||
egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
|
|
||||||
mEGLConfig = configs[0];
|
|
||||||
mEGLContext = egl.eglCreateContext(dpy, mEGLConfig, EGL10.EGL_NO_CONTEXT, null);
|
|
||||||
mEGLDisplay = dpy;
|
|
||||||
|
|
||||||
mClock = new Clock();
|
mClock = new Clock();
|
||||||
|
|
||||||
|
startEGL();
|
||||||
|
|
||||||
setFocusable(true);
|
setFocusable(true);
|
||||||
setFocusableInTouchMode(true);
|
setFocusableInTouchMode(true);
|
||||||
requestFocus();
|
requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
/**
|
||||||
loadAssets(am);
|
* Creates an egl context. If the state of the activity is right, also
|
||||||
} catch (IOException ioe) {
|
* creates the egl surface. Otherwise the surface will be created in a
|
||||||
ioe.printStackTrace();
|
* future call to createEGLSurface().
|
||||||
throw new RuntimeException(ioe);
|
*/
|
||||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
private void startEGL() {
|
||||||
aioobe.printStackTrace();
|
EGL10 egl = (EGL10)EGLContext.getEGL();
|
||||||
throw new RuntimeException(aioobe);
|
|
||||||
|
if (mEGLContext == null) {
|
||||||
|
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||||
|
int[] version = new int[2];
|
||||||
|
egl.eglInitialize(dpy, version);
|
||||||
|
int[] configSpec = {
|
||||||
|
EGL10.EGL_DEPTH_SIZE, 16,
|
||||||
|
EGL10.EGL_NONE
|
||||||
|
};
|
||||||
|
EGLConfig[] configs = new EGLConfig[1];
|
||||||
|
int[] num_config = new int[1];
|
||||||
|
egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config);
|
||||||
|
mEGLConfig = configs[0];
|
||||||
|
|
||||||
|
mEGLContext = egl.eglCreateContext(dpy, mEGLConfig,
|
||||||
|
EGL10.EGL_NO_CONTEXT, null);
|
||||||
|
mEGLDisplay = dpy;
|
||||||
|
|
||||||
|
AssetManager am = mContext.getAssets();
|
||||||
|
try {
|
||||||
|
loadAssets(am);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ioe.printStackTrace();
|
||||||
|
throw new RuntimeException(ioe);
|
||||||
|
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||||
|
aioobe.printStackTrace();
|
||||||
|
throw new RuntimeException(aioobe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEGLSurface == null && !mPaused && mHaveSurface) {
|
||||||
|
mEGLSurface = egl.eglCreateWindowSurface(mEGLDisplay, mEGLConfig,
|
||||||
|
this, null);
|
||||||
|
egl.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface,
|
||||||
|
mEGLContext);
|
||||||
|
mInitialized = false;
|
||||||
|
if (mStartAnimating) {
|
||||||
|
startAnimating();
|
||||||
|
mStartAnimating = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the view.
|
* Destroys the egl context. If an egl surface has been created, it is
|
||||||
|
* destroyed as well.
|
||||||
*/
|
*/
|
||||||
public void destroy() {
|
private void stopEGL() {
|
||||||
EGL10 egl = (EGL10)EGLContext.getEGL();
|
EGL10 egl = (EGL10)EGLContext.getEGL();
|
||||||
egl.eglMakeCurrent(mEGLDisplay,
|
if (mEGLSurface != null) {
|
||||||
egl.EGL_NO_SURFACE, egl.EGL_NO_SURFACE, egl.EGL_NO_CONTEXT);
|
egl.eglMakeCurrent(mEGLDisplay,
|
||||||
egl.eglDestroyContext(mEGLDisplay, mEGLContext);
|
egl.EGL_NO_SURFACE, egl.EGL_NO_SURFACE, egl.EGL_NO_CONTEXT);
|
||||||
egl.eglDestroySurface(mEGLDisplay, mEGLSurface);
|
egl.eglDestroySurface(mEGLDisplay, mEGLSurface);
|
||||||
egl.eglTerminate(mEGLDisplay);
|
mEGLSurface = null;
|
||||||
mEGLContext = null;
|
}
|
||||||
|
|
||||||
|
if (mEGLContext != null) {
|
||||||
|
egl.eglDestroyContext(mEGLDisplay, mEGLContext);
|
||||||
|
egl.eglTerminate(mEGLDisplay);
|
||||||
|
mEGLContext = null;
|
||||||
|
mEGLDisplay = null;
|
||||||
|
mEGLConfig = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPause() {
|
||||||
|
mPaused = true;
|
||||||
|
stopAnimating();
|
||||||
|
stopEGL();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResume() {
|
||||||
|
mPaused = false;
|
||||||
|
startEGL();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
stopAnimating();
|
||||||
|
stopEGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begin animation.
|
* Begin animation.
|
||||||
*/
|
*/
|
||||||
public void startAnimating() {
|
public void startAnimating() {
|
||||||
mHandler.sendEmptyMessage(INVALIDATE);
|
if (mEGLSurface == null) {
|
||||||
|
mStartAnimating = true; // will start when egl surface is created
|
||||||
|
} else {
|
||||||
|
mHandler.sendEmptyMessage(INVALIDATE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1390,32 +1449,25 @@ public class GlobalTime extends Activity {
|
|||||||
|
|
||||||
GTView gtView = null;
|
GTView gtView = null;
|
||||||
|
|
||||||
private void setGTView() {
|
|
||||||
if (gtView == null) {
|
|
||||||
gtView = new GTView(this);
|
|
||||||
setContentView(gtView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override protected void onCreate(Bundle icicle) {
|
@Override protected void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
setGTView();
|
gtView = new GTView(this);
|
||||||
|
setContentView(gtView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void onResume() {
|
@Override protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
setGTView();
|
gtView.onResume();
|
||||||
Looper.myQueue().addIdleHandler(new Idler());
|
Looper.myQueue().addIdleHandler(new Idler());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void onPause() {
|
@Override protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
gtView.stopAnimating();
|
gtView.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void onStop() {
|
@Override protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
gtView.stopAnimating();
|
|
||||||
gtView.destroy();
|
gtView.destroy();
|
||||||
gtView = null;
|
gtView = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,5 +19,5 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<dimen name="key_height">46px</dimen>
|
<dimen name="key_height">46dip</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<dimen name="key_height">50px</dimen>
|
<dimen name="key_height">50dip</dimen>
|
||||||
<dimen name="candidate_font_height">16sp</dimen>
|
<dimen name="candidate_font_height">16sp</dimen>
|
||||||
<dimen name="candidate_vertical_padding">6sp</dimen>
|
<dimen name="candidate_vertical_padding">6sp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -27,6 +27,7 @@ import android.view.View;
|
|||||||
import android.view.inputmethod.CompletionInfo;
|
import android.view.inputmethod.CompletionInfo;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -73,11 +74,19 @@ public class SoftKeyboard extends InputMethodService
|
|||||||
private String mWordSeparators;
|
private String mWordSeparators;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to generate the various keyboard layouts used by the
|
* Main initialization of the input method component. Be sure to call
|
||||||
* input method. Takes care of regenerating the layouts if the width
|
* to super class.
|
||||||
* of the input method changes.
|
|
||||||
*/
|
*/
|
||||||
private void makeKeyboards() {
|
@Override public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
mWordSeparators = getResources().getString(R.string.word_separators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the point where you can do all of your UI initialization. It
|
||||||
|
* is called after creation and any configuration change.
|
||||||
|
*/
|
||||||
|
@Override public void onInitializeInterface() {
|
||||||
if (mQwertyKeyboard != null) {
|
if (mQwertyKeyboard != null) {
|
||||||
// Configuration changes can happen after the keyboard gets recreated,
|
// Configuration changes can happen after the keyboard gets recreated,
|
||||||
// so we need to be able to re-build the keyboards if the available
|
// so we need to be able to re-build the keyboards if the available
|
||||||
@@ -91,16 +100,6 @@ public class SoftKeyboard extends InputMethodService
|
|||||||
mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the framework when your view for creating input needs to
|
* Called by the framework when your view for creating input needs to
|
||||||
* be generated. This will be called the first time your input method
|
* be generated. This will be called the first time your input method
|
||||||
@@ -108,9 +107,6 @@ public class SoftKeyboard extends InputMethodService
|
|||||||
* a configuration change.
|
* a configuration change.
|
||||||
*/
|
*/
|
||||||
@Override public View onCreateInputView() {
|
@Override public View onCreateInputView() {
|
||||||
// We call makeKeyboards() here to regenerate them if needed due to
|
|
||||||
// a configuration change.
|
|
||||||
makeKeyboards();
|
|
||||||
mInputView = (KeyboardView) getLayoutInflater().inflate(
|
mInputView = (KeyboardView) getLayoutInflater().inflate(
|
||||||
R.layout.input, null);
|
R.layout.input, null);
|
||||||
mInputView.setOnKeyboardActionListener(this);
|
mInputView.setOnKeyboardActionListener(this);
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ void PropertyServer::SetDefaultProperties(void)
|
|||||||
{ "dalvik.vm.stack-trace-file", "/data/anr/traces.txt" },
|
{ "dalvik.vm.stack-trace-file", "/data/anr/traces.txt" },
|
||||||
//{ "dalvik.vm.execution-mode", "int:portable" },
|
//{ "dalvik.vm.execution-mode", "int:portable" },
|
||||||
{ "dalvik.vm.enableassertions", "all" }, // -ea
|
{ "dalvik.vm.enableassertions", "all" }, // -ea
|
||||||
{ "dalvik.vm.verify-bytecode", "false" }, // -Xverify
|
{ "dalvik.vm.dexopt-flags", "" }, // e.g. "v=a,o=v,m=n"
|
||||||
{ "dalvik.vm.deadlock-predict", "off" }, // -Xdeadlockpredict
|
{ "dalvik.vm.deadlock-predict", "off" }, // -Xdeadlockpredict
|
||||||
//{ "dalvik.vm.jniopts", "forcecopy" }, // -Xjniopts
|
//{ "dalvik.vm.jniopts", "forcecopy" }, // -Xjniopts
|
||||||
{ "log.redirect-stdio", "false" }, // -Xlog-stdio
|
{ "log.redirect-stdio", "false" }, // -Xlog-stdio
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007 The Android Open Source Project
|
* Copyright 2007 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Magic entries in /sys/android_power/.
|
* Magic entries in /sys/class/power_supply/.
|
||||||
*/
|
*/
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
@@ -12,30 +12,6 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* Set of entries found in /sys/android_power.
|
|
||||||
*/
|
|
||||||
typedef enum DeviceIndex {
|
|
||||||
kPowerUnknown = 0,
|
|
||||||
|
|
||||||
kPowerAutoOffTimeout,
|
|
||||||
kPowerBatteryLevel,
|
|
||||||
kPowerBatteryLevelLow,
|
|
||||||
kPowerBatteryLevelRaw,
|
|
||||||
kPowerBatteryLevelScale,
|
|
||||||
kPowerBatteryLowLevel,
|
|
||||||
kPowerBatteryShutdownLevel,
|
|
||||||
kPowerChargingState,
|
|
||||||
kPowerRequestState,
|
|
||||||
kPowerState,
|
|
||||||
|
|
||||||
kPowerAcquireFullWakeLock,
|
|
||||||
kPowerAcquirePartialWakeLock,
|
|
||||||
kPowerReleaseWakeLock,
|
|
||||||
} DeviceIndex;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map filename to device index.
|
* Map filename to device index.
|
||||||
*
|
*
|
||||||
@@ -47,38 +23,26 @@ static const struct {
|
|||||||
//DeviceIndex idx;
|
//DeviceIndex idx;
|
||||||
const char* data;
|
const char* data;
|
||||||
} gDeviceMap[] = {
|
} gDeviceMap[] = {
|
||||||
{ "auto_off_timeout", //kPowerAutoOffTimeout,
|
{ "ac/online",
|
||||||
"\n" },
|
|
||||||
{ "battery_level", //kPowerBatteryLevel,
|
|
||||||
"9\n" },
|
|
||||||
{ "battery_level_low", //kPowerBatteryLevelLow,
|
|
||||||
"0\n" },
|
"0\n" },
|
||||||
{ "battery_level_raw", //kPowerBatteryLevelRaw,
|
|
||||||
|
{ "battery/batt_temp",
|
||||||
|
"281\n", },
|
||||||
|
{ "battery/batt_vol",
|
||||||
|
"4170\n" },
|
||||||
|
{ "battery/capacity",
|
||||||
"100\n" },
|
"100\n" },
|
||||||
{ "battery_level_scale", //kPowerBatteryLevelScale,
|
{ "battery/health",
|
||||||
"9\n" },
|
"Good\n" },
|
||||||
{ "battery_low_level", //kPowerBatteryLowLevel,
|
{ "battery/present",
|
||||||
"10\n" },
|
"0\n" },
|
||||||
{ "battery_shutdown_level", //kPowerBatteryShutdownLevel,
|
{ "battery/status",
|
||||||
"5\n", },
|
"Full" },
|
||||||
{ "charging_state", //kPowerChargingState,
|
{ "battery/technology",
|
||||||
"Maintaining\n" },
|
"Li-ion\n" },
|
||||||
{ "request_state", //kPowerRequestState,
|
|
||||||
"wake\n" },
|
|
||||||
{ "state", //kPowerState,
|
|
||||||
"0-1-0\n" },
|
|
||||||
|
|
||||||
{ "acquire_full_wake_lock", //kPowerAcquireFullWakeLock,
|
|
||||||
"\n" },
|
|
||||||
{ "acquire_partial_wake_lock", //kPowerAcquirePartialWakeLock,
|
|
||||||
"\n" },
|
|
||||||
{ "release_wake_lock", //kPowerReleaseWakeLock,
|
|
||||||
"radio-interface PowerManagerService KeyEvents\n" },
|
|
||||||
{ "wait_for_fb_sleep", //kSleepFileName,
|
|
||||||
"" }, // this means "block forever on read"
|
|
||||||
{ "wait_for_fb_wake", //kWakeFileName,
|
|
||||||
"0" },
|
|
||||||
|
|
||||||
|
{ "usb/online",
|
||||||
|
"1\n" },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -96,7 +60,7 @@ typedef struct PowerState {
|
|||||||
*/
|
*/
|
||||||
static void configureInitialState(const char* pathName, PowerState* powerState)
|
static void configureInitialState(const char* pathName, PowerState* powerState)
|
||||||
{
|
{
|
||||||
const char* cp = pathName + strlen("/sys/android_power/");
|
const char* cp = pathName + strlen("/sys/class/power_supply/");
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
powerState->which = -1;
|
powerState->which = -1;
|
||||||
@@ -134,8 +98,11 @@ static ssize_t readPower(FakeDev* dev, int fd, void* buf, size_t count)
|
|||||||
|
|
||||||
wsLog("%s: read %d\n", dev->debugName, count);
|
wsLog("%s: read %d\n", dev->debugName, count);
|
||||||
|
|
||||||
if (state->which < 0 || state->which >= sizeof(gDeviceMap)/sizeof(gDeviceMap[0]))
|
if (state->which < 0 ||
|
||||||
|
state->which >= (int) (sizeof(gDeviceMap)/sizeof(gDeviceMap[0])))
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char* data = gDeviceMap[state->which].data;
|
const char* data = gDeviceMap[state->which].data;
|
||||||
size_t strLen = strlen(data);
|
size_t strLen = strlen(data);
|
||||||
|
|||||||
@@ -47,10 +47,6 @@ resources.)
|
|||||||
* Devices we intercept.
|
* Devices we intercept.
|
||||||
*
|
*
|
||||||
* Needed:
|
* Needed:
|
||||||
* /sys/android_power/battery_level_scale
|
|
||||||
* /sys/android_power/battery_level
|
|
||||||
* /sys/android_power/battery_level_raw
|
|
||||||
* /sys/android_power/charging_state
|
|
||||||
* /dev/alarm
|
* /dev/alarm
|
||||||
* radio
|
* radio
|
||||||
*/
|
*/
|
||||||
@@ -70,7 +66,7 @@ FakedPath fakedpaths[] =
|
|||||||
{ "/dev/input/event0", wsOpenDevEvent },
|
{ "/dev/input/event0", wsOpenDevEvent },
|
||||||
{ "/dev/input/*", NULL },
|
{ "/dev/input/*", NULL },
|
||||||
{ "/dev/log/*", wsOpenDevLog },
|
{ "/dev/log/*", wsOpenDevLog },
|
||||||
{ "/sys/android_power/*", wsOpenDevPower },
|
{ "/sys/class/power_supply/*", wsOpenDevPower },
|
||||||
{ "/sys/devices/platform/android-vibrator/enable", wsOpenDevVibrator },
|
{ "/sys/devices/platform/android-vibrator/enable", wsOpenDevVibrator },
|
||||||
{ "/sys/qemu_trace/*", NULL },
|
{ "/sys/qemu_trace/*", NULL },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ public final class AndroidLocation {
|
|||||||
private static final String ANDROID_SDK_VERSION = "SDK-1.0";
|
private static final String ANDROID_SDK_VERSION = "SDK-1.0";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VM folder inside the path returned by {@link #getFolder()}
|
* Virtual Device folder inside the path returned by {@link #getFolder()}
|
||||||
*/
|
*/
|
||||||
public static final String FOLDER_VMS = "vm";
|
public static final String FOLDER_AVD = "avd";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw when the location of the android folder couldn't be found.
|
* Throw when the location of the android folder couldn't be found.
|
||||||
@@ -56,7 +56,7 @@ public final class AndroidLocation {
|
|||||||
*/
|
*/
|
||||||
public final static String getFolder() throws AndroidLocationException {
|
public final static String getFolder() throws AndroidLocationException {
|
||||||
if (sPrefsLocation == null) {
|
if (sPrefsLocation == null) {
|
||||||
String home = findValidPath("user.home", "HOME");
|
String home = findValidPath("ANDROID_SDK_HOME", "user.home", "HOME");
|
||||||
|
|
||||||
// if the above failed, we throw an exception.
|
// if the above failed, we throw an exception.
|
||||||
if (home == null) {
|
if (home == null) {
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ public final class ApkBuilder {
|
|||||||
* @param files
|
* @param files
|
||||||
* @param javaResources
|
* @param javaResources
|
||||||
* @param storeType the optional type of the debug keystore. If <code>null</code>, the default
|
* @param storeType the optional type of the debug keystore. If <code>null</code>, the default
|
||||||
* keystore type of the VM is used.
|
* keystore type of the Java VM is used.
|
||||||
*/
|
*/
|
||||||
private void createPackage(File outFile, ArrayList<FileInputStream> zipArchives,
|
private void createPackage(File outFile, ArrayList<FileInputStream> zipArchives,
|
||||||
ArrayList<File> files, ArrayList<ApkFile> javaResources,
|
ArrayList<File> files, ArrayList<ApkFile> javaResources,
|
||||||
|
|||||||
@@ -268,56 +268,61 @@ final class AdbHelper {
|
|||||||
};
|
};
|
||||||
byte[] reply;
|
byte[] reply;
|
||||||
|
|
||||||
SocketChannel adbChan = SocketChannel.open(adbSockAddr);
|
SocketChannel adbChan = null;
|
||||||
adbChan.configureBlocking(false);
|
try {
|
||||||
|
adbChan = SocketChannel.open(adbSockAddr);
|
||||||
|
adbChan.configureBlocking(false);
|
||||||
|
|
||||||
// if the device is not -1, then we first tell adb we're looking to talk
|
// if the device is not -1, then we first tell adb we're looking to talk
|
||||||
// to a specific device
|
// to a specific device
|
||||||
setDevice(adbChan, device);
|
setDevice(adbChan, device);
|
||||||
|
|
||||||
if (write(adbChan, request) == false)
|
if (write(adbChan, request) == false)
|
||||||
throw new IOException("failed asking for frame buffer");
|
throw new IOException("failed asking for frame buffer");
|
||||||
|
|
||||||
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
||||||
if (!resp.ioSuccess || !resp.okay) {
|
if (!resp.ioSuccess || !resp.okay) {
|
||||||
Log.w("ddms", "Got timeout or unhappy response from ADB fb req: "
|
Log.w("ddms", "Got timeout or unhappy response from ADB fb req: "
|
||||||
+ resp.message);
|
+ resp.message);
|
||||||
adbChan.close();
|
adbChan.close();
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply = new byte[16];
|
||||||
|
if (read(adbChan, reply) == false) {
|
||||||
|
Log.w("ddms", "got partial reply from ADB fb:");
|
||||||
|
Log.hexDump("ddms", LogLevel.WARN, reply, 0, reply.length);
|
||||||
|
adbChan.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(reply);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
imageParams.bpp = buf.getInt();
|
||||||
|
imageParams.size = buf.getInt();
|
||||||
|
imageParams.width = buf.getInt();
|
||||||
|
imageParams.height = buf.getInt();
|
||||||
|
|
||||||
|
Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size="
|
||||||
|
+ imageParams.size + ", width=" + imageParams.width
|
||||||
|
+ ", height=" + imageParams.height);
|
||||||
|
|
||||||
|
if (write(adbChan, nudge) == false)
|
||||||
|
throw new IOException("failed nudging");
|
||||||
|
|
||||||
|
reply = new byte[imageParams.size];
|
||||||
|
if (read(adbChan, reply) == false) {
|
||||||
|
Log.w("ddms", "got truncated reply from ADB fb data");
|
||||||
|
adbChan.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
imageParams.data = reply;
|
||||||
|
} finally {
|
||||||
|
if (adbChan != null) {
|
||||||
|
adbChan.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reply = new byte[16];
|
|
||||||
if (read(adbChan, reply) == false) {
|
|
||||||
Log.w("ddms", "got partial reply from ADB fb:");
|
|
||||||
Log.hexDump("ddms", LogLevel.WARN, reply, 0, reply.length);
|
|
||||||
adbChan.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ByteBuffer buf = ByteBuffer.wrap(reply);
|
|
||||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
imageParams.bpp = buf.getInt();
|
|
||||||
imageParams.size = buf.getInt();
|
|
||||||
imageParams.width = buf.getInt();
|
|
||||||
imageParams.height = buf.getInt();
|
|
||||||
|
|
||||||
Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size="
|
|
||||||
+ imageParams.size + ", width=" + imageParams.width
|
|
||||||
+ ", height=" + imageParams.height);
|
|
||||||
|
|
||||||
if (write(adbChan, nudge) == false)
|
|
||||||
throw new IOException("failed nudging");
|
|
||||||
|
|
||||||
reply = new byte[imageParams.size];
|
|
||||||
if (read(adbChan, reply) == false) {
|
|
||||||
Log.w("ddms", "got truncated reply from ADB fb data");
|
|
||||||
adbChan.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
imageParams.data = reply;
|
|
||||||
|
|
||||||
adbChan.close();
|
|
||||||
|
|
||||||
return imageParams;
|
return imageParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,58 +335,61 @@ final class AdbHelper {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
Log.v("ddms", "execute: running " + command);
|
Log.v("ddms", "execute: running " + command);
|
||||||
|
|
||||||
SocketChannel adbChan = SocketChannel.open(adbSockAddr);
|
SocketChannel adbChan = null;
|
||||||
adbChan.configureBlocking(false);
|
try {
|
||||||
|
adbChan = SocketChannel.open(adbSockAddr);
|
||||||
|
adbChan.configureBlocking(false);
|
||||||
|
|
||||||
// if the device is not -1, then we first tell adb we're looking to talk
|
// if the device is not -1, then we first tell adb we're looking to
|
||||||
// to a specific device
|
// talk
|
||||||
setDevice(adbChan, device);
|
// to a specific device
|
||||||
|
setDevice(adbChan, device);
|
||||||
|
|
||||||
byte[] request = formAdbRequest("shell:" + command); //$NON-NLS-1$
|
byte[] request = formAdbRequest("shell:" + command); //$NON-NLS-1$
|
||||||
if (write(adbChan, request) == false)
|
if (write(adbChan, request) == false)
|
||||||
throw new IOException("failed submitting shell command");
|
throw new IOException("failed submitting shell command");
|
||||||
|
|
||||||
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
||||||
if (!resp.ioSuccess || !resp.okay) {
|
if (!resp.ioSuccess || !resp.okay) {
|
||||||
Log.e("ddms", "ADB rejected shell command (" + command + "): "
|
Log.e("ddms", "ADB rejected shell command (" + command + "): " + resp.message);
|
||||||
+ resp.message);
|
throw new IOException("sad result from adb: " + resp.message);
|
||||||
throw new IOException("sad result from adb: " + resp.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] data = new byte[16384];
|
|
||||||
ByteBuffer buf = ByteBuffer.wrap(data);
|
|
||||||
while (true) {
|
|
||||||
int count;
|
|
||||||
|
|
||||||
if (rcvr != null && rcvr.isCancelled()) {
|
|
||||||
Log.v("ddms", "execute: cancelled");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count = adbChan.read(buf);
|
byte[] data = new byte[16384];
|
||||||
if (count < 0) {
|
ByteBuffer buf = ByteBuffer.wrap(data);
|
||||||
// we're at the end, we flush the output
|
while (true) {
|
||||||
rcvr.flush();
|
int count;
|
||||||
Log.v("ddms",
|
|
||||||
"execute '" + command + "' on '" + device + "' : EOF hit. Read: " + count);
|
if (rcvr != null && rcvr.isCancelled()) {
|
||||||
break;
|
Log.v("ddms", "execute: cancelled");
|
||||||
} else if (count == 0) {
|
break;
|
||||||
try {
|
|
||||||
Thread.sleep(WAIT_TIME * 5);
|
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (rcvr != null) {
|
count = adbChan.read(buf);
|
||||||
rcvr.addOutput(buf.array(), buf.arrayOffset(), buf
|
if (count < 0) {
|
||||||
.position());
|
// we're at the end, we flush the output
|
||||||
|
rcvr.flush();
|
||||||
|
Log.v("ddms", "execute '" + command + "' on '" + device + "' : EOF hit. Read: "
|
||||||
|
+ count);
|
||||||
|
break;
|
||||||
|
} else if (count == 0) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(WAIT_TIME * 5);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rcvr != null) {
|
||||||
|
rcvr.addOutput(buf.array(), buf.arrayOffset(), buf.position());
|
||||||
|
}
|
||||||
|
buf.rewind();
|
||||||
}
|
}
|
||||||
buf.rewind();
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
if (adbChan != null) {
|
||||||
|
adbChan.close();
|
||||||
|
}
|
||||||
|
Log.v("ddms", "execute: returning");
|
||||||
}
|
}
|
||||||
|
|
||||||
adbChan.close();
|
|
||||||
|
|
||||||
Log.v("ddms", "execute: returning");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -407,49 +415,55 @@ final class AdbHelper {
|
|||||||
*/
|
*/
|
||||||
public static void runLogService(InetSocketAddress adbSockAddr, Device device, String logName,
|
public static void runLogService(InetSocketAddress adbSockAddr, Device device, String logName,
|
||||||
LogReceiver rcvr) throws IOException {
|
LogReceiver rcvr) throws IOException {
|
||||||
SocketChannel adbChan = SocketChannel.open(adbSockAddr);
|
SocketChannel adbChan = null;
|
||||||
adbChan.configureBlocking(false);
|
|
||||||
|
|
||||||
// if the device is not -1, then we first tell adb we're looking to talk
|
try {
|
||||||
// to a specific device
|
adbChan = SocketChannel.open(adbSockAddr);
|
||||||
setDevice(adbChan, device);
|
adbChan.configureBlocking(false);
|
||||||
|
|
||||||
byte[] request = formAdbRequest("log:" + logName);
|
// if the device is not -1, then we first tell adb we're looking to talk
|
||||||
if (write(adbChan, request) == false) {
|
// to a specific device
|
||||||
throw new IOException("failed to submit the log command");
|
setDevice(adbChan, device);
|
||||||
}
|
|
||||||
|
|
||||||
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
byte[] request = formAdbRequest("log:" + logName);
|
||||||
if (!resp.ioSuccess || !resp.okay) {
|
if (write(adbChan, request) == false) {
|
||||||
throw new IOException("Device rejected log command: " + resp.message);
|
throw new IOException("failed to submit the log command");
|
||||||
}
|
|
||||||
|
|
||||||
byte[] data = new byte[16384];
|
|
||||||
ByteBuffer buf = ByteBuffer.wrap(data);
|
|
||||||
while (true) {
|
|
||||||
int count;
|
|
||||||
|
|
||||||
if (rcvr != null && rcvr.isCancelled()) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count = adbChan.read(buf);
|
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
||||||
if (count < 0) {
|
if (!resp.ioSuccess || !resp.okay) {
|
||||||
break;
|
throw new IOException("Device rejected log command: " + resp.message);
|
||||||
} else if (count == 0) {
|
}
|
||||||
try {
|
|
||||||
Thread.sleep(WAIT_TIME * 5);
|
byte[] data = new byte[16384];
|
||||||
} catch (InterruptedException ie) {
|
ByteBuffer buf = ByteBuffer.wrap(data);
|
||||||
|
while (true) {
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if (rcvr != null && rcvr.isCancelled()) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (rcvr != null) {
|
count = adbChan.read(buf);
|
||||||
rcvr.parseNewData(buf.array(), buf.arrayOffset(), buf.position());
|
if (count < 0) {
|
||||||
|
break;
|
||||||
|
} else if (count == 0) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(WAIT_TIME * 5);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rcvr != null) {
|
||||||
|
rcvr.parseNewData(buf.array(), buf.arrayOffset(), buf.position());
|
||||||
|
}
|
||||||
|
buf.rewind();
|
||||||
}
|
}
|
||||||
buf.rewind();
|
}
|
||||||
|
} finally {
|
||||||
|
if (adbChan != null) {
|
||||||
|
adbChan.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
adbChan.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -464,24 +478,29 @@ final class AdbHelper {
|
|||||||
public static boolean createForward(InetSocketAddress adbSockAddr, Device device, int localPort,
|
public static boolean createForward(InetSocketAddress adbSockAddr, Device device, int localPort,
|
||||||
int remotePort) throws IOException {
|
int remotePort) throws IOException {
|
||||||
|
|
||||||
SocketChannel adbChan = SocketChannel.open(adbSockAddr);
|
SocketChannel adbChan = null;
|
||||||
adbChan.configureBlocking(false);
|
try {
|
||||||
|
adbChan = SocketChannel.open(adbSockAddr);
|
||||||
|
adbChan.configureBlocking(false);
|
||||||
|
|
||||||
byte[] request = formAdbRequest(String.format(
|
byte[] request = formAdbRequest(String.format(
|
||||||
"host-serial:%1$s:forward:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$
|
"host-serial:%1$s:forward:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$
|
||||||
device.serialNumber, localPort, remotePort));
|
device.serialNumber, localPort, remotePort));
|
||||||
|
|
||||||
if (write(adbChan, request) == false) {
|
if (write(adbChan, request) == false) {
|
||||||
throw new IOException("failed to submit the forward command.");
|
throw new IOException("failed to submit the forward command.");
|
||||||
|
}
|
||||||
|
|
||||||
|
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
||||||
|
if (!resp.ioSuccess || !resp.okay) {
|
||||||
|
throw new IOException("Device rejected command: " + resp.message);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (adbChan != null) {
|
||||||
|
adbChan.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
|
||||||
if (!resp.ioSuccess || !resp.okay) {
|
|
||||||
throw new IOException("Device rejected command: " + resp.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
adbChan.close();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,24 +516,29 @@ final class AdbHelper {
|
|||||||
public static boolean removeForward(InetSocketAddress adbSockAddr, Device device, int localPort,
|
public static boolean removeForward(InetSocketAddress adbSockAddr, Device device, int localPort,
|
||||||
int remotePort) throws IOException {
|
int remotePort) throws IOException {
|
||||||
|
|
||||||
SocketChannel adbChan = SocketChannel.open(adbSockAddr);
|
SocketChannel adbChan = null;
|
||||||
adbChan.configureBlocking(false);
|
try {
|
||||||
|
adbChan = SocketChannel.open(adbSockAddr);
|
||||||
|
adbChan.configureBlocking(false);
|
||||||
|
|
||||||
byte[] request = formAdbRequest(String.format(
|
byte[] request = formAdbRequest(String.format(
|
||||||
"host-serial:%1$s:killforward:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$
|
"host-serial:%1$s:killforward:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$
|
||||||
device.serialNumber, localPort, remotePort));
|
device.serialNumber, localPort, remotePort));
|
||||||
|
|
||||||
if (!write(adbChan, request)) {
|
if (!write(adbChan, request)) {
|
||||||
throw new IOException("failed to submit the remove forward command.");
|
throw new IOException("failed to submit the remove forward command.");
|
||||||
|
}
|
||||||
|
|
||||||
|
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
||||||
|
if (!resp.ioSuccess || !resp.okay) {
|
||||||
|
throw new IOException("Device rejected command: " + resp.message);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (adbChan != null) {
|
||||||
|
adbChan.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
|
|
||||||
if (!resp.ioSuccess || !resp.okay) {
|
|
||||||
throw new IOException("Device rejected command: " + resp.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
adbChan.close();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ public final class Device implements IDevice {
|
|||||||
/** Serial number of the device */
|
/** Serial number of the device */
|
||||||
String serialNumber = null;
|
String serialNumber = null;
|
||||||
|
|
||||||
/** Name of the vm */
|
/** Name of the AVD */
|
||||||
String mVmName = null;
|
String mAvdName = null;
|
||||||
|
|
||||||
/** State of the device. */
|
/** State of the device. */
|
||||||
DeviceState state = null;
|
DeviceState state = null;
|
||||||
@@ -94,8 +94,8 @@ public final class Device implements IDevice {
|
|||||||
return serialNumber;
|
return serialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVmName() {
|
public String getAvdName() {
|
||||||
return mVmName;
|
return mAvdName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -420,11 +420,11 @@ final class DeviceMonitor {
|
|||||||
device.executeShellCommand(GetPropReceiver.GETPROP_COMMAND,
|
device.executeShellCommand(GetPropReceiver.GETPROP_COMMAND,
|
||||||
new GetPropReceiver(device));
|
new GetPropReceiver(device));
|
||||||
|
|
||||||
// now get the emulator VM name (if applicable).
|
// now get the emulator Virtual Device name (if applicable).
|
||||||
if (device.isEmulator()) {
|
if (device.isEmulator()) {
|
||||||
EmulatorConsole console = EmulatorConsole.getConsole(device);
|
EmulatorConsole console = EmulatorConsole.getConsole(device);
|
||||||
if (console != null) {
|
if (console != null) {
|
||||||
device.mVmName = console.getVmName();
|
device.mAvdName = console.getAvdName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -470,7 +470,7 @@ final class DeviceMonitor {
|
|||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
// we can ignore that one. It may already have been closed.
|
// we can ignore that one. It may already have been closed.
|
||||||
}
|
}
|
||||||
Log.e("DeviceMonitor",
|
Log.d("DeviceMonitor",
|
||||||
"Connection Failure when starting to monitor device '"
|
"Connection Failure when starting to monitor device '"
|
||||||
+ device + "' : " + e.getMessage());
|
+ device + "' : " + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -558,7 +558,7 @@ final class DeviceMonitor {
|
|||||||
|
|
||||||
processIncomingJdwpData(device, socket, length);
|
processIncomingJdwpData(device, socket, length);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.e("DeviceMonitor",
|
Log.d("DeviceMonitor",
|
||||||
"Error reading jdwp list: " + ioe.getMessage());
|
"Error reading jdwp list: " + ioe.getMessage());
|
||||||
socket.close();
|
socket.close();
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public final class EmulatorConsole {
|
|||||||
private final static String HOST = "127.0.0.1"; //$NON-NLS-1$
|
private final static String HOST = "127.0.0.1"; //$NON-NLS-1$
|
||||||
|
|
||||||
private final static String COMMAND_PING = "help\r\n"; //$NON-NLS-1$
|
private final static String COMMAND_PING = "help\r\n"; //$NON-NLS-1$
|
||||||
private final static String COMMAND_VM_NAME = "vm name\r\n"; //$NON-NLS-1$
|
private final static String COMMAND_AVD_NAME = "vm name\r\n"; //$NON-NLS-1$ // TODO change with emulator
|
||||||
private final static String COMMAND_KILL = "kill\r\n"; //$NON-NLS-1$
|
private final static String COMMAND_KILL = "kill\r\n"; //$NON-NLS-1$
|
||||||
private final static String COMMAND_GSM_STATUS = "gsm status\r\n"; //$NON-NLS-1$
|
private final static String COMMAND_GSM_STATUS = "gsm status\r\n"; //$NON-NLS-1$
|
||||||
private final static String COMMAND_GSM_CALL = "gsm call %1$s\r\n"; //$NON-NLS-1$
|
private final static String COMMAND_GSM_CALL = "gsm call %1$s\r\n"; //$NON-NLS-1$
|
||||||
@@ -309,8 +309,8 @@ public final class EmulatorConsole {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized String getVmName() {
|
public synchronized String getAvdName() {
|
||||||
if (sendCommand(COMMAND_VM_NAME)) {
|
if (sendCommand(COMMAND_AVD_NAME)) {
|
||||||
String[] result = readLines();
|
String[] result = readLines();
|
||||||
if (result != null && result.length == 2) { // this should be the name on first line,
|
if (result != null && result.length == 2) { // this should be the name on first line,
|
||||||
// and ok on 2nd line
|
// and ok on 2nd line
|
||||||
|
|||||||
@@ -46,13 +46,13 @@ public interface IDevice {
|
|||||||
public String getSerialNumber();
|
public String getSerialNumber();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the VM the emulator is running.
|
* Returns the name of the AVD the emulator is running.
|
||||||
* <p/>This is only valid if {@link #isEmulator()} returns true.
|
* <p/>This is only valid if {@link #isEmulator()} returns true.
|
||||||
* <p/>If the emulator is not running any VM (for instance it's running from an Android source
|
* <p/>If the emulator is not running any AVD (for instance it's running from an Android source
|
||||||
* tree build), this method will return "<code><build></code>".
|
* tree build), this method will return "<code><build></code>".
|
||||||
* @return the name of the VM or <code>null</code> if there isn't any.
|
* @return the name of the AVD or <code>null</code> if there isn't any.
|
||||||
*/
|
*/
|
||||||
public String getVmName();
|
public String getAvdName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the state of the device.
|
* Returns the state of the device.
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVmName() {
|
public String getAvdName() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,15 +200,15 @@ public final class DevicePanel extends Panel implements IDebugBridgeChangeListen
|
|||||||
case DEVICE_COL_STATE:
|
case DEVICE_COL_STATE:
|
||||||
return getStateString(device);
|
return getStateString(device);
|
||||||
case DEVICE_COL_BUILD: {
|
case DEVICE_COL_BUILD: {
|
||||||
String vmName = device.getVmName();
|
String avdName = device.getAvdName();
|
||||||
String debuggable = device.getProperty(Device.PROP_DEBUGGABLE);
|
String debuggable = device.getProperty(Device.PROP_DEBUGGABLE);
|
||||||
String version = device.getProperty(Device.PROP_BUILD_VERSION);
|
String version = device.getProperty(Device.PROP_BUILD_VERSION);
|
||||||
if (device.isEmulator()) {
|
if (device.isEmulator()) {
|
||||||
if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
|
if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
|
||||||
return String.format("%1$s [%2$s, debug]", vmName, //$NON-NLS-1$
|
return String.format("%1$s [%2$s, debug]", avdName, //$NON-NLS-1$
|
||||||
version);
|
version);
|
||||||
} else {
|
} else {
|
||||||
return String.format("%1$s [%2$s]", vmName, version); //$NON-NLS-1$
|
return String.format("%1$s [%2$s]", avdName, version); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
|
if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.ddmuilib.log.event;
|
||||||
|
|
||||||
|
import com.android.ddmlib.log.EventContainer;
|
||||||
|
import com.android.ddmlib.log.EventLogParser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class DisplayFilteredLog extends DisplayLog {
|
||||||
|
|
||||||
|
public DisplayFilteredLog(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds event to the display.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void newEvent(EventContainer event, EventLogParser logParser) {
|
||||||
|
ArrayList<ValueDisplayDescriptor> valueDescriptors =
|
||||||
|
new ArrayList<ValueDisplayDescriptor>();
|
||||||
|
|
||||||
|
ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors =
|
||||||
|
new ArrayList<OccurrenceDisplayDescriptor>();
|
||||||
|
|
||||||
|
if (filterEvent(event, valueDescriptors, occurrenceDescriptors)) {
|
||||||
|
addToLog(event, logParser, valueDescriptors, occurrenceDescriptors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets display type
|
||||||
|
*
|
||||||
|
* @return display type as an integer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
int getDisplayType() {
|
||||||
|
return DISPLAY_TYPE_FILTERED_LOG;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.ddmuilib.log.event;
|
||||||
|
|
||||||
|
import com.android.ddmlib.log.EventContainer;
|
||||||
|
import com.android.ddmlib.log.EventLogParser;
|
||||||
|
import com.android.ddmlib.log.EventValueDescription;
|
||||||
|
import com.android.ddmlib.log.InvalidTypeException;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
import org.jfree.chart.axis.AxisLocation;
|
||||||
|
import org.jfree.chart.axis.NumberAxis;
|
||||||
|
import org.jfree.chart.plot.XYPlot;
|
||||||
|
import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
|
||||||
|
import org.jfree.chart.renderer.xy.XYAreaRenderer;
|
||||||
|
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||||
|
import org.jfree.data.time.Millisecond;
|
||||||
|
import org.jfree.data.time.TimeSeries;
|
||||||
|
import org.jfree.data.time.TimeSeriesCollection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DisplayGraph extends EventDisplay {
|
||||||
|
|
||||||
|
public DisplayGraph(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the display.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void resetUI() {
|
||||||
|
Collection<TimeSeriesCollection> datasets = mValueTypeDataSetMap.values();
|
||||||
|
for (TimeSeriesCollection dataset : datasets) {
|
||||||
|
dataset.removeAllSeries();
|
||||||
|
}
|
||||||
|
if (mOccurrenceDataSet != null) {
|
||||||
|
mOccurrenceDataSet.removeAllSeries();
|
||||||
|
}
|
||||||
|
mValueDescriptorSeriesMap.clear();
|
||||||
|
mOcurrenceDescriptorSeriesMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the UI for the event display.
|
||||||
|
* @param parent the parent composite.
|
||||||
|
* @param logParser the current log parser.
|
||||||
|
* @return the created control (which may have children).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Control createComposite(final Composite parent, EventLogParser logParser,
|
||||||
|
final ILogColumnListener listener) {
|
||||||
|
String title = getChartTitle(logParser);
|
||||||
|
return createCompositeChart(parent, logParser, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds event to the display.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void newEvent(EventContainer event, EventLogParser logParser) {
|
||||||
|
ArrayList<ValueDisplayDescriptor> valueDescriptors =
|
||||||
|
new ArrayList<ValueDisplayDescriptor>();
|
||||||
|
|
||||||
|
ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors =
|
||||||
|
new ArrayList<OccurrenceDisplayDescriptor>();
|
||||||
|
|
||||||
|
if (filterEvent(event, valueDescriptors, occurrenceDescriptors)) {
|
||||||
|
updateChart(event, logParser, valueDescriptors, occurrenceDescriptors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the chart with the {@link EventContainer} by adding the values/occurrences defined
|
||||||
|
* by the {@link ValueDisplayDescriptor} and {@link OccurrenceDisplayDescriptor} objects from
|
||||||
|
* the two lists.
|
||||||
|
* <p/>This method is only called when at least one of the descriptor list is non empty.
|
||||||
|
* @param event
|
||||||
|
* @param logParser
|
||||||
|
* @param valueDescriptors
|
||||||
|
* @param occurrenceDescriptors
|
||||||
|
*/
|
||||||
|
private void updateChart(EventContainer event, EventLogParser logParser,
|
||||||
|
ArrayList<ValueDisplayDescriptor> valueDescriptors,
|
||||||
|
ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors) {
|
||||||
|
Map<Integer, String> tagMap = logParser.getTagMap();
|
||||||
|
|
||||||
|
Millisecond millisecondTime = null;
|
||||||
|
long msec = -1;
|
||||||
|
|
||||||
|
// If the event container is a cpu container (tag == 2721), and there is no descriptor
|
||||||
|
// for the total CPU load, then we do accumulate all the values.
|
||||||
|
boolean accumulateValues = false;
|
||||||
|
double accumulatedValue = 0;
|
||||||
|
|
||||||
|
if (event.mTag == 2721) {
|
||||||
|
accumulateValues = true;
|
||||||
|
for (ValueDisplayDescriptor descriptor : valueDescriptors) {
|
||||||
|
accumulateValues &= (descriptor.valueIndex != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ValueDisplayDescriptor descriptor : valueDescriptors) {
|
||||||
|
try {
|
||||||
|
// get the hashmap for this descriptor
|
||||||
|
HashMap<Integer, TimeSeries> map = mValueDescriptorSeriesMap.get(descriptor);
|
||||||
|
|
||||||
|
// if it's not there yet, we create it.
|
||||||
|
if (map == null) {
|
||||||
|
map = new HashMap<Integer, TimeSeries>();
|
||||||
|
mValueDescriptorSeriesMap.put(descriptor, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the TimeSeries for this pid
|
||||||
|
TimeSeries timeSeries = map.get(event.pid);
|
||||||
|
|
||||||
|
// if it doesn't exist yet, we create it
|
||||||
|
if (timeSeries == null) {
|
||||||
|
// get the series name
|
||||||
|
String seriesFullName = null;
|
||||||
|
String seriesLabel = getSeriesLabel(event, descriptor);
|
||||||
|
|
||||||
|
switch (mValueDescriptorCheck) {
|
||||||
|
case EVENT_CHECK_SAME_TAG:
|
||||||
|
seriesFullName = String.format("%1$s / %2$s", seriesLabel,
|
||||||
|
descriptor.valueName);
|
||||||
|
break;
|
||||||
|
case EVENT_CHECK_SAME_VALUE:
|
||||||
|
seriesFullName = String.format("%1$s", seriesLabel);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
seriesFullName = String.format("%1$s / %2$s: %3$s", seriesLabel,
|
||||||
|
tagMap.get(descriptor.eventTag),
|
||||||
|
descriptor.valueName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the data set for this ValueType
|
||||||
|
TimeSeriesCollection dataset = getValueDataset(
|
||||||
|
logParser.getEventInfoMap().get(event.mTag)[descriptor.valueIndex]
|
||||||
|
.getValueType(),
|
||||||
|
accumulateValues);
|
||||||
|
|
||||||
|
// create the series
|
||||||
|
timeSeries = new TimeSeries(seriesFullName, Millisecond.class);
|
||||||
|
if (mMaximumChartItemAge != -1) {
|
||||||
|
timeSeries.setMaximumItemAge(mMaximumChartItemAge * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataset.addSeries(timeSeries);
|
||||||
|
|
||||||
|
// add it to the map.
|
||||||
|
map.put(event.pid, timeSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the timeSeries.
|
||||||
|
|
||||||
|
// get the value from the event
|
||||||
|
double value = event.getValueAsDouble(descriptor.valueIndex);
|
||||||
|
|
||||||
|
// accumulate the values if needed.
|
||||||
|
if (accumulateValues) {
|
||||||
|
accumulatedValue += value;
|
||||||
|
value = accumulatedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the time
|
||||||
|
if (millisecondTime == null) {
|
||||||
|
msec = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
millisecondTime = new Millisecond(new Date(msec));
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the value to the time series
|
||||||
|
timeSeries.addOrUpdate(millisecondTime, value);
|
||||||
|
} catch (InvalidTypeException e) {
|
||||||
|
// just ignore this descriptor if there's a type mismatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (OccurrenceDisplayDescriptor descriptor : occurrenceDescriptors) {
|
||||||
|
try {
|
||||||
|
// get the hashmap for this descriptor
|
||||||
|
HashMap<Integer, TimeSeries> map = mOcurrenceDescriptorSeriesMap.get(descriptor);
|
||||||
|
|
||||||
|
// if it's not there yet, we create it.
|
||||||
|
if (map == null) {
|
||||||
|
map = new HashMap<Integer, TimeSeries>();
|
||||||
|
mOcurrenceDescriptorSeriesMap.put(descriptor, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the TimeSeries for this pid
|
||||||
|
TimeSeries timeSeries = map.get(event.pid);
|
||||||
|
|
||||||
|
// if it doesn't exist yet, we create it.
|
||||||
|
if (timeSeries == null) {
|
||||||
|
String seriesLabel = getSeriesLabel(event, descriptor);
|
||||||
|
|
||||||
|
String seriesFullName = String.format("[%1$s:%2$s]",
|
||||||
|
tagMap.get(descriptor.eventTag), seriesLabel);
|
||||||
|
|
||||||
|
timeSeries = new TimeSeries(seriesFullName, Millisecond.class);
|
||||||
|
if (mMaximumChartItemAge != -1) {
|
||||||
|
timeSeries.setMaximumItemAge(mMaximumChartItemAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
getOccurrenceDataSet().addSeries(timeSeries);
|
||||||
|
|
||||||
|
map.put(event.pid, timeSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the series
|
||||||
|
|
||||||
|
// get the time
|
||||||
|
if (millisecondTime == null) {
|
||||||
|
msec = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
millisecondTime = new Millisecond(new Date(msec));
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the value to the time series
|
||||||
|
timeSeries.addOrUpdate(millisecondTime, 0); // the value is unused
|
||||||
|
} catch (InvalidTypeException e) {
|
||||||
|
// just ignore this descriptor if there's a type mismatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// go through all the series and remove old values.
|
||||||
|
if (msec != -1 && mMaximumChartItemAge != -1) {
|
||||||
|
Collection<HashMap<Integer, TimeSeries>> pidMapValues =
|
||||||
|
mValueDescriptorSeriesMap.values();
|
||||||
|
|
||||||
|
for (HashMap<Integer, TimeSeries> pidMapValue : pidMapValues) {
|
||||||
|
Collection<TimeSeries> seriesCollection = pidMapValue.values();
|
||||||
|
|
||||||
|
for (TimeSeries timeSeries : seriesCollection) {
|
||||||
|
timeSeries.removeAgedItems(msec, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pidMapValues = mOcurrenceDescriptorSeriesMap.values();
|
||||||
|
for (HashMap<Integer, TimeSeries> pidMapValue : pidMapValues) {
|
||||||
|
Collection<TimeSeries> seriesCollection = pidMapValue.values();
|
||||||
|
|
||||||
|
for (TimeSeries timeSeries : seriesCollection) {
|
||||||
|
timeSeries.removeAgedItems(msec, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link TimeSeriesCollection} for a specific {@link com.android.ddmlib.log.EventValueDescription.ValueType}.
|
||||||
|
* If the data set is not yet created, it is first allocated and set up into the
|
||||||
|
* {@link org.jfree.chart.JFreeChart} object.
|
||||||
|
* @param type the {@link com.android.ddmlib.log.EventValueDescription.ValueType} of the data set.
|
||||||
|
* @param accumulateValues
|
||||||
|
*/
|
||||||
|
private TimeSeriesCollection getValueDataset(EventValueDescription.ValueType type, boolean accumulateValues) {
|
||||||
|
TimeSeriesCollection dataset = mValueTypeDataSetMap.get(type);
|
||||||
|
if (dataset == null) {
|
||||||
|
// create the data set and store it in the map
|
||||||
|
dataset = new TimeSeriesCollection();
|
||||||
|
mValueTypeDataSetMap.put(type, dataset);
|
||||||
|
|
||||||
|
// create the renderer and configure it depending on the ValueType
|
||||||
|
AbstractXYItemRenderer renderer;
|
||||||
|
if (type == EventValueDescription.ValueType.PERCENT && accumulateValues) {
|
||||||
|
renderer = new XYAreaRenderer();
|
||||||
|
} else {
|
||||||
|
XYLineAndShapeRenderer r = new XYLineAndShapeRenderer();
|
||||||
|
r.setBaseShapesVisible(type != EventValueDescription.ValueType.PERCENT);
|
||||||
|
|
||||||
|
renderer = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set both the dataset and the renderer in the plot object.
|
||||||
|
XYPlot xyPlot = mChart.getXYPlot();
|
||||||
|
xyPlot.setDataset(mDataSetCount, dataset);
|
||||||
|
xyPlot.setRenderer(mDataSetCount, renderer);
|
||||||
|
|
||||||
|
// put a new axis label, and configure it.
|
||||||
|
NumberAxis axis = new NumberAxis(type.toString());
|
||||||
|
|
||||||
|
if (type == EventValueDescription.ValueType.PERCENT) {
|
||||||
|
// force percent range to be (0,100) fixed.
|
||||||
|
axis.setAutoRange(false);
|
||||||
|
axis.setRange(0., 100.);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for the index, we ignore the occurrence dataset
|
||||||
|
int count = mDataSetCount;
|
||||||
|
if (mOccurrenceDataSet != null) {
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
xyPlot.setRangeAxis(count, axis);
|
||||||
|
if ((count % 2) == 0) {
|
||||||
|
xyPlot.setRangeAxisLocation(count, AxisLocation.BOTTOM_OR_LEFT);
|
||||||
|
} else {
|
||||||
|
xyPlot.setRangeAxisLocation(count, AxisLocation.TOP_OR_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we link the dataset and the axis
|
||||||
|
xyPlot.mapDatasetToRangeAxis(mDataSetCount, count);
|
||||||
|
|
||||||
|
mDataSetCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the series label for this event. This only contains the pid information.
|
||||||
|
* @param event the {@link EventContainer}
|
||||||
|
* @param descriptor the {@link OccurrenceDisplayDescriptor}
|
||||||
|
* @return the series label.
|
||||||
|
* @throws InvalidTypeException
|
||||||
|
*/
|
||||||
|
private String getSeriesLabel(EventContainer event, OccurrenceDisplayDescriptor descriptor)
|
||||||
|
throws InvalidTypeException {
|
||||||
|
if (descriptor.seriesValueIndex != -1) {
|
||||||
|
if (descriptor.includePid == false) {
|
||||||
|
return event.getValueAsString(descriptor.seriesValueIndex);
|
||||||
|
} else {
|
||||||
|
return String.format("%1$s (%2$d)",
|
||||||
|
event.getValueAsString(descriptor.seriesValueIndex), event.pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Integer.toString(event.pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link TimeSeriesCollection} for the occurrence display. If the data set is not
|
||||||
|
* yet created, it is first allocated and set up into the {@link org.jfree.chart.JFreeChart} object.
|
||||||
|
*/
|
||||||
|
private TimeSeriesCollection getOccurrenceDataSet() {
|
||||||
|
if (mOccurrenceDataSet == null) {
|
||||||
|
mOccurrenceDataSet = new TimeSeriesCollection();
|
||||||
|
|
||||||
|
XYPlot xyPlot = mChart.getXYPlot();
|
||||||
|
xyPlot.setDataset(mDataSetCount, mOccurrenceDataSet);
|
||||||
|
|
||||||
|
OccurrenceRenderer renderer = new OccurrenceRenderer();
|
||||||
|
renderer.setBaseShapesVisible(false);
|
||||||
|
xyPlot.setRenderer(mDataSetCount, renderer);
|
||||||
|
|
||||||
|
mDataSetCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mOccurrenceDataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets display type
|
||||||
|
*
|
||||||
|
* @return display type as an integer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
int getDisplayType() {
|
||||||
|
return DISPLAY_TYPE_GRAPH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current {@link EventLogParser} object.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void setNewLogParser(EventLogParser logParser) {
|
||||||
|
if (mChart != null) {
|
||||||
|
mChart.setTitle(getChartTitle(logParser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a meaningful chart title based on the value of {@link #mValueDescriptorCheck}.
|
||||||
|
*
|
||||||
|
* @param logParser the logParser.
|
||||||
|
* @return the chart title.
|
||||||
|
*/
|
||||||
|
private String getChartTitle(EventLogParser logParser) {
|
||||||
|
if (mValueDescriptors.size() > 0) {
|
||||||
|
String chartDesc = null;
|
||||||
|
switch (mValueDescriptorCheck) {
|
||||||
|
case EVENT_CHECK_SAME_TAG:
|
||||||
|
if (logParser != null) {
|
||||||
|
chartDesc = logParser.getTagMap().get(mValueDescriptors.get(0).eventTag);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_CHECK_SAME_VALUE:
|
||||||
|
if (logParser != null) {
|
||||||
|
chartDesc = String.format("%1$s / %2$s",
|
||||||
|
logParser.getTagMap().get(mValueDescriptors.get(0).eventTag),
|
||||||
|
mValueDescriptors.get(0).valueName);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chartDesc != null) {
|
||||||
|
return String.format("%1$s - %2$s", mName, chartDesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,379 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.ddmuilib.log.event;
|
||||||
|
|
||||||
|
import com.android.ddmlib.log.EventContainer;
|
||||||
|
import com.android.ddmlib.log.EventLogParser;
|
||||||
|
import com.android.ddmlib.log.EventValueDescription;
|
||||||
|
import com.android.ddmlib.log.InvalidTypeException;
|
||||||
|
import com.android.ddmuilib.DdmUiPreferences;
|
||||||
|
import com.android.ddmuilib.TableHelper;
|
||||||
|
import org.eclipse.jface.preference.IPreferenceStore;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.ControlAdapter;
|
||||||
|
import org.eclipse.swt.events.ControlEvent;
|
||||||
|
import org.eclipse.swt.events.DisposeEvent;
|
||||||
|
import org.eclipse.swt.events.DisposeListener;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
import org.eclipse.swt.widgets.ScrollBar;
|
||||||
|
import org.eclipse.swt.widgets.Table;
|
||||||
|
import org.eclipse.swt.widgets.TableColumn;
|
||||||
|
import org.eclipse.swt.widgets.TableItem;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
public class DisplayLog extends EventDisplay {
|
||||||
|
public DisplayLog(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static String PREFS_COL_DATE = "EventLogPanel.log.Col1"; //$NON-NLS-1$
|
||||||
|
private final static String PREFS_COL_PID = "EventLogPanel.log.Col2"; //$NON-NLS-1$
|
||||||
|
private final static String PREFS_COL_EVENTTAG = "EventLogPanel.log.Col3"; //$NON-NLS-1$
|
||||||
|
private final static String PREFS_COL_VALUENAME = "EventLogPanel.log.Col4"; //$NON-NLS-1$
|
||||||
|
private final static String PREFS_COL_VALUE = "EventLogPanel.log.Col5"; //$NON-NLS-1$
|
||||||
|
private final static String PREFS_COL_TYPE = "EventLogPanel.log.Col6"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the display.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void resetUI() {
|
||||||
|
mLogTable.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds event to the display.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void newEvent(EventContainer event, EventLogParser logParser) {
|
||||||
|
addToLog(event, logParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the UI for the event display.
|
||||||
|
*
|
||||||
|
* @param parent the parent composite.
|
||||||
|
* @param logParser the current log parser.
|
||||||
|
* @return the created control (which may have children).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
Control createComposite(Composite parent, EventLogParser logParser, ILogColumnListener listener) {
|
||||||
|
return createLogUI(parent, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an {@link EventContainer} to the log.
|
||||||
|
*
|
||||||
|
* @param event the event.
|
||||||
|
* @param logParser the log parser.
|
||||||
|
*/
|
||||||
|
private void addToLog(EventContainer event, EventLogParser logParser) {
|
||||||
|
ScrollBar bar = mLogTable.getVerticalBar();
|
||||||
|
boolean scroll = bar.getMaximum() == bar.getSelection() + bar.getThumb();
|
||||||
|
|
||||||
|
// get the date.
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
long msec = (long) event.sec * 1000L;
|
||||||
|
c.setTimeInMillis(msec);
|
||||||
|
|
||||||
|
// convert the time into a string
|
||||||
|
String date = String.format("%1$tF %1$tT", c);
|
||||||
|
|
||||||
|
String eventName = logParser.getTagMap().get(event.mTag);
|
||||||
|
String pidName = Integer.toString(event.pid);
|
||||||
|
|
||||||
|
// get the value description
|
||||||
|
EventValueDescription[] valueDescription = logParser.getEventInfoMap().get(event.mTag);
|
||||||
|
if (valueDescription != null) {
|
||||||
|
for (int i = 0; i < valueDescription.length; i++) {
|
||||||
|
EventValueDescription description = valueDescription[i];
|
||||||
|
try {
|
||||||
|
String value = event.getValueAsString(i);
|
||||||
|
|
||||||
|
logValue(date, pidName, eventName, description.getName(), value,
|
||||||
|
description.getEventValueType(), description.getValueType());
|
||||||
|
} catch (InvalidTypeException e) {
|
||||||
|
logValue(date, pidName, eventName, description.getName(), e.getMessage(),
|
||||||
|
description.getEventValueType(), description.getValueType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll if needed, by showing the last item
|
||||||
|
if (scroll) {
|
||||||
|
int itemCount = mLogTable.getItemCount();
|
||||||
|
if (itemCount > 0) {
|
||||||
|
mLogTable.showItem(mLogTable.getItem(itemCount - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an {@link EventContainer} to the log. Only add the values/occurrences defined by
|
||||||
|
* the list of descriptors. If an event is configured to be displayed by value and occurrence,
|
||||||
|
* only the values are displayed (as they mark an event occurrence anyway).
|
||||||
|
* <p/>This method is only called when at least one of the descriptor list is non empty.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @param logParser
|
||||||
|
* @param valueDescriptors
|
||||||
|
* @param occurrenceDescriptors
|
||||||
|
*/
|
||||||
|
protected void addToLog(EventContainer event, EventLogParser logParser,
|
||||||
|
ArrayList<ValueDisplayDescriptor> valueDescriptors,
|
||||||
|
ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors) {
|
||||||
|
ScrollBar bar = mLogTable.getVerticalBar();
|
||||||
|
boolean scroll = bar.getMaximum() == bar.getSelection() + bar.getThumb();
|
||||||
|
|
||||||
|
// get the date.
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
long msec = (long) event.sec * 1000L;
|
||||||
|
c.setTimeInMillis(msec);
|
||||||
|
|
||||||
|
// convert the time into a string
|
||||||
|
String date = String.format("%1$tF %1$tT", c);
|
||||||
|
|
||||||
|
String eventName = logParser.getTagMap().get(event.mTag);
|
||||||
|
String pidName = Integer.toString(event.pid);
|
||||||
|
|
||||||
|
if (valueDescriptors.size() > 0) {
|
||||||
|
for (ValueDisplayDescriptor descriptor : valueDescriptors) {
|
||||||
|
logDescriptor(event, descriptor, date, pidName, eventName, logParser);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we display the event. Since the StringBuilder contains the header (date, event name,
|
||||||
|
// pid) at this point, there isn't anything else to display.
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll if needed, by showing the last item
|
||||||
|
if (scroll) {
|
||||||
|
int itemCount = mLogTable.getItemCount();
|
||||||
|
if (itemCount > 0) {
|
||||||
|
mLogTable.showItem(mLogTable.getItem(itemCount - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a value in the ui.
|
||||||
|
*
|
||||||
|
* @param date
|
||||||
|
* @param pid
|
||||||
|
* @param event
|
||||||
|
* @param valueName
|
||||||
|
* @param value
|
||||||
|
* @param eventValueType
|
||||||
|
* @param valueType
|
||||||
|
*/
|
||||||
|
private void logValue(String date, String pid, String event, String valueName,
|
||||||
|
String value, EventContainer.EventValueType eventValueType, EventValueDescription.ValueType valueType) {
|
||||||
|
|
||||||
|
TableItem item = new TableItem(mLogTable, SWT.NONE);
|
||||||
|
item.setText(0, date);
|
||||||
|
item.setText(1, pid);
|
||||||
|
item.setText(2, event);
|
||||||
|
item.setText(3, valueName);
|
||||||
|
item.setText(4, value);
|
||||||
|
|
||||||
|
String type;
|
||||||
|
if (valueType != EventValueDescription.ValueType.NOT_APPLICABLE) {
|
||||||
|
type = String.format("%1$s, %2$s", eventValueType.toString(), valueType.toString());
|
||||||
|
} else {
|
||||||
|
type = eventValueType.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
item.setText(5, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a value from an {@link EventContainer} as defined by the {@link ValueDisplayDescriptor}.
|
||||||
|
*
|
||||||
|
* @param event the EventContainer
|
||||||
|
* @param descriptor the ValueDisplayDescriptor defining which value to display.
|
||||||
|
* @param date the date of the event in a string.
|
||||||
|
* @param pidName
|
||||||
|
* @param eventName
|
||||||
|
* @param logParser
|
||||||
|
*/
|
||||||
|
private void logDescriptor(EventContainer event, ValueDisplayDescriptor descriptor,
|
||||||
|
String date, String pidName, String eventName, EventLogParser logParser) {
|
||||||
|
|
||||||
|
String value;
|
||||||
|
try {
|
||||||
|
value = event.getValueAsString(descriptor.valueIndex);
|
||||||
|
} catch (InvalidTypeException e) {
|
||||||
|
value = e.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventValueDescription[] values = logParser.getEventInfoMap().get(event.mTag);
|
||||||
|
|
||||||
|
EventValueDescription valueDescription = values[descriptor.valueIndex];
|
||||||
|
|
||||||
|
logValue(date, pidName, eventName, descriptor.valueName, value,
|
||||||
|
valueDescription.getEventValueType(), valueDescription.getValueType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the UI for a log display.
|
||||||
|
*
|
||||||
|
* @param parent the parent {@link Composite}
|
||||||
|
* @param listener the {@link ILogColumnListener} to notify on column resize events.
|
||||||
|
* @return the top Composite of the UI.
|
||||||
|
*/
|
||||||
|
private Control createLogUI(Composite parent, final ILogColumnListener listener) {
|
||||||
|
Composite mainComp = new Composite(parent, SWT.NONE);
|
||||||
|
GridLayout gl;
|
||||||
|
mainComp.setLayout(gl = new GridLayout(1, false));
|
||||||
|
gl.marginHeight = gl.marginWidth = 0;
|
||||||
|
mainComp.addDisposeListener(new DisposeListener() {
|
||||||
|
public void widgetDisposed(DisposeEvent e) {
|
||||||
|
mLogTable = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Label l = new Label(mainComp, SWT.CENTER);
|
||||||
|
l.setText(mName);
|
||||||
|
l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
|
||||||
|
mLogTable = new Table(mainComp, SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL |
|
||||||
|
SWT.BORDER);
|
||||||
|
mLogTable.setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||||
|
|
||||||
|
IPreferenceStore store = DdmUiPreferences.getStore();
|
||||||
|
|
||||||
|
TableColumn col = TableHelper.createTableColumn(
|
||||||
|
mLogTable, "Time",
|
||||||
|
SWT.LEFT, "0000-00-00 00:00:00", PREFS_COL_DATE, store); //$NON-NLS-1$
|
||||||
|
col.addControlListener(new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Object source = e.getSource();
|
||||||
|
if (source instanceof TableColumn) {
|
||||||
|
listener.columnResized(0, (TableColumn) source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
col = TableHelper.createTableColumn(
|
||||||
|
mLogTable, "pid",
|
||||||
|
SWT.LEFT, "0000", PREFS_COL_PID, store); //$NON-NLS-1$
|
||||||
|
col.addControlListener(new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Object source = e.getSource();
|
||||||
|
if (source instanceof TableColumn) {
|
||||||
|
listener.columnResized(1, (TableColumn) source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
col = TableHelper.createTableColumn(
|
||||||
|
mLogTable, "Event",
|
||||||
|
SWT.LEFT, "abcdejghijklmno", PREFS_COL_EVENTTAG, store); //$NON-NLS-1$
|
||||||
|
col.addControlListener(new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Object source = e.getSource();
|
||||||
|
if (source instanceof TableColumn) {
|
||||||
|
listener.columnResized(2, (TableColumn) source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
col = TableHelper.createTableColumn(
|
||||||
|
mLogTable, "Name",
|
||||||
|
SWT.LEFT, "Process Name", PREFS_COL_VALUENAME, store); //$NON-NLS-1$
|
||||||
|
col.addControlListener(new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Object source = e.getSource();
|
||||||
|
if (source instanceof TableColumn) {
|
||||||
|
listener.columnResized(3, (TableColumn) source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
col = TableHelper.createTableColumn(
|
||||||
|
mLogTable, "Value",
|
||||||
|
SWT.LEFT, "0000000", PREFS_COL_VALUE, store); //$NON-NLS-1$
|
||||||
|
col.addControlListener(new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Object source = e.getSource();
|
||||||
|
if (source instanceof TableColumn) {
|
||||||
|
listener.columnResized(4, (TableColumn) source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
col = TableHelper.createTableColumn(
|
||||||
|
mLogTable, "Type",
|
||||||
|
SWT.LEFT, "long, seconds", PREFS_COL_TYPE, store); //$NON-NLS-1$
|
||||||
|
col.addControlListener(new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Object source = e.getSource();
|
||||||
|
if (source instanceof TableColumn) {
|
||||||
|
listener.columnResized(5, (TableColumn) source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mLogTable.setHeaderVisible(true);
|
||||||
|
mLogTable.setLinesVisible(true);
|
||||||
|
|
||||||
|
return mainComp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes the <code>index</code>-th column of the log {@link Table} (if applicable).
|
||||||
|
* <p/>
|
||||||
|
* This does nothing if the <code>Table</code> object is <code>null</code> (because the display
|
||||||
|
* type does not use a column) or if the <code>index</code>-th column is in fact the originating
|
||||||
|
* column passed as argument.
|
||||||
|
*
|
||||||
|
* @param index the index of the column to resize
|
||||||
|
* @param sourceColumn the original column that was resize, and on which we need to sync the
|
||||||
|
* index-th column width.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void resizeColumn(int index, TableColumn sourceColumn) {
|
||||||
|
if (mLogTable != null) {
|
||||||
|
TableColumn col = mLogTable.getColumn(index);
|
||||||
|
if (col != sourceColumn) {
|
||||||
|
col.setWidth(sourceColumn.getWidth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets display type
|
||||||
|
*
|
||||||
|
* @return display type as an integer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
int getDisplayType() {
|
||||||
|
return DISPLAY_TYPE_LOG_ALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.ddmuilib.log.event;
|
||||||
|
|
||||||
|
import com.android.ddmlib.log.EventContainer;
|
||||||
|
import com.android.ddmlib.log.EventLogParser;
|
||||||
|
import com.android.ddmlib.log.InvalidTypeException;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
import org.jfree.chart.labels.CustomXYToolTipGenerator;
|
||||||
|
import org.jfree.chart.plot.XYPlot;
|
||||||
|
import org.jfree.chart.renderer.xy.XYBarRenderer;
|
||||||
|
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||||
|
import org.jfree.data.time.FixedMillisecond;
|
||||||
|
import org.jfree.data.time.SimpleTimePeriod;
|
||||||
|
import org.jfree.data.time.TimePeriodValues;
|
||||||
|
import org.jfree.data.time.TimePeriodValuesCollection;
|
||||||
|
import org.jfree.data.time.TimeSeries;
|
||||||
|
import org.jfree.data.time.TimeSeriesCollection;
|
||||||
|
import org.jfree.util.ShapeUtilities;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class DisplaySync extends EventDisplay {
|
||||||
|
|
||||||
|
// Information to graph for each authority
|
||||||
|
private TimePeriodValues mDatasetsSync[];
|
||||||
|
private List<String> mTooltipsSync[];
|
||||||
|
private CustomXYToolTipGenerator mTooltipGenerators[];
|
||||||
|
private TimeSeries mDatasetsSyncTickle[];
|
||||||
|
|
||||||
|
// Dataset of error events to graph
|
||||||
|
private TimeSeries mDatasetError;
|
||||||
|
|
||||||
|
// State information while processing the event stream
|
||||||
|
private int mLastState; // 0 if event started, 1 if event stopped
|
||||||
|
private long mLastStartTime; // ms
|
||||||
|
private long mLastStopTime; //ms
|
||||||
|
private String mLastDetails;
|
||||||
|
private int mLastEvent; // server, poll, etc
|
||||||
|
|
||||||
|
public DisplaySync(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the display.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void resetUI() {
|
||||||
|
initSyncDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the UI for the event display.
|
||||||
|
* @param parent the parent composite.
|
||||||
|
* @param logParser the current log parser.
|
||||||
|
* @return the created control (which may have children).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Control createComposite(final Composite parent, EventLogParser logParser,
|
||||||
|
final ILogColumnListener listener) {
|
||||||
|
Control composite = createCompositeChart(parent, logParser, "Sync Status");
|
||||||
|
initSyncDisplay();
|
||||||
|
return composite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Plot and series data for the sync display.
|
||||||
|
*/
|
||||||
|
void initSyncDisplay() {
|
||||||
|
XYPlot xyPlot = mChart.getXYPlot();
|
||||||
|
|
||||||
|
XYBarRenderer br = new XYBarRenderer();
|
||||||
|
mDatasetsSync = new TimePeriodValues[NUM_AUTHS];
|
||||||
|
mTooltipsSync = new List[NUM_AUTHS];
|
||||||
|
mTooltipGenerators = new CustomXYToolTipGenerator[NUM_AUTHS];
|
||||||
|
mLastDetails = "";
|
||||||
|
|
||||||
|
TimePeriodValuesCollection tpvc = new TimePeriodValuesCollection();
|
||||||
|
xyPlot.setDataset(tpvc);
|
||||||
|
xyPlot.setRenderer(0, br);
|
||||||
|
|
||||||
|
XYLineAndShapeRenderer ls = new XYLineAndShapeRenderer();
|
||||||
|
ls.setBaseLinesVisible(false);
|
||||||
|
mDatasetsSyncTickle = new TimeSeries[NUM_AUTHS];
|
||||||
|
TimeSeriesCollection tsc = new TimeSeriesCollection();
|
||||||
|
xyPlot.setDataset(1, tsc);
|
||||||
|
xyPlot.setRenderer(1, ls);
|
||||||
|
|
||||||
|
mDatasetError = new TimeSeries("Errors", FixedMillisecond.class);
|
||||||
|
xyPlot.setDataset(2, new TimeSeriesCollection(mDatasetError));
|
||||||
|
XYLineAndShapeRenderer errls = new XYLineAndShapeRenderer();
|
||||||
|
errls.setBaseLinesVisible(false);
|
||||||
|
errls.setSeriesPaint(0, Color.RED);
|
||||||
|
xyPlot.setRenderer(2, errls);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_AUTHS; i++) {
|
||||||
|
br.setSeriesPaint(i, AUTH_COLORS[i]);
|
||||||
|
ls.setSeriesPaint(i, AUTH_COLORS[i]);
|
||||||
|
mDatasetsSync[i] = new TimePeriodValues(AUTH_NAMES[i]);
|
||||||
|
tpvc.addSeries(mDatasetsSync[i]);
|
||||||
|
mTooltipsSync[i] = new ArrayList<String>();
|
||||||
|
mTooltipGenerators[i] = new CustomXYToolTipGenerator();
|
||||||
|
br.setSeriesToolTipGenerator(i, mTooltipGenerators[i]);
|
||||||
|
mTooltipGenerators[i].addToolTipSeries(mTooltipsSync[i]);
|
||||||
|
|
||||||
|
mDatasetsSyncTickle[i] = new TimeSeries(AUTH_NAMES[i] + " tickle", FixedMillisecond.class);
|
||||||
|
tsc.addSeries(mDatasetsSyncTickle[i]);
|
||||||
|
ls.setSeriesShape(i, ShapeUtilities.createUpTriangle(2.5f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the display with a new event. This is the main entry point for
|
||||||
|
* each event. This method has the logic to tie together the start event,
|
||||||
|
* stop event, and details event into one graph item. Note that the details
|
||||||
|
* can happen before or after the stop event.
|
||||||
|
* @param event The event
|
||||||
|
* @param logParser the log parser (unused)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void newEvent(EventContainer event, EventLogParser logParser) {
|
||||||
|
try {
|
||||||
|
if (event.mTag == EVENT_SYNC) {
|
||||||
|
int state = Integer.parseInt(event.getValueAsString(1));
|
||||||
|
if (state == 0) { // start
|
||||||
|
mLastStartTime = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
mLastState = 0;
|
||||||
|
mLastEvent = Integer.parseInt(event.getValueAsString(2));
|
||||||
|
mLastDetails = "";
|
||||||
|
} else if (state == 1) { // stop
|
||||||
|
if (mLastState == 0) {
|
||||||
|
mLastStopTime = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
if (mLastStartTime == 0) {
|
||||||
|
// Log starts with a stop event
|
||||||
|
mLastStartTime = mLastStopTime;
|
||||||
|
}
|
||||||
|
addEvent(event);
|
||||||
|
mLastState = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event.mTag == EVENT_TICKLE) {
|
||||||
|
int auth = getAuth(event.getValueAsString(0));
|
||||||
|
if (auth >= 0) {
|
||||||
|
long msec = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
mDatasetsSyncTickle[auth].addOrUpdate(new FixedMillisecond(msec), -1);
|
||||||
|
}
|
||||||
|
} else if (event.mTag == EVENT_SYNC_DETAILS) {
|
||||||
|
int auth = getAuth(event.getValueAsString(0));
|
||||||
|
mLastDetails = event.getValueAsString(3);
|
||||||
|
if (mLastState != 0) { // Not inside event
|
||||||
|
long updateTime = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
if (updateTime - mLastStopTime <= 250) {
|
||||||
|
// Got details within 250ms after event, so delete and re-insert
|
||||||
|
// Details later than 250ms (arbitrary) are discarded as probably
|
||||||
|
// unrelated.
|
||||||
|
int lastItem = mDatasetsSync[auth].getItemCount();
|
||||||
|
mDatasetsSync[auth].delete(lastItem-1, lastItem-1);
|
||||||
|
mTooltipsSync[auth].remove(lastItem-1);
|
||||||
|
addEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidTypeException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the height for an event.
|
||||||
|
* Height is somewhat arbitrarily the count of "things" that happened
|
||||||
|
* during the sync.
|
||||||
|
* When network traffic measurements are available, code should be modified
|
||||||
|
* to use that instead.
|
||||||
|
* @param details The details string associated with the event
|
||||||
|
* @return The height in arbirary units (0-100)
|
||||||
|
*/
|
||||||
|
private int getHeightFromDetails(String details) {
|
||||||
|
if (details == null) {
|
||||||
|
return 1; // Arbitrary
|
||||||
|
}
|
||||||
|
int total = 0;
|
||||||
|
String parts[] = details.split("[a-zA-Z]");
|
||||||
|
for (String part : parts) {
|
||||||
|
if ("".equals(part)) continue;
|
||||||
|
total += Integer.parseInt(part);
|
||||||
|
}
|
||||||
|
if (total == 0) {
|
||||||
|
total = 1;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the tooltips text for an event.
|
||||||
|
* This method decodes the cryptic details string.
|
||||||
|
* @param auth The authority associated with the event
|
||||||
|
* @param details The details string
|
||||||
|
* @param eventSource server, poll, etc.
|
||||||
|
* @return The text to display in the tooltips
|
||||||
|
*/
|
||||||
|
private String getTextFromDetails(int auth, String details, int eventSource) {
|
||||||
|
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
sb.append(AUTH_NAMES[auth]).append(": \n");
|
||||||
|
|
||||||
|
Scanner scanner = new Scanner(details);
|
||||||
|
Pattern charPat = Pattern.compile("[a-zA-Z]");
|
||||||
|
Pattern numPat = Pattern.compile("[0-9]+");
|
||||||
|
while (scanner.hasNext()) {
|
||||||
|
String key = scanner.findInLine(charPat);
|
||||||
|
int val = Integer.parseInt(scanner.findInLine(numPat));
|
||||||
|
if (auth == GMAIL && "M".equals(key)) {
|
||||||
|
sb.append("messages from server: ").append(val).append("\n");
|
||||||
|
} else if (auth == GMAIL && "L".equals(key)) {
|
||||||
|
sb.append("labels from server: ").append(val).append("\n");
|
||||||
|
} else if (auth == GMAIL && "C".equals(key)) {
|
||||||
|
sb.append("check conversation requests from server: ").append(val).append("\n");
|
||||||
|
} else if (auth == GMAIL && "A".equals(key)) {
|
||||||
|
sb.append("attachments from server: ").append(val).append("\n");
|
||||||
|
} else if (auth == GMAIL && "U".equals(key)) {
|
||||||
|
sb.append("op updates from server: ").append(val).append("\n");
|
||||||
|
} else if (auth == GMAIL && "u".equals(key)) {
|
||||||
|
sb.append("op updates to server: ").append(val).append("\n");
|
||||||
|
} else if (auth == GMAIL && "S".equals(key)) {
|
||||||
|
sb.append("send/receive cycles: ").append(val).append("\n");
|
||||||
|
} else if ("Q".equals(key)) {
|
||||||
|
sb.append("queries to server: ").append(val).append("\n");
|
||||||
|
} else if ("E".equals(key)) {
|
||||||
|
sb.append("entries from server: ").append(val).append("\n");
|
||||||
|
} else if ("u".equals(key)) {
|
||||||
|
sb.append("updates from client: ").append(val).append("\n");
|
||||||
|
} else if ("i".equals(key)) {
|
||||||
|
sb.append("inserts from client: ").append(val).append("\n");
|
||||||
|
} else if ("d".equals(key)) {
|
||||||
|
sb.append("deletes from client: ").append(val).append("\n");
|
||||||
|
} else if ("f".equals(key)) {
|
||||||
|
sb.append("full sync requested\n");
|
||||||
|
} else if ("r".equals(key)) {
|
||||||
|
sb.append("partial sync unavailable\n");
|
||||||
|
} else if ("X".equals(key)) {
|
||||||
|
sb.append("hard error\n");
|
||||||
|
} else if ("e".equals(key)) {
|
||||||
|
sb.append("number of parse exceptions: ").append(val).append("\n");
|
||||||
|
} else if ("c".equals(key)) {
|
||||||
|
sb.append("number of conflicts: ").append(val).append("\n");
|
||||||
|
} else if ("a".equals(key)) {
|
||||||
|
sb.append("number of auth exceptions: ").append(val).append("\n");
|
||||||
|
} else if ("D".equals(key)) {
|
||||||
|
sb.append("too many deletions\n");
|
||||||
|
} else if ("R".equals(key)) {
|
||||||
|
sb.append("too many retries: ").append(val).append("\n");
|
||||||
|
} else if ("b".equals(key)) {
|
||||||
|
sb.append("database error\n");
|
||||||
|
} else if ("x".equals(key)) {
|
||||||
|
sb.append("soft error\n");
|
||||||
|
} else if ("l".equals(key)) {
|
||||||
|
sb.append("sync already in progress\n");
|
||||||
|
} else if ("I".equals(key)) {
|
||||||
|
sb.append("io exception\n");
|
||||||
|
} else if (auth == CONTACTS && "p".equals(key)) {
|
||||||
|
sb.append("photos uploaded from client: ").append(val).append("\n");
|
||||||
|
} else if (auth == CONTACTS && "P".equals(key)) {
|
||||||
|
sb.append("photos downloaded from server: ").append(val).append("\n");
|
||||||
|
} else if (auth == CALENDAR && "F".equals(key)) {
|
||||||
|
sb.append("server refresh\n");
|
||||||
|
} else if (auth == CALENDAR && "s".equals(key)) {
|
||||||
|
sb.append("server diffs fetched\n");
|
||||||
|
} else {
|
||||||
|
sb.append(key).append("=").append(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eventSource == 0) {
|
||||||
|
sb.append("(server)");
|
||||||
|
} else if (eventSource == 1) {
|
||||||
|
sb.append("(local)");
|
||||||
|
} else if (eventSource == 2) {
|
||||||
|
sb.append("(poll)");
|
||||||
|
} else if (eventSource == 3) {
|
||||||
|
sb.append("(user)");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to add an event to the data series.
|
||||||
|
* Also updates error series if appropriate (x or X in details).
|
||||||
|
* @param event The event
|
||||||
|
*/
|
||||||
|
private void addEvent(EventContainer event) {
|
||||||
|
try {
|
||||||
|
int auth = getAuth(event.getValueAsString(0));
|
||||||
|
double height = getHeightFromDetails(mLastDetails);
|
||||||
|
height = height / (mLastStopTime - mLastStartTime + 1) * 10000;
|
||||||
|
if (height > 30) {
|
||||||
|
height = 30;
|
||||||
|
}
|
||||||
|
mDatasetsSync[auth].add(new SimpleTimePeriod(mLastStartTime, mLastStopTime), height);
|
||||||
|
mTooltipsSync[auth].add(getTextFromDetails(auth, mLastDetails,
|
||||||
|
mLastEvent));
|
||||||
|
mTooltipGenerators[auth].addToolTipSeries(mTooltipsSync[auth]);
|
||||||
|
if (mLastDetails.indexOf('x') >= 0 || mLastDetails.indexOf('X') >= 0) {
|
||||||
|
long msec = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
mDatasetError.addOrUpdate(new FixedMillisecond(msec), -1);
|
||||||
|
}
|
||||||
|
} catch (InvalidTypeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets display type
|
||||||
|
*
|
||||||
|
* @return display type as an integer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
int getDisplayType() {
|
||||||
|
return DISPLAY_TYPE_SYNC;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.ddmuilib.log.event;
|
||||||
|
|
||||||
|
import com.android.ddmlib.log.EventContainer;
|
||||||
|
import com.android.ddmlib.log.EventLogParser;
|
||||||
|
import com.android.ddmlib.log.InvalidTypeException;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
import org.jfree.chart.plot.XYPlot;
|
||||||
|
import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
|
||||||
|
import org.jfree.chart.renderer.xy.XYBarRenderer;
|
||||||
|
import org.jfree.data.time.RegularTimePeriod;
|
||||||
|
import org.jfree.data.time.SimpleTimePeriod;
|
||||||
|
import org.jfree.data.time.TimePeriodValues;
|
||||||
|
import org.jfree.data.time.TimePeriodValuesCollection;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
public class DisplaySyncHistogram extends EventDisplay {
|
||||||
|
|
||||||
|
|
||||||
|
// State information while processing the event stream
|
||||||
|
protected int mLastState; // 0 if event started, 1 if event stopped
|
||||||
|
protected long mLastStartTime; // ms
|
||||||
|
protected long mLastStopTime; //ms
|
||||||
|
protected String mLastDetails;
|
||||||
|
protected int mLastEvent; // server, poll, etc
|
||||||
|
|
||||||
|
public DisplaySyncHistogram(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the display.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void resetUI() {
|
||||||
|
initSyncHistogramDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the UI for the event display.
|
||||||
|
* @param parent the parent composite.
|
||||||
|
* @param logParser the current log parser.
|
||||||
|
* @return the created control (which may have children).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Control createComposite(final Composite parent, EventLogParser logParser,
|
||||||
|
final ILogColumnListener listener) {
|
||||||
|
Control composite = createCompositeChart(parent, logParser, "Sync Histogram");
|
||||||
|
initSyncHistogramDisplay();
|
||||||
|
return composite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Information to graph for each authority
|
||||||
|
private TimePeriodValues mDatasetsSyncHist[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the display.
|
||||||
|
*/
|
||||||
|
private void initSyncHistogramDisplay() {
|
||||||
|
XYPlot xyPlot = mChart.getXYPlot();
|
||||||
|
|
||||||
|
AbstractXYItemRenderer br = new XYBarRenderer();
|
||||||
|
mDatasetsSyncHist = new TimePeriodValues[NUM_AUTHS+1];
|
||||||
|
mLastDetails = "";
|
||||||
|
mTimePeriodMap = new HashMap[NUM_AUTHS + 1];
|
||||||
|
|
||||||
|
TimePeriodValuesCollection tpvc = new TimePeriodValuesCollection();
|
||||||
|
xyPlot.setDataset(tpvc);
|
||||||
|
xyPlot.setRenderer(br);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_AUTHS + 1; i++) {
|
||||||
|
br.setSeriesPaint(i, AUTH_COLORS[i]);
|
||||||
|
mDatasetsSyncHist[i] = new TimePeriodValues(AUTH_NAMES[i]);
|
||||||
|
tpvc.addSeries(mDatasetsSyncHist[i]);
|
||||||
|
mTimePeriodMap[i] = new HashMap<SimpleTimePeriod, Integer>();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the display with a new event. This is the main entry point for
|
||||||
|
* each event. This method has the logic to tie together the start event,
|
||||||
|
* stop event, and details event into one graph item. Note that the details
|
||||||
|
* can happen before or after the stop event.
|
||||||
|
* @param event The event
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void newEvent(EventContainer event, EventLogParser logParser) {
|
||||||
|
try {
|
||||||
|
if (event.mTag == EVENT_SYNC) {
|
||||||
|
int state = Integer.parseInt(event.getValueAsString(1));
|
||||||
|
if (state == 0) { // start
|
||||||
|
mLastStartTime = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
mLastState = 0;
|
||||||
|
mLastEvent = Integer.parseInt(event.getValueAsString(2));
|
||||||
|
mLastDetails = "";
|
||||||
|
} else if (state == 1) { // stop
|
||||||
|
if (mLastState == 0) {
|
||||||
|
mLastStopTime = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
if (mLastStartTime == 0) {
|
||||||
|
// Log starts with a stop event
|
||||||
|
mLastStartTime = mLastStopTime;
|
||||||
|
}
|
||||||
|
int auth = getAuth(event.getValueAsString(0));
|
||||||
|
if (mLastDetails.indexOf('x') >= 0 || mLastDetails.indexOf('X') >= 0) {
|
||||||
|
auth = ERRORS;
|
||||||
|
}
|
||||||
|
double delta = (mLastStopTime - mLastStartTime) * 100. / 1000 / 3600; // Percent of hour
|
||||||
|
addHistEvent(event, auth, delta);
|
||||||
|
mLastState = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event.mTag == EVENT_SYNC_DETAILS) {
|
||||||
|
int auth = getAuth(event.getValueAsString(0));
|
||||||
|
mLastDetails = event.getValueAsString(3);
|
||||||
|
if (mLastState != 0) { // Not inside event
|
||||||
|
long updateTime = (long)event.sec * 1000L + (event.nsec / 1000000L);
|
||||||
|
if (updateTime - mLastStopTime <= 250) {
|
||||||
|
// Got details within 250ms after event, so delete and re-insert
|
||||||
|
// Details later than 250ms (arbitrary) are discarded as probably
|
||||||
|
// unrelated.
|
||||||
|
//int lastItem = mDatasetsSync[auth].getItemCount();
|
||||||
|
//addHistEvent(event);
|
||||||
|
if (mLastDetails.indexOf('x') >= 0 || mLastDetails.indexOf('X') >= 0) {
|
||||||
|
// Item turns out to be in error, so transfer time from old auth to error.
|
||||||
|
|
||||||
|
double delta = (mLastStopTime - mLastStartTime) * 100. / 1000 / 3600; // Percent of hour
|
||||||
|
addHistEvent(event, auth, -delta);
|
||||||
|
addHistEvent(event, ERRORS, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidTypeException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to add an event to the data series.
|
||||||
|
* Also updates error series if appropriate (x or X in details).
|
||||||
|
* @param event The event
|
||||||
|
* @param auth
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
private void addHistEvent(EventContainer event, int auth, double value) {
|
||||||
|
SimpleTimePeriod hour = getTimePeriod(mLastStopTime, mHistWidth);
|
||||||
|
|
||||||
|
// Loop over all datasets to do the stacking.
|
||||||
|
for (int i = auth; i <= ERRORS; i++) {
|
||||||
|
addToPeriod(mDatasetsSyncHist, i, hour, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<SimpleTimePeriod, Integer> mTimePeriodMap[];
|
||||||
|
|
||||||
|
private void addToPeriod(TimePeriodValues tpv[], int auth, SimpleTimePeriod period, double value) {
|
||||||
|
int index;
|
||||||
|
if (mTimePeriodMap[auth].containsKey(period)) {
|
||||||
|
index = mTimePeriodMap[auth].get(period);
|
||||||
|
double oldValue = tpv[auth].getValue(index).doubleValue();
|
||||||
|
tpv[auth].update(index, oldValue + value);
|
||||||
|
} else {
|
||||||
|
index = tpv[auth].getItemCount();
|
||||||
|
mTimePeriodMap[auth].put(period, index);
|
||||||
|
tpv[auth].add(period, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a multiple-hour time period for the histogram.
|
||||||
|
* @param time Time in milliseconds.
|
||||||
|
* @param numHoursWide: should divide into a day.
|
||||||
|
* @return SimpleTimePeriod covering the number of hours and containing time.
|
||||||
|
*/
|
||||||
|
private SimpleTimePeriod getTimePeriod(long time, long numHoursWide) {
|
||||||
|
Date date = new Date(time);
|
||||||
|
TimeZone zone = RegularTimePeriod.DEFAULT_TIME_ZONE;
|
||||||
|
Calendar calendar = Calendar.getInstance(zone);
|
||||||
|
calendar.setTime(date);
|
||||||
|
long hoursOfYear = calendar.get(Calendar.HOUR_OF_DAY) + calendar.get(Calendar.DAY_OF_YEAR) * 24;
|
||||||
|
int year = calendar.get(Calendar.YEAR);
|
||||||
|
hoursOfYear = (hoursOfYear / numHoursWide) * numHoursWide;
|
||||||
|
calendar.clear();
|
||||||
|
calendar.set(year, 0, 1, 0, 0); // Jan 1
|
||||||
|
long start = calendar.getTimeInMillis() + hoursOfYear * 3600 * 1000;
|
||||||
|
return new SimpleTimePeriod(start, start + numHoursWide * 3600 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets display type
|
||||||
|
*
|
||||||
|
* @return display type as an integer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
int getDisplayType() {
|
||||||
|
return DISPLAY_TYPE_SYNC_HIST;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,6 @@ import com.android.ddmuilib.DdmUiPreferences;
|
|||||||
import com.android.ddmuilib.IImageLoader;
|
import com.android.ddmuilib.IImageLoader;
|
||||||
import com.android.ddmuilib.log.event.EventDisplay.OccurrenceDisplayDescriptor;
|
import com.android.ddmuilib.log.event.EventDisplay.OccurrenceDisplayDescriptor;
|
||||||
import com.android.ddmuilib.log.event.EventDisplay.ValueDisplayDescriptor;
|
import com.android.ddmuilib.log.event.EventDisplay.ValueDisplayDescriptor;
|
||||||
|
|
||||||
import org.eclipse.jface.preference.IPreferenceStore;
|
import org.eclipse.jface.preference.IPreferenceStore;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.events.ModifyEvent;
|
import org.eclipse.swt.events.ModifyEvent;
|
||||||
@@ -444,10 +443,13 @@ class EventDisplayOptions extends Dialog {
|
|||||||
@Override
|
@Override
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
EventDisplay eventDisplay = getCurrentEventDisplay();
|
EventDisplay eventDisplay = getCurrentEventDisplay();
|
||||||
if (eventDisplay != null) {
|
if (eventDisplay != null && eventDisplay.getDisplayType() != mDisplayTypeCombo.getSelectionIndex()) {
|
||||||
|
/* Replace the EventDisplay object with a different subclass */
|
||||||
setModified();
|
setModified();
|
||||||
eventDisplay.setDisplayType(mDisplayTypeCombo.getSelectionIndex());
|
String name = eventDisplay.getName();
|
||||||
fillUiWith(eventDisplay);
|
EventDisplay newEventDisplay = EventDisplay.eventDisplayFactory(mDisplayTypeCombo.getSelectionIndex(), name);
|
||||||
|
setCurrentEventDisplay(newEventDisplay);
|
||||||
|
fillUiWith(newEventDisplay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -693,7 +695,7 @@ class EventDisplayOptions extends Dialog {
|
|||||||
|
|
||||||
private void duplicateEventDisplay(ArrayList<EventDisplay> displayList) {
|
private void duplicateEventDisplay(ArrayList<EventDisplay> displayList) {
|
||||||
for (EventDisplay eventDisplay : displayList) {
|
for (EventDisplay eventDisplay : displayList) {
|
||||||
mDisplayList.add(new EventDisplay(eventDisplay));
|
mDisplayList.add(EventDisplay.clone(eventDisplay));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,7 +746,7 @@ class EventDisplayOptions extends Dialog {
|
|||||||
|
|
||||||
String name = String.format("display %1$d", count + 1);
|
String name = String.format("display %1$d", count + 1);
|
||||||
|
|
||||||
EventDisplay eventDisplay = new EventDisplay(name);
|
EventDisplay eventDisplay = EventDisplay.eventDisplayFactory(0 /* type*/, name);
|
||||||
|
|
||||||
mDisplayList.add(eventDisplay);
|
mDisplayList.add(eventDisplay);
|
||||||
mEventDisplayList.add(name);
|
mEventDisplayList.add(name);
|
||||||
@@ -780,6 +782,13 @@ class EventDisplayOptions extends Dialog {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setCurrentEventDisplay(EventDisplay eventDisplay) {
|
||||||
|
int selection = mEventDisplayList.getSelectionIndex();
|
||||||
|
if (selection != -1) {
|
||||||
|
mDisplayList.set(selection, eventDisplay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleEventDisplaySelection() {
|
private void handleEventDisplaySelection() {
|
||||||
EventDisplay eventDisplay = getCurrentEventDisplay();
|
EventDisplay eventDisplay = getCurrentEventDisplay();
|
||||||
if (eventDisplay != null) {
|
if (eventDisplay != null) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class EventLogImporter {
|
|||||||
if (top == null) {
|
if (top == null) {
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
}
|
}
|
||||||
final String tagFile = top + "/data/etc/event-log-tags";
|
final String tagFile = top + "/system/core/logcat/event-log-tags";
|
||||||
BufferedReader tagReader = new BufferedReader(
|
BufferedReader tagReader = new BufferedReader(
|
||||||
new InputStreamReader(new FileInputStream(tagFile)));
|
new InputStreamReader(new FileInputStream(tagFile)));
|
||||||
BufferedReader eventReader = new BufferedReader(
|
BufferedReader eventReader = new BufferedReader(
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
|
|
||||||
// First thing we do is go through the resource delta to not
|
// First thing we do is go through the resource delta to not
|
||||||
// lose it if we have to abort the build for any reason.
|
// lose it if we have to abort the build for any reason.
|
||||||
|
ApkDeltaVisitor dv = null;
|
||||||
if (kind == FULL_BUILD) {
|
if (kind == FULL_BUILD) {
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
||||||
Messages.Start_Full_Apk_Build);
|
Messages.Start_Full_Apk_Build);
|
||||||
@@ -233,22 +234,13 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
mConvertToDex = true;
|
mConvertToDex = true;
|
||||||
mBuildFinalPackage = true;
|
mBuildFinalPackage = true;
|
||||||
} else {
|
} else {
|
||||||
ApkDeltaVisitor dv = new ApkDeltaVisitor(this, sourceList, outputFolder);
|
dv = new ApkDeltaVisitor(this, sourceList, outputFolder);
|
||||||
delta.accept(dv);
|
delta.accept(dv);
|
||||||
|
|
||||||
// save the state
|
// save the state
|
||||||
mPackageResources |= dv.getPackageResources();
|
mPackageResources |= dv.getPackageResources();
|
||||||
mConvertToDex |= dv.getConvertToDex();
|
mConvertToDex |= dv.getConvertToDex();
|
||||||
mBuildFinalPackage |= dv.getMakeFinalPackage();
|
mBuildFinalPackage |= dv.getMakeFinalPackage();
|
||||||
|
|
||||||
if (dv.mXmlError) {
|
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
|
||||||
Messages.Xml_Error);
|
|
||||||
|
|
||||||
// if there was some XML errors, we just return w/o doing
|
|
||||||
// anything since we've put some markers in the files anyway
|
|
||||||
return referencedProjects;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// also go through the delta for all the referenced projects, until we are forced to
|
// also go through the delta for all the referenced projects, until we are forced to
|
||||||
@@ -258,13 +250,13 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
IJavaProject referencedJavaProject = referencedJavaProjects[i];
|
IJavaProject referencedJavaProject = referencedJavaProjects[i];
|
||||||
delta = getDelta(referencedJavaProject.getProject());
|
delta = getDelta(referencedJavaProject.getProject());
|
||||||
if (delta != null) {
|
if (delta != null) {
|
||||||
ReferencedProjectDeltaVisitor dv = new ReferencedProjectDeltaVisitor(
|
ReferencedProjectDeltaVisitor refProjectDv = new ReferencedProjectDeltaVisitor(
|
||||||
referencedJavaProject);
|
referencedJavaProject);
|
||||||
delta.accept(dv);
|
delta.accept(refProjectDv);
|
||||||
|
|
||||||
// save the state
|
// save the state
|
||||||
mConvertToDex |= dv.needDexConvertion();
|
mConvertToDex |= refProjectDv.needDexConvertion();
|
||||||
mBuildFinalPackage |= dv.needMakeFinalPackage();
|
mBuildFinalPackage |= refProjectDv.needMakeFinalPackage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,29 +299,14 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
|
|
||||||
// At this point, we can abort the build if we have to, as we have computed
|
// At this point, we can abort the build if we have to, as we have computed
|
||||||
// our resource delta and stored the result.
|
// our resource delta and stored the result.
|
||||||
|
abortOnBadSetup(javaProject);
|
||||||
|
|
||||||
// check if we have finished loading the SDK.
|
if (dv != null && dv.mXmlError) {
|
||||||
if (AdtPlugin.getDefault().getSdkLoadStatus(javaProject) != LoadStatus.LOADED) {
|
|
||||||
// we exit silently
|
|
||||||
return referencedProjects;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now check the compiler compliance level, not displaying the error
|
|
||||||
// message since this is not the first builder.
|
|
||||||
if (ProjectHelper.checkCompilerCompliance(getProject())
|
|
||||||
!= ProjectHelper.COMPILER_COMPLIANCE_OK) {
|
|
||||||
return referencedProjects;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now check if the project has problem marker already
|
|
||||||
if (ProjectHelper.hasError(project, true)) {
|
|
||||||
// we found a marker with error severity: we abort the build.
|
|
||||||
// Since this is going to happen every time we save a file while
|
|
||||||
// errors are remaining, we do not force the display of the console, which
|
|
||||||
// would, in most cases, show on top of the Problem view (which is more
|
|
||||||
// important in that case).
|
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
||||||
Messages.Project_Has_Errors);
|
Messages.Xml_Error);
|
||||||
|
|
||||||
|
// if there was some XML errors, we just return w/o doing
|
||||||
|
// anything since we've put some markers in the files anyway
|
||||||
return referencedProjects;
|
return referencedProjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,13 @@ package com.android.ide.eclipse.adt.build;
|
|||||||
import com.android.ide.eclipse.adt.AdtConstants;
|
import com.android.ide.eclipse.adt.AdtConstants;
|
||||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||||
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||||
|
import com.android.ide.eclipse.adt.sdk.LoadStatus;
|
||||||
|
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.common.AndroidConstants;
|
import com.android.ide.eclipse.common.AndroidConstants;
|
||||||
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
||||||
import com.android.ide.eclipse.common.project.XmlErrorHandler;
|
import com.android.ide.eclipse.common.project.XmlErrorHandler;
|
||||||
import com.android.ide.eclipse.common.project.XmlErrorHandler.XmlErrorListener;
|
import com.android.ide.eclipse.common.project.XmlErrorHandler.XmlErrorListener;
|
||||||
|
import com.android.sdklib.IAndroidTarget;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IContainer;
|
import org.eclipse.core.resources.IContainer;
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
@@ -34,6 +37,8 @@ import org.eclipse.core.resources.IncrementalProjectBuilder;
|
|||||||
import org.eclipse.core.resources.ResourcesPlugin;
|
import org.eclipse.core.resources.ResourcesPlugin;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
import org.eclipse.core.runtime.IPath;
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
import org.eclipse.jdt.core.IClasspathEntry;
|
import org.eclipse.jdt.core.IClasspathEntry;
|
||||||
import org.eclipse.jdt.core.IJavaProject;
|
import org.eclipse.jdt.core.IJavaProject;
|
||||||
import org.eclipse.jdt.core.JavaCore;
|
import org.eclipse.jdt.core.JavaCore;
|
||||||
@@ -841,4 +846,53 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
|
|||||||
|
|
||||||
return oslibraryList.toArray(new String[oslibraryList.size()]);
|
return oslibraryList.toArray(new String[oslibraryList.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aborts the build if the SDK/project setups are broken. This does not
|
||||||
|
* display any errors.
|
||||||
|
*
|
||||||
|
* @param javaProject The {@link IJavaProject} being compiled.
|
||||||
|
* @throws CoreException
|
||||||
|
*/
|
||||||
|
protected final void abortOnBadSetup(IJavaProject javaProject) throws CoreException {
|
||||||
|
// check if we have finished loading the SDK.
|
||||||
|
if (AdtPlugin.getDefault().getSdkLoadStatus(javaProject) != LoadStatus.LOADED) {
|
||||||
|
// we exit silently
|
||||||
|
stopBuild("SDK is not loaded yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the compiler compliance level.
|
||||||
|
if (ProjectHelper.checkCompilerCompliance(getProject()) !=
|
||||||
|
ProjectHelper.COMPILER_COMPLIANCE_OK) {
|
||||||
|
// we exit silently
|
||||||
|
stopBuild(Messages.Compiler_Compliance_Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the SDK directory has been setup.
|
||||||
|
String osSdkFolder = AdtPlugin.getOsSdkFolder();
|
||||||
|
|
||||||
|
if (osSdkFolder == null || osSdkFolder.length() == 0) {
|
||||||
|
stopBuild(Messages.No_SDK_Setup_Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(javaProject.getProject());
|
||||||
|
if (projectTarget == null) {
|
||||||
|
// no target. error has been output by the container initializer:
|
||||||
|
// exit silently.
|
||||||
|
stopBuild("Project has no target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an exception to cancel the build.
|
||||||
|
*
|
||||||
|
* @param error the error message
|
||||||
|
* @param args the printf-style arguments to the error message.
|
||||||
|
* @throws CoreException
|
||||||
|
*/
|
||||||
|
protected final void stopBuild(String error, Object... args) throws CoreException {
|
||||||
|
throw new CoreException(new Status(IStatus.CANCEL, AdtPlugin.PLUGIN_ID,
|
||||||
|
String.format(error, args)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import com.android.ide.eclipse.adt.AdtConstants;
|
|||||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||||
import com.android.ide.eclipse.adt.project.FixLaunchConfig;
|
import com.android.ide.eclipse.adt.project.FixLaunchConfig;
|
||||||
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||||
import com.android.ide.eclipse.adt.sdk.LoadStatus;
|
|
||||||
import com.android.ide.eclipse.adt.sdk.Sdk;
|
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.common.AndroidConstants;
|
import com.android.ide.eclipse.common.AndroidConstants;
|
||||||
import com.android.ide.eclipse.common.project.AndroidManifestHelper;
|
import com.android.ide.eclipse.common.project.AndroidManifestHelper;
|
||||||
@@ -275,15 +274,6 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
dv.getAidlToRemove());
|
dv.getAidlToRemove());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there was some XML errors, we just return w/o doing
|
|
||||||
// anything since we've put some markers in the files anyway.
|
|
||||||
if (dv.mXmlError) {
|
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
|
||||||
Messages.Xml_Error);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the java package from the visitor
|
// get the java package from the visitor
|
||||||
javaPackage = dv.getManifestPackage();
|
javaPackage = dv.getManifestPackage();
|
||||||
}
|
}
|
||||||
@@ -295,38 +285,18 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
|
|
||||||
// At this point we have stored what needs to be build, so we can
|
// At this point we have stored what needs to be build, so we can
|
||||||
// do some high level test and abort if needed.
|
// do some high level test and abort if needed.
|
||||||
|
abortOnBadSetup(javaProject);
|
||||||
|
|
||||||
// check if we have finished loading the SDK.
|
// if there was some XML errors, we just return w/o doing
|
||||||
if (AdtPlugin.getDefault().getSdkLoadStatus(javaProject) != LoadStatus.LOADED) {
|
// anything since we've put some markers in the files anyway.
|
||||||
// we exit silently
|
if (dv != null && dv.mXmlError) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the compiler compliance level, not displaying the error message
|
|
||||||
// since this is not the first builder.
|
|
||||||
if (ProjectHelper.checkCompilerCompliance(getProject())
|
|
||||||
!= ProjectHelper.COMPILER_COMPLIANCE_OK) {
|
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
||||||
Messages.Compiler_Compliance_Error);
|
Messages.Xml_Error);
|
||||||
return null;
|
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(Messages.Xml_Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the SDK directory has been setup.
|
|
||||||
String osSdkFolder = AdtPlugin.getOsSdkFolder();
|
|
||||||
|
|
||||||
if (osSdkFolder == null || osSdkFolder.length() == 0) {
|
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
|
||||||
Messages.No_SDK_Setup_Error);
|
|
||||||
markProject(AdtConstants.MARKER_ADT, Messages.No_SDK_Setup_Error,
|
|
||||||
IMarker.SEVERITY_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
|
|
||||||
if (projectTarget == null) {
|
|
||||||
// no target. error has been output by the container initializer: exit silently.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the manifest file
|
// get the manifest file
|
||||||
IFile manifest = AndroidManifestHelper.getManifest(project);
|
IFile manifest = AndroidManifestHelper.getManifest(project);
|
||||||
@@ -336,7 +306,9 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
AndroidConstants.FN_ANDROID_MANIFEST);
|
AndroidConstants.FN_ANDROID_MANIFEST);
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
||||||
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
|
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
|
||||||
return null;
|
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// lets check the XML of the manifest first, if that hasn't been done by the
|
// lets check the XML of the manifest first, if that hasn't been done by the
|
||||||
@@ -353,7 +325,9 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
String msg = String.format(Messages.s_Contains_Xml_Error,
|
String msg = String.format(Messages.s_Contains_Xml_Error,
|
||||||
AndroidConstants.FN_ANDROID_MANIFEST);
|
AndroidConstants.FN_ANDROID_MANIFEST);
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
||||||
return null;
|
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the java package from the parser
|
// get the java package from the parser
|
||||||
@@ -366,7 +340,9 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
AndroidConstants.FN_ANDROID_MANIFEST);
|
AndroidConstants.FN_ANDROID_MANIFEST);
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
||||||
msg);
|
msg);
|
||||||
return null;
|
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point we have the java package. We need to make sure it's not a different package
|
// at this point we have the java package. We need to make sure it's not a different package
|
||||||
@@ -409,7 +385,8 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, message);
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, message);
|
||||||
|
|
||||||
// abort
|
// abort
|
||||||
return null;
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -430,6 +407,8 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
String osResPath = resLocation.toOSString();
|
String osResPath = resLocation.toOSString();
|
||||||
String osManifestPath = manifestLocation.toOSString();
|
String osManifestPath = manifestLocation.toOSString();
|
||||||
|
|
||||||
|
IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
|
||||||
|
|
||||||
// remove the aapt markers
|
// remove the aapt markers
|
||||||
removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT);
|
removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT);
|
||||||
removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT);
|
removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT);
|
||||||
@@ -517,20 +496,25 @@ public class PreCompilerBuilder extends BaseBuilder {
|
|||||||
Messages.AAPT_Error);
|
Messages.AAPT_Error);
|
||||||
|
|
||||||
// abort if exec failed.
|
// abort if exec failed.
|
||||||
return null;
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(Messages.AAPT_Error);
|
||||||
}
|
}
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
// something happen while executing the process,
|
// something happen while executing the process,
|
||||||
// mark the project and exit
|
// mark the project and exit
|
||||||
String msg = String.format(Messages.AAPT_Exec_Error, array.get(0));
|
String msg = String.format(Messages.AAPT_Exec_Error, array.get(0));
|
||||||
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
|
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
|
||||||
return null;
|
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(msg);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// we got interrupted waiting for the process to end...
|
// we got interrupted waiting for the process to end...
|
||||||
// mark the project and exit
|
// mark the project and exit
|
||||||
String msg = String.format(Messages.AAPT_Exec_Error, array.get(0));
|
String msg = String.format(Messages.AAPT_Exec_Error, array.get(0));
|
||||||
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
|
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
|
||||||
return null;
|
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the return code was OK, we refresh the folder that
|
// if the return code was OK, we refresh the folder that
|
||||||
|
|||||||
@@ -19,16 +19,20 @@ package com.android.ide.eclipse.adt.build;
|
|||||||
import com.android.ide.eclipse.adt.AdtConstants;
|
import com.android.ide.eclipse.adt.AdtConstants;
|
||||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||||
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||||
|
import com.android.ide.eclipse.adt.sdk.LoadStatus;
|
||||||
|
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.common.AndroidConstants;
|
import com.android.ide.eclipse.common.AndroidConstants;
|
||||||
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
||||||
|
import com.android.sdklib.IAndroidTarget;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IFolder;
|
import org.eclipse.core.resources.IFolder;
|
||||||
import org.eclipse.core.resources.IMarker;
|
import org.eclipse.core.resources.IMarker;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
import org.eclipse.core.resources.IncrementalProjectBuilder;
|
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
import org.eclipse.core.runtime.IProgressMonitor;
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.jdt.core.IJavaProject;
|
||||||
|
import org.eclipse.jdt.core.JavaCore;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -36,7 +40,7 @@ import java.util.Map;
|
|||||||
* Resource manager builder whose only purpose is to refresh the resource folder
|
* Resource manager builder whose only purpose is to refresh the resource folder
|
||||||
* so that the other builder use an up to date version.
|
* so that the other builder use an up to date version.
|
||||||
*/
|
*/
|
||||||
public class ResourceManagerBuilder extends IncrementalProjectBuilder {
|
public class ResourceManagerBuilder extends BaseBuilder {
|
||||||
|
|
||||||
public static final String ID = "com.android.ide.eclipse.adt.ResourceManagerBuilder"; //$NON-NLS-1$
|
public static final String ID = "com.android.ide.eclipse.adt.ResourceManagerBuilder"; //$NON-NLS-1$
|
||||||
|
|
||||||
@@ -72,6 +76,38 @@ public class ResourceManagerBuilder extends IncrementalProjectBuilder {
|
|||||||
BaseProjectHelper.addMarker(project, AdtConstants.MARKER_ADT, errorMessage,
|
BaseProjectHelper.addMarker(project, AdtConstants.MARKER_ADT, errorMessage,
|
||||||
IMarker.SEVERITY_ERROR);
|
IMarker.SEVERITY_ERROR);
|
||||||
AdtPlugin.printErrorToConsole(project, errorMessage);
|
AdtPlugin.printErrorToConsole(project, errorMessage);
|
||||||
|
|
||||||
|
// interrupt the build. The next builders will not run.
|
||||||
|
stopBuild(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the SDK directory has been setup.
|
||||||
|
String osSdkFolder = AdtPlugin.getOsSdkFolder();
|
||||||
|
|
||||||
|
if (osSdkFolder == null || osSdkFolder.length() == 0) {
|
||||||
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
|
||||||
|
Messages.No_SDK_Setup_Error);
|
||||||
|
markProject(AdtConstants.MARKER_ADT, Messages.No_SDK_Setup_Error,
|
||||||
|
IMarker.SEVERITY_ERROR);
|
||||||
|
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild(Messages.No_SDK_Setup_Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we have finished loading the SDK.
|
||||||
|
IJavaProject javaProject = JavaCore.create(project);
|
||||||
|
if (AdtPlugin.getDefault().getSdkLoadStatus(javaProject) != LoadStatus.LOADED) {
|
||||||
|
// we exit silently
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild("SDK is not loaded yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the project has a target
|
||||||
|
IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
|
||||||
|
if (projectTarget == null) {
|
||||||
|
// no target. marker has been set by the container initializer: exit silently.
|
||||||
|
// This interrupts the build. The next builders will not run.
|
||||||
|
stopBuild("Project has no target");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the preference to be sure we are supposed to refresh
|
// Check the preference to be sure we are supposed to refresh
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ import com.android.ide.eclipse.adt.sdk.Sdk;
|
|||||||
import com.android.ide.eclipse.common.project.AndroidManifestHelper;
|
import com.android.ide.eclipse.common.project.AndroidManifestHelper;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
import com.android.sdklib.vm.VmManager;
|
import com.android.sdklib.avd.AvdManager;
|
||||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
import com.android.sdklib.avd.AvdManager.AvdInfo;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
@@ -74,7 +74,7 @@ import java.util.regex.Pattern;
|
|||||||
public final class AndroidLaunchController implements IDebugBridgeChangeListener,
|
public final class AndroidLaunchController implements IDebugBridgeChangeListener,
|
||||||
IDeviceChangeListener, IClientChangeListener {
|
IDeviceChangeListener, IClientChangeListener {
|
||||||
|
|
||||||
private static final String FLAG_VM = "-vm"; //$NON-NLS-1$
|
private static final String FLAG_AVD = "-avd"; //$NON-NLS-1$
|
||||||
private static final String FLAG_NETDELAY = "-netdelay"; //$NON-NLS-1$
|
private static final String FLAG_NETDELAY = "-netdelay"; //$NON-NLS-1$
|
||||||
private static final String FLAG_NETSPEED = "-netspeed"; //$NON-NLS-1$
|
private static final String FLAG_NETSPEED = "-netspeed"; //$NON-NLS-1$
|
||||||
private static final String FLAG_WIPE_DATA = "-wipe-data"; //$NON-NLS-1$
|
private static final String FLAG_WIPE_DATA = "-wipe-data"; //$NON-NLS-1$
|
||||||
@@ -228,9 +228,9 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
public boolean mNoBootAnim = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM;
|
public boolean mNoBootAnim = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vm Name.
|
* AVD Name.
|
||||||
*/
|
*/
|
||||||
public String mVmName = null;
|
public String mAvdName = null;
|
||||||
|
|
||||||
public String mNetworkSpeed = EmulatorConfigTab.getSpeed(
|
public String mNetworkSpeed = EmulatorConfigTab.getSpeed(
|
||||||
LaunchConfigDelegate.DEFAULT_SPEED);
|
LaunchConfigDelegate.DEFAULT_SPEED);
|
||||||
@@ -262,7 +262,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mVmName = config.getAttribute(LaunchConfigDelegate.ATTR_VM_NAME, mVmName);
|
mAvdName = config.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, mAvdName);
|
||||||
} catch (CoreException e) {
|
} catch (CoreException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,8 +531,8 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
wc.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
|
wc.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
|
||||||
LaunchConfigDelegate.DEFAULT_TARGET_MODE);
|
LaunchConfigDelegate.DEFAULT_TARGET_MODE);
|
||||||
|
|
||||||
// default VM: None
|
// default AVD: None
|
||||||
wc.setAttribute(LaunchConfigDelegate.ATTR_VM_NAME, (String)null);
|
wc.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String)null);
|
||||||
|
|
||||||
// set the default network speed
|
// set the default network speed
|
||||||
wc.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
|
wc.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
|
||||||
@@ -629,12 +629,12 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
|
|
||||||
// get the SDK
|
// get the SDK
|
||||||
Sdk currentSdk = Sdk.getCurrent();
|
Sdk currentSdk = Sdk.getCurrent();
|
||||||
VmManager vmManager = currentSdk.getVmManager();
|
AvdManager avdManager = currentSdk.getAvdManager();
|
||||||
|
|
||||||
// get the project target
|
// get the project target
|
||||||
final IAndroidTarget projectTarget = currentSdk.getTarget(project);
|
final IAndroidTarget projectTarget = currentSdk.getTarget(project);
|
||||||
|
|
||||||
// FIXME: check errors on missing sdk, vm manager, or project target.
|
// FIXME: check errors on missing sdk, AVD manager, or project target.
|
||||||
|
|
||||||
// device chooser response object.
|
// device chooser response object.
|
||||||
final DeviceChooserResponse response = new DeviceChooserResponse();
|
final DeviceChooserResponse response = new DeviceChooserResponse();
|
||||||
@@ -644,81 +644,81 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
* - Manually Mode
|
* - Manually Mode
|
||||||
* Always display a UI that lets a user see the current running emulators/devices.
|
* Always display a UI that lets a user see the current running emulators/devices.
|
||||||
* The UI must show which devices are compatibles, and allow launching new emulators
|
* The UI must show which devices are compatibles, and allow launching new emulators
|
||||||
* with compatible (and not yet running) VM.
|
* with compatible (and not yet running) AVD.
|
||||||
* - Automatic Way
|
* - Automatic Way
|
||||||
* * Preferred VM set.
|
* * Preferred AVD set.
|
||||||
* If Preferred VM is not running: launch it.
|
* If Preferred AVD is not running: launch it.
|
||||||
* Launch the application on the preferred VM.
|
* Launch the application on the preferred AVD.
|
||||||
* * No preferred VM.
|
* * No preferred AVD.
|
||||||
* Count the number of compatible emulators/devices.
|
* Count the number of compatible emulators/devices.
|
||||||
* If != 1, display a UI similar to manual mode.
|
* If != 1, display a UI similar to manual mode.
|
||||||
* If == 1, launch the application on this VM/device.
|
* If == 1, launch the application on this AVD/device.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (config.mTargetMode == AndroidLaunchConfiguration.AUTO_TARGET_MODE) {
|
if (config.mTargetMode == AndroidLaunchConfiguration.AUTO_TARGET_MODE) {
|
||||||
// if we are in automatic target mode, we need to find the current devices
|
// if we are in automatic target mode, we need to find the current devices
|
||||||
Device[] devices = AndroidDebugBridge.getBridge().getDevices();
|
Device[] devices = AndroidDebugBridge.getBridge().getDevices();
|
||||||
|
|
||||||
// first check if we have a preferred VM name, and if it actually exists, and is valid
|
// first check if we have a preferred AVD name, and if it actually exists, and is valid
|
||||||
// (ie able to run the project).
|
// (ie able to run the project).
|
||||||
// We need to check this in case the VM was recreated with a different target that is
|
// We need to check this in case the AVD was recreated with a different target that is
|
||||||
// not compatible.
|
// not compatible.
|
||||||
VmInfo preferredVm = null;
|
AvdInfo preferredAvd = null;
|
||||||
if (config.mVmName != null) {
|
if (config.mAvdName != null) {
|
||||||
preferredVm = vmManager.getVm(config.mVmName);
|
preferredAvd = avdManager.getAvd(config.mAvdName);
|
||||||
if (projectTarget.isCompatibleBaseFor(preferredVm.getTarget()) == false) {
|
if (projectTarget.isCompatibleBaseFor(preferredAvd.getTarget()) == false) {
|
||||||
preferredVm = null;
|
preferredAvd = null;
|
||||||
|
|
||||||
AdtPlugin.printErrorToConsole(project, String.format(
|
AdtPlugin.printErrorToConsole(project, String.format(
|
||||||
"Preferred VM '%1$s' is not compatible with the project target '%2$s'. Looking for a compatible VM...",
|
"Preferred AVD '%1$s' is not compatible with the project target '%2$s'. Looking for a compatible AVD...",
|
||||||
config.mVmName, projectTarget.getName()));
|
config.mAvdName, projectTarget.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preferredVm != null) {
|
if (preferredAvd != null) {
|
||||||
// look for a matching device
|
// look for a matching device
|
||||||
for (Device d : devices) {
|
for (Device d : devices) {
|
||||||
String deviceVm = d.getVmName();
|
String deviceAvd = d.getAvdName();
|
||||||
if (deviceVm != null && deviceVm.equals(config.mVmName)) {
|
if (deviceAvd != null && deviceAvd.equals(config.mAvdName)) {
|
||||||
response.mustContinue = true;
|
response.mustContinue = true;
|
||||||
response.mustLaunchEmulator = false;
|
response.mustLaunchEmulator = false;
|
||||||
response.deviceToUse = d;
|
response.deviceToUse = d;
|
||||||
|
|
||||||
AdtPlugin.printToConsole(project, String.format(
|
AdtPlugin.printToConsole(project, String.format(
|
||||||
"Automatic Target Mode: Preferred VM '%1$s' is available on emulator '%2$s'",
|
"Automatic Target Mode: Preferred AVD '%1$s' is available on emulator '%2$s'",
|
||||||
config.mVmName, d));
|
config.mAvdName, d));
|
||||||
|
|
||||||
continueLaunch(response, project, launch, launchInfo, config);
|
continueLaunch(response, project, launch, launchInfo, config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point we have a valid preferred VM that is not running.
|
// at this point we have a valid preferred AVD that is not running.
|
||||||
// We need to start it.
|
// We need to start it.
|
||||||
response.mustContinue = true;
|
response.mustContinue = true;
|
||||||
response.mustLaunchEmulator = true;
|
response.mustLaunchEmulator = true;
|
||||||
response.vmToLaunch = preferredVm;
|
response.avdToLaunch = preferredAvd;
|
||||||
|
|
||||||
AdtPlugin.printToConsole(project, String.format(
|
AdtPlugin.printToConsole(project, String.format(
|
||||||
"Automatic Target Mode: Preferred VM '%1$s' is not available. Launching new emulator.",
|
"Automatic Target Mode: Preferred AVD '%1$s' is not available. Launching new emulator.",
|
||||||
config.mVmName));
|
config.mAvdName));
|
||||||
|
|
||||||
continueLaunch(response, project, launch, launchInfo, config);
|
continueLaunch(response, project, launch, launchInfo, config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no (valid) preferred VM? look for one.
|
// no (valid) preferred AVD? look for one.
|
||||||
HashMap<Device, VmInfo> compatibleRunningVms = new HashMap<Device, VmInfo>();
|
HashMap<Device, AvdInfo> compatibleRunningAvds = new HashMap<Device, AvdInfo>();
|
||||||
boolean hasDevice = false; // if there's 1+ device running, we may force manual mode,
|
boolean hasDevice = false; // if there's 1+ device running, we may force manual mode,
|
||||||
// as we cannot always detect proper compatibility with
|
// as we cannot always detect proper compatibility with
|
||||||
// devices. This is the case if the project target is not
|
// devices. This is the case if the project target is not
|
||||||
// a standard platform
|
// a standard platform
|
||||||
for (Device d : devices) {
|
for (Device d : devices) {
|
||||||
String deviceVm = d.getVmName();
|
String deviceAvd = d.getAvdName();
|
||||||
if (deviceVm != null) { // physical devices return null.
|
if (deviceAvd != null) { // physical devices return null.
|
||||||
VmInfo info = vmManager.getVm(deviceVm);
|
AvdInfo info = avdManager.getAvd(deviceAvd);
|
||||||
if (info != null && projectTarget.isCompatibleBaseFor(info.getTarget())) {
|
if (info != null && projectTarget.isCompatibleBaseFor(info.getTarget())) {
|
||||||
compatibleRunningVms.put(d, info);
|
compatibleRunningAvds.put(d, info);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (projectTarget.isPlatform()) { // means this can run on any device as long
|
if (projectTarget.isPlatform()) { // means this can run on any device as long
|
||||||
@@ -728,7 +728,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
int apiNumber = Integer.parseInt(apiString);
|
int apiNumber = Integer.parseInt(apiString);
|
||||||
if (apiNumber >= projectTarget.getApiVersionNumber()) {
|
if (apiNumber >= projectTarget.getApiVersionNumber()) {
|
||||||
// device is compatible with project
|
// device is compatible with project
|
||||||
compatibleRunningVms.put(d, null);
|
compatibleRunningAvds.put(d, null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
@@ -741,54 +741,54 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
|
|
||||||
// depending on the number of devices, we'll simulate an automatic choice
|
// depending on the number of devices, we'll simulate an automatic choice
|
||||||
// from the device chooser or simply show up the device chooser.
|
// from the device chooser or simply show up the device chooser.
|
||||||
if (hasDevice == false && compatibleRunningVms.size() == 0) {
|
if (hasDevice == false && compatibleRunningAvds.size() == 0) {
|
||||||
// if zero emulators/devices, we launch an emulator.
|
// if zero emulators/devices, we launch an emulator.
|
||||||
// We need to figure out which VM first.
|
// We need to figure out which AVD first.
|
||||||
|
|
||||||
// we are going to take the closest VM. ie a compatible VM that has the API level
|
// we are going to take the closest AVD. ie a compatible AVD that has the API level
|
||||||
// closest to the project target.
|
// closest to the project target.
|
||||||
VmInfo[] vms = vmManager.getVms();
|
AvdInfo[] avds = avdManager.getAvds();
|
||||||
VmInfo defaultVm = null;
|
AvdInfo defaultAvd = null;
|
||||||
for (VmInfo vm : vms) {
|
for (AvdInfo avd : avds) {
|
||||||
if (projectTarget.isCompatibleBaseFor(vm.getTarget())) {
|
if (projectTarget.isCompatibleBaseFor(avd.getTarget())) {
|
||||||
if (defaultVm == null ||
|
if (defaultAvd == null ||
|
||||||
vm.getTarget().getApiVersionNumber() <
|
avd.getTarget().getApiVersionNumber() <
|
||||||
defaultVm.getTarget().getApiVersionNumber()) {
|
defaultAvd.getTarget().getApiVersionNumber()) {
|
||||||
defaultVm = vm;
|
defaultAvd = avd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultVm != null) {
|
if (defaultAvd != null) {
|
||||||
response.mustContinue = true;
|
response.mustContinue = true;
|
||||||
response.mustLaunchEmulator = true;
|
response.mustLaunchEmulator = true;
|
||||||
response.vmToLaunch = defaultVm;
|
response.avdToLaunch = defaultAvd;
|
||||||
|
|
||||||
AdtPlugin.printToConsole(project, String.format(
|
AdtPlugin.printToConsole(project, String.format(
|
||||||
"Automatic Target Mode: launching new emulator with compatible VM '%1$s'",
|
"Automatic Target Mode: launching new emulator with compatible AVD '%1$s'",
|
||||||
defaultVm.getName()));
|
defaultAvd.getName()));
|
||||||
|
|
||||||
continueLaunch(response, project, launch, launchInfo, config);
|
continueLaunch(response, project, launch, launchInfo, config);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// FIXME: ask the user if he wants to create a VM.
|
// FIXME: ask the user if he wants to create a AVD.
|
||||||
// we found no compatible VM.
|
// we found no compatible AVD.
|
||||||
AdtPlugin.printErrorToConsole(project, String.format(
|
AdtPlugin.printErrorToConsole(project, String.format(
|
||||||
"Failed to find a VM compatible with target '%1$s'. Launch aborted.",
|
"Failed to find a AVD compatible with target '%1$s'. Launch aborted.",
|
||||||
projectTarget.getName()));
|
projectTarget.getName()));
|
||||||
launch.stopLaunch();
|
launch.stopLaunch();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (hasDevice == false && compatibleRunningVms.size() == 1) {
|
} else if (hasDevice == false && compatibleRunningAvds.size() == 1) {
|
||||||
Entry<Device, VmInfo> e = compatibleRunningVms.entrySet().iterator().next();
|
Entry<Device, AvdInfo> e = compatibleRunningAvds.entrySet().iterator().next();
|
||||||
response.mustContinue = true;
|
response.mustContinue = true;
|
||||||
response.mustLaunchEmulator = false;
|
response.mustLaunchEmulator = false;
|
||||||
response.deviceToUse = e.getKey();
|
response.deviceToUse = e.getKey();
|
||||||
|
|
||||||
// get the VmInfo, if null, the device is a physical device.
|
// get the AvdInfo, if null, the device is a physical device.
|
||||||
VmInfo vmInfo = e.getValue();
|
AvdInfo avdInfo = e.getValue();
|
||||||
if (vmInfo != null) {
|
if (avdInfo != null) {
|
||||||
message = String.format("Automatic Target Mode: using existing emulator '%1$s' running compatible VM '%2$s'",
|
message = String.format("Automatic Target Mode: using existing emulator '%1$s' running compatible AVD '%2$s'",
|
||||||
response.deviceToUse, e.getValue().getName());
|
response.deviceToUse, e.getValue().getName());
|
||||||
} else {
|
} else {
|
||||||
message = String.format("Automatic Target Mode: using device '%1$s'",
|
message = String.format("Automatic Target Mode: using device '%1$s'",
|
||||||
@@ -801,7 +801,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if more than one device, we'll bring up the DeviceChooser dialog below.
|
// if more than one device, we'll bring up the DeviceChooser dialog below.
|
||||||
if (compatibleRunningVms.size() >= 2) {
|
if (compatibleRunningAvds.size() >= 2) {
|
||||||
message = "Automatic Target Mode: Several compatible targets. Please select a target device.";
|
message = "Automatic Target Mode: Several compatible targets. Please select a target device.";
|
||||||
} else if (hasDevice) {
|
} else if (hasDevice) {
|
||||||
message = "Automatic Target Mode: Unable to detect device compatibility. Please select a target device.";
|
message = "Automatic Target Mode: Unable to detect device compatibility. Please select a target device.";
|
||||||
@@ -849,7 +849,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
synchronized (sListLock) {
|
synchronized (sListLock) {
|
||||||
mWaitingForEmulatorLaunches.add(launchInfo);
|
mWaitingForEmulatorLaunches.add(launchInfo);
|
||||||
AdtPlugin.printToConsole(project, "Launching a new emulator.");
|
AdtPlugin.printToConsole(project, "Launching a new emulator.");
|
||||||
boolean status = launchEmulator(config, response.vmToLaunch);
|
boolean status = launchEmulator(config, response.avdToLaunch);
|
||||||
|
|
||||||
if (status == false) {
|
if (status == false) {
|
||||||
// launching the emulator failed!
|
// launching the emulator failed!
|
||||||
@@ -1323,7 +1323,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean launchEmulator(AndroidLaunchConfiguration config, VmInfo vmToLaunch) {
|
private boolean launchEmulator(AndroidLaunchConfiguration config, AvdInfo avdToLaunch) {
|
||||||
|
|
||||||
// split the custom command line in segments
|
// split the custom command line in segments
|
||||||
ArrayList<String> customArgs = new ArrayList<String>();
|
ArrayList<String> customArgs = new ArrayList<String>();
|
||||||
@@ -1353,8 +1353,8 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
|||||||
ArrayList<String> list = new ArrayList<String>();
|
ArrayList<String> list = new ArrayList<String>();
|
||||||
|
|
||||||
list.add(AdtPlugin.getOsAbsoluteEmulator());
|
list.add(AdtPlugin.getOsAbsoluteEmulator());
|
||||||
list.add(FLAG_VM);
|
list.add(FLAG_AVD);
|
||||||
list.add(vmToLaunch.getName());
|
list.add(avdToLaunch.getName());
|
||||||
|
|
||||||
if (config.mNetworkSpeed != null) {
|
if (config.mNetworkSpeed != null) {
|
||||||
list.add(FLAG_NETSPEED);
|
list.add(FLAG_NETSPEED);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController.Delay
|
|||||||
import com.android.ide.eclipse.adt.sdk.Sdk;
|
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
import com.android.sdklib.avd.AvdManager.AvdInfo;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.jface.preference.IPreferenceStore;
|
import org.eclipse.jface.preference.IPreferenceStore;
|
||||||
@@ -70,10 +70,10 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
|||||||
private final static int ICON_WIDTH = 16;
|
private final static int ICON_WIDTH = 16;
|
||||||
|
|
||||||
private final static String PREFS_COL_SERIAL = "deviceChooser.serial"; //$NON-NLS-1$
|
private final static String PREFS_COL_SERIAL = "deviceChooser.serial"; //$NON-NLS-1$
|
||||||
private final static String PREFS_COL_STATE = "deviceChooser.state"; //$NON-NLS-1$
|
private final static String PREFS_COL_STATE = "deviceChooser.state"; //$NON-NLS-1$
|
||||||
private final static String PREFS_COL_VM = "deviceChooser.vm"; //$NON-NLS-1$
|
private final static String PREFS_COL_AVD = "deviceChooser.avd"; //$NON-NLS-1$
|
||||||
private final static String PREFS_COL_TARGET = "deviceChooser.target"; //$NON-NLS-1$
|
private final static String PREFS_COL_TARGET = "deviceChooser.target"; //$NON-NLS-1$
|
||||||
private final static String PREFS_COL_DEBUG = "deviceChooser.debug"; //$NON-NLS-1$
|
private final static String PREFS_COL_DEBUG = "deviceChooser.debug"; //$NON-NLS-1$
|
||||||
|
|
||||||
private Table mDeviceTable;
|
private Table mDeviceTable;
|
||||||
private TableViewer mViewer;
|
private TableViewer mViewer;
|
||||||
@@ -149,8 +149,8 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
|||||||
return mNoMatchImage;
|
return mNoMatchImage;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// get the VmInfo
|
// get the AvdInfo
|
||||||
VmInfo info = mSdk.getVmManager().getVm(device.getVmName());
|
AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName());
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
return mWarningImage;
|
return mWarningImage;
|
||||||
}
|
}
|
||||||
@@ -171,13 +171,13 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
|||||||
return device.getSerialNumber();
|
return device.getSerialNumber();
|
||||||
case 1:
|
case 1:
|
||||||
if (device.isEmulator()) {
|
if (device.isEmulator()) {
|
||||||
return device.getVmName();
|
return device.getAvdName();
|
||||||
} else {
|
} else {
|
||||||
return "N/A"; // devices don't have VM names.
|
return "N/A"; // devices don't have AVD names.
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
if (device.isEmulator()) {
|
if (device.isEmulator()) {
|
||||||
VmInfo info = mSdk.getVmManager().getVm(device.getVmName());
|
AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName());
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
|||||||
public static class DeviceChooserResponse {
|
public static class DeviceChooserResponse {
|
||||||
public boolean mustContinue;
|
public boolean mustContinue;
|
||||||
public boolean mustLaunchEmulator;
|
public boolean mustLaunchEmulator;
|
||||||
public VmInfo vmToLaunch;
|
public AvdInfo avdToLaunch;
|
||||||
public Device deviceToUse;
|
public Device deviceToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,9 +314,9 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
|||||||
SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
|
SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
|
||||||
PREFS_COL_SERIAL, store);
|
PREFS_COL_SERIAL, store);
|
||||||
|
|
||||||
TableHelper.createTableColumn(mDeviceTable, "VM Name",
|
TableHelper.createTableColumn(mDeviceTable, "AVD Name",
|
||||||
SWT.LEFT, "engineering", //$NON-NLS-1$
|
SWT.LEFT, "engineering", //$NON-NLS-1$
|
||||||
PREFS_COL_VM, store);
|
PREFS_COL_AVD, store);
|
||||||
|
|
||||||
TableHelper.createTableColumn(mDeviceTable, "Target",
|
TableHelper.createTableColumn(mDeviceTable, "Target",
|
||||||
SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$
|
SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
|
|||||||
*/
|
*/
|
||||||
public static final String ATTR_ACTIVITY = AdtPlugin.PLUGIN_ID + ".activity"; //$NON-NLS-1$
|
public static final String ATTR_ACTIVITY = AdtPlugin.PLUGIN_ID + ".activity"; //$NON-NLS-1$
|
||||||
|
|
||||||
public static final String ATTR_VM_NAME = AdtPlugin.PLUGIN_ID + ".vm"; //$NON-NLS-1$
|
public static final String ATTR_AVD_NAME = AdtPlugin.PLUGIN_ID + ".avd"; //$NON-NLS-1$
|
||||||
|
|
||||||
public static final String ATTR_SPEED = AdtPlugin.PLUGIN_ID + ".speed"; //$NON-NLS-1$
|
public static final String ATTR_SPEED = AdtPlugin.PLUGIN_ID + ".speed"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import com.android.ide.eclipse.adt.sdk.Sdk;
|
|||||||
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
||||||
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.vm.VmManager;
|
import com.android.sdklib.avd.AvdManager;
|
||||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
import com.android.sdklib.avd.AvdManager.AvdInfo;
|
||||||
import com.android.sdkuilib.VmSelector;
|
import com.android.sdkuilib.AvdSelector;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
@@ -75,7 +75,7 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
|||||||
private Button mAutoTargetButton;
|
private Button mAutoTargetButton;
|
||||||
private Button mManualTargetButton;
|
private Button mManualTargetButton;
|
||||||
|
|
||||||
private VmSelector mPreferredVmSelector;
|
private AvdSelector mPreferredAvdSelector;
|
||||||
|
|
||||||
private Combo mSpeedCombo;
|
private Combo mSpeedCombo;
|
||||||
|
|
||||||
@@ -163,11 +163,11 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
new Label(targetModeGroup, SWT.NONE).setText("Preferred VM");
|
new Label(targetModeGroup, SWT.NONE).setText("Preferred Android Virtual Device");
|
||||||
VmInfo[] vms = new VmInfo[0];
|
AvdInfo[] avds = new AvdInfo[0];
|
||||||
mPreferredVmSelector = new VmSelector(targetModeGroup, vms,
|
mPreferredAvdSelector = new AvdSelector(targetModeGroup, avds,
|
||||||
false /*allowMultipleSelection*/);
|
false /*allowMultipleSelection*/);
|
||||||
mPreferredVmSelector.setSelectionListener(new SelectionAdapter() {
|
mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
updateLaunchConfigurationDialog();
|
updateLaunchConfigurationDialog();
|
||||||
@@ -277,7 +277,7 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
|||||||
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
|
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
|
||||||
*/
|
*/
|
||||||
public void initializeFrom(ILaunchConfiguration configuration) {
|
public void initializeFrom(ILaunchConfiguration configuration) {
|
||||||
VmManager vmManager = Sdk.getCurrent().getVmManager();
|
AvdManager avdManager = Sdk.getCurrent().getAvdManager();
|
||||||
|
|
||||||
boolean value = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true == automatic
|
boolean value = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true == automatic
|
||||||
try {
|
try {
|
||||||
@@ -311,34 +311,34 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the VM list
|
// update the AVD list
|
||||||
VmInfo[] vms = null;
|
AvdInfo[] avds = null;
|
||||||
if (vmManager != null) {
|
if (avdManager != null) {
|
||||||
vms = vmManager.getVms();
|
avds = avdManager.getAvds();
|
||||||
}
|
}
|
||||||
|
|
||||||
IAndroidTarget projectTarget = null;
|
IAndroidTarget projectTarget = null;
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
projectTarget = Sdk.getCurrent().getTarget(project);
|
projectTarget = Sdk.getCurrent().getTarget(project);
|
||||||
} else {
|
} else {
|
||||||
vms = null; // no project? we don't want to display any "compatible" VMs.
|
avds = null; // no project? we don't want to display any "compatible" AVDs.
|
||||||
}
|
}
|
||||||
|
|
||||||
mPreferredVmSelector.setVms(vms, projectTarget);
|
mPreferredAvdSelector.setAvds(avds, projectTarget);
|
||||||
|
|
||||||
stringValue = "";
|
stringValue = "";
|
||||||
try {
|
try {
|
||||||
stringValue = configuration.getAttribute(LaunchConfigDelegate.ATTR_VM_NAME,
|
stringValue = configuration.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME,
|
||||||
stringValue);
|
stringValue);
|
||||||
} catch (CoreException e) {
|
} catch (CoreException e) {
|
||||||
// let's not do anything here, we'll use the default value
|
// let's not do anything here, we'll use the default value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stringValue != null && stringValue.length() > 0 && vmManager != null) {
|
if (stringValue != null && stringValue.length() > 0 && avdManager != null) {
|
||||||
VmInfo targetVm = vmManager.getVm(stringValue);
|
AvdInfo targetAvd = avdManager.getAvd(stringValue);
|
||||||
mPreferredVmSelector.setSelection(targetVm);
|
mPreferredAvdSelector.setSelection(targetAvd);
|
||||||
} else {
|
} else {
|
||||||
mPreferredVmSelector.setSelection(null);
|
mPreferredAvdSelector.setSelection(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
value = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
|
value = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
|
||||||
@@ -404,11 +404,11 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
|||||||
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
|
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
|
||||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
|
configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
|
||||||
mAutoTargetButton.getSelection());
|
mAutoTargetButton.getSelection());
|
||||||
VmInfo vm = mPreferredVmSelector.getFirstSelected();
|
AvdInfo avd = mPreferredAvdSelector.getFirstSelected();
|
||||||
if (vm != null) {
|
if (avd != null) {
|
||||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_VM_NAME, vm.getName());
|
configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, avd.getName());
|
||||||
} else {
|
} else {
|
||||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_VM_NAME, (String)null);
|
configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String)null);
|
||||||
}
|
}
|
||||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
|
configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
|
||||||
mSpeedCombo.getSelectionIndex());
|
mSpeedCombo.getSelectionIndex());
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ public final class ProjectHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link IProject} by its running application name, as it returned by the VM.
|
* Returns a {@link IProject} by its running application name, as it returned by the AVD.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <var>applicationName</var> will in most case be the package declared in the manifest, but
|
* <var>applicationName</var> will in most case be the package declared in the manifest, but
|
||||||
* can, in some cases, be a custom process name declared in the manifest, in the
|
* can, in some cases, be a custom process name declared in the manifest, in the
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import com.android.sdklib.IAndroidTarget;
|
|||||||
import com.android.sdklib.ISdkLog;
|
import com.android.sdklib.ISdkLog;
|
||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
|
import com.android.sdklib.avd.AvdManager;
|
||||||
import com.android.sdklib.project.ProjectProperties;
|
import com.android.sdklib.project.ProjectProperties;
|
||||||
import com.android.sdklib.project.ProjectProperties.PropertyType;
|
import com.android.sdklib.project.ProjectProperties.PropertyType;
|
||||||
import com.android.sdklib.vm.VmManager;
|
|
||||||
|
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.runtime.IStatus;
|
import org.eclipse.core.runtime.IStatus;
|
||||||
@@ -52,7 +52,7 @@ public class Sdk {
|
|||||||
private static Sdk sCurrentSdk = null;
|
private static Sdk sCurrentSdk = null;
|
||||||
|
|
||||||
private final SdkManager mManager;
|
private final SdkManager mManager;
|
||||||
private final VmManager mVmManager;
|
private final AvdManager mAvdManager;
|
||||||
|
|
||||||
private final HashMap<IProject, IAndroidTarget> mProjectMap =
|
private final HashMap<IProject, IAndroidTarget> mProjectMap =
|
||||||
new HashMap<IProject, IAndroidTarget>();
|
new HashMap<IProject, IAndroidTarget>();
|
||||||
@@ -95,13 +95,13 @@ public class Sdk {
|
|||||||
// get an SdkManager object for the location
|
// get an SdkManager object for the location
|
||||||
SdkManager manager = SdkManager.createManager(sdkLocation, log);
|
SdkManager manager = SdkManager.createManager(sdkLocation, log);
|
||||||
if (manager != null) {
|
if (manager != null) {
|
||||||
VmManager vmManager = null;
|
AvdManager avdManager = null;
|
||||||
try {
|
try {
|
||||||
vmManager = new VmManager(manager, log);
|
avdManager = new AvdManager(manager, log);
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
log.error(e, "Error parsing the VMs");
|
log.error(e, "Error parsing the AVDs");
|
||||||
}
|
}
|
||||||
sCurrentSdk = new Sdk(manager, vmManager);
|
sCurrentSdk = new Sdk(manager, avdManager);
|
||||||
return sCurrentSdk;
|
return sCurrentSdk;
|
||||||
} else {
|
} else {
|
||||||
StringBuilder sb = new StringBuilder("Error Loading the SDK:\n");
|
StringBuilder sb = new StringBuilder("Error Loading the SDK:\n");
|
||||||
@@ -255,16 +255,16 @@ public class Sdk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link VmManager}. If the VmManager failed to parse the VM folder, this could
|
* Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could
|
||||||
* be <code>null</code>.
|
* be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public VmManager getVmManager() {
|
public AvdManager getAvdManager() {
|
||||||
return mVmManager;
|
return mAvdManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Sdk(SdkManager manager, VmManager vmManager) {
|
private Sdk(SdkManager manager, AvdManager avdManager) {
|
||||||
mManager = manager;
|
mManager = manager;
|
||||||
mVmManager = vmManager;
|
mAvdManager = avdManager;
|
||||||
|
|
||||||
// pre-compute some paths
|
// pre-compute some paths
|
||||||
mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
|
mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ public final class CustomViewDescriptorService {
|
|||||||
* @param type
|
* @param type
|
||||||
* @param project
|
* @param project
|
||||||
* @param typeHierarchy
|
* @param typeHierarchy
|
||||||
* @return A ViewElementDescriptor
|
* @return A ViewElementDescriptor or null if type or typeHierarchy is null.
|
||||||
*/
|
*/
|
||||||
private ViewElementDescriptor getDescriptor(IType type, IProject project,
|
private ViewElementDescriptor getDescriptor(IType type, IProject project,
|
||||||
ITypeHierarchy typeHierarchy) {
|
ITypeHierarchy typeHierarchy) {
|
||||||
@@ -198,12 +198,17 @@ public final class CustomViewDescriptorService {
|
|||||||
List<ElementDescriptor> builtInList = null;
|
List<ElementDescriptor> builtInList = null;
|
||||||
|
|
||||||
Sdk currentSdk = Sdk.getCurrent();
|
Sdk currentSdk = Sdk.getCurrent();
|
||||||
IAndroidTarget target = currentSdk.getTarget(project);
|
IAndroidTarget target = currentSdk == null ? null : currentSdk.getTarget(project);
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
AndroidTargetData data = currentSdk.getTargetData(target);
|
AndroidTargetData data = currentSdk.getTargetData(target);
|
||||||
builtInList = data.getLayoutDescriptors().getViewDescriptors();
|
builtInList = data.getLayoutDescriptors().getViewDescriptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// give up if there's no type
|
||||||
|
if (type == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String canonicalName = type.getFullyQualifiedName();
|
String canonicalName = type.getFullyQualifiedName();
|
||||||
|
|
||||||
if (builtInList != null) {
|
if (builtInList != null) {
|
||||||
@@ -218,6 +223,11 @@ public final class CustomViewDescriptorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// it's not a built-in class? Lets look if the superclass is built-in
|
// it's not a built-in class? Lets look if the superclass is built-in
|
||||||
|
// give up if there's no type
|
||||||
|
if (typeHierarchy == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
IType parentType = typeHierarchy.getSuperclass(type);
|
IType parentType = typeHierarchy.getSuperclass(type);
|
||||||
if (parentType != null) {
|
if (parentType != null) {
|
||||||
ViewElementDescriptor parentDescriptor = getDescriptor(parentType, project,
|
ViewElementDescriptor parentDescriptor = getDescriptor(parentType, project,
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public abstract class UiAbstractTextAttributeNode extends UiAttributeNode
|
|||||||
public void updateValue(Node xml_attribute_node) {
|
public void updateValue(Node xml_attribute_node) {
|
||||||
mCurrentValue = DEFAULT_VALUE;
|
mCurrentValue = DEFAULT_VALUE;
|
||||||
if (xml_attribute_node != null) {
|
if (xml_attribute_node != null) {
|
||||||
mCurrentValue = xml_attribute_node.getNodeValue().trim();
|
mCurrentValue = xml_attribute_node.getNodeValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValid() && !getTextWidgetValue().equals(mCurrentValue)) {
|
if (isValid() && !getTextWidgetValue().equals(mCurrentValue)) {
|
||||||
@@ -101,7 +101,7 @@ public abstract class UiAbstractTextAttributeNode extends UiAttributeNode
|
|||||||
public void commit() {
|
public void commit() {
|
||||||
UiElementNode parent = getUiParent();
|
UiElementNode parent = getUiParent();
|
||||||
if (parent != null && isValid() && isDirty()) {
|
if (parent != null && isValid() && isDirty()) {
|
||||||
String value = getTextWidgetValue().trim();
|
String value = getTextWidgetValue();
|
||||||
if (parent.commitAttributeToXml(this, value)) {
|
if (parent.commitAttributeToXml(this, value)) {
|
||||||
mCurrentValue = value;
|
mCurrentValue = value;
|
||||||
setDirty(false);
|
setDirty(false);
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import com.android.ide.eclipse.mock.JavaProjectMock;
|
|||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
import org.eclipse.jdt.core.IClasspathEntry;
|
import org.eclipse.jdt.core.IClasspathEntry;
|
||||||
import org.eclipse.jdt.core.JavaModelException;
|
import org.eclipse.jdt.core.JavaModelException;
|
||||||
import org.eclipse.jdt.launching.JavaRuntime;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import java.util.HashMap;
|
|||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit Test for {@link FrameworkClassLoader}.
|
* Unit Test for {@link AndroidJarLoader}.
|
||||||
*
|
*
|
||||||
* Uses the classes jar.example.Class1/Class2 stored in tests/data/jar_example.jar.
|
* Uses the classes jar.example.Class1/Class2 stored in tests/data/jar_example.jar.
|
||||||
*/
|
*/
|
||||||
@@ -36,7 +36,7 @@ public class AndroidJarLoaderTest extends TestCase {
|
|||||||
|
|
||||||
private AndroidJarLoader mFrameworkClassLoader;
|
private AndroidJarLoader mFrameworkClassLoader;
|
||||||
|
|
||||||
/** Creates an instance of {@link FrameworkClassLoader} on our test data JAR */
|
/** Creates an instance of {@link AndroidJarLoader} on our test data JAR */
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
String jarfilePath = AdtTestData.getInstance().getTestFilePath("jar_example.jar"); //$NON-NLS-1$
|
String jarfilePath = AdtTestData.getInstance().getTestFilePath("jar_example.jar"); //$NON-NLS-1$
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import junit.framework.TestCase;
|
|||||||
* Test the inner private methods of PlatformDataParser.
|
* Test the inner private methods of PlatformDataParser.
|
||||||
*
|
*
|
||||||
* Convention: method names that start with an underscore are actually local wrappers
|
* Convention: method names that start with an underscore are actually local wrappers
|
||||||
* that call private methods from {@link FrameworkResourceParser} using reflection.
|
* that call private methods from {@link AndroidTargetParser} using reflection.
|
||||||
* This is inspired by the Python coding rule which mandates underscores prefixes for
|
* This is inspired by the Python coding rule which mandates underscores prefixes for
|
||||||
* "private" methods.
|
* "private" methods.
|
||||||
*/
|
*/
|
||||||
@@ -131,6 +131,7 @@ public class LayoutParamsParserTest extends TestCase {
|
|||||||
//---- access to private methods
|
//---- access to private methods
|
||||||
|
|
||||||
/** Calls the private constructor of the parser */
|
/** Calls the private constructor of the parser */
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private AndroidTargetParser _Constructor(String osJarPath) throws Exception {
|
private AndroidTargetParser _Constructor(String osJarPath) throws Exception {
|
||||||
Constructor<AndroidTargetParser> constructor =
|
Constructor<AndroidTargetParser> constructor =
|
||||||
AndroidTargetParser.class.getDeclaredConstructor(String.class);
|
AndroidTargetParser.class.getDeclaredConstructor(String.class);
|
||||||
@@ -139,6 +140,7 @@ public class LayoutParamsParserTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** calls the private getLayoutClasses() of the parser */
|
/** calls the private getLayoutClasses() of the parser */
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private void _getLayoutClasses() throws Exception {
|
private void _getLayoutClasses() throws Exception {
|
||||||
Method method = AndroidTargetParser.class.getDeclaredMethod("getLayoutClasses"); //$NON-NLS-1$
|
Method method = AndroidTargetParser.class.getDeclaredMethod("getLayoutClasses"); //$NON-NLS-1$
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
@@ -146,6 +148,7 @@ public class LayoutParamsParserTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** calls the private addGroup() of the parser */
|
/** calls the private addGroup() of the parser */
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private ViewClassInfo _addGroup(Class<?> groupClass) throws Exception {
|
private ViewClassInfo _addGroup(Class<?> groupClass) throws Exception {
|
||||||
Method method = LayoutParamsParser.class.getDeclaredMethod("addGroup", //$NON-NLS-1$
|
Method method = LayoutParamsParser.class.getDeclaredMethod("addGroup", //$NON-NLS-1$
|
||||||
IClassDescriptor.class);
|
IClassDescriptor.class);
|
||||||
@@ -154,6 +157,7 @@ public class LayoutParamsParserTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** calls the private addLayoutParams() of the parser */
|
/** calls the private addLayoutParams() of the parser */
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private LayoutParamsInfo _addLayoutParams(Class<?> groupClass) throws Exception {
|
private LayoutParamsInfo _addLayoutParams(Class<?> groupClass) throws Exception {
|
||||||
Method method = LayoutParamsParser.class.getDeclaredMethod("addLayoutParams", //$NON-NLS-1$
|
Method method = LayoutParamsParser.class.getDeclaredMethod("addLayoutParams", //$NON-NLS-1$
|
||||||
IClassDescriptor.class);
|
IClassDescriptor.class);
|
||||||
|
|||||||
@@ -25,9 +25,24 @@ fi
|
|||||||
|
|
||||||
for app in $apps
|
for app in $apps
|
||||||
do
|
do
|
||||||
|
echo '-----------------------------------------------------------'
|
||||||
if [ -d $app/res ]
|
if [ -d $app/res ]
|
||||||
then
|
then
|
||||||
appname=$(basename $app)
|
appname=$(basename $app)
|
||||||
|
resources=
|
||||||
|
for res in $(echo $app/res/*)
|
||||||
|
do
|
||||||
|
resources="$resources $(echo $res | grep -v '\-mcc\|[a-z]*-[a-z][a-z]$\|[a-z]*-[a-z][a-z]-.*')"
|
||||||
|
done
|
||||||
|
sources=$app/src
|
||||||
|
if [ -d $app/tests ]
|
||||||
|
then
|
||||||
|
sources="$sources $app/tests"
|
||||||
|
fi
|
||||||
|
if [ -d $app/samples ]
|
||||||
|
then
|
||||||
|
sources="$sources $app/samples"
|
||||||
|
fi
|
||||||
|
|
||||||
# find the R.java file that contains all the generated resource identifiers
|
# find the R.java file that contains all the generated resource identifiers
|
||||||
rDotJava=$(find out/target/common/obj/APPS/${appname}_intermediates/ -name R.java)
|
rDotJava=$(find out/target/common/obj/APPS/${appname}_intermediates/ -name R.java)
|
||||||
@@ -40,7 +55,7 @@ do
|
|||||||
# refer to such constants from java by using an underscore instead of a period, we also
|
# refer to such constants from java by using an underscore instead of a period, we also
|
||||||
# replace all underscores with a pattern that will match periods and underscores.
|
# replace all underscores with a pattern that will match periods and underscores.
|
||||||
p=$(echo $i | sed 's/_/[\\._]/g')
|
p=$(echo $i | sed 's/_/[\\._]/g')
|
||||||
echo $i $(grep -Rw R\\..*\\.$i\\\|@style/$p\\\|@drawable/$p\\\|@anim/$p\\\|@color/$p\\\|@xml/$p\\\|@layout/$p\\\|@menu/$p\\\|@+id/$p\\\|@array/$p\\\|@string/$p $app | wc -l)
|
echo $i $(grep -Rw R\\..*\\.$i\\\|@style/$p\\\|@drawable/$p\\\|@anim/$p\\\|@color/$p\\\|@xml/$p\\\|@layout/$p\\\|@menu/$p\\\|@+id/$p\\\|@array/$p\\\|@string/$p\\\|@dimen/$p $resources $sources $app/AndroidManifest.xml | wc -l)
|
||||||
done | grep " 0$" | {
|
done | grep " 0$" | {
|
||||||
# this block gets as its input a list of constants which no references were found, one per line
|
# this block gets as its input a list of constants which no references were found, one per line
|
||||||
if [ "$showall" == "yes" ]
|
if [ "$showall" == "yes" ]
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ function showUsage() {
|
|||||||
#
|
#
|
||||||
# In order to define the most common cases simply, "#" can be used for some of
|
# In order to define the most common cases simply, "#" can be used for some of
|
||||||
# the fields, with the following default values:
|
# the fields, with the following default values:
|
||||||
# <test-package> = "#": test class is fully qualified with package
|
|
||||||
# <build-path> = "#": skip build/sync step
|
# <build-path> = "#": skip build/sync step
|
||||||
|
# <test-package> = "#": test class is fully qualified with package
|
||||||
# <test-class> = "#": omit "-e class" section
|
# <test-class> = "#": omit "-e class" section
|
||||||
# <testrunner-package> = "#": use same value as test-package
|
# <testrunner-package> = "#": use same value as test-package
|
||||||
# <testrunner-component> = "#": use "android.test.InstrumentationTestRunner"
|
# <testrunner-component> = "#": use "android.test.InstrumentationTestRunner"
|
||||||
@@ -117,7 +117,8 @@ knownTests=(
|
|||||||
"smoke frameworks/base/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 #"
|
"core frameworks/base/tests/CoreTests # android.core.CoreTests android.core #"
|
||||||
"libcore frameworks/base/tests/CoreTests # android.core.JavaTests android.core #"
|
"libcore frameworks/base/tests/CoreTests # android.core.JavaTests android.core #"
|
||||||
"apidemos samples/ApiDemos com.example.android.apis # com.example.android.apis.tests #"
|
"apidemos development/samples/ApiDemos com.example.android.apis # com.example.android.apis.tests #"
|
||||||
|
"launchperf development/apps/launchperf com.android.launchperf # # .SimpleActivityLaunchPerformance"
|
||||||
|
|
||||||
# targeted framework tests
|
# targeted framework tests
|
||||||
"heap frameworks/base/tests/AndroidTests com.android.unit_tests HeapTest # #"
|
"heap frameworks/base/tests/AndroidTests com.android.unit_tests HeapTest # #"
|
||||||
@@ -130,7 +131,7 @@ knownTests=(
|
|||||||
"browser packages/apps/Browser com.android.browser # # .BrowserTestRunner"
|
"browser packages/apps/Browser com.android.browser # # .BrowserTestRunner"
|
||||||
"browserfunc packages/apps/Browser com.android.browser # # .BrowserFunctionalTestRunner"
|
"browserfunc packages/apps/Browser com.android.browser # # .BrowserFunctionalTestRunner"
|
||||||
"calendar packages/apps/Calendar/tests com.android.calendar.tests # # #"
|
"calendar packages/apps/Calendar/tests com.android.calendar.tests # # #"
|
||||||
"calprov content/providers/calendar com.android.providers.calendar.tests # # #"
|
"calprov packages/providers/CalendarProvider com.android.providers.calendar # com.android.providers.calendar.tests #"
|
||||||
"camera tests/Camera com.android.cameratests # # CameraInstrumentationTestRunner"
|
"camera tests/Camera com.android.cameratests # # CameraInstrumentationTestRunner"
|
||||||
"contactsprov packages/providers/GoogleContactsProvider/tests com.android.providers.contacts # com.android.providers.contactstests #"
|
"contactsprov packages/providers/GoogleContactsProvider/tests com.android.providers.contacts # com.android.providers.contactstests #"
|
||||||
"email packages/apps/Email com.android.email # com.android.email.tests #"
|
"email packages/apps/Email com.android.email # com.android.email.tests #"
|
||||||
|
|||||||
202
tools/scripts/app_engine_server/LICENSE
Normal file
202
tools/scripts/app_engine_server/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
||||||
16
tools/scripts/app_engine_server/app.yaml
Executable file
16
tools/scripts/app_engine_server/app.yaml
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
application: androidappdocs-staging
|
||||||
|
version: 1
|
||||||
|
runtime: python
|
||||||
|
api_version: 1
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- url: /gae_shell/static
|
||||||
|
static_dir: gae_shell/static
|
||||||
|
expiration: 1d
|
||||||
|
|
||||||
|
- url: /gae_shell/.*
|
||||||
|
script: /gae_shell/shell.py
|
||||||
|
login: admin
|
||||||
|
|
||||||
|
- url: .*
|
||||||
|
script: main.py
|
||||||
17
tools/scripts/app_engine_server/gae_shell/README
Normal file
17
tools/scripts/app_engine_server/gae_shell/README
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
An interactive, stateful AJAX shell that runs Python code on the server.
|
||||||
|
|
||||||
|
Part of http://code.google.com/p/google-app-engine-samples/.
|
||||||
|
|
||||||
|
May be run as a standalone app or in an existing app as an admin-only handler.
|
||||||
|
Can be used for system administration tasks, as an interactive way to try out
|
||||||
|
APIs, or as a debugging aid during development.
|
||||||
|
|
||||||
|
The logging, os, sys, db, and users modules are imported automatically.
|
||||||
|
|
||||||
|
Interpreter state is stored in the datastore so that variables, function
|
||||||
|
definitions, and other values in the global and local namespaces can be used
|
||||||
|
across commands.
|
||||||
|
|
||||||
|
To use the shell in your app, copy shell.py, static/*, and templates/* into
|
||||||
|
your app's source directory. Then, copy the URL handlers from app.yaml into
|
||||||
|
your app.yaml.
|
||||||
BIN
tools/scripts/app_engine_server/gae_shell/__init__.pyc
Normal file
BIN
tools/scripts/app_engine_server/gae_shell/__init__.pyc
Normal file
Binary file not shown.
308
tools/scripts/app_engine_server/gae_shell/shell.py
Executable file
308
tools/scripts/app_engine_server/gae_shell/shell.py
Executable file
@@ -0,0 +1,308 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2007 Google Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
An interactive, stateful AJAX shell that runs Python code on the server.
|
||||||
|
|
||||||
|
Part of http://code.google.com/p/google-app-engine-samples/.
|
||||||
|
|
||||||
|
May be run as a standalone app or in an existing app as an admin-only handler.
|
||||||
|
Can be used for system administration tasks, as an interactive way to try out
|
||||||
|
APIs, or as a debugging aid during development.
|
||||||
|
|
||||||
|
The logging, os, sys, db, and users modules are imported automatically.
|
||||||
|
|
||||||
|
Interpreter state is stored in the datastore so that variables, function
|
||||||
|
definitions, and other values in the global and local namespaces can be used
|
||||||
|
across commands.
|
||||||
|
|
||||||
|
To use the shell in your app, copy shell.py, static/*, and templates/* into
|
||||||
|
your app's source directory. Then, copy the URL handlers from app.yaml into
|
||||||
|
your app.yaml.
|
||||||
|
|
||||||
|
TODO: unit tests!
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import new
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import types
|
||||||
|
import wsgiref.handlers
|
||||||
|
|
||||||
|
from google.appengine.api import users
|
||||||
|
from google.appengine.ext import db
|
||||||
|
from google.appengine.ext import webapp
|
||||||
|
from google.appengine.ext.webapp import template
|
||||||
|
|
||||||
|
|
||||||
|
# Set to True if stack traces should be shown in the browser, etc.
|
||||||
|
_DEBUG = True
|
||||||
|
|
||||||
|
# The entity kind for shell sessions. Feel free to rename to suit your app.
|
||||||
|
_SESSION_KIND = '_Shell_Session'
|
||||||
|
|
||||||
|
# Types that can't be pickled.
|
||||||
|
UNPICKLABLE_TYPES = (
|
||||||
|
types.ModuleType,
|
||||||
|
types.TypeType,
|
||||||
|
types.ClassType,
|
||||||
|
types.FunctionType,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Unpicklable statements to seed new sessions with.
|
||||||
|
INITIAL_UNPICKLABLES = [
|
||||||
|
'import logging',
|
||||||
|
'import os',
|
||||||
|
'import sys',
|
||||||
|
'from google.appengine.ext import db',
|
||||||
|
'from google.appengine.api import users',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Session(db.Model):
|
||||||
|
"""A shell session. Stores the session's globals.
|
||||||
|
|
||||||
|
Each session globals is stored in one of two places:
|
||||||
|
|
||||||
|
If the global is picklable, it's stored in the parallel globals and
|
||||||
|
global_names list properties. (They're parallel lists to work around the
|
||||||
|
unfortunate fact that the datastore can't store dictionaries natively.)
|
||||||
|
|
||||||
|
If the global is not picklable (e.g. modules, classes, and functions), or if
|
||||||
|
it was created by the same statement that created an unpicklable global,
|
||||||
|
it's not stored directly. Instead, the statement is stored in the
|
||||||
|
unpicklables list property. On each request, before executing the current
|
||||||
|
statement, the unpicklable statements are evaluated to recreate the
|
||||||
|
unpicklable globals.
|
||||||
|
|
||||||
|
The unpicklable_names property stores all of the names of globals that were
|
||||||
|
added by unpicklable statements. When we pickle and store the globals after
|
||||||
|
executing a statement, we skip the ones in unpicklable_names.
|
||||||
|
|
||||||
|
Using Text instead of string is an optimization. We don't query on any of
|
||||||
|
these properties, so they don't need to be indexed.
|
||||||
|
"""
|
||||||
|
global_names = db.ListProperty(db.Text)
|
||||||
|
globals = db.ListProperty(db.Blob)
|
||||||
|
unpicklable_names = db.ListProperty(db.Text)
|
||||||
|
unpicklables = db.ListProperty(db.Text)
|
||||||
|
|
||||||
|
def set_global(self, name, value):
|
||||||
|
"""Adds a global, or updates it if it already exists.
|
||||||
|
|
||||||
|
Also removes the global from the list of unpicklable names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: the name of the global to remove
|
||||||
|
value: any picklable value
|
||||||
|
"""
|
||||||
|
blob = db.Blob(pickle.dumps(value))
|
||||||
|
|
||||||
|
if name in self.global_names:
|
||||||
|
index = self.global_names.index(name)
|
||||||
|
self.globals[index] = blob
|
||||||
|
else:
|
||||||
|
self.global_names.append(db.Text(name))
|
||||||
|
self.globals.append(blob)
|
||||||
|
|
||||||
|
self.remove_unpicklable_name(name)
|
||||||
|
|
||||||
|
def remove_global(self, name):
|
||||||
|
"""Removes a global, if it exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: string, the name of the global to remove
|
||||||
|
"""
|
||||||
|
if name in self.global_names:
|
||||||
|
index = self.global_names.index(name)
|
||||||
|
del self.global_names[index]
|
||||||
|
del self.globals[index]
|
||||||
|
|
||||||
|
def globals_dict(self):
|
||||||
|
"""Returns a dictionary view of the globals.
|
||||||
|
"""
|
||||||
|
return dict((name, pickle.loads(val))
|
||||||
|
for name, val in zip(self.global_names, self.globals))
|
||||||
|
|
||||||
|
def add_unpicklable(self, statement, names):
|
||||||
|
"""Adds a statement and list of names to the unpicklables.
|
||||||
|
|
||||||
|
Also removes the names from the globals.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
statement: string, the statement that created new unpicklable global(s).
|
||||||
|
names: list of strings; the names of the globals created by the statement.
|
||||||
|
"""
|
||||||
|
self.unpicklables.append(db.Text(statement))
|
||||||
|
|
||||||
|
for name in names:
|
||||||
|
self.remove_global(name)
|
||||||
|
if name not in self.unpicklable_names:
|
||||||
|
self.unpicklable_names.append(db.Text(name))
|
||||||
|
|
||||||
|
def remove_unpicklable_name(self, name):
|
||||||
|
"""Removes a name from the list of unpicklable names, if it exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: string, the name of the unpicklable global to remove
|
||||||
|
"""
|
||||||
|
if name in self.unpicklable_names:
|
||||||
|
self.unpicklable_names.remove(name)
|
||||||
|
|
||||||
|
|
||||||
|
class FrontPageHandler(webapp.RequestHandler):
|
||||||
|
"""Creates a new session and renders the shell.html template.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
# set up the session. TODO: garbage collect old shell sessions
|
||||||
|
session_key = self.request.get('session')
|
||||||
|
if session_key:
|
||||||
|
session = Session.get(session_key)
|
||||||
|
else:
|
||||||
|
# create a new session
|
||||||
|
session = Session()
|
||||||
|
session.unpicklables = [db.Text(line) for line in INITIAL_UNPICKLABLES]
|
||||||
|
session_key = session.put()
|
||||||
|
|
||||||
|
template_file = os.path.join(os.path.dirname(__file__), 'templates',
|
||||||
|
'shell.html')
|
||||||
|
session_url = '/?session=%s' % session_key
|
||||||
|
vars = { 'server_software': os.environ['SERVER_SOFTWARE'],
|
||||||
|
'python_version': sys.version,
|
||||||
|
'session': str(session_key),
|
||||||
|
'user': users.get_current_user(),
|
||||||
|
'login_url': users.create_login_url(session_url),
|
||||||
|
'logout_url': users.create_logout_url(session_url),
|
||||||
|
}
|
||||||
|
rendered = webapp.template.render(template_file, vars, debug=_DEBUG)
|
||||||
|
self.response.out.write(rendered)
|
||||||
|
|
||||||
|
|
||||||
|
class StatementHandler(webapp.RequestHandler):
|
||||||
|
"""Evaluates a python statement in a given session and returns the result.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
self.response.headers['Content-Type'] = 'text/plain'
|
||||||
|
|
||||||
|
# extract the statement to be run
|
||||||
|
statement = self.request.get('statement')
|
||||||
|
if not statement:
|
||||||
|
return
|
||||||
|
|
||||||
|
# the python compiler doesn't like network line endings
|
||||||
|
statement = statement.replace('\r\n', '\n')
|
||||||
|
|
||||||
|
# add a couple newlines at the end of the statement. this makes
|
||||||
|
# single-line expressions such as 'class Foo: pass' evaluate happily.
|
||||||
|
statement += '\n\n'
|
||||||
|
|
||||||
|
# log and compile the statement up front
|
||||||
|
try:
|
||||||
|
logging.info('Compiling and evaluating:\n%s' % statement)
|
||||||
|
compiled = compile(statement, '<string>', 'single')
|
||||||
|
except:
|
||||||
|
self.response.out.write(traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
# create a dedicated module to be used as this statement's __main__
|
||||||
|
statement_module = new.module('__main__')
|
||||||
|
|
||||||
|
# use this request's __builtin__, since it changes on each request.
|
||||||
|
# this is needed for import statements, among other things.
|
||||||
|
import __builtin__
|
||||||
|
statement_module.__builtins__ = __builtin__
|
||||||
|
|
||||||
|
# load the session from the datastore
|
||||||
|
session = Session.get(self.request.get('session'))
|
||||||
|
|
||||||
|
# swap in our custom module for __main__. then unpickle the session
|
||||||
|
# globals, run the statement, and re-pickle the session globals, all
|
||||||
|
# inside it.
|
||||||
|
old_main = sys.modules.get('__main__')
|
||||||
|
try:
|
||||||
|
sys.modules['__main__'] = statement_module
|
||||||
|
statement_module.__name__ = '__main__'
|
||||||
|
|
||||||
|
# re-evaluate the unpicklables
|
||||||
|
for code in session.unpicklables:
|
||||||
|
exec code in statement_module.__dict__
|
||||||
|
|
||||||
|
# re-initialize the globals
|
||||||
|
for name, val in session.globals_dict().items():
|
||||||
|
try:
|
||||||
|
statement_module.__dict__[name] = val
|
||||||
|
except:
|
||||||
|
msg = 'Dropping %s since it could not be unpickled.\n' % name
|
||||||
|
self.response.out.write(msg)
|
||||||
|
logging.warning(msg + traceback.format_exc())
|
||||||
|
session.remove_global(name)
|
||||||
|
|
||||||
|
# run!
|
||||||
|
old_globals = dict(statement_module.__dict__)
|
||||||
|
try:
|
||||||
|
old_stdout = sys.stdout
|
||||||
|
old_stderr = sys.stderr
|
||||||
|
try:
|
||||||
|
sys.stdout = self.response.out
|
||||||
|
sys.stderr = self.response.out
|
||||||
|
exec compiled in statement_module.__dict__
|
||||||
|
finally:
|
||||||
|
sys.stdout = old_stdout
|
||||||
|
sys.stderr = old_stderr
|
||||||
|
except:
|
||||||
|
self.response.out.write(traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
# extract the new globals that this statement added
|
||||||
|
new_globals = {}
|
||||||
|
for name, val in statement_module.__dict__.items():
|
||||||
|
if name not in old_globals or val != old_globals[name]:
|
||||||
|
new_globals[name] = val
|
||||||
|
|
||||||
|
if True in [isinstance(val, UNPICKLABLE_TYPES)
|
||||||
|
for val in new_globals.values()]:
|
||||||
|
# this statement added an unpicklable global. store the statement and
|
||||||
|
# the names of all of the globals it added in the unpicklables.
|
||||||
|
session.add_unpicklable(statement, new_globals.keys())
|
||||||
|
logging.debug('Storing this statement as an unpicklable.')
|
||||||
|
|
||||||
|
else:
|
||||||
|
# this statement didn't add any unpicklables. pickle and store the
|
||||||
|
# new globals back into the datastore.
|
||||||
|
for name, val in new_globals.items():
|
||||||
|
if not name.startswith('__'):
|
||||||
|
session.set_global(name, val)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
sys.modules['__main__'] = old_main
|
||||||
|
|
||||||
|
session.put()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
application = webapp.WSGIApplication(
|
||||||
|
[('/gae_shell/', FrontPageHandler),
|
||||||
|
('/gae_shell/shell.do', StatementHandler)], debug=_DEBUG)
|
||||||
|
wsgiref.handlers.CGIHandler().run(application)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
308
tools/scripts/app_engine_server/gae_shell/shell.py~
Executable file
308
tools/scripts/app_engine_server/gae_shell/shell.py~
Executable file
@@ -0,0 +1,308 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2007 Google Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
An interactive, stateful AJAX shell that runs Python code on the server.
|
||||||
|
|
||||||
|
Part of http://code.google.com/p/google-app-engine-samples/.
|
||||||
|
|
||||||
|
May be run as a standalone app or in an existing app as an admin-only handler.
|
||||||
|
Can be used for system administration tasks, as an interactive way to try out
|
||||||
|
APIs, or as a debugging aid during development.
|
||||||
|
|
||||||
|
The logging, os, sys, db, and users modules are imported automatically.
|
||||||
|
|
||||||
|
Interpreter state is stored in the datastore so that variables, function
|
||||||
|
definitions, and other values in the global and local namespaces can be used
|
||||||
|
across commands.
|
||||||
|
|
||||||
|
To use the shell in your app, copy shell.py, static/*, and templates/* into
|
||||||
|
your app's source directory. Then, copy the URL handlers from app.yaml into
|
||||||
|
your app.yaml.
|
||||||
|
|
||||||
|
TODO: unit tests!
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import new
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import types
|
||||||
|
import wsgiref.handlers
|
||||||
|
|
||||||
|
from google.appengine.api import users
|
||||||
|
from google.appengine.ext import db
|
||||||
|
from google.appengine.ext import webapp
|
||||||
|
from google.appengine.ext.webapp import template
|
||||||
|
|
||||||
|
|
||||||
|
# Set to True if stack traces should be shown in the browser, etc.
|
||||||
|
_DEBUG = True
|
||||||
|
|
||||||
|
# The entity kind for shell sessions. Feel free to rename to suit your app.
|
||||||
|
_SESSION_KIND = '_Shell_Session'
|
||||||
|
|
||||||
|
# Types that can't be pickled.
|
||||||
|
UNPICKLABLE_TYPES = (
|
||||||
|
types.ModuleType,
|
||||||
|
types.TypeType,
|
||||||
|
types.ClassType,
|
||||||
|
types.FunctionType,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Unpicklable statements to seed new sessions with.
|
||||||
|
INITIAL_UNPICKLABLES = [
|
||||||
|
'import logging',
|
||||||
|
'import os',
|
||||||
|
'import sys',
|
||||||
|
'from google.appengine.ext import db',
|
||||||
|
'from google.appengine.api import users',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Session(db.Model):
|
||||||
|
"""A shell session. Stores the session's globals.
|
||||||
|
|
||||||
|
Each session globals is stored in one of two places:
|
||||||
|
|
||||||
|
If the global is picklable, it's stored in the parallel globals and
|
||||||
|
global_names list properties. (They're parallel lists to work around the
|
||||||
|
unfortunate fact that the datastore can't store dictionaries natively.)
|
||||||
|
|
||||||
|
If the global is not picklable (e.g. modules, classes, and functions), or if
|
||||||
|
it was created by the same statement that created an unpicklable global,
|
||||||
|
it's not stored directly. Instead, the statement is stored in the
|
||||||
|
unpicklables list property. On each request, before executing the current
|
||||||
|
statement, the unpicklable statements are evaluated to recreate the
|
||||||
|
unpicklable globals.
|
||||||
|
|
||||||
|
The unpicklable_names property stores all of the names of globals that were
|
||||||
|
added by unpicklable statements. When we pickle and store the globals after
|
||||||
|
executing a statement, we skip the ones in unpicklable_names.
|
||||||
|
|
||||||
|
Using Text instead of string is an optimization. We don't query on any of
|
||||||
|
these properties, so they don't need to be indexed.
|
||||||
|
"""
|
||||||
|
global_names = db.ListProperty(db.Text)
|
||||||
|
globals = db.ListProperty(db.Blob)
|
||||||
|
unpicklable_names = db.ListProperty(db.Text)
|
||||||
|
unpicklables = db.ListProperty(db.Text)
|
||||||
|
|
||||||
|
def set_global(self, name, value):
|
||||||
|
"""Adds a global, or updates it if it already exists.
|
||||||
|
|
||||||
|
Also removes the global from the list of unpicklable names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: the name of the global to remove
|
||||||
|
value: any picklable value
|
||||||
|
"""
|
||||||
|
blob = db.Blob(pickle.dumps(value))
|
||||||
|
|
||||||
|
if name in self.global_names:
|
||||||
|
index = self.global_names.index(name)
|
||||||
|
self.globals[index] = blob
|
||||||
|
else:
|
||||||
|
self.global_names.append(db.Text(name))
|
||||||
|
self.globals.append(blob)
|
||||||
|
|
||||||
|
self.remove_unpicklable_name(name)
|
||||||
|
|
||||||
|
def remove_global(self, name):
|
||||||
|
"""Removes a global, if it exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: string, the name of the global to remove
|
||||||
|
"""
|
||||||
|
if name in self.global_names:
|
||||||
|
index = self.global_names.index(name)
|
||||||
|
del self.global_names[index]
|
||||||
|
del self.globals[index]
|
||||||
|
|
||||||
|
def globals_dict(self):
|
||||||
|
"""Returns a dictionary view of the globals.
|
||||||
|
"""
|
||||||
|
return dict((name, pickle.loads(val))
|
||||||
|
for name, val in zip(self.global_names, self.globals))
|
||||||
|
|
||||||
|
def add_unpicklable(self, statement, names):
|
||||||
|
"""Adds a statement and list of names to the unpicklables.
|
||||||
|
|
||||||
|
Also removes the names from the globals.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
statement: string, the statement that created new unpicklable global(s).
|
||||||
|
names: list of strings; the names of the globals created by the statement.
|
||||||
|
"""
|
||||||
|
self.unpicklables.append(db.Text(statement))
|
||||||
|
|
||||||
|
for name in names:
|
||||||
|
self.remove_global(name)
|
||||||
|
if name not in self.unpicklable_names:
|
||||||
|
self.unpicklable_names.append(db.Text(name))
|
||||||
|
|
||||||
|
def remove_unpicklable_name(self, name):
|
||||||
|
"""Removes a name from the list of unpicklable names, if it exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: string, the name of the unpicklable global to remove
|
||||||
|
"""
|
||||||
|
if name in self.unpicklable_names:
|
||||||
|
self.unpicklable_names.remove(name)
|
||||||
|
|
||||||
|
|
||||||
|
class FrontPageHandler(webapp.RequestHandler):
|
||||||
|
"""Creates a new session and renders the shell.html template.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
# set up the session. TODO: garbage collect old shell sessions
|
||||||
|
session_key = self.request.get('session')
|
||||||
|
if session_key:
|
||||||
|
session = Session.get(session_key)
|
||||||
|
else:
|
||||||
|
# create a new session
|
||||||
|
session = Session()
|
||||||
|
session.unpicklables = [db.Text(line) for line in INITIAL_UNPICKLABLES]
|
||||||
|
session_key = session.put()
|
||||||
|
|
||||||
|
template_file = os.path.join(os.path.dirname(__file__), 'templates',
|
||||||
|
'shell.html')
|
||||||
|
session_url = '/?session=%s' % session_key
|
||||||
|
vars = { 'server_software': os.environ['SERVER_SOFTWARE'],
|
||||||
|
'python_version': sys.version,
|
||||||
|
'session': str(session_key),
|
||||||
|
'user': users.get_current_user(),
|
||||||
|
'login_url': users.create_login_url(session_url),
|
||||||
|
'logout_url': users.create_logout_url(session_url),
|
||||||
|
}
|
||||||
|
rendered = webapp.template.render(template_file, vars, debug=_DEBUG)
|
||||||
|
self.response.out.write(rendered)
|
||||||
|
|
||||||
|
|
||||||
|
class StatementHandler(webapp.RequestHandler):
|
||||||
|
"""Evaluates a python statement in a given session and returns the result.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
self.response.headers['Content-Type'] = 'text/plain'
|
||||||
|
|
||||||
|
# extract the statement to be run
|
||||||
|
statement = self.request.get('statement')
|
||||||
|
if not statement:
|
||||||
|
return
|
||||||
|
|
||||||
|
# the python compiler doesn't like network line endings
|
||||||
|
statement = statement.replace('\r\n', '\n')
|
||||||
|
|
||||||
|
# add a couple newlines at the end of the statement. this makes
|
||||||
|
# single-line expressions such as 'class Foo: pass' evaluate happily.
|
||||||
|
statement += '\n\n'
|
||||||
|
|
||||||
|
# log and compile the statement up front
|
||||||
|
try:
|
||||||
|
logging.info('Compiling and evaluating:\n%s' % statement)
|
||||||
|
compiled = compile(statement, '<string>', 'single')
|
||||||
|
except:
|
||||||
|
self.response.out.write(traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
# create a dedicated module to be used as this statement's __main__
|
||||||
|
statement_module = new.module('__main__')
|
||||||
|
|
||||||
|
# use this request's __builtin__, since it changes on each request.
|
||||||
|
# this is needed for import statements, among other things.
|
||||||
|
import __builtin__
|
||||||
|
statement_module.__builtins__ = __builtin__
|
||||||
|
|
||||||
|
# load the session from the datastore
|
||||||
|
session = Session.get(self.request.get('session'))
|
||||||
|
|
||||||
|
# swap in our custom module for __main__. then unpickle the session
|
||||||
|
# globals, run the statement, and re-pickle the session globals, all
|
||||||
|
# inside it.
|
||||||
|
old_main = sys.modules.get('__main__')
|
||||||
|
try:
|
||||||
|
sys.modules['__main__'] = statement_module
|
||||||
|
statement_module.__name__ = '__main__'
|
||||||
|
|
||||||
|
# re-evaluate the unpicklables
|
||||||
|
for code in session.unpicklables:
|
||||||
|
exec code in statement_module.__dict__
|
||||||
|
|
||||||
|
# re-initialize the globals
|
||||||
|
for name, val in session.globals_dict().items():
|
||||||
|
try:
|
||||||
|
statement_module.__dict__[name] = val
|
||||||
|
except:
|
||||||
|
msg = 'Dropping %s since it could not be unpickled.\n' % name
|
||||||
|
self.response.out.write(msg)
|
||||||
|
logging.warning(msg + traceback.format_exc())
|
||||||
|
session.remove_global(name)
|
||||||
|
|
||||||
|
# run!
|
||||||
|
old_globals = dict(statement_module.__dict__)
|
||||||
|
try:
|
||||||
|
old_stdout = sys.stdout
|
||||||
|
old_stderr = sys.stderr
|
||||||
|
try:
|
||||||
|
sys.stdout = self.response.out
|
||||||
|
sys.stderr = self.response.out
|
||||||
|
exec compiled in statement_module.__dict__
|
||||||
|
finally:
|
||||||
|
sys.stdout = old_stdout
|
||||||
|
sys.stderr = old_stderr
|
||||||
|
except:
|
||||||
|
self.response.out.write(traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
# extract the new globals that this statement added
|
||||||
|
new_globals = {}
|
||||||
|
for name, val in statement_module.__dict__.items():
|
||||||
|
if name not in old_globals or val != old_globals[name]:
|
||||||
|
new_globals[name] = val
|
||||||
|
|
||||||
|
if True in [isinstance(val, UNPICKLABLE_TYPES)
|
||||||
|
for val in new_globals.values()]:
|
||||||
|
# this statement added an unpicklable global. store the statement and
|
||||||
|
# the names of all of the globals it added in the unpicklables.
|
||||||
|
session.add_unpicklable(statement, new_globals.keys())
|
||||||
|
logging.debug('Storing this statement as an unpicklable.')
|
||||||
|
|
||||||
|
else:
|
||||||
|
# this statement didn't add any unpicklables. pickle and store the
|
||||||
|
# new globals back into the datastore.
|
||||||
|
for name, val in new_globals.items():
|
||||||
|
if not name.startswith('__'):
|
||||||
|
session.set_global(name, val)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
sys.modules['__main__'] = old_main
|
||||||
|
|
||||||
|
session.put()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
application = webapp.WSGIApplication(
|
||||||
|
[('/', FrontPageHandler),
|
||||||
|
('/shell.do', StatementHandler)], debug=_DEBUG)
|
||||||
|
wsgiref.handlers.CGIHandler().run(application)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
195
tools/scripts/app_engine_server/gae_shell/static/shell.js
Normal file
195
tools/scripts/app_engine_server/gae_shell/static/shell.js
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
// Copyright 2007 Google Inc.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview
|
||||||
|
* Javascript code for the interactive AJAX shell.
|
||||||
|
*
|
||||||
|
* Part of http://code.google.com/p/google-app-engine-samples/.
|
||||||
|
*
|
||||||
|
* Includes a function (shell.runStatement) that sends the current python
|
||||||
|
* statement in the shell prompt text box to the server, and a callback
|
||||||
|
* (shell.done) that displays the results when the XmlHttpRequest returns.
|
||||||
|
*
|
||||||
|
* Also includes cross-browser code (shell.getXmlHttpRequest) to get an
|
||||||
|
* XmlHttpRequest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shell namespace.
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
var shell = {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The shell history. history is an array of strings, ordered oldest to
|
||||||
|
* newest. historyCursor is the current history element that the user is on.
|
||||||
|
*
|
||||||
|
* The last history element is the statement that the user is currently
|
||||||
|
* typing. When a statement is run, it's frozen in the history, a new history
|
||||||
|
* element is added to the end of the array for the new statement, and
|
||||||
|
* historyCursor is updated to point to the new element.
|
||||||
|
*
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
shell.history = [''];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See {shell.history}
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
shell.historyCursor = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A constant for the XmlHttpRequest 'done' state.
|
||||||
|
* @type Number
|
||||||
|
*/
|
||||||
|
shell.DONE_STATE = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cross-browser function to get an XmlHttpRequest object.
|
||||||
|
*
|
||||||
|
* @return {XmlHttpRequest?} a new XmlHttpRequest
|
||||||
|
*/
|
||||||
|
shell.getXmlHttpRequest = function() {
|
||||||
|
if (window.XMLHttpRequest) {
|
||||||
|
return new XMLHttpRequest();
|
||||||
|
} else if (window.ActiveXObject) {
|
||||||
|
try {
|
||||||
|
return new ActiveXObject('Msxml2.XMLHTTP');
|
||||||
|
} catch(e) {
|
||||||
|
return new ActiveXObject('Microsoft.XMLHTTP');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the prompt textarea's onkeypress handler. Depending on the key that
|
||||||
|
* was pressed, it will run the statement, navigate the history, or update the
|
||||||
|
* current statement in the history.
|
||||||
|
*
|
||||||
|
* @param {Event} event the keypress event
|
||||||
|
* @return {Boolean} false to tell the browser not to submit the form.
|
||||||
|
*/
|
||||||
|
shell.onPromptKeyPress = function(event) {
|
||||||
|
var statement = document.getElementById('statement');
|
||||||
|
|
||||||
|
if (this.historyCursor == this.history.length - 1) {
|
||||||
|
// we're on the current statement. update it in the history before doing
|
||||||
|
// anything.
|
||||||
|
this.history[this.historyCursor] = statement.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should we pull something from the history?
|
||||||
|
if (event.ctrlKey && event.keyCode == 38 /* up arrow */) {
|
||||||
|
if (this.historyCursor > 0) {
|
||||||
|
statement.value = this.history[--this.historyCursor];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (event.ctrlKey && event.keyCode == 40 /* down arrow */) {
|
||||||
|
if (this.historyCursor < this.history.length - 1) {
|
||||||
|
statement.value = this.history[++this.historyCursor];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (!event.altKey) {
|
||||||
|
// probably changing the statement. update it in the history.
|
||||||
|
this.historyCursor = this.history.length - 1;
|
||||||
|
this.history[this.historyCursor] = statement.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should we submit?
|
||||||
|
var ctrlEnter = (document.getElementById('submit_key').value == 'ctrl-enter');
|
||||||
|
if (event.keyCode == 13 /* enter */ && !event.altKey && !event.shiftKey &&
|
||||||
|
event.ctrlKey == ctrlEnter) {
|
||||||
|
return this.runStatement();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The XmlHttpRequest callback. If the request succeeds, it adds the command
|
||||||
|
* and its resulting output to the shell history div.
|
||||||
|
*
|
||||||
|
* @param {XmlHttpRequest} req the XmlHttpRequest we used to send the current
|
||||||
|
* statement to the server
|
||||||
|
*/
|
||||||
|
shell.done = function(req) {
|
||||||
|
if (req.readyState == this.DONE_STATE) {
|
||||||
|
var statement = document.getElementById('statement')
|
||||||
|
statement.className = 'prompt';
|
||||||
|
|
||||||
|
// add the command to the shell output
|
||||||
|
var output = document.getElementById('output');
|
||||||
|
|
||||||
|
output.value += '\n>>> ' + statement.value;
|
||||||
|
statement.value = '';
|
||||||
|
|
||||||
|
// add a new history element
|
||||||
|
this.history.push('');
|
||||||
|
this.historyCursor = this.history.length - 1;
|
||||||
|
|
||||||
|
// add the command's result
|
||||||
|
var result = req.responseText.replace(/^\s*|\s*$/g, ''); // trim whitespace
|
||||||
|
if (result != '')
|
||||||
|
output.value += '\n' + result;
|
||||||
|
|
||||||
|
// scroll to the bottom
|
||||||
|
output.scrollTop = output.scrollHeight;
|
||||||
|
if (output.createTextRange) {
|
||||||
|
var range = output.createTextRange();
|
||||||
|
range.collapse(false);
|
||||||
|
range.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the form's onsubmit handler. It sends the python statement to the
|
||||||
|
* server, and registers shell.done() as the callback to run when it returns.
|
||||||
|
*
|
||||||
|
* @return {Boolean} false to tell the browser not to submit the form.
|
||||||
|
*/
|
||||||
|
shell.runStatement = function() {
|
||||||
|
var form = document.getElementById('form');
|
||||||
|
|
||||||
|
// build a XmlHttpRequest
|
||||||
|
var req = this.getXmlHttpRequest();
|
||||||
|
if (!req) {
|
||||||
|
document.getElementById('ajax-status').innerHTML =
|
||||||
|
"<span class='error'>Your browser doesn't support AJAX. :(</span>";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.onreadystatechange = function() { shell.done(req); };
|
||||||
|
|
||||||
|
// build the query parameter string
|
||||||
|
var params = '';
|
||||||
|
for (i = 0; i < form.elements.length; i++) {
|
||||||
|
var elem = form.elements[i];
|
||||||
|
if (elem.type != 'submit' && elem.type != 'button' && elem.id != 'caret') {
|
||||||
|
var value = escape(elem.value).replace(/\+/g, '%2B'); // escape ignores +
|
||||||
|
params += '&' + elem.name + '=' + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the request and tell the user.
|
||||||
|
document.getElementById('statement').className = 'prompt processing';
|
||||||
|
req.open(form.method, form.action + '?' + params, true);
|
||||||
|
req.setRequestHeader('Content-type',
|
||||||
|
'application/x-www-form-urlencoded;charset=UTF-8');
|
||||||
|
req.send(null);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
BIN
tools/scripts/app_engine_server/gae_shell/static/spinner.gif
Normal file
BIN
tools/scripts/app_engine_server/gae_shell/static/spinner.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
122
tools/scripts/app_engine_server/gae_shell/templates/shell.html
Normal file
122
tools/scripts/app_engine_server/gae_shell/templates/shell.html
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
|
<title> Interactive Shell </title>
|
||||||
|
<script type="text/javascript" src="/gae_shell/static/shell.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt, #output {
|
||||||
|
width: 45em;
|
||||||
|
border: 1px solid silver;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-size: 10pt;
|
||||||
|
margin: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
padding-right: 0em;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolbar {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#caret {
|
||||||
|
width: 2.5em;
|
||||||
|
margin-right: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
border-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#statement {
|
||||||
|
width: 43em;
|
||||||
|
margin-left: -1em;
|
||||||
|
padding-left: 0px;
|
||||||
|
border-left: 0px;
|
||||||
|
background-position: top right;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.processing {
|
||||||
|
background-image: url("/gae_shell/static/spinner.gif");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ajax-status {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
color: #8AD;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: #F44;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p> Interactive server-side Python shell for
|
||||||
|
<a href="http://code.google.com/appengine/">Google App Engine</a>.
|
||||||
|
(<a href="http://code.google.com/p/google-app-engine-samples/">source</a>)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<textarea id="output" rows="22" readonly="readonly">
|
||||||
|
{{ server_software }}
|
||||||
|
Python {{ python_version }}
|
||||||
|
</textarea>
|
||||||
|
|
||||||
|
<form id="form" action="shell.do" method="get">
|
||||||
|
<nobr>
|
||||||
|
<textarea class="prompt" id="caret" readonly="readonly" rows="4"
|
||||||
|
onfocus="document.getElementById('statement').focus()"
|
||||||
|
>>>></textarea>
|
||||||
|
<textarea class="prompt" name="statement" id="statement" rows="4"
|
||||||
|
onkeypress="return shell.onPromptKeyPress(event);"></textarea>
|
||||||
|
</nobr>
|
||||||
|
<input type="hidden" name="session" value="{{ session }}" />
|
||||||
|
<input type="submit" style="display: none" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p id="ajax-status"></p>
|
||||||
|
|
||||||
|
<p id="toolbar">
|
||||||
|
{% if user %}
|
||||||
|
<span class="username">{{ user.nickname }}</span>
|
||||||
|
(<a href="{{ logout_url }}">log out</a>)
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ login_url }}">log in</a>
|
||||||
|
{% endif %}
|
||||||
|
| Ctrl-Up/Down for history |
|
||||||
|
<select id="submit_key">
|
||||||
|
<option value="enter">Enter</option>
|
||||||
|
<option value="ctrl-enter" selected="selected">Ctrl-Enter</option>
|
||||||
|
</select>
|
||||||
|
<label for="submit_key">submits</label>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('statement').focus();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
12
tools/scripts/app_engine_server/index.yaml
Normal file
12
tools/scripts/app_engine_server/index.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
indexes:
|
||||||
|
|
||||||
|
# AUTOGENERATED
|
||||||
|
|
||||||
|
# This index.yaml is automatically updated whenever the dev_appserver
|
||||||
|
# detects that a new type of query is run. If you want to manage the
|
||||||
|
# index.yaml file manually, remove the above marker line (the line
|
||||||
|
# saying "# AUTOGENERATED"). If you want to manage some indexes
|
||||||
|
# manually, move them above the marker line. The index.yaml file is
|
||||||
|
# automatically uploaded to the admin console when you next deploy
|
||||||
|
# your application using appcfg.py.
|
||||||
|
|
||||||
412
tools/scripts/app_engine_server/memcache_zipserve.py
Normal file
412
tools/scripts/app_engine_server/memcache_zipserve.py
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2009 Google Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""A class to serve pages from zip files and use memcache for performance.
|
||||||
|
|
||||||
|
This contains a class and a function to create an anonymous instance of the
|
||||||
|
class to serve HTTP GET requests. Memcache is used to increase response speed
|
||||||
|
and lower processing cycles used in serving. Credit to Guido van Rossum and
|
||||||
|
his implementation of zipserve which served as a reference as I wrote this.
|
||||||
|
|
||||||
|
MemcachedZipHandler: Class that serves request
|
||||||
|
create_handler: method to create instance of MemcachedZipHandler
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'jmatt@google.com (Justin Mattson)'
|
||||||
|
|
||||||
|
import email.Utils
|
||||||
|
import logging
|
||||||
|
import mimetypes
|
||||||
|
import time
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
from google.appengine.api import memcache
|
||||||
|
from google.appengine.ext import webapp
|
||||||
|
from google.appengine.ext.webapp import util
|
||||||
|
|
||||||
|
|
||||||
|
def create_handler(zip_files, max_age=None, public=None):
|
||||||
|
"""Factory method to create a MemcachedZipHandler instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
zip_files: A list of file names, or a list of lists of file name, first
|
||||||
|
member of file mappings. See MemcachedZipHandler documentation for
|
||||||
|
more information about using the list of lists format
|
||||||
|
max_age: The maximum client-side cache lifetime
|
||||||
|
public: Whether this should be declared public in the client-side cache
|
||||||
|
Returns:
|
||||||
|
A MemcachedZipHandler wrapped in a pretty, anonymous bow for use with App
|
||||||
|
Engine
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: if the zip_files argument is not a list
|
||||||
|
"""
|
||||||
|
# verify argument integrity. If the argument is passed in list format,
|
||||||
|
# convert it to list of lists format
|
||||||
|
|
||||||
|
if zip_files and type(zip_files).__name__ == 'list':
|
||||||
|
num_items = len(zip_files)
|
||||||
|
while num_items > 0:
|
||||||
|
if type(zip_files[num_items - 1]).__name__ != 'list':
|
||||||
|
zip_files[num_items - 1] = [zip_files[num_items-1]]
|
||||||
|
num_items -= 1
|
||||||
|
else:
|
||||||
|
raise ValueError('File name arguments must be a list')
|
||||||
|
|
||||||
|
class HandlerWrapper(MemcachedZipHandler):
|
||||||
|
"""Simple wrapper for an instance of MemcachedZipHandler.
|
||||||
|
|
||||||
|
I'm still not sure why this is needed
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get(self, name):
|
||||||
|
self.zipfilenames = zip_files
|
||||||
|
self.TrueGet(name)
|
||||||
|
if max_age is not None:
|
||||||
|
MAX_AGE = max_age
|
||||||
|
if public is not None:
|
||||||
|
PUBLIC = public
|
||||||
|
|
||||||
|
return HandlerWrapper
|
||||||
|
|
||||||
|
|
||||||
|
class MemcachedZipHandler(webapp.RequestHandler):
|
||||||
|
"""Handles get requests for a given URL.
|
||||||
|
|
||||||
|
Serves a GET request from a series of zip files. As files are served they are
|
||||||
|
put into memcache, which is much faster than retreiving them from the zip
|
||||||
|
source file again. It also uses considerably fewer CPU cycles.
|
||||||
|
"""
|
||||||
|
zipfile_cache = {} # class cache of source zip files
|
||||||
|
MAX_AGE = 600 # max client-side cache lifetime
|
||||||
|
PUBLIC = True # public cache setting
|
||||||
|
CACHE_PREFIX = 'cache://' # memcache key prefix for actual URLs
|
||||||
|
NEG_CACHE_PREFIX = 'noncache://' # memcache key prefix for non-existant URL
|
||||||
|
|
||||||
|
def TrueGet(self, name):
|
||||||
|
"""The top-level entry point to serving requests.
|
||||||
|
|
||||||
|
Called 'True' get because it does the work when called from the wrapper
|
||||||
|
class' get method
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: URL requested
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
name = self.PreprocessUrl(name)
|
||||||
|
|
||||||
|
# see if we have the page in the memcache
|
||||||
|
resp_data = self.GetFromCache(name)
|
||||||
|
if resp_data is None:
|
||||||
|
logging.info('Cache miss for %s', name)
|
||||||
|
resp_data = self.GetFromNegativeCache(name)
|
||||||
|
if resp_data is None:
|
||||||
|
resp_data = self.GetFromStore(name)
|
||||||
|
|
||||||
|
# IF we have the file, put it in the memcache
|
||||||
|
# ELSE put it in the negative cache
|
||||||
|
if resp_data is not None:
|
||||||
|
self.StoreOrUpdateInCache(name, resp_data)
|
||||||
|
else:
|
||||||
|
logging.info('Adding %s to negative cache, serving 404', name)
|
||||||
|
self.StoreInNegativeCache(name)
|
||||||
|
self.Write404Error()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.Write404Error()
|
||||||
|
return
|
||||||
|
|
||||||
|
content_type, encoding = mimetypes.guess_type(name)
|
||||||
|
if content_type:
|
||||||
|
self.response.headers['Content-Type'] = content_type
|
||||||
|
self.SetCachingHeaders()
|
||||||
|
self.response.out.write(resp_data)
|
||||||
|
|
||||||
|
def PreprocessUrl(self, name):
|
||||||
|
"""Any preprocessing work on the URL when it comes it.
|
||||||
|
|
||||||
|
Put any work related to interpretting the incoming URL here. For example,
|
||||||
|
this is used to redirect requests for a directory to the index.html file
|
||||||
|
in that directory. Subclasses should override this method to do different
|
||||||
|
preprocessing.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The incoming URL
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The processed URL
|
||||||
|
"""
|
||||||
|
# handle special case of requesting the domain itself
|
||||||
|
if not name:
|
||||||
|
name = 'index.html'
|
||||||
|
|
||||||
|
# determine if this is a request for a directory
|
||||||
|
final_path_segment = name
|
||||||
|
final_slash_offset = name.rfind('/')
|
||||||
|
if final_slash_offset != len(name) - 1:
|
||||||
|
final_path_segment = name[final_slash_offset + 1:]
|
||||||
|
if final_path_segment.find('.') == -1:
|
||||||
|
name = ''.join([name, '/'])
|
||||||
|
|
||||||
|
# if this is a directory, redirect to index.html
|
||||||
|
if name[len(name) - 1:] == '/':
|
||||||
|
return '%s%s' % (name, 'index.html')
|
||||||
|
else:
|
||||||
|
return name
|
||||||
|
|
||||||
|
def GetFromStore(self, file_path):
|
||||||
|
"""Retrieve file from zip files.
|
||||||
|
|
||||||
|
Get the file from the source, it must not have been in the memcache. If
|
||||||
|
possible, we'll use the zip file index to quickly locate where the file
|
||||||
|
should be found. (See MapToFileArchive documentation for assumptions about
|
||||||
|
file ordering.) If we don't have an index or don't find the file where the
|
||||||
|
index says we should, look through all the zip files to find it.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: the file that we're looking for
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The contents of the requested file
|
||||||
|
"""
|
||||||
|
resp_data = None
|
||||||
|
file_itr = iter(self.zipfilenames)
|
||||||
|
|
||||||
|
# check the index, if we have one, to see what archive the file is in
|
||||||
|
archive_name = self.MapFileToArchive(file_path)
|
||||||
|
if not archive_name:
|
||||||
|
archive_name = file_itr.next()[0]
|
||||||
|
|
||||||
|
while resp_data is None and archive_name:
|
||||||
|
zip_archive = self.LoadZipFile(archive_name)
|
||||||
|
if zip_archive:
|
||||||
|
|
||||||
|
# we expect some lookups will fail, and that's okay, 404s will deal
|
||||||
|
# with that
|
||||||
|
try:
|
||||||
|
resp_data = zip_archive.read(file_path)
|
||||||
|
except (KeyError, RuntimeError), err:
|
||||||
|
# no op
|
||||||
|
x = False
|
||||||
|
if resp_data is not None:
|
||||||
|
logging.info('%s read from %s', file_path, archive_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
archive_name = file_itr.next()[0]
|
||||||
|
except (StopIteration), err:
|
||||||
|
archive_name = False
|
||||||
|
|
||||||
|
return resp_data
|
||||||
|
|
||||||
|
def LoadZipFile(self, zipfilename):
|
||||||
|
"""Convenience method to load zip file.
|
||||||
|
|
||||||
|
Just a convenience method to load the zip file from the data store. This is
|
||||||
|
useful if we ever want to change data stores and also as a means of
|
||||||
|
dependency injection for testing. This method will look at our file cache
|
||||||
|
first, and then load and cache the file if there's a cache miss
|
||||||
|
|
||||||
|
Args:
|
||||||
|
zipfilename: the name of the zip file to load
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The zip file requested, or None if there is an I/O error
|
||||||
|
"""
|
||||||
|
zip_archive = None
|
||||||
|
zip_archive = self.zipfile_cache.get(zipfilename)
|
||||||
|
if zip_archive is None:
|
||||||
|
try:
|
||||||
|
zip_archive = zipfile.ZipFile(zipfilename)
|
||||||
|
self.zipfile_cache[zipfilename] = zip_archive
|
||||||
|
except (IOError, RuntimeError), err:
|
||||||
|
logging.error('Can\'t open zipfile %s, cause: %s' % (zipfilename,
|
||||||
|
err))
|
||||||
|
return zip_archive
|
||||||
|
|
||||||
|
def MapFileToArchive(self, file_path):
|
||||||
|
"""Given a file name, determine what archive it should be in.
|
||||||
|
|
||||||
|
This method makes two critical assumptions.
|
||||||
|
(1) The zip files passed as an argument to the handler, if concatenated
|
||||||
|
in that same order, would result in a total ordering
|
||||||
|
of all the files. See (2) for ordering type.
|
||||||
|
(2) Upper case letters before lower case letters. The traversal of a
|
||||||
|
directory tree is depth first. A parent directory's files are added
|
||||||
|
before the files of any child directories
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: the file to be mapped to an archive
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The name of the archive where we expect the file to be
|
||||||
|
"""
|
||||||
|
num_archives = len(self.zipfilenames)
|
||||||
|
while num_archives > 0:
|
||||||
|
target = self.zipfilenames[num_archives - 1]
|
||||||
|
if len(target) > 1:
|
||||||
|
if self.CompareFilenames(target[1], file_path) >= 0:
|
||||||
|
return target[0]
|
||||||
|
num_archives -= 1
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def CompareFilenames(self, file1, file2):
|
||||||
|
"""Determines whether file1 is lexigraphically 'before' file2.
|
||||||
|
|
||||||
|
WARNING: This method assumes that paths are output in a depth-first,
|
||||||
|
with parent directories' files stored before childs'
|
||||||
|
|
||||||
|
We say that file1 is lexigraphically before file2 if the last non-matching
|
||||||
|
path segment of file1 is alphabetically before file2.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file1: the first file path
|
||||||
|
file2: the second file path
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A positive number if file1 is before file2
|
||||||
|
A negative number if file2 is before file1
|
||||||
|
0 if filenames are the same
|
||||||
|
"""
|
||||||
|
f1_segments = file1.split('/')
|
||||||
|
f2_segments = file2.split('/')
|
||||||
|
|
||||||
|
segment_ptr = 0
|
||||||
|
while (segment_ptr < len(f1_segments) and
|
||||||
|
segment_ptr < len(f2_segments) and
|
||||||
|
f1_segments[segment_ptr] == f2_segments[segment_ptr]):
|
||||||
|
segment_ptr += 1
|
||||||
|
|
||||||
|
if len(f1_segments) == len(f2_segments):
|
||||||
|
|
||||||
|
# we fell off the end, the paths much be the same
|
||||||
|
if segment_ptr == len(f1_segments):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# we didn't fall of the end, compare the segments where they differ
|
||||||
|
if f1_segments[segment_ptr] < f2_segments[segment_ptr]:
|
||||||
|
return 1
|
||||||
|
elif f1_segments[segment_ptr] > f2_segments[segment_ptr]:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# the number of segments differs, we either mismatched comparing
|
||||||
|
# directories, or comparing a file to a directory
|
||||||
|
else:
|
||||||
|
|
||||||
|
# IF we were looking at the last segment of one of the paths,
|
||||||
|
# the one with fewer segments is first because files come before
|
||||||
|
# directories
|
||||||
|
# ELSE we just need to compare directory names
|
||||||
|
if (segment_ptr + 1 == len(f1_segments) or
|
||||||
|
segment_ptr + 1 == len(f2_segments)):
|
||||||
|
return len(f2_segments) - len(f1_segments)
|
||||||
|
else:
|
||||||
|
if f1_segments[segment_ptr] < f2_segments[segment_ptr]:
|
||||||
|
return 1
|
||||||
|
elif f1_segments[segment_ptr] > f2_segments[segment_ptr]:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def SetCachingHeaders(self):
|
||||||
|
"""Set caching headers for the request."""
|
||||||
|
max_age = self.MAX_AGE
|
||||||
|
self.response.headers['Expires'] = email.Utils.formatdate(
|
||||||
|
time.time() + max_age, usegmt=True)
|
||||||
|
cache_control = []
|
||||||
|
if self.PUBLIC:
|
||||||
|
cache_control.append('public')
|
||||||
|
cache_control.append('max-age=%d' % max_age)
|
||||||
|
self.response.headers['Cache-Control'] = ', '.join(cache_control)
|
||||||
|
|
||||||
|
def GetFromCache(self, filename):
|
||||||
|
"""Get file from memcache, if available.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: The URL of the file to return
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The content of the file
|
||||||
|
"""
|
||||||
|
return memcache.get('%s%s' % (self.CACHE_PREFIX, filename))
|
||||||
|
|
||||||
|
def StoreOrUpdateInCache(self, filename, data):
|
||||||
|
"""Store data in the cache.
|
||||||
|
|
||||||
|
Store a piece of data in the memcache. Memcache has a maximum item size of
|
||||||
|
1*10^6 bytes. If the data is too large, fail, but log the failure. Future
|
||||||
|
work will consider compressing the data before storing or chunking it
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: the name of the file to store
|
||||||
|
data: the data of the file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if not memcache.add('%s%s' % (self.CACHE_PREFIX, filename), data):
|
||||||
|
memcache.replace('%s%s' % (self.CACHE_PREFIX, filename), data)
|
||||||
|
except (ValueError), err:
|
||||||
|
logging.warning('Data size too large to cache\n%s' % err)
|
||||||
|
|
||||||
|
def Write404Error(self):
|
||||||
|
"""Ouptut a simple 404 response."""
|
||||||
|
self.error(404)
|
||||||
|
self.response.out.write(
|
||||||
|
''.join(['<html><head><title>404: Not Found</title></head>',
|
||||||
|
'<body><b><h2>Error 404</h2><br/>',
|
||||||
|
'File not found</b></body></html>']))
|
||||||
|
|
||||||
|
def StoreInNegativeCache(self, filename):
|
||||||
|
"""If a non-existant URL is accessed, cache this result as well.
|
||||||
|
|
||||||
|
Future work should consider setting a maximum negative cache size to
|
||||||
|
prevent it from from negatively impacting the real cache.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: URL to add ot negative cache
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
memcache.add('%s%s' % (self.NEG_CACHE_PREFIX, filename), -1)
|
||||||
|
|
||||||
|
def GetFromNegativeCache(self, filename):
|
||||||
|
"""Retrieve from negative cache.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: URL to retreive
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The file contents if present in the negative cache.
|
||||||
|
"""
|
||||||
|
return memcache.get('%s%s' % (self.NEG_CACHE_PREFIX, filename))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
application = webapp.WSGIApplication([('/([^/]+)/(.*)',
|
||||||
|
MemcachedZipHandler)])
|
||||||
|
util.run_wsgi_app(application)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -2,22 +2,36 @@
|
|||||||
|
|
||||||
function replace()
|
function replace()
|
||||||
{
|
{
|
||||||
echo replacing $1
|
echo replacing $1
|
||||||
rm -rf $UNZIPPED_BASE_DIR/$1
|
rm $V -rf "$UNZIPPED_BASE_DIR"/$1
|
||||||
cp -rf $UNZIPPED_IMAGE_DIR/$1 $UNZIPPED_BASE_DIR/$1
|
cp $V -rf "$UNZIPPED_IMAGE_DIR"/$1 "$UNZIPPED_BASE_DIR"/$1
|
||||||
}
|
}
|
||||||
|
|
||||||
BASE=$1
|
V=""
|
||||||
IMAGES=$2
|
Q="-q"
|
||||||
OUTPUT=$3
|
if [ "$1" == "-v" ]; then
|
||||||
|
V="-v"
|
||||||
|
Q=""
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z $BASE || -z $IMAGES || -z $OUTPUT ]] ; then
|
NOZIP=""
|
||||||
echo "usage: combine_sdks.sh BASE IMAGES OUTPUT"
|
if [ "$1" == "-nozip" ]; then
|
||||||
|
NOZIP="1"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
BASE="$1"
|
||||||
|
IMAGES="$2"
|
||||||
|
OUTPUT="$3"
|
||||||
|
|
||||||
|
if [[ -z "$BASE" || -z "$IMAGES" || -z "$OUTPUT" ]] ; then
|
||||||
|
echo "usage: combine_sdks.sh [-v] [-nozip] BASE IMAGES OUTPUT"
|
||||||
echo
|
echo
|
||||||
echo " BASE and IMAGES should be sdk zip files. The system image files,"
|
echo " BASE and IMAGES should be sdk zip files. The system image files,"
|
||||||
echo " emulator and other runtime files will be copied from IMAGES and"
|
echo " emulator and other runtime files will be copied from IMAGES and"
|
||||||
echo " everything else will be copied from BASE. All of this will be"
|
echo " everything else will be copied from BASE. All of this will be"
|
||||||
echo " bundled into OUTPUT and zipped up again."
|
echo " bundled into OUTPUT and zipped up again (unless -nozip is specified)."
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -26,15 +40,25 @@ TMP=$(mktemp -d)
|
|||||||
|
|
||||||
TMP_ZIP=tmp.zip
|
TMP_ZIP=tmp.zip
|
||||||
|
|
||||||
BASE_DIR=$TMP/base
|
# determine executable extension
|
||||||
IMAGES_DIR=$TMP/images
|
case `uname -s` in
|
||||||
OUTPUT_TMP_ZIP=$BASE_DIR/$TMP_ZIP
|
*_NT-*) # for Windows
|
||||||
|
EXE=.exe
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
EXE=
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
unzip -q $BASE -d $BASE_DIR
|
BASE_DIR="$TMP"/base
|
||||||
unzip -q $IMAGES -d $IMAGES_DIR
|
IMAGES_DIR="$TMP"/images
|
||||||
|
OUTPUT_TMP_ZIP="$BASE_DIR/$TMP_ZIP"
|
||||||
|
|
||||||
UNZIPPED_BASE_DIR=$(echo $BASE_DIR/*)
|
unzip $Q "$BASE" -d "$BASE_DIR"
|
||||||
UNZIPPED_IMAGE_DIR=$(echo $IMAGES_DIR/*)
|
unzip $Q "$IMAGES" -d "$IMAGES_DIR"
|
||||||
|
|
||||||
|
UNZIPPED_BASE_DIR=$(echo "$BASE_DIR"/*)
|
||||||
|
UNZIPPED_IMAGE_DIR=$(echo "$IMAGES_DIR"/*)
|
||||||
|
|
||||||
#
|
#
|
||||||
# The commands to copy over the files that we want
|
# The commands to copy over the files that we want
|
||||||
@@ -42,21 +66,40 @@ UNZIPPED_IMAGE_DIR=$(echo $IMAGES_DIR/*)
|
|||||||
|
|
||||||
# replace tools/emulator # at this time we do not want the exe from SDK1.x
|
# replace tools/emulator # at this time we do not want the exe from SDK1.x
|
||||||
replace tools/lib/images
|
replace tools/lib/images
|
||||||
|
replace tools/lib/res
|
||||||
|
replace tools/lib/fonts
|
||||||
|
replace tools/lib/layoutlib.jar
|
||||||
replace docs
|
replace docs
|
||||||
replace android.jar
|
replace android.jar
|
||||||
|
|
||||||
|
for i in widgets categories broadcast_actions service_actions; do
|
||||||
|
replace tools/lib/$i.txt
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -d "$UNZIPPED_BASE_DIR"/usb_driver ]; then
|
||||||
|
replace usb_driver
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
|
|
||||||
pushd $BASE_DIR &> /dev/null
|
if [ -z "$NOZIP" ]; then
|
||||||
# rename the directory to the leaf minus the .zip of OUTPUT
|
pushd "$BASE_DIR" &> /dev/null
|
||||||
LEAF=$(echo $OUTPUT | sed -e "s:.*\.zip/::" | sed -e "s:.zip$::")
|
# rename the directory to the leaf minus the .zip of OUTPUT
|
||||||
mv * $LEAF
|
LEAF=$(echo "$OUTPUT" | sed -e "s:.*\.zip/::" | sed -e "s:.zip$::")
|
||||||
# zip it
|
mv * "$LEAF"
|
||||||
zip -qr $TMP_ZIP $LEAF
|
# zip it
|
||||||
popd &> /dev/null
|
zip $V -qr "$TMP_ZIP" "$LEAF"
|
||||||
|
popd &> /dev/null
|
||||||
|
|
||||||
cp $OUTPUT_TMP_ZIP $OUTPUT
|
cp $V "$OUTPUT_TMP_ZIP" "$OUTPUT"
|
||||||
|
echo "Combined SDK available at $OUTPUT"
|
||||||
|
else
|
||||||
|
OUT_DIR="${OUTPUT//.zip/}"
|
||||||
|
mv $V "$BASE_DIR"/* "$OUT_DIR"
|
||||||
|
echo "Unzipped combined SDK available at $OUT_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm $V -rf "$TMP"
|
||||||
|
|
||||||
rm -rf $TMP
|
|
||||||
|
|||||||
@@ -31,15 +31,16 @@ import java.util.Map.Entry;
|
|||||||
* <li>define flags for your actions.
|
* <li>define flags for your actions.
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
* To use, call {@link #parseArgs(String[])} and then call {@link #getValue(String, String)}.
|
* To use, call {@link #parseArgs(String[])} and then
|
||||||
|
* call {@link #getValue(String, String, String)}.
|
||||||
*/
|
*/
|
||||||
public class CommandLineProcessor {
|
public class CommandLineProcessor {
|
||||||
|
|
||||||
/** Internal action name for all global flags. */
|
/** Internal verb name for internally hidden flags. */
|
||||||
public final static String GLOBAL_FLAG = "global";
|
public final static String GLOBAL_FLAG_VERB = "@@internal@@";
|
||||||
/** Internal action name for internally hidden flags.
|
|
||||||
* This is currently used to store the requested action name. */
|
/** String to use when the verb doesn't need any object. */
|
||||||
public final static String INTERNAL_FLAG = "internal";
|
public final static String NO_VERB_OBJECT = "";
|
||||||
|
|
||||||
/** The global help flag. */
|
/** The global help flag. */
|
||||||
public static final String KEY_HELP = "help";
|
public static final String KEY_HELP = "help";
|
||||||
@@ -47,36 +48,50 @@ public class CommandLineProcessor {
|
|||||||
public static final String KEY_VERBOSE = "verbose";
|
public static final String KEY_VERBOSE = "verbose";
|
||||||
/** The global silent flag. */
|
/** The global silent flag. */
|
||||||
public static final String KEY_SILENT = "silent";
|
public static final String KEY_SILENT = "silent";
|
||||||
/** The internal action flag. */
|
|
||||||
public static final String KEY_ACTION = "action";
|
|
||||||
|
|
||||||
/** List of available actions.
|
/** Verb requested by the user. Null if none specified, which will be an error. */
|
||||||
|
private String mVerbRequested;
|
||||||
|
/** Direct object requested by the user. Can be null. */
|
||||||
|
private String mDirectObjectRequested;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action definitions.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Each entry must be a 2-string array with first the action name and then
|
* Each entry is a string array with:
|
||||||
* a description.
|
* <ul>
|
||||||
|
* <li> the verb.
|
||||||
|
* <li> a direct object (use #NO_VERB_OBJECT if there's no object).
|
||||||
|
* <li> a description.
|
||||||
|
* <li> an alternate form for the object (e.g. plural).
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
private final String[][] mActions;
|
private final String[][] mActions;
|
||||||
/** The hash of all defined arguments.
|
|
||||||
|
private static final int ACTION_VERB_INDEX = 0;
|
||||||
|
private static final int ACTION_OBJECT_INDEX = 1;
|
||||||
|
private static final int ACTION_DESC_INDEX = 2;
|
||||||
|
private static final int ACTION_ALT_OBJECT_INDEX = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of all defined arguments.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The key is a string "action/longName".
|
* The key is a string "verb/directObject/longName".
|
||||||
*/
|
*/
|
||||||
private final HashMap<String, Arg> mArguments = new HashMap<String, Arg>();
|
private final HashMap<String, Arg> mArguments = new HashMap<String, Arg>();
|
||||||
|
/** Logger */
|
||||||
private final ISdkLog mLog;
|
private final ISdkLog mLog;
|
||||||
|
|
||||||
public CommandLineProcessor(ISdkLog logger, String[][] actions) {
|
public CommandLineProcessor(ISdkLog logger, String[][] actions) {
|
||||||
mLog = logger;
|
mLog = logger;
|
||||||
mActions = actions;
|
mActions = actions;
|
||||||
|
|
||||||
define(MODE.STRING, false, INTERNAL_FLAG, null, KEY_ACTION,
|
define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "v", KEY_VERBOSE,
|
||||||
"Selected Action", null);
|
|
||||||
|
|
||||||
define(MODE.BOOLEAN, false, GLOBAL_FLAG, "v", KEY_VERBOSE,
|
|
||||||
"Verbose mode: errors, warnings and informational messages are printed.",
|
"Verbose mode: errors, warnings and informational messages are printed.",
|
||||||
false);
|
false);
|
||||||
define(MODE.BOOLEAN, false, GLOBAL_FLAG, "s", KEY_SILENT,
|
define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "s", KEY_SILENT,
|
||||||
"Silent mode: only errors are printed out.",
|
"Silent mode: only errors are printed out.",
|
||||||
false);
|
false);
|
||||||
define(MODE.BOOLEAN, false, GLOBAL_FLAG, "h", KEY_HELP,
|
define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "h", KEY_HELP,
|
||||||
"This help.",
|
"This help.",
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
@@ -86,47 +101,54 @@ public class CommandLineProcessor {
|
|||||||
|
|
||||||
/** Helper that returns true if --verbose was requested. */
|
/** Helper that returns true if --verbose was requested. */
|
||||||
public boolean isVerbose() {
|
public boolean isVerbose() {
|
||||||
return ((Boolean) getValue(GLOBAL_FLAG, KEY_VERBOSE)).booleanValue();
|
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_VERBOSE)).booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper that returns true if --silent was requested. */
|
/** Helper that returns true if --silent was requested. */
|
||||||
public boolean isSilent() {
|
public boolean isSilent() {
|
||||||
return ((Boolean) getValue(GLOBAL_FLAG, KEY_SILENT)).booleanValue();
|
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_SILENT)).booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper that returns true if --help was requested. */
|
/** Helper that returns true if --help was requested. */
|
||||||
public boolean isHelpRequested() {
|
public boolean isHelpRequested() {
|
||||||
return ((Boolean) getValue(GLOBAL_FLAG, KEY_HELP)).booleanValue();
|
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_HELP)).booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper that returns the requested action name. */
|
/** Returns the verb name from the command-line. Can be null. */
|
||||||
public String getActionRequested() {
|
public String getVerb() {
|
||||||
return (String) getValue(INTERNAL_FLAG, KEY_ACTION);
|
return mVerbRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the direct object name from the command-line. Can be null. */
|
||||||
|
public String getDirectObject() {
|
||||||
|
return mDirectObjectRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------
|
//------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw access to parsed parameter values.
|
* Raw access to parsed parameter values.
|
||||||
* @param action The action name, including {@link #GLOBAL_FLAG} and {@link #INTERNAL_FLAG}
|
* @param verb The verb name, including {@link #GLOBAL_FLAG_VERB}.
|
||||||
|
* @param directObject The direct object name, including {@link #NO_VERB_OBJECT}.
|
||||||
* @param longFlagName The long flag name for the given action.
|
* @param longFlagName The long flag name for the given action.
|
||||||
* @return The current value object stored in the parameter, which depends on the argument mode.
|
* @return The current value object stored in the parameter, which depends on the argument mode.
|
||||||
*/
|
*/
|
||||||
public Object getValue(String action, String longFlagName) {
|
public Object getValue(String verb, String directObject, String longFlagName) {
|
||||||
String key = action + "/" + longFlagName;
|
String key = verb + "/" + directObject + "/" + longFlagName;
|
||||||
Arg arg = mArguments.get(key);
|
Arg arg = mArguments.get(key);
|
||||||
return arg.getCurrentValue();
|
return arg.getCurrentValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal setter for raw parameter value.
|
* Internal setter for raw parameter value.
|
||||||
* @param action The action name, including {@link #GLOBAL_FLAG} and {@link #INTERNAL_FLAG}
|
* @param verb The verb name, including {@link #GLOBAL_FLAG_VERB}.
|
||||||
|
* @param directObject The direct object name, including {@link #NO_VERB_OBJECT}.
|
||||||
* @param longFlagName The long flag name for the given action.
|
* @param longFlagName The long flag name for the given action.
|
||||||
* @param value The new current value object stored in the parameter, which depends on the
|
* @param value The new current value object stored in the parameter, which depends on the
|
||||||
* argument mode.
|
* argument mode.
|
||||||
*/
|
*/
|
||||||
protected void setValue(String action, String longFlagName, Object value) {
|
protected void setValue(String verb, String directObject, String longFlagName, Object value) {
|
||||||
String key = action + "/" + longFlagName;
|
String key = verb + "/" + directObject + "/" + longFlagName;
|
||||||
Arg arg = mArguments.get(key);
|
Arg arg = mArguments.get(key);
|
||||||
arg.setCurrentValue(value);
|
arg.setCurrentValue(value);
|
||||||
}
|
}
|
||||||
@@ -140,114 +162,172 @@ public class CommandLineProcessor {
|
|||||||
*/
|
*/
|
||||||
public void parseArgs(String[] args) {
|
public void parseArgs(String[] args) {
|
||||||
String needsHelp = null;
|
String needsHelp = null;
|
||||||
String action = null;
|
String verb = null;
|
||||||
|
String directObject = null;
|
||||||
|
|
||||||
int n = args.length;
|
try {
|
||||||
for (int i = 0; i < n; i++) {
|
int n = args.length;
|
||||||
Arg arg = null;
|
for (int i = 0; i < n; i++) {
|
||||||
String a = args[i];
|
Arg arg = null;
|
||||||
if (a.startsWith("--")) {
|
String a = args[i];
|
||||||
arg = findLongArg(action, a.substring(2));
|
if (a.startsWith("--")) {
|
||||||
} else if (a.startsWith("-")) {
|
arg = findLongArg(verb, directObject, a.substring(2));
|
||||||
arg = findShortArg(action, a.substring(1));
|
} else if (a.startsWith("-")) {
|
||||||
}
|
arg = findShortArg(verb, directObject, a.substring(1));
|
||||||
|
|
||||||
// Not a keyword and we don't have an action yet, this should be an action
|
|
||||||
if (arg == null && action == null) {
|
|
||||||
|
|
||||||
if (a.startsWith("-")) {
|
|
||||||
// Got a keyword but not valid for global flags
|
|
||||||
needsHelp = String.format(
|
|
||||||
"Flag '%1$s' is not a valid global flag. Did you mean to specify it after the action name?",
|
|
||||||
a, action);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String[] actionDesc : mActions) {
|
// No matching argument name found
|
||||||
if (actionDesc[0].equals(a)) {
|
if (arg == null) {
|
||||||
action = a;
|
// Does it looks like a dashed parameter?
|
||||||
break;
|
if (a.startsWith("-")) {
|
||||||
}
|
if (verb == null || directObject == null) {
|
||||||
}
|
// It looks like a dashed parameter and we don't have a a verb/object
|
||||||
|
// set yet, the parameter was just given too early.
|
||||||
|
|
||||||
if (action == null) {
|
needsHelp = String.format(
|
||||||
needsHelp = String.format(
|
"Flag '%1$s' is not a valid global flag. Did you mean to specify it after the verb/object name?",
|
||||||
"Expected action name after global parameters but found %1$s instead.",
|
a);
|
||||||
a);
|
return;
|
||||||
break;
|
} else {
|
||||||
}
|
// It looks like a dashed parameter and but it is unknown by this
|
||||||
} else if (arg == null && action != null) {
|
// verb-object combination
|
||||||
// Got a keyword but not valid for the current action
|
|
||||||
needsHelp = String.format(
|
|
||||||
"Flag '%1$s' is not valid for action '%2$s'.",
|
|
||||||
a, action);
|
|
||||||
break;
|
|
||||||
|
|
||||||
} else if (arg != null) {
|
needsHelp = String.format(
|
||||||
// Process keyword
|
"Flag '%1$s' is not valid for '%2$s %3$s'.",
|
||||||
String error = null;
|
a, verb, directObject);
|
||||||
if (arg.getMode().needsExtra()) {
|
return;
|
||||||
if (++i >= n) {
|
}
|
||||||
needsHelp = String.format("Missing argument for flag %1$s.", a);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error = arg.getMode().process(arg, args[i]);
|
if (verb == null) {
|
||||||
} else {
|
// Fill verb first. Find it.
|
||||||
error = arg.getMode().process(arg, null);
|
for (String[] actionDesc : mActions) {
|
||||||
|
if (actionDesc[ACTION_VERB_INDEX].equals(a)) {
|
||||||
|
verb = a;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we just toggled help, we want to exit now without printing any error.
|
// Error if it was not a valid verb
|
||||||
// We do this test here only when a Boolean flag is toggled since booleans
|
if (verb == null) {
|
||||||
// are the only flags that don't take parameters and help is a boolean.
|
needsHelp = String.format(
|
||||||
if (isHelpRequested()) {
|
"Expected verb after global parameters but found '%1$s' instead.",
|
||||||
printHelpAndExit(null);
|
a);
|
||||||
// The call above should terminate however in unit tests we override
|
return;
|
||||||
// it so we still need to return here.
|
}
|
||||||
|
|
||||||
|
} else if (directObject == null) {
|
||||||
|
// Then fill the direct object. Find it.
|
||||||
|
for (String[] actionDesc : mActions) {
|
||||||
|
if (actionDesc[ACTION_VERB_INDEX].equals(verb)) {
|
||||||
|
if (actionDesc[ACTION_OBJECT_INDEX].equals(a)) {
|
||||||
|
directObject = a;
|
||||||
|
break;
|
||||||
|
} else if (actionDesc.length > ACTION_ALT_OBJECT_INDEX &&
|
||||||
|
actionDesc[ACTION_ALT_OBJECT_INDEX].equals(a)) {
|
||||||
|
// if the alternate form exist and is used, we internally
|
||||||
|
// only memorize the default direct object form.
|
||||||
|
directObject = actionDesc[ACTION_OBJECT_INDEX];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error if it was not a valid object for that verb
|
||||||
|
if (directObject == null) {
|
||||||
|
needsHelp = String.format(
|
||||||
|
"Expected verb after global parameters but found '%1$s' instead.",
|
||||||
|
a);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (arg != null) {
|
||||||
|
// Process keyword
|
||||||
|
String error = null;
|
||||||
|
if (arg.getMode().needsExtra()) {
|
||||||
|
if (++i >= n) {
|
||||||
|
needsHelp = String.format("Missing argument for flag %1$s.", a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = arg.getMode().process(arg, args[i]);
|
||||||
|
} else {
|
||||||
|
error = arg.getMode().process(arg, null);
|
||||||
|
|
||||||
|
// If we just toggled help, we want to exit now without printing any error.
|
||||||
|
// We do this test here only when a Boolean flag is toggled since booleans
|
||||||
|
// are the only flags that don't take parameters and help is a boolean.
|
||||||
|
if (isHelpRequested()) {
|
||||||
|
printHelpAndExit(null);
|
||||||
|
// The call above should terminate however in unit tests we override
|
||||||
|
// it so we still need to return here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != null) {
|
||||||
|
needsHelp = String.format("Invalid usage for flag %1$s: %2$s.", a, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error != null) {
|
|
||||||
needsHelp = String.format("Invalid usage for flag %1$s: %2$s.", a, error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (needsHelp == null) {
|
if (needsHelp == null) {
|
||||||
if (action == null) {
|
if (verb == null) {
|
||||||
needsHelp = "Missing action name.";
|
needsHelp = "Missing verb name.";
|
||||||
} else {
|
} else {
|
||||||
// Validate that all mandatory arguments are non-null for this action
|
if (directObject == null) {
|
||||||
String missing = null;
|
// Make sure this verb has an optional direct object
|
||||||
boolean plural = false;
|
for (String[] actionDesc : mActions) {
|
||||||
for (Entry<String, Arg> entry : mArguments.entrySet()) {
|
if (actionDesc[ACTION_VERB_INDEX].equals(verb) &&
|
||||||
Arg arg = entry.getValue();
|
actionDesc[ACTION_OBJECT_INDEX].equals(NO_VERB_OBJECT)) {
|
||||||
if (arg.getAction().equals(action)) {
|
directObject = NO_VERB_OBJECT;
|
||||||
if (arg.isMandatory() && arg.getCurrentValue() == null) {
|
break;
|
||||||
if (missing == null) {
|
}
|
||||||
missing = "--" + arg.getLongArg();
|
}
|
||||||
} else {
|
|
||||||
missing += ", --" + arg.getLongArg();
|
if (directObject == null) {
|
||||||
plural = true;
|
needsHelp = String.format("Missing object name for verb '%1$s'.", verb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.getVerb().equals(verb) &&
|
||||||
|
arg.getDirectObject().equals(directObject)) {
|
||||||
|
if (arg.isMandatory() && arg.getCurrentValue() == null) {
|
||||||
|
if (missing == null) {
|
||||||
|
missing = "--" + arg.getLongArg();
|
||||||
|
} else {
|
||||||
|
missing += ", --" + arg.getLongArg();
|
||||||
|
plural = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (missing != null) {
|
if (missing != null) {
|
||||||
needsHelp = String.format("The %1$s %2$s must be defined for action '%3$s'",
|
needsHelp = String.format(
|
||||||
plural ? "parameters" : "parameter",
|
"The %1$s %2$s must be defined for action '%3$s %4$s'",
|
||||||
missing,
|
plural ? "parameters" : "parameter",
|
||||||
action);
|
missing,
|
||||||
}
|
verb,
|
||||||
|
directObject);
|
||||||
|
}
|
||||||
|
|
||||||
setValue(INTERNAL_FLAG, KEY_ACTION, action);
|
mVerbRequested = verb;
|
||||||
|
mDirectObjectRequested = directObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (needsHelp != null) {
|
||||||
|
printHelpAndExitForAction(verb, directObject, needsHelp);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (needsHelp != null) {
|
|
||||||
printHelpAndExitForAction(action, needsHelp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,11 +335,14 @@ public class CommandLineProcessor {
|
|||||||
* Finds an {@link Arg} given an action name and a long flag name.
|
* Finds an {@link Arg} given an action name and a long flag name.
|
||||||
* @return The {@link Arg} found or null.
|
* @return The {@link Arg} found or null.
|
||||||
*/
|
*/
|
||||||
protected Arg findLongArg(String action, String longName) {
|
protected Arg findLongArg(String verb, String directObject, String longName) {
|
||||||
if (action == null) {
|
if (verb == null) {
|
||||||
action = GLOBAL_FLAG;
|
verb = GLOBAL_FLAG_VERB;
|
||||||
}
|
}
|
||||||
String key = action + "/" + longName;
|
if (directObject == null) {
|
||||||
|
directObject = NO_VERB_OBJECT;
|
||||||
|
}
|
||||||
|
String key = verb + "/" + directObject + "/" + longName;
|
||||||
return mArguments.get(key);
|
return mArguments.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,14 +350,17 @@ public class CommandLineProcessor {
|
|||||||
* Finds an {@link Arg} given an action name and a short flag name.
|
* Finds an {@link Arg} given an action name and a short flag name.
|
||||||
* @return The {@link Arg} found or null.
|
* @return The {@link Arg} found or null.
|
||||||
*/
|
*/
|
||||||
protected Arg findShortArg(String action, String shortName) {
|
protected Arg findShortArg(String verb, String directObject, String shortName) {
|
||||||
if (action == null) {
|
if (verb == null) {
|
||||||
action = GLOBAL_FLAG;
|
verb = GLOBAL_FLAG_VERB;
|
||||||
|
}
|
||||||
|
if (directObject == null) {
|
||||||
|
directObject = NO_VERB_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Entry<String, Arg> entry : mArguments.entrySet()) {
|
for (Entry<String, Arg> entry : mArguments.entrySet()) {
|
||||||
Arg arg = entry.getValue();
|
Arg arg = entry.getValue();
|
||||||
if (arg.getAction().equals(action)) {
|
if (arg.getVerb().equals(verb) && arg.getDirectObject().equals(directObject)) {
|
||||||
if (shortName.equals(arg.getShortArg())) {
|
if (shortName.equals(arg.getShortArg())) {
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
@@ -291,18 +377,22 @@ public class CommandLineProcessor {
|
|||||||
* @param args Arguments for String.format
|
* @param args Arguments for String.format
|
||||||
*/
|
*/
|
||||||
public void printHelpAndExit(String errorFormat, Object... args) {
|
public void printHelpAndExit(String errorFormat, Object... args) {
|
||||||
printHelpAndExitForAction(null /*actionFilter*/, errorFormat, args);
|
printHelpAndExitForAction(null /*verb*/, null /*directObject*/, errorFormat, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the help/usage and exits.
|
* Prints the help/usage and exits.
|
||||||
*
|
*
|
||||||
* @param actionFilter If null, displays help for all actions. If not null, display help only
|
* @param verb If null, displays help for all verbs. If not null, display help only
|
||||||
* for that specific action. In all cases also display general usage and action list.
|
* for that specific verb. In all cases also displays general usage and action list.
|
||||||
|
* @param directObject If null, displays help for all verb objects.
|
||||||
|
* If not null, displays help only for that specific action
|
||||||
|
* In all cases also display general usage and action list.
|
||||||
* @param errorFormat Optional error message to print prior to usage using String.format
|
* @param errorFormat Optional error message to print prior to usage using String.format
|
||||||
* @param args Arguments for String.format
|
* @param args Arguments for String.format
|
||||||
*/
|
*/
|
||||||
public void printHelpAndExitForAction(String actionFilter, String errorFormat, Object... args) {
|
public void printHelpAndExitForAction(String verb, String directObject,
|
||||||
|
String errorFormat, Object... args) {
|
||||||
if (errorFormat != null) {
|
if (errorFormat != null) {
|
||||||
stderr(errorFormat, args);
|
stderr(errorFormat, args);
|
||||||
}
|
}
|
||||||
@@ -316,25 +406,27 @@ public class CommandLineProcessor {
|
|||||||
" android [global options] action [action options]\n" +
|
" android [global options] action [action options]\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"Global options:");
|
"Global options:");
|
||||||
listOptions(GLOBAL_FLAG);
|
listOptions(GLOBAL_FLAG_VERB, NO_VERB_OBJECT);
|
||||||
|
|
||||||
stdout("\nValid actions:");
|
stdout("\nValid actions are composed of a verb and an optional direct object:");
|
||||||
for (String[] action : mActions) {
|
for (String[] action : mActions) {
|
||||||
String filler = "";
|
|
||||||
int len = action[0].length();
|
|
||||||
if (len < 10) {
|
|
||||||
filler = " ".substring(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout("- %1$s:%2$s %3$s", action[0], filler, action[1]);
|
stdout("- %1$6s %2$-7s: %3$s",
|
||||||
|
action[ACTION_VERB_INDEX],
|
||||||
|
action[ACTION_OBJECT_INDEX],
|
||||||
|
action[ACTION_DESC_INDEX]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String[] action : mActions) {
|
for (String[] action : mActions) {
|
||||||
if (actionFilter == null || actionFilter.equals(action[0])) {
|
if (verb == null || verb.equals(action[ACTION_VERB_INDEX])) {
|
||||||
stdout("\nAction \"%1$s\":", action[0]);
|
if (directObject == null || directObject.equals(action[ACTION_OBJECT_INDEX])) {
|
||||||
stdout(" %1$s", action[1]);
|
stdout("\nAction \"%1$s %2$s\":",
|
||||||
stdout("Options:");
|
action[ACTION_VERB_INDEX],
|
||||||
listOptions(action[0]);
|
action[ACTION_OBJECT_INDEX]);
|
||||||
|
stdout(" %1$s", action[ACTION_DESC_INDEX]);
|
||||||
|
stdout("Options:");
|
||||||
|
listOptions(action[ACTION_VERB_INDEX], action[ACTION_OBJECT_INDEX]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,11 +436,11 @@ public class CommandLineProcessor {
|
|||||||
/**
|
/**
|
||||||
* Internal helper to print all the option flags for a given action name.
|
* Internal helper to print all the option flags for a given action name.
|
||||||
*/
|
*/
|
||||||
protected void listOptions(String action) {
|
protected void listOptions(String verb, String directObject) {
|
||||||
int numOptions = 0;
|
int numOptions = 0;
|
||||||
for (Entry<String, Arg> entry : mArguments.entrySet()) {
|
for (Entry<String, Arg> entry : mArguments.entrySet()) {
|
||||||
Arg arg = entry.getValue();
|
Arg arg = entry.getValue();
|
||||||
if (arg.getAction().equals(action)) {
|
if (arg.getVerb().equals(verb) && arg.getDirectObject().equals(directObject)) {
|
||||||
|
|
||||||
String value = "";
|
String value = "";
|
||||||
if (arg.getDefaultValue() instanceof String[]) {
|
if (arg.getDefaultValue() instanceof String[]) {
|
||||||
@@ -483,21 +575,22 @@ public class CommandLineProcessor {
|
|||||||
* or a String array (in which case the first item is the current by default.)
|
* or a String array (in which case the first item is the current by default.)
|
||||||
*/
|
*/
|
||||||
static class Arg {
|
static class Arg {
|
||||||
private final String mAction;
|
private final String mVerb;
|
||||||
|
private final String mDirectObject;
|
||||||
private final String mShortName;
|
private final String mShortName;
|
||||||
private final String mLongName;
|
private final String mLongName;
|
||||||
private final String mDescription;
|
private final String mDescription;
|
||||||
private final Object mDefaultValue;
|
private final Object mDefaultValue;
|
||||||
private Object mCurrentValue;
|
|
||||||
private final MODE mMode;
|
private final MODE mMode;
|
||||||
private final boolean mMandatory;
|
private final boolean mMandatory;
|
||||||
|
private Object mCurrentValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new argument flag description.
|
* Creates a new argument flag description.
|
||||||
*
|
*
|
||||||
* @param mode The {@link MODE} for the argument.
|
* @param mode The {@link MODE} for the argument.
|
||||||
* @param mandatory True if this argument is mandatory for this action.
|
* @param mandatory True if this argument is mandatory for this action.
|
||||||
* @param action The action name. Can be #GLOBAL_FLAG or #INTERNAL_FLAG.
|
* @param directObject The action name. Can be #NO_VERB_OBJECT or #INTERNAL_FLAG.
|
||||||
* @param shortName The one-letter short argument name. Cannot be empty nor null.
|
* @param shortName The one-letter short argument name. Cannot be empty nor null.
|
||||||
* @param longName The long argument name. Cannot be empty nor null.
|
* @param longName The long argument name. Cannot be empty nor null.
|
||||||
* @param description The description. Cannot be null.
|
* @param description The description. Cannot be null.
|
||||||
@@ -505,14 +598,16 @@ public class CommandLineProcessor {
|
|||||||
*/
|
*/
|
||||||
public Arg(MODE mode,
|
public Arg(MODE mode,
|
||||||
boolean mandatory,
|
boolean mandatory,
|
||||||
String action,
|
String verb,
|
||||||
|
String directObject,
|
||||||
String shortName,
|
String shortName,
|
||||||
String longName,
|
String longName,
|
||||||
String description,
|
String description,
|
||||||
Object defaultValue) {
|
Object defaultValue) {
|
||||||
mMode = mode;
|
mMode = mode;
|
||||||
mMandatory = mandatory;
|
mMandatory = mandatory;
|
||||||
mAction = action;
|
mVerb = verb;
|
||||||
|
mDirectObject = directObject;
|
||||||
mShortName = shortName;
|
mShortName = shortName;
|
||||||
mLongName = longName;
|
mLongName = longName;
|
||||||
mDescription = description;
|
mDescription = description;
|
||||||
@@ -540,8 +635,12 @@ public class CommandLineProcessor {
|
|||||||
return mDescription;
|
return mDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAction() {
|
public String getVerb() {
|
||||||
return mAction;
|
return mVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDirectObject() {
|
||||||
|
return mDirectObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getDefaultValue() {
|
public Object getDefaultValue() {
|
||||||
@@ -565,7 +664,8 @@ public class CommandLineProcessor {
|
|||||||
* Internal helper to define a new argument for a give action.
|
* Internal helper to define a new argument for a give action.
|
||||||
*
|
*
|
||||||
* @param mode The {@link MODE} for the argument.
|
* @param mode The {@link MODE} for the argument.
|
||||||
* @param action The action name. Can be #GLOBAL_FLAG or #INTERNAL_FLAG.
|
* @param verb The verb name. Can be #INTERNAL_VERB.
|
||||||
|
* @param directObject The action name. Can be #NO_VERB_OBJECT or #INTERNAL_FLAG.
|
||||||
* @param shortName The one-letter short argument name. Cannot be empty nor null.
|
* @param shortName The one-letter short argument name. Cannot be empty nor null.
|
||||||
* @param longName The long argument name. Cannot be empty nor null.
|
* @param longName The long argument name. Cannot be empty nor null.
|
||||||
* @param description The description. Cannot be null.
|
* @param description The description. Cannot be null.
|
||||||
@@ -573,14 +673,19 @@ public class CommandLineProcessor {
|
|||||||
*/
|
*/
|
||||||
protected void define(MODE mode,
|
protected void define(MODE mode,
|
||||||
boolean mandatory,
|
boolean mandatory,
|
||||||
String action,
|
String verb,
|
||||||
|
String directObject,
|
||||||
String shortName, String longName,
|
String shortName, String longName,
|
||||||
String description, Object defaultValue) {
|
String description, Object defaultValue) {
|
||||||
assert(mandatory || mode == MODE.BOOLEAN); // a boolean mode cannot be mandatory
|
assert(mandatory || mode == MODE.BOOLEAN); // a boolean mode cannot be mandatory
|
||||||
|
|
||||||
String key = action + "/" + longName;
|
if (directObject == null) {
|
||||||
|
directObject = NO_VERB_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = verb + "/" + directObject + "/" + longName;
|
||||||
mArguments.put(key, new Arg(mode, mandatory,
|
mArguments.put(key, new Arg(mode, mandatory,
|
||||||
action, shortName, longName, description, defaultValue));
|
verb, directObject, shortName, longName, description, defaultValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ import com.android.sdklib.ISdkLog;
|
|||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
|
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
|
||||||
|
import com.android.sdklib.avd.AvdManager;
|
||||||
|
import com.android.sdklib.avd.HardwareProperties;
|
||||||
|
import com.android.sdklib.avd.AvdManager.AvdInfo;
|
||||||
|
import com.android.sdklib.avd.HardwareProperties.HardwareProperty;
|
||||||
import com.android.sdklib.project.ProjectCreator;
|
import com.android.sdklib.project.ProjectCreator;
|
||||||
import com.android.sdklib.project.ProjectCreator.OutputLevel;
|
import com.android.sdklib.project.ProjectCreator.OutputLevel;
|
||||||
import com.android.sdklib.vm.HardwareProperties;
|
|
||||||
import com.android.sdklib.vm.VmManager;
|
|
||||||
import com.android.sdklib.vm.HardwareProperties.HardwareProperty;
|
|
||||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -56,8 +56,8 @@ class Main {
|
|||||||
private ISdkLog mSdkLog;
|
private ISdkLog mSdkLog;
|
||||||
/** The SDK manager parses the SDK folder and gives access to the content. */
|
/** The SDK manager parses the SDK folder and gives access to the content. */
|
||||||
private SdkManager mSdkManager;
|
private SdkManager mSdkManager;
|
||||||
/** Virtual Machine manager to access the list of VMs or create new ones. */
|
/** Virtual Machine manager to access the list of AVDs or create new ones. */
|
||||||
private VmManager mVmManager;
|
private AvdManager mAvdManager;
|
||||||
/** Command-line processor with options specific to SdkManager. */
|
/** Command-line processor with options specific to SdkManager. */
|
||||||
private SdkCommandLine mSdkCommandLine;
|
private SdkCommandLine mSdkCommandLine;
|
||||||
/** The working directory, either null or set to an existing absolute canonical directory. */
|
/** The working directory, either null or set to an existing absolute canonical directory. */
|
||||||
@@ -183,26 +183,31 @@ class Main {
|
|||||||
* Actually do an action...
|
* Actually do an action...
|
||||||
*/
|
*/
|
||||||
private void doAction() {
|
private void doAction() {
|
||||||
String action = mSdkCommandLine.getActionRequested();
|
String verb = mSdkCommandLine.getVerb();
|
||||||
|
String directObject = mSdkCommandLine.getDirectObject();
|
||||||
|
|
||||||
if (SdkCommandLine.ACTION_LIST.equals(action)) {
|
if (SdkCommandLine.VERB_LIST.equals(verb)) {
|
||||||
// list action.
|
// list action.
|
||||||
if (SdkCommandLine.ARG_TARGET.equals(mSdkCommandLine.getListFilter())) {
|
if (SdkCommandLine.OBJECT_TARGET.equals(directObject)) {
|
||||||
displayTargetList();
|
displayTargetList();
|
||||||
} else if (SdkCommandLine.ARG_VM.equals(mSdkCommandLine.getListFilter())) {
|
} else if (SdkCommandLine.OBJECT_AVD.equals(directObject)) {
|
||||||
displayVmList();
|
displayAvdList();
|
||||||
} else {
|
} else {
|
||||||
displayTargetList();
|
displayTargetList();
|
||||||
displayVmList();
|
displayAvdList();
|
||||||
}
|
}
|
||||||
} else if (SdkCommandLine.ACTION_NEW_VM.equals(action)) {
|
|
||||||
createVm();
|
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
|
||||||
} else if (SdkCommandLine.ACTION_NEW_PROJECT.equals(action)) {
|
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
|
||||||
|
createAvd();
|
||||||
|
|
||||||
|
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
|
||||||
|
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
|
||||||
// get the target and try to resolve it.
|
// get the target and try to resolve it.
|
||||||
int targetId = mSdkCommandLine.getNewProjectTargetId();
|
int targetId = mSdkCommandLine.getCreateProjectTargetId();
|
||||||
IAndroidTarget[] targets = mSdkManager.getTargets();
|
IAndroidTarget[] targets = mSdkManager.getTargets();
|
||||||
if (targetId < 1 || targetId > targets.length) {
|
if (targetId < 1 || targetId > targets.length) {
|
||||||
errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
|
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
|
||||||
SdkConstants.androidCmdName());
|
SdkConstants.androidCmdName());
|
||||||
}
|
}
|
||||||
IAndroidTarget target = targets[targetId - 1];
|
IAndroidTarget target = targets[targetId - 1];
|
||||||
@@ -213,22 +218,24 @@ class Main {
|
|||||||
OutputLevel.NORMAL,
|
OutputLevel.NORMAL,
|
||||||
mSdkLog);
|
mSdkLog);
|
||||||
|
|
||||||
String projectDir = getProjectLocation(mSdkCommandLine.getNewProjectLocation());
|
String projectDir = getProjectLocation(mSdkCommandLine.getCreateProjectLocation());
|
||||||
|
|
||||||
creator.createProject(projectDir,
|
creator.createProject(projectDir,
|
||||||
mSdkCommandLine.getNewProjectName(),
|
mSdkCommandLine.getCreateProjectName(),
|
||||||
mSdkCommandLine.getNewProjectPackage(),
|
mSdkCommandLine.getCreateProjectPackage(),
|
||||||
mSdkCommandLine.getNewProjectActivity(),
|
mSdkCommandLine.getCreateProjectActivity(),
|
||||||
target,
|
target,
|
||||||
false /* isTestProject*/);
|
false /* isTestProject*/);
|
||||||
} else if (SdkCommandLine.ACTION_UPDATE_PROJECT.equals(action)) {
|
|
||||||
|
} else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
|
||||||
|
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
|
||||||
// get the target and try to resolve it.
|
// get the target and try to resolve it.
|
||||||
IAndroidTarget target = null;
|
IAndroidTarget target = null;
|
||||||
int targetId = mSdkCommandLine.getUpdateProjectTargetId();
|
int targetId = mSdkCommandLine.getUpdateProjectTargetId();
|
||||||
if (targetId >= 0) {
|
if (targetId >= 0) {
|
||||||
IAndroidTarget[] targets = mSdkManager.getTargets();
|
IAndroidTarget[] targets = mSdkManager.getTargets();
|
||||||
if (targetId < 1 || targetId > targets.length) {
|
if (targetId < 1 || targetId > targets.length) {
|
||||||
errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
|
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
|
||||||
SdkConstants.androidCmdName());
|
SdkConstants.androidCmdName());
|
||||||
}
|
}
|
||||||
target = targets[targetId - 1];
|
target = targets[targetId - 1];
|
||||||
@@ -340,20 +347,20 @@ class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the list of available VMs.
|
* Displays the list of available AVDs.
|
||||||
*/
|
*/
|
||||||
private void displayVmList() {
|
private void displayAvdList() {
|
||||||
try {
|
try {
|
||||||
mVmManager = new VmManager(mSdkManager, null /* sdklog */);
|
mAvdManager = new AvdManager(mSdkManager, null /* sdklog */);
|
||||||
|
|
||||||
mSdkLog.printf("Available Android VMs:\n");
|
mSdkLog.printf("Available Android Virtual Devices:\n");
|
||||||
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
for (VmInfo info : mVmManager.getVms()) {
|
for (AvdInfo info : mAvdManager.getAvds()) {
|
||||||
mSdkLog.printf("[%d] %s\n", index, info.getName());
|
mSdkLog.printf("[%d] %s\n", index, info.getName());
|
||||||
mSdkLog.printf(" Path: %s\n", info.getPath());
|
mSdkLog.printf(" Path: %s\n", info.getPath());
|
||||||
|
|
||||||
// get the target of the Vm
|
// get the target of the AVD
|
||||||
IAndroidTarget target = info.getTarget();
|
IAndroidTarget target = info.getTarget();
|
||||||
if (target.isPlatform()) {
|
if (target.isPlatform()) {
|
||||||
mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
|
mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
|
||||||
@@ -373,57 +380,85 @@ class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new VM. This is a text based creation with command line prompt.
|
* Creates a new AVD. This is a text based creation with command line prompt.
|
||||||
*/
|
*/
|
||||||
private void createVm() {
|
private void createAvd() {
|
||||||
// find a matching target
|
// find a matching target
|
||||||
int targetId = mSdkCommandLine.getNewVmTargetId();
|
int targetId = mSdkCommandLine.getCreateAvdTargetId();
|
||||||
IAndroidTarget target = null;
|
IAndroidTarget target = null;
|
||||||
|
|
||||||
if (targetId >= 1 && targetId <= mSdkManager.getTargets().length) {
|
if (targetId >= 1 && targetId <= mSdkManager.getTargets().length) {
|
||||||
target = mSdkManager.getTargets()[targetId-1]; // target it is 1-based
|
target = mSdkManager.getTargets()[targetId-1]; // target it is 1-based
|
||||||
} else {
|
} else {
|
||||||
errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
|
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
|
||||||
SdkConstants.androidCmdName());
|
SdkConstants.androidCmdName());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mVmManager = new VmManager(mSdkManager, mSdkLog);
|
boolean removePrevious = false;
|
||||||
|
mAvdManager = new AvdManager(mSdkManager, mSdkLog);
|
||||||
|
|
||||||
String vmName = mSdkCommandLine.getNewVmName();
|
String avdName = mSdkCommandLine.getCreateAvdName();
|
||||||
VmInfo info = mVmManager.getVm(vmName);
|
AvdInfo info = mAvdManager.getAvd(avdName);
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
errorAndExit("VM %s already exists.", vmName);
|
if (mSdkCommandLine.getCreateAvdForce()) {
|
||||||
} else {
|
removePrevious = true;
|
||||||
String vmParentFolder = mSdkCommandLine.getNewVmLocation();
|
mSdkLog.warning(
|
||||||
if (vmParentFolder == null) {
|
"Android Virtual Device '%s' already exists and will be replaced.",
|
||||||
vmParentFolder = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
|
avdName);
|
||||||
|
} else {
|
||||||
|
errorAndExit("Android Virtual Device '%s' already exists.", avdName);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> hardwareConfig = null;
|
|
||||||
if (target.isPlatform()) {
|
|
||||||
try {
|
|
||||||
hardwareConfig = promptForHardware(target);
|
|
||||||
} catch (IOException e) {
|
|
||||||
errorAndExit(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mVmManager.createVm(vmParentFolder,
|
|
||||||
mSdkCommandLine.getNewVmName(),
|
|
||||||
target,
|
|
||||||
mSdkCommandLine.getNewVmSkin(),
|
|
||||||
mSdkCommandLine.getNewVmSdCard(),
|
|
||||||
hardwareConfig,
|
|
||||||
mSdkLog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String avdParentFolder = mSdkCommandLine.getCreateAvdLocation();
|
||||||
|
if (avdParentFolder == null) {
|
||||||
|
avdParentFolder = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> hardwareConfig = null;
|
||||||
|
if (target.isPlatform()) {
|
||||||
|
try {
|
||||||
|
hardwareConfig = promptForHardware(target);
|
||||||
|
} catch (IOException e) {
|
||||||
|
errorAndExit(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AvdInfo oldAvdInfo = null;
|
||||||
|
if (removePrevious) {
|
||||||
|
oldAvdInfo = mAvdManager.getAvd(avdName);
|
||||||
|
}
|
||||||
|
|
||||||
|
AvdInfo newAvdInfo = mAvdManager.createAvd(avdParentFolder,
|
||||||
|
avdName,
|
||||||
|
target,
|
||||||
|
mSdkCommandLine.getCreateAvdSkin(),
|
||||||
|
mSdkCommandLine.getCreateAvdSdCard(),
|
||||||
|
hardwareConfig,
|
||||||
|
removePrevious,
|
||||||
|
mSdkLog);
|
||||||
|
|
||||||
|
if (newAvdInfo != null &&
|
||||||
|
oldAvdInfo != null &&
|
||||||
|
!oldAvdInfo.getPath().equals(newAvdInfo.getPath())) {
|
||||||
|
mSdkLog.warning("Removing previous AVD directory at %s", oldAvdInfo.getPath());
|
||||||
|
// Remove the old data directory
|
||||||
|
File dir = new File(oldAvdInfo.getPath());
|
||||||
|
mAvdManager.recursiveDelete(dir);
|
||||||
|
dir.delete();
|
||||||
|
// Remove old avd info from manager
|
||||||
|
mAvdManager.removeAvd(oldAvdInfo);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
errorAndExit(e.getMessage());
|
errorAndExit(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompts the user to setup a hardware config for a Platform-based VM.
|
* Prompts the user to setup a hardware config for a Platform-based AVD.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private Map<String, String> promptForHardware(IAndroidTarget createTarget) throws IOException {
|
private Map<String, String> promptForHardware(IAndroidTarget createTarget) throws IOException {
|
||||||
|
|||||||
@@ -25,152 +25,218 @@ import com.android.sdklib.SdkManager;
|
|||||||
*/
|
*/
|
||||||
public class SdkCommandLine extends CommandLineProcessor {
|
public class SdkCommandLine extends CommandLineProcessor {
|
||||||
|
|
||||||
public static final String ARG_ALIAS = "alias";
|
public final static String VERB_LIST = "list";
|
||||||
|
public final static String VERB_CREATE = "create";
|
||||||
|
public final static String VERB_RENAME = "rename";
|
||||||
|
public final static String VERB_MOVE = "move";
|
||||||
|
public final static String VERB_DELETE = "delete";
|
||||||
|
public final static String VERB_UPDATE = "update";
|
||||||
|
|
||||||
|
public static final String OBJECT_AVD = "avd";
|
||||||
|
public static final String OBJECT_AVDS = "avds";
|
||||||
|
public static final String OBJECT_TARGET = "target";
|
||||||
|
public static final String OBJECT_TARGETS = "targets";
|
||||||
|
public static final String OBJECT_PROJECT = "project";
|
||||||
|
|
||||||
|
public static final String ARG_ALIAS = "alias";
|
||||||
public static final String ARG_ACTIVITY = "activity";
|
public static final String ARG_ACTIVITY = "activity";
|
||||||
public static final String ARG_VM = "vm";
|
|
||||||
public static final String ARG_TARGET = "target";
|
|
||||||
public static final String ARG_ALL = "all";
|
|
||||||
|
|
||||||
public static final String KEY_ACTIVITY = ARG_ACTIVITY;
|
public static final String KEY_ACTIVITY = ARG_ACTIVITY;
|
||||||
public static final String KEY_PACKAGE = "package";
|
public static final String KEY_PACKAGE = "package";
|
||||||
public static final String KEY_MODE = "mode";
|
public static final String KEY_MODE = "mode";
|
||||||
public static final String KEY_TARGET_ID = ARG_TARGET;
|
public static final String KEY_TARGET_ID = OBJECT_TARGET;
|
||||||
public static final String KEY_NAME = "name";
|
public static final String KEY_NAME = "name";
|
||||||
public static final String KEY_OUT = "out";
|
public static final String KEY_PATH = "path";
|
||||||
public static final String KEY_FILTER = "filter";
|
public static final String KEY_FILTER = "filter";
|
||||||
public static final String KEY_SKIN = "skin";
|
public static final String KEY_SKIN = "skin";
|
||||||
public static final String KEY_SDCARD = "sdcard";
|
public static final String KEY_SDCARD = "sdcard";
|
||||||
|
public static final String KEY_FORCE = "force";
|
||||||
public final static String ACTION_LIST = "list";
|
|
||||||
public final static String ACTION_NEW_VM = ARG_VM;
|
|
||||||
public final static String ACTION_NEW_PROJECT = "project";
|
|
||||||
public final static String ACTION_UPDATE_PROJECT = "update";
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action definitions for SdkManager command line.
|
||||||
|
* <p/>
|
||||||
|
* Each entry is a string array with:
|
||||||
|
* <ul>
|
||||||
|
* <li> the verb.
|
||||||
|
* <li> an object (use #NO_VERB_OBJECT if there's no object).
|
||||||
|
* <li> a description.
|
||||||
|
* <li> an alternate form for the object (e.g. plural).
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
private final static String[][] ACTIONS = {
|
private final static String[][] ACTIONS = {
|
||||||
{ ACTION_LIST,
|
{ VERB_LIST,
|
||||||
"Lists existing targets or VMs." },
|
NO_VERB_OBJECT,
|
||||||
{ ACTION_NEW_VM,
|
"Lists existing targets or virtual devices." },
|
||||||
"Creates a new VM." },
|
{ VERB_LIST,
|
||||||
{ ACTION_NEW_PROJECT,
|
OBJECT_AVD,
|
||||||
"Creates a new project using a template." },
|
"Lists existing Android Virtual Devices.",
|
||||||
{ ACTION_UPDATE_PROJECT,
|
OBJECT_AVDS },
|
||||||
"Updates a project from existing source (must have an AndroidManifest.xml)." },
|
{ VERB_LIST,
|
||||||
|
OBJECT_TARGET,
|
||||||
|
"Lists existing targets.",
|
||||||
|
OBJECT_TARGETS },
|
||||||
|
|
||||||
|
{ VERB_CREATE,
|
||||||
|
OBJECT_AVD,
|
||||||
|
"Creates a new Android Virtual Device." },
|
||||||
|
{ VERB_RENAME,
|
||||||
|
OBJECT_AVD,
|
||||||
|
"Renames a new Android Virtual Device." },
|
||||||
|
{ VERB_MOVE,
|
||||||
|
OBJECT_AVD,
|
||||||
|
"Moves a new Android Virtual Device." },
|
||||||
|
{ VERB_DELETE,
|
||||||
|
OBJECT_AVD,
|
||||||
|
"Deletes a new Android Virtual Device." },
|
||||||
|
|
||||||
|
{ VERB_CREATE,
|
||||||
|
OBJECT_PROJECT,
|
||||||
|
"Creates a new Android Project." },
|
||||||
|
{ VERB_UPDATE,
|
||||||
|
OBJECT_PROJECT,
|
||||||
|
"Updates an Android Project (must have an AndroidManifest.xml)." },
|
||||||
};
|
};
|
||||||
|
|
||||||
public SdkCommandLine(ISdkLog logger) {
|
public SdkCommandLine(ISdkLog logger) {
|
||||||
super(logger, ACTIONS);
|
super(logger, ACTIONS);
|
||||||
|
|
||||||
define(MODE.ENUM, false, ACTION_LIST, "f", KEY_FILTER,
|
define(MODE.STRING, false,
|
||||||
"List filter", new String[] { ARG_ALL, ARG_TARGET, ARG_VM });
|
VERB_CREATE, OBJECT_AVD,
|
||||||
|
"p", KEY_PATH,
|
||||||
|
"Location path of the parent directory where the new AVD will be created", null);
|
||||||
|
define(MODE.STRING, true,
|
||||||
|
VERB_CREATE, OBJECT_AVD,
|
||||||
|
"n", KEY_NAME,
|
||||||
|
"Name of the new AVD", null);
|
||||||
|
define(MODE.INTEGER, true,
|
||||||
|
VERB_CREATE, OBJECT_AVD,
|
||||||
|
"t", KEY_TARGET_ID,
|
||||||
|
"Target id of the new AVD", null);
|
||||||
|
define(MODE.STRING, true,
|
||||||
|
VERB_CREATE, OBJECT_AVD,
|
||||||
|
"s", KEY_SKIN,
|
||||||
|
"Skin of the new AVD", null);
|
||||||
|
define(MODE.STRING, false,
|
||||||
|
VERB_CREATE, OBJECT_AVD,
|
||||||
|
"c", KEY_SDCARD,
|
||||||
|
"Path to a shared SD card image, or size of a new sdcard for the new AVD", null);
|
||||||
|
define(MODE.BOOLEAN, false,
|
||||||
|
VERB_CREATE, OBJECT_AVD,
|
||||||
|
"f", KEY_FORCE,
|
||||||
|
"Force creation (override an existing AVD)", false);
|
||||||
|
|
||||||
define(MODE.STRING, false, ACTION_NEW_VM, "o", KEY_OUT,
|
define(MODE.ENUM, true,
|
||||||
"Location path of new VM", null);
|
VERB_CREATE, OBJECT_PROJECT,
|
||||||
define(MODE.STRING, true, ACTION_NEW_VM, "n", KEY_NAME,
|
"m", KEY_MODE,
|
||||||
"Name of the new VM", null);
|
|
||||||
define(MODE.INTEGER, true, ACTION_NEW_VM, "t", KEY_TARGET_ID,
|
|
||||||
"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, 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 });
|
"Project mode", new String[] { ARG_ACTIVITY, ARG_ALIAS });
|
||||||
define(MODE.STRING, true, ACTION_NEW_PROJECT, "o", KEY_OUT,
|
define(MODE.STRING, true,
|
||||||
|
VERB_CREATE, OBJECT_PROJECT,
|
||||||
|
"p", KEY_PATH,
|
||||||
"Location path of new project", null);
|
"Location path of new project", null);
|
||||||
define(MODE.INTEGER, true, ACTION_NEW_PROJECT, "t", KEY_TARGET_ID,
|
define(MODE.INTEGER, true,
|
||||||
|
VERB_CREATE, OBJECT_PROJECT,
|
||||||
|
"t", KEY_TARGET_ID,
|
||||||
"Target id of the new project", null);
|
"Target id of the new project", null);
|
||||||
define(MODE.STRING, true, ACTION_NEW_PROJECT, "p", KEY_PACKAGE,
|
define(MODE.STRING, true,
|
||||||
|
VERB_CREATE, OBJECT_PROJECT,
|
||||||
|
"k", KEY_PACKAGE,
|
||||||
"Package name", null);
|
"Package name", null);
|
||||||
define(MODE.STRING, true, ACTION_NEW_PROJECT, "a", KEY_ACTIVITY,
|
define(MODE.STRING, true,
|
||||||
|
VERB_CREATE, OBJECT_PROJECT,
|
||||||
|
"a", KEY_ACTIVITY,
|
||||||
"Activity name", null);
|
"Activity name", null);
|
||||||
define(MODE.STRING, false, ACTION_NEW_PROJECT, "n", KEY_NAME,
|
define(MODE.STRING, false,
|
||||||
|
VERB_CREATE, OBJECT_PROJECT,
|
||||||
|
"n", KEY_NAME,
|
||||||
"Project name", null);
|
"Project name", null);
|
||||||
|
|
||||||
define(MODE.STRING, true, ACTION_UPDATE_PROJECT, "o", KEY_OUT,
|
define(MODE.STRING, true,
|
||||||
|
VERB_UPDATE, OBJECT_PROJECT,
|
||||||
|
"p", KEY_PATH,
|
||||||
"Location path of the project", null);
|
"Location path of the project", null);
|
||||||
define(MODE.INTEGER, true, ACTION_UPDATE_PROJECT, "t", KEY_TARGET_ID,
|
define(MODE.INTEGER, true,
|
||||||
|
VERB_UPDATE, OBJECT_PROJECT,
|
||||||
|
"t", KEY_TARGET_ID,
|
||||||
"Target id to set for the project", -1);
|
"Target id to set for the project", -1);
|
||||||
define(MODE.STRING, false, ACTION_UPDATE_PROJECT, "n", KEY_NAME,
|
define(MODE.STRING, false,
|
||||||
|
VERB_UPDATE, OBJECT_PROJECT,
|
||||||
|
"n", KEY_NAME,
|
||||||
"Project name", null);
|
"Project name", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- some helpers for list action flags
|
// -- some helpers for AVD action flags
|
||||||
|
|
||||||
/** Helper to retrieve the --filter for the list action. */
|
/** Helper to retrieve the --out location for the new AVD action. */
|
||||||
public String getListFilter() {
|
public String getCreateAvdLocation() {
|
||||||
return ((String) getValue(ACTION_LIST, KEY_FILTER));
|
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- some helpers for vm action flags
|
/** Helper to retrieve the --target id for the new AVD action. */
|
||||||
|
public int getCreateAvdTargetId() {
|
||||||
/** Helper to retrieve the --out location for the new vm action. */
|
return ((Integer) getValue(VERB_CREATE, OBJECT_AVD, KEY_TARGET_ID)).intValue();
|
||||||
public String getNewVmLocation() {
|
|
||||||
return ((String) getValue(ACTION_NEW_VM, KEY_OUT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --target id for the new vm action. */
|
/** Helper to retrieve the --name for the new AVD action. */
|
||||||
public int getNewVmTargetId() {
|
public String getCreateAvdName() {
|
||||||
return ((Integer) getValue(ACTION_NEW_VM, KEY_TARGET_ID)).intValue();
|
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --name for the new vm action. */
|
/** Helper to retrieve the --skin name for the new AVD action. */
|
||||||
public String getNewVmName() {
|
public String getCreateAvdSkin() {
|
||||||
return ((String) getValue(ACTION_NEW_VM, KEY_NAME));
|
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_SKIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --skin name for the new vm action. */
|
/** Helper to retrieve the --sdcard data for the new AVD action. */
|
||||||
public String getNewVmSkin() {
|
public String getCreateAvdSdCard() {
|
||||||
return ((String) getValue(ACTION_NEW_VM, KEY_SKIN));
|
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_SDCARD));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --sdcard data for the new vm action. */
|
public boolean getCreateAvdForce() {
|
||||||
public String getNewVmSdCard() {
|
return ((Boolean) getValue(VERB_CREATE, OBJECT_AVD, KEY_FORCE)).booleanValue();
|
||||||
return ((String) getValue(ACTION_NEW_VM, KEY_SDCARD));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -- some helpers for project action flags
|
// -- some helpers for project action flags
|
||||||
|
|
||||||
/** Helper to retrieve the --out location for the new project action. */
|
/** Helper to retrieve the --out location for the new project action. */
|
||||||
public String getNewProjectLocation() {
|
public String getCreateProjectLocation() {
|
||||||
return ((String) getValue(ACTION_NEW_PROJECT, KEY_OUT));
|
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --target id for the new project action. */
|
/** Helper to retrieve the --target id for the new project action. */
|
||||||
public int getNewProjectTargetId() {
|
public int getCreateProjectTargetId() {
|
||||||
return ((Integer) getValue(ACTION_NEW_PROJECT, KEY_TARGET_ID)).intValue();
|
return ((Integer) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_TARGET_ID)).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --name for the new project action. */
|
/** Helper to retrieve the --name for the new project action. */
|
||||||
public String getNewProjectName() {
|
public String getCreateProjectName() {
|
||||||
return ((String) getValue(ACTION_NEW_PROJECT, KEY_NAME));
|
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --package for the new project action. */
|
/** Helper to retrieve the --package for the new project action. */
|
||||||
public String getNewProjectPackage() {
|
public String getCreateProjectPackage() {
|
||||||
return ((String) getValue(ACTION_NEW_PROJECT, KEY_PACKAGE));
|
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_PACKAGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --activity for the new project action. */
|
/** Helper to retrieve the --activity for the new project action. */
|
||||||
public String getNewProjectActivity() {
|
public String getCreateProjectActivity() {
|
||||||
return ((String) getValue(ACTION_NEW_PROJECT, KEY_ACTIVITY));
|
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_ACTIVITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- some helpers for update action flags
|
// -- some helpers for update action flags
|
||||||
|
|
||||||
/** Helper to retrieve the --out location for the update project action. */
|
/** Helper to retrieve the --out location for the update project action. */
|
||||||
public String getUpdateProjectLocation() {
|
public String getUpdateProjectLocation() {
|
||||||
return ((String) getValue(ACTION_UPDATE_PROJECT, KEY_OUT));
|
return ((String) getValue(VERB_UPDATE, OBJECT_PROJECT, KEY_PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --target id for the update project action. */
|
/** Helper to retrieve the --target id for the update project action. */
|
||||||
public int getUpdateProjectTargetId() {
|
public int getUpdateProjectTargetId() {
|
||||||
return ((Integer) getValue(ACTION_UPDATE_PROJECT, KEY_TARGET_ID)).intValue();
|
return ((Integer) getValue(VERB_UPDATE, OBJECT_PROJECT, KEY_TARGET_ID)).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to retrieve the --name for the update project action. */
|
/** Helper to retrieve the --name for the update project action. */
|
||||||
public String getUpdateProjectName() {
|
public String getUpdateProjectName() {
|
||||||
return ((String) getValue(ACTION_UPDATE_PROJECT, KEY_NAME));
|
return ((String) getValue(VERB_UPDATE, OBJECT_PROJECT, KEY_NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,20 +38,20 @@ public class CommandLineProcessorTest extends TestCase {
|
|||||||
public MockCommandLineProcessor(ISdkLog logger) {
|
public MockCommandLineProcessor(ISdkLog logger) {
|
||||||
super(logger,
|
super(logger,
|
||||||
new String[][] {
|
new String[][] {
|
||||||
{ "action1", "Some action" },
|
{ "verb1", "action1", "Some action" },
|
||||||
{ "action2", "Another action" },
|
{ "verb1", "action2", "Another action" },
|
||||||
});
|
});
|
||||||
define(MODE.STRING, false /*mandatory*/,
|
define(MODE.STRING, false /*mandatory*/,
|
||||||
"action1", "1", "first", "non-mandatory flag", null);
|
"verb1", "action1", "1", "first", "non-mandatory flag", null);
|
||||||
define(MODE.STRING, true /*mandatory*/,
|
define(MODE.STRING, true /*mandatory*/,
|
||||||
"action1", "2", "second", "mandatory flag", null);
|
"verb1", "action1", "2", "second", "mandatory flag", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void printHelpAndExitForAction(String actionFilter,
|
public void printHelpAndExitForAction(String verb, String directObject,
|
||||||
String errorFormat, Object... args) {
|
String errorFormat, Object... args) {
|
||||||
mHelpCalled = true;
|
mHelpCalled = true;
|
||||||
super.printHelpAndExitForAction(actionFilter, errorFormat, args);
|
super.printHelpAndExitForAction(verb, directObject, errorFormat, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -132,14 +132,14 @@ public class CommandLineProcessorTest extends TestCase {
|
|||||||
assertTrue(c.isVerbose());
|
assertTrue(c.isVerbose());
|
||||||
assertTrue(c.wasExitCalled());
|
assertTrue(c.wasExitCalled());
|
||||||
assertTrue(c.wasHelpCalled());
|
assertTrue(c.wasHelpCalled());
|
||||||
assertTrue(c.getStdErr().indexOf("Missing action name.") != -1);
|
assertTrue(c.getStdErr().indexOf("Missing verb name.") != -1);
|
||||||
|
|
||||||
c = new MockCommandLineProcessor(mLog);
|
c = new MockCommandLineProcessor(mLog);
|
||||||
c.parseArgs(new String[] { "--verbose" });
|
c.parseArgs(new String[] { "--verbose" });
|
||||||
assertTrue(c.isVerbose());
|
assertTrue(c.isVerbose());
|
||||||
assertTrue(c.wasExitCalled());
|
assertTrue(c.wasExitCalled());
|
||||||
assertTrue(c.wasHelpCalled());
|
assertTrue(c.wasHelpCalled());
|
||||||
assertTrue(c.getStdErr().indexOf("Missing action name.") != -1);
|
assertTrue(c.getStdErr().indexOf("Missing verb name.") != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void testHelp() {
|
public final void testHelp() {
|
||||||
@@ -148,39 +148,39 @@ public class CommandLineProcessorTest extends TestCase {
|
|||||||
c.parseArgs(new String[] { "-h" });
|
c.parseArgs(new String[] { "-h" });
|
||||||
assertTrue(c.wasExitCalled());
|
assertTrue(c.wasExitCalled());
|
||||||
assertTrue(c.wasHelpCalled());
|
assertTrue(c.wasHelpCalled());
|
||||||
assertTrue(c.getStdErr().indexOf("Missing action name.") == -1);
|
assertTrue(c.getStdErr().indexOf("Missing verb name.") == -1);
|
||||||
|
|
||||||
c = new MockCommandLineProcessor(mLog);
|
c = new MockCommandLineProcessor(mLog);
|
||||||
c.parseArgs(new String[] { "--help" });
|
c.parseArgs(new String[] { "--help" });
|
||||||
assertTrue(c.wasExitCalled());
|
assertTrue(c.wasExitCalled());
|
||||||
assertTrue(c.wasHelpCalled());
|
assertTrue(c.wasHelpCalled());
|
||||||
assertTrue(c.getStdErr().indexOf("Missing action name.") == -1);
|
assertTrue(c.getStdErr().indexOf("Missing verb name.") == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void testMandatory() {
|
public final void testMandatory() {
|
||||||
MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
|
MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
|
||||||
|
|
||||||
c.parseArgs(new String[] { "action1", "-1", "value1", "-2", "value2" });
|
c.parseArgs(new String[] { "verb1", "action1", "-1", "value1", "-2", "value2" });
|
||||||
assertFalse(c.wasExitCalled());
|
assertFalse(c.wasExitCalled());
|
||||||
assertFalse(c.wasHelpCalled());
|
assertFalse(c.wasHelpCalled());
|
||||||
assertEquals("", c.getStdErr());
|
assertEquals("", c.getStdErr());
|
||||||
assertEquals("value1", c.getValue("action1", "first"));
|
assertEquals("value1", c.getValue("verb1", "action1", "first"));
|
||||||
assertEquals("value2", c.getValue("action1", "second"));
|
assertEquals("value2", c.getValue("verb1", "action1", "second"));
|
||||||
|
|
||||||
c = new MockCommandLineProcessor(mLog);
|
c = new MockCommandLineProcessor(mLog);
|
||||||
c.parseArgs(new String[] { "action1", "-2", "value2" });
|
c.parseArgs(new String[] { "verb1", "action1", "-2", "value2" });
|
||||||
assertFalse(c.wasExitCalled());
|
assertFalse(c.wasExitCalled());
|
||||||
assertFalse(c.wasHelpCalled());
|
assertFalse(c.wasHelpCalled());
|
||||||
assertEquals("", c.getStdErr());
|
assertEquals("", c.getStdErr());
|
||||||
assertEquals(null, c.getValue("action1", "first"));
|
assertEquals(null, c.getValue("verb1", "action1", "first"));
|
||||||
assertEquals("value2", c.getValue("action1", "second"));
|
assertEquals("value2", c.getValue("verb1", "action1", "second"));
|
||||||
|
|
||||||
c = new MockCommandLineProcessor(mLog);
|
c = new MockCommandLineProcessor(mLog);
|
||||||
c.parseArgs(new String[] { "action1" });
|
c.parseArgs(new String[] { "verb1", "action1" });
|
||||||
assertTrue(c.wasExitCalled());
|
assertTrue(c.wasExitCalled());
|
||||||
assertTrue(c.wasHelpCalled());
|
assertTrue(c.wasHelpCalled());
|
||||||
assertTrue(c.getStdErr().indexOf("must be defined") != -1);
|
assertTrue(c.getStdErr().indexOf("must be defined") != -1);
|
||||||
assertEquals(null, c.getValue("action1", "first"));
|
assertEquals(null, c.getValue("verb1", "action1", "first"));
|
||||||
assertEquals(null, c.getValue("action1", "second"));
|
assertEquals(null, c.getValue("verb1", "action1", "second"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ public class SdkCommandLineTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void printHelpAndExitForAction(String actionFilter,
|
public void printHelpAndExitForAction(String verb, String directObject,
|
||||||
String errorFormat, Object... args) {
|
String errorFormat, Object... args) {
|
||||||
mHelpCalled = true;
|
mHelpCalled = true;
|
||||||
super.printHelpAndExitForAction(actionFilter, errorFormat, args);
|
super.printHelpAndExitForAction(verb, directObject, errorFormat, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,34 +78,64 @@ public class SdkCommandLineTest extends TestCase {
|
|||||||
super.tearDown();
|
super.tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test list with long name and verbose */
|
/** Test list */
|
||||||
public final void testList_Long_Verbose() {
|
public final void testList_Avd_Verbose() {
|
||||||
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
||||||
assertEquals("all", c.getListFilter());
|
c.parseArgs(new String[] { "-v", "list", "avd" });
|
||||||
c.parseArgs(new String[] { "-v", "list", "--filter", "vm" });
|
|
||||||
assertFalse(c.wasHelpCalled());
|
assertFalse(c.wasHelpCalled());
|
||||||
assertFalse(c.wasExitCalled());
|
assertFalse(c.wasExitCalled());
|
||||||
assertEquals("vm", c.getListFilter());
|
assertEquals("list", c.getVerb());
|
||||||
|
assertEquals("avd", c.getDirectObject());
|
||||||
assertTrue(c.isVerbose());
|
assertTrue(c.isVerbose());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test list with short name and no verbose */
|
public final void testList_Target() {
|
||||||
public final void testList_Short() {
|
|
||||||
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
||||||
assertEquals("all", c.getListFilter());
|
c.parseArgs(new String[] { "list", "target" });
|
||||||
c.parseArgs(new String[] { "list", "-f", "vm" });
|
|
||||||
assertFalse(c.wasHelpCalled());
|
assertFalse(c.wasHelpCalled());
|
||||||
assertFalse(c.wasExitCalled());
|
assertFalse(c.wasExitCalled());
|
||||||
assertEquals("vm", c.getListFilter());
|
assertEquals("list", c.getVerb());
|
||||||
|
assertEquals("target", c.getDirectObject());
|
||||||
|
assertFalse(c.isVerbose());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test list with long name and missing parameter */
|
public final void testList_None() {
|
||||||
public final void testList_Long_MissingParam() {
|
|
||||||
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
||||||
assertEquals("all", c.getListFilter());
|
c.parseArgs(new String[] { "list" });
|
||||||
c.parseArgs(new String[] { "list", "--filter" });
|
assertFalse(c.wasHelpCalled());
|
||||||
|
assertFalse(c.wasExitCalled());
|
||||||
|
assertEquals("list", c.getVerb());
|
||||||
|
assertEquals("", c.getDirectObject());
|
||||||
|
assertFalse(c.isVerbose());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void testList_Invalid() {
|
||||||
|
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
||||||
|
c.parseArgs(new String[] { "list", "unknown" });
|
||||||
assertTrue(c.wasHelpCalled());
|
assertTrue(c.wasHelpCalled());
|
||||||
assertTrue(c.wasExitCalled());
|
assertTrue(c.wasExitCalled());
|
||||||
assertEquals("all", c.getListFilter());
|
assertEquals(null, c.getVerb());
|
||||||
|
assertEquals(null, c.getDirectObject());
|
||||||
|
assertFalse(c.isVerbose());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void testList_Plural() {
|
||||||
|
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
|
||||||
|
c.parseArgs(new String[] { "list", "avds" });
|
||||||
|
assertFalse(c.wasHelpCalled());
|
||||||
|
assertFalse(c.wasExitCalled());
|
||||||
|
assertEquals("list", c.getVerb());
|
||||||
|
// we get the non-plural form
|
||||||
|
assertEquals("avd", c.getDirectObject());
|
||||||
|
assertFalse(c.isVerbose());
|
||||||
|
|
||||||
|
c = new MockSdkCommandLine(mLog);
|
||||||
|
c.parseArgs(new String[] { "list", "targets" });
|
||||||
|
assertFalse(c.wasHelpCalled());
|
||||||
|
assertFalse(c.wasExitCalled());
|
||||||
|
assertEquals("list", c.getVerb());
|
||||||
|
// we get the non-plural form
|
||||||
|
assertEquals("target", c.getDirectObject());
|
||||||
|
assertFalse(c.isVerbose());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,48 @@
|
|||||||
|
|
||||||
package com.android.sdklib;
|
package com.android.sdklib;
|
||||||
|
|
||||||
|
import java.util.Formatter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface used to display warnings/errors while parsing the SDK content.
|
* Interface used to display warnings/errors while parsing the SDK content.
|
||||||
*/
|
*/
|
||||||
public interface ISdkLog {
|
public interface ISdkLog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a warning message on stdout.
|
||||||
|
* <p/>
|
||||||
|
* Implementations should only display warnings in verbose mode.
|
||||||
|
* The message should be prefixed with "Warning:".
|
||||||
|
*
|
||||||
|
* @param warningFormat is an optional error format. If non-null, it will be printed
|
||||||
|
* using a {@link Formatter} with the provided arguments.
|
||||||
|
* @param args provides the arguments for warningFormat.
|
||||||
|
*/
|
||||||
void warning(String warningFormat, Object... args);
|
void warning(String warningFormat, Object... args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints an error message on stderr.
|
||||||
|
* <p/>
|
||||||
|
* Implementation should always display errors, independent of verbose mode.
|
||||||
|
* The message should be prefixed with "Error:".
|
||||||
|
*
|
||||||
|
* @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's
|
||||||
|
* message will be printed out.
|
||||||
|
* @param errorFormat is an optional error format. If non-null, it will be printed
|
||||||
|
* using a {@link Formatter} with the provided arguments.
|
||||||
|
* @param args provides the arguments for errorFormat.
|
||||||
|
*/
|
||||||
void error(Throwable t, String errorFormat, Object... args);
|
void error(Throwable t, String errorFormat, Object... args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a message as-is on stdout.
|
||||||
|
* <p/>
|
||||||
|
* Implementation should always display errors, independent of verbose mode.
|
||||||
|
* No prefix is used, the message is printed as-is after formatting.
|
||||||
|
*
|
||||||
|
* @param msgFormat is an optional error format. If non-null, it will be printed
|
||||||
|
* using a {@link Formatter} with the provided arguments.
|
||||||
|
* @param args provides the arguments for msgFormat.
|
||||||
|
*/
|
||||||
void printf(String msgFormat, Object... args);
|
void printf(String msgFormat, Object... args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.sdklib.vm;
|
package com.android.sdklib.avd;
|
||||||
|
|
||||||
import com.android.prefs.AndroidLocation;
|
import com.android.prefs.AndroidLocation;
|
||||||
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||||
@@ -39,12 +39,13 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Virtual Machine manager to access the list of VMs or create new ones.
|
* Virtual Device Manager to access the list of AVDs or create new ones.
|
||||||
*/
|
*/
|
||||||
public final class VmManager {
|
public final class AvdManager {
|
||||||
|
|
||||||
private final static String VM_INFO_PATH = "path";
|
private static final String AVD_FOLDER_EXTENSION = ".avd";
|
||||||
private final static String VM_INFO_TARGET = "target";
|
private final static String AVD_INFO_PATH = "path";
|
||||||
|
private final static String AVD_INFO_TARGET = "target";
|
||||||
|
|
||||||
private final static String IMAGE_USERDATA = "userdata.img";
|
private final static String IMAGE_USERDATA = "userdata.img";
|
||||||
private final static String CONFIG_INI = "config.ini";
|
private final static String CONFIG_INI = "config.ini";
|
||||||
@@ -54,7 +55,7 @@ public final class VmManager {
|
|||||||
|
|
||||||
private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]?");
|
private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]?");
|
||||||
|
|
||||||
public static final class VmInfo {
|
public static final class AvdInfo {
|
||||||
String name;
|
String name;
|
||||||
String path;
|
String path;
|
||||||
IAndroidTarget target;
|
IAndroidTarget target;
|
||||||
@@ -72,30 +73,30 @@ public final class VmManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ArrayList<VmInfo> mVmList = new ArrayList<VmInfo>();
|
private final ArrayList<AvdInfo> mAvdList = new ArrayList<AvdInfo>();
|
||||||
private ISdkLog mSdkLog;
|
private ISdkLog mSdkLog;
|
||||||
private final SdkManager mSdk;
|
private final SdkManager mSdk;
|
||||||
|
|
||||||
public VmManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
|
public AvdManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
|
||||||
mSdk = sdk;
|
mSdk = sdk;
|
||||||
mSdkLog = sdkLog;
|
mSdkLog = sdkLog;
|
||||||
buildVmList();
|
buildAvdList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the existing VMs.
|
* Returns the existing AVDs.
|
||||||
* @return a newly allocated arrays containing all the VMs.
|
* @return a newly allocated array containing all the AVDs.
|
||||||
*/
|
*/
|
||||||
public VmInfo[] getVms() {
|
public AvdInfo[] getAvds() {
|
||||||
return mVmList.toArray(new VmInfo[mVmList.size()]);
|
return mAvdList.toArray(new AvdInfo[mAvdList.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link VmInfo} matching the given <var>name</var>.
|
* Returns the {@link AvdInfo} matching the given <var>name</var>.
|
||||||
* @return the matching VmInfo or <code>null</code> if none were found.
|
* @return the matching AvdInfo or <code>null</code> if none were found.
|
||||||
*/
|
*/
|
||||||
public VmInfo getVm(String name) {
|
public AvdInfo getAvd(String name) {
|
||||||
for (VmInfo info : mVmList) {
|
for (AvdInfo info : mAvdList) {
|
||||||
if (info.name.equals(name)) {
|
if (info.name.equals(name)) {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@@ -105,19 +106,20 @@ public final class VmManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new VM. It is expected that there is no existing VM with this name already.
|
* Creates a new AVD. It is expected that there is no existing AVD with this name already.
|
||||||
* @param parentFolder the folder to contain the VM. A new folder will be created in this
|
* @param parentFolder the folder to contain the AVD. A new folder will be created in this
|
||||||
* folder with the name of the VM
|
* folder with the name of the AVD
|
||||||
* @param name the name of the VM
|
* @param name the name of the AVD
|
||||||
* @param target the target of the VM
|
* @param target the target of the AVD
|
||||||
* @param skinName the name of the skin. Can be null.
|
* @param skinName the name of the skin. Can be null.
|
||||||
* @param sdcard the parameter value for the sdCard. Can be null. This is either a path to
|
* @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).
|
* an existing sdcard image or a sdcard size (\d+, \d+K, \dM).
|
||||||
* @param hardwareConfig the hardware setup for the VM
|
* @param hardwareConfig the hardware setup for the AVD
|
||||||
|
* @param removePrevious If true remove any previous files.
|
||||||
*/
|
*/
|
||||||
public VmInfo createVm(String parentFolder, String name, IAndroidTarget target,
|
public AvdInfo createAvd(String parentFolder, String name, IAndroidTarget target,
|
||||||
String skinName, String sdcard, Map<String,String> hardwareConfig,
|
String skinName, String sdcard, Map<String,String> hardwareConfig,
|
||||||
ISdkLog log) {
|
boolean removePrevious, ISdkLog log) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File rootDirectory = new File(parentFolder);
|
File rootDirectory = new File(parentFolder);
|
||||||
@@ -128,24 +130,31 @@ public final class VmManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
File vmFolder = new File(parentFolder, name + ".avm");
|
File avdFolder = new File(parentFolder, name + AVD_FOLDER_EXTENSION);
|
||||||
if (vmFolder.exists()) {
|
if (avdFolder.exists()) {
|
||||||
if (log != null) {
|
if (removePrevious) {
|
||||||
log.error(null, "Folder %s is in the way.", vmFolder.getAbsolutePath());
|
// AVD already exists and removePrevious is set, try to remove the
|
||||||
|
// directory's content first (but not the directory itself).
|
||||||
|
recursiveDelete(avdFolder);
|
||||||
|
} else {
|
||||||
|
// AVD shouldn't already exist if removePrevious is false.
|
||||||
|
if (log != null) {
|
||||||
|
log.error(null, "Folder %s is in the way.", avdFolder.getAbsolutePath());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the vm folder.
|
// create the AVD folder.
|
||||||
vmFolder.mkdir();
|
avdFolder.mkdir();
|
||||||
|
|
||||||
HashMap<String, String> values = new HashMap<String, String>();
|
HashMap<String, String> values = new HashMap<String, String>();
|
||||||
|
|
||||||
// prepare the ini file.
|
// prepare the ini file.
|
||||||
String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
|
String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
|
||||||
File iniFile = new File(vmRoot, name + ".ini");
|
File iniFile = new File(avdRoot, name + ".ini");
|
||||||
values.put(VM_INFO_PATH, vmFolder.getAbsolutePath());
|
values.put(AVD_INFO_PATH, avdFolder.getAbsolutePath());
|
||||||
values.put(VM_INFO_TARGET, target.hashString());
|
values.put(AVD_INFO_TARGET, target.hashString());
|
||||||
createConfigIni(iniFile, values);
|
createConfigIni(iniFile, values);
|
||||||
|
|
||||||
// writes the userdata.img in it.
|
// writes the userdata.img in it.
|
||||||
@@ -153,7 +162,7 @@ public final class VmManager {
|
|||||||
File userdataSrc = new File(imagePath, IMAGE_USERDATA);
|
File userdataSrc = new File(imagePath, IMAGE_USERDATA);
|
||||||
FileInputStream fis = new FileInputStream(userdataSrc);
|
FileInputStream fis = new FileInputStream(userdataSrc);
|
||||||
|
|
||||||
File userdataDest = new File(vmFolder, IMAGE_USERDATA);
|
File userdataDest = new File(avdFolder, IMAGE_USERDATA);
|
||||||
FileOutputStream fos = new FileOutputStream(userdataDest);
|
FileOutputStream fos = new FileOutputStream(userdataDest);
|
||||||
|
|
||||||
byte[] buffer = new byte[4096];
|
byte[] buffer = new byte[4096];
|
||||||
@@ -193,7 +202,7 @@ public final class VmManager {
|
|||||||
Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard);
|
Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard);
|
||||||
if (m.matches()) {
|
if (m.matches()) {
|
||||||
// create the sdcard.
|
// create the sdcard.
|
||||||
sdcardFile = new File(vmFolder, "sdcard.img");
|
sdcardFile = new File(avdFolder, "sdcard.img");
|
||||||
String path = sdcardFile.getAbsolutePath();
|
String path = sdcardFile.getAbsolutePath();
|
||||||
|
|
||||||
// execute mksdcard with the proper parameters.
|
// execute mksdcard with the proper parameters.
|
||||||
@@ -224,28 +233,27 @@ public final class VmManager {
|
|||||||
values.putAll(hardwareConfig);
|
values.putAll(hardwareConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
File configIniFile = new File(vmFolder, CONFIG_INI);
|
File configIniFile = new File(avdFolder, CONFIG_INI);
|
||||||
createConfigIni(configIniFile, values);
|
createConfigIni(configIniFile, values);
|
||||||
|
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
if (target.isPlatform()) {
|
if (target.isPlatform()) {
|
||||||
log.printf("Created VM '%s' based on %s\n", name, target.getName());
|
log.printf("Created AVD '%s' based on %s\n", name, target.getName());
|
||||||
} else {
|
} else {
|
||||||
log.printf(
|
log.printf("Created AVD '%s' based on %s (%s)\n", name, target.getName(),
|
||||||
"Created VM '%s' based on %s (%s)\n", name, target.getName(),
|
target.getVendor());
|
||||||
target.getVendor());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the VmInfo object, and add it to the list
|
// create the AvdInfo object, and add it to the list
|
||||||
VmInfo vmInfo = new VmInfo();
|
AvdInfo avdInfo = new AvdInfo();
|
||||||
vmInfo.name = name;
|
avdInfo.name = name;
|
||||||
vmInfo.path = vmFolder.getAbsolutePath();
|
avdInfo.path = avdFolder.getAbsolutePath();
|
||||||
vmInfo.target = target;
|
avdInfo.target = target;
|
||||||
|
|
||||||
mVmList.add(vmInfo);
|
mAvdList.add(avdInfo);
|
||||||
|
|
||||||
return vmInfo;
|
return avdInfo;
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
log.error(e, null);
|
log.error(e, null);
|
||||||
@@ -259,21 +267,35 @@ public final class VmManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildVmList() throws AndroidLocationException {
|
/**
|
||||||
|
* Helper method to recursively delete a folder's content (but not the folder itself).
|
||||||
|
*
|
||||||
|
* @throws SecurityException like {@link File#delete()} does if file/folder is not writable.
|
||||||
|
*/
|
||||||
|
public void recursiveDelete(File folder) {
|
||||||
|
for (File f : folder.listFiles()) {
|
||||||
|
if (f.isDirectory()) {
|
||||||
|
recursiveDelete(folder);
|
||||||
|
}
|
||||||
|
f.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildAvdList() throws AndroidLocationException {
|
||||||
// get the Android prefs location.
|
// get the Android prefs location.
|
||||||
String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
|
String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
|
||||||
|
|
||||||
// ensure folder validity.
|
// ensure folder validity.
|
||||||
File folder = new File(vmRoot);
|
File folder = new File(avdRoot);
|
||||||
if (folder.isFile()) {
|
if (folder.isFile()) {
|
||||||
throw new AndroidLocationException(String.format("%s is not a valid folder.", vmRoot));
|
throw new AndroidLocationException(String.format("%s is not a valid folder.", avdRoot));
|
||||||
} else if (folder.exists() == false) {
|
} else if (folder.exists() == false) {
|
||||||
// folder is not there, we create it and return
|
// folder is not there, we create it and return
|
||||||
folder.mkdirs();
|
folder.mkdirs();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
File[] vms = folder.listFiles(new FilenameFilter() {
|
File[] avds = folder.listFiles(new FilenameFilter() {
|
||||||
public boolean accept(File parent, String name) {
|
public boolean accept(File parent, String name) {
|
||||||
if (INI_NAME_PATTERN.matcher(name).matches()) {
|
if (INI_NAME_PATTERN.matcher(name).matches()) {
|
||||||
// check it's a file and not a folder
|
// check it's a file and not a folder
|
||||||
@@ -284,23 +306,23 @@ public final class VmManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (File vm : vms) {
|
for (File avd : avds) {
|
||||||
VmInfo info = parseVmInfo(vm);
|
AvdInfo info = parseAvdInfo(avd);
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
mVmList.add(info);
|
mAvdList.add(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private VmInfo parseVmInfo(File path) {
|
private AvdInfo parseAvdInfo(File path) {
|
||||||
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
|
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
|
||||||
|
|
||||||
String vmPath = map.get(VM_INFO_PATH);
|
String avdPath = map.get(AVD_INFO_PATH);
|
||||||
if (vmPath == null) {
|
if (avdPath == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String targetHash = map.get(VM_INFO_TARGET);
|
String targetHash = map.get(AVD_INFO_TARGET);
|
||||||
if (targetHash == null) {
|
if (targetHash == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -310,14 +332,14 @@ public final class VmManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
VmInfo info = new VmInfo();
|
AvdInfo info = new AvdInfo();
|
||||||
Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
|
Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
|
||||||
if (matcher.matches()) {
|
if (matcher.matches()) {
|
||||||
info.name = matcher.group(1);
|
info.name = matcher.group(1);
|
||||||
} else {
|
} else {
|
||||||
info.name = path.getName(); // really this should not happen.
|
info.name = path.getName(); // really this should not happen.
|
||||||
}
|
}
|
||||||
info.path = vmPath;
|
info.path = avdPath;
|
||||||
info.target = target;
|
info.target = target;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
@@ -447,4 +469,14 @@ public final class VmManager {
|
|||||||
return process.waitFor();
|
return process.waitFor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an {@link AvdInfo} from the internal list.
|
||||||
|
*
|
||||||
|
* @param avdInfo The {@link AvdInfo} to remove.
|
||||||
|
* @return true if this {@link AvdInfo} was present and has been removed.
|
||||||
|
*/
|
||||||
|
public boolean removeAvd(AvdInfo avdInfo) {
|
||||||
|
return mAvdList.remove(avdInfo);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.sdklib.vm;
|
package com.android.sdklib.avd;
|
||||||
|
|
||||||
import com.android.sdklib.ISdkLog;
|
import com.android.sdklib.ISdkLog;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
package com.android.sdkuilib;
|
package com.android.sdkuilib;
|
||||||
|
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
import com.android.sdklib.avd.AvdManager.AvdInfo;
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.events.ControlAdapter;
|
import org.eclipse.swt.events.ControlAdapter;
|
||||||
@@ -40,16 +40,16 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The VM selector is a table that is added to the given parent composite.
|
* The AVD selector is a table that is added to the given parent composite.
|
||||||
* <p/>
|
* <p/>
|
||||||
* To use, create it using {@link #VmSelector(Composite, VmInfo[], boolean)} then
|
* To use, create it using {@link #AvdSelector(Composite, AvdInfo[], boolean)} then
|
||||||
* call {@link #setSelection(VmInfo)}, {@link #setSelectionListener(SelectionListener)}
|
* call {@link #setSelection(AvdInfo)}, {@link #setSelectionListener(SelectionListener)}
|
||||||
* and finally use {@link #getFirstSelected()} or {@link #getAllSelected()} to retrieve the
|
* and finally use {@link #getFirstSelected()} or {@link #getAllSelected()} to retrieve the
|
||||||
* selection.
|
* selection.
|
||||||
*/
|
*/
|
||||||
public final class VmSelector {
|
public final class AvdSelector {
|
||||||
|
|
||||||
private VmInfo[] mVms;
|
private AvdInfo[] mAvds;
|
||||||
private final boolean mAllowMultipleSelection;
|
private final boolean mAllowMultipleSelection;
|
||||||
private SelectionListener mSelectionListener;
|
private SelectionListener mSelectionListener;
|
||||||
private Table mTable;
|
private Table mTable;
|
||||||
@@ -59,12 +59,12 @@ public final class VmSelector {
|
|||||||
* Creates a new SDK Target Selector.
|
* Creates a new SDK Target Selector.
|
||||||
*
|
*
|
||||||
* @param parent The parent composite where the selector will be added.
|
* @param parent The parent composite where the selector will be added.
|
||||||
* @param vms The list of vms. This is <em>not</em> copied, the caller must not modify.
|
* @param avds The list of AVDs. This is <em>not</em> copied, the caller must not modify.
|
||||||
* @param allowMultipleSelection True if more than one SDK target can be selected at the same
|
* @param allowMultipleSelection True if more than one SDK target can be selected at the same
|
||||||
* time.
|
* time.
|
||||||
*/
|
*/
|
||||||
public VmSelector(Composite parent, VmInfo[] vms, boolean allowMultipleSelection) {
|
public AvdSelector(Composite parent, AvdInfo[] avds, boolean allowMultipleSelection) {
|
||||||
mVms = vms;
|
mAvds = avds;
|
||||||
|
|
||||||
// Layout has 1 column
|
// Layout has 1 column
|
||||||
Composite group = new Composite(parent, SWT.NONE);
|
Composite group = new Composite(parent, SWT.NONE);
|
||||||
@@ -89,7 +89,7 @@ public final class VmSelector {
|
|||||||
|
|
||||||
// create the table columns
|
// create the table columns
|
||||||
final TableColumn column0 = new TableColumn(mTable, SWT.NONE);
|
final TableColumn column0 = new TableColumn(mTable, SWT.NONE);
|
||||||
column0.setText("VM Name");
|
column0.setText("AVD Name");
|
||||||
final TableColumn column1 = new TableColumn(mTable, SWT.NONE);
|
final TableColumn column1 = new TableColumn(mTable, SWT.NONE);
|
||||||
column1.setText("Target Name");
|
column1.setText("Target Name");
|
||||||
final TableColumn column2 = new TableColumn(mTable, SWT.NONE);
|
final TableColumn column2 = new TableColumn(mTable, SWT.NONE);
|
||||||
@@ -104,25 +104,25 @@ public final class VmSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new set of VM, with an optional filter.
|
* Sets a new set of AVD, with an optional filter.
|
||||||
* <p/>This must be called from the UI thread.
|
* <p/>This must be called from the UI thread.
|
||||||
*
|
*
|
||||||
* @param vms The list of vms. This is <em>not</em> copied, the caller must not modify.
|
* @param avds The list of AVDs. This is <em>not</em> copied, the caller must not modify.
|
||||||
* @param filter An IAndroidTarget. If non-null, only VM whose target are compatible with the
|
* @param filter An IAndroidTarget. If non-null, only AVD whose target are compatible with the
|
||||||
* filter target will displayed an available for selection.
|
* filter target will displayed an available for selection.
|
||||||
*/
|
*/
|
||||||
public void setVms(VmInfo[] vms, IAndroidTarget filter) {
|
public void setAvds(AvdInfo[] avds, IAndroidTarget filter) {
|
||||||
mVms = vms;
|
mAvds = avds;
|
||||||
fillTable(mTable, filter);
|
fillTable(mTable, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of known Vms.
|
* Returns the list of known AVDs.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is not a copy. Callers must <em>not</em> modify this array.
|
* This is not a copy. Callers must <em>not</em> modify this array.
|
||||||
*/
|
*/
|
||||||
public VmInfo[] getVms() {
|
public AvdInfo[] getAvds() {
|
||||||
return mVms;
|
return mAvds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,11 +151,11 @@ public final class VmSelector {
|
|||||||
* @param target the target to be selection
|
* @param target the target to be selection
|
||||||
* @return true if the target could be selected, false otherwise.
|
* @return true if the target could be selected, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean setSelection(VmInfo target) {
|
public boolean setSelection(AvdInfo target) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
boolean modified = false;
|
boolean modified = false;
|
||||||
for (TableItem i : mTable.getItems()) {
|
for (TableItem i : mTable.getItems()) {
|
||||||
if ((VmInfo) i.getData() == target) {
|
if ((AvdInfo) i.getData() == target) {
|
||||||
found = true;
|
found = true;
|
||||||
if (!i.getChecked()) {
|
if (!i.getChecked()) {
|
||||||
modified = true;
|
modified = true;
|
||||||
@@ -181,14 +181,14 @@ public final class VmSelector {
|
|||||||
* @see #getFirstSelected()
|
* @see #getFirstSelected()
|
||||||
* @return An array of selected items. The list can be empty but not null.
|
* @return An array of selected items. The list can be empty but not null.
|
||||||
*/
|
*/
|
||||||
public VmInfo[] getAllSelected() {
|
public AvdInfo[] getAllSelected() {
|
||||||
ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
|
ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
|
||||||
for (TableItem i : mTable.getItems()) {
|
for (TableItem i : mTable.getItems()) {
|
||||||
if (i.getChecked()) {
|
if (i.getChecked()) {
|
||||||
list.add((IAndroidTarget) i.getData());
|
list.add((IAndroidTarget) i.getData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list.toArray(new VmInfo[list.size()]);
|
return list.toArray(new AvdInfo[list.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,10 +198,10 @@ public final class VmSelector {
|
|||||||
* @see #getAllSelected()
|
* @see #getAllSelected()
|
||||||
* @return The first selected item or null.
|
* @return The first selected item or null.
|
||||||
*/
|
*/
|
||||||
public VmInfo getFirstSelected() {
|
public AvdInfo getFirstSelected() {
|
||||||
for (TableItem i : mTable.getItems()) {
|
for (TableItem i : mTable.getItems()) {
|
||||||
if (i.getChecked()) {
|
if (i.getChecked()) {
|
||||||
return (VmInfo) i.getData();
|
return (AvdInfo) i.getData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -283,7 +283,7 @@ public final class VmSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills the table with all VM.
|
* Fills the table with all AVD.
|
||||||
* The table columns are:
|
* The table columns are:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>column 0: sdk name
|
* <li>column 0: sdk name
|
||||||
@@ -294,14 +294,14 @@ public final class VmSelector {
|
|||||||
*/
|
*/
|
||||||
private void fillTable(final Table table, IAndroidTarget filter) {
|
private void fillTable(final Table table, IAndroidTarget filter) {
|
||||||
table.removeAll();
|
table.removeAll();
|
||||||
if (mVms != null && mVms.length > 0) {
|
if (mAvds != null && mAvds.length > 0) {
|
||||||
table.setEnabled(true);
|
table.setEnabled(true);
|
||||||
for (VmInfo vm : mVms) {
|
for (AvdInfo avd : mAvds) {
|
||||||
if (filter == null || filter.isCompatibleBaseFor(vm.getTarget())) {
|
if (filter == null || filter.isCompatibleBaseFor(avd.getTarget())) {
|
||||||
TableItem item = new TableItem(table, SWT.NONE);
|
TableItem item = new TableItem(table, SWT.NONE);
|
||||||
item.setData(vm);
|
item.setData(avd);
|
||||||
item.setText(0, vm.getName());
|
item.setText(0, avd.getName());
|
||||||
IAndroidTarget target = vm.getTarget();
|
IAndroidTarget target = avd.getTarget();
|
||||||
item.setText(1, target.getFullName());
|
item.setText(1, target.getFullName());
|
||||||
item.setText(2, target.getApiVersionName());
|
item.setText(2, target.getApiVersionName());
|
||||||
item.setText(3, Integer.toString(target.getApiVersionNumber()));
|
item.setText(3, Integer.toString(target.getApiVersionNumber()));
|
||||||
@@ -314,7 +314,7 @@ public final class VmSelector {
|
|||||||
TableItem item = new TableItem(table, SWT.NONE);
|
TableItem item = new TableItem(table, SWT.NONE);
|
||||||
item.setData(null);
|
item.setData(null);
|
||||||
item.setText(0, "--");
|
item.setText(0, "--");
|
||||||
item.setText(1, "No VM available");
|
item.setText(1, "No AVD available");
|
||||||
item.setText(2, "--");
|
item.setText(2, "--");
|
||||||
item.setText(3, "--");
|
item.setText(3, "--");
|
||||||
}
|
}
|
||||||
@@ -365,13 +365,13 @@ public final class VmSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the description label with the path of the item's VM, if any.
|
* Updates the description label with the path of the item's AVD, if any.
|
||||||
*/
|
*/
|
||||||
private void updateDescription(TableItem item) {
|
private void updateDescription(TableItem item) {
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
Object data = item.getData();
|
Object data = item.getData();
|
||||||
if (data instanceof VmInfo) {
|
if (data instanceof AvdInfo) {
|
||||||
String newTooltip = ((VmInfo) data).getPath();
|
String newTooltip = ((AvdInfo) data).getPath();
|
||||||
mDescription.setText(newTooltip == null ? "" : newTooltip); //$NON-NLS-1$
|
mDescription.setText(newTooltip == null ? "" : newTooltip); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user