From 8aca5b8afd039e2bee31c940951e12a6325595be Mon Sep 17 00:00:00 2001 From: Swarna Kumar Date: Thu, 30 Jul 2009 15:03:25 -0700 Subject: [PATCH 01/87] Since bug 1966269 is fixed, marking calprov tests as continuous=true --- testrunner/test_defs.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml index 85488230a..9d03558d2 100644 --- a/testrunner/test_defs.xml +++ b/testrunner/test_defs.xml @@ -305,11 +305,11 @@ See test_defs.xsd for more information. coverage_target="Calendar" continuous="true" /> - + coverage_target="CalendarProvider" + continuous="true" /> Date: Fri, 31 Jul 2009 13:17:52 -0400 Subject: [PATCH 02/87] ADT: fix PreCompilerBuilder to use minSdkVersion as a string, not an int. --- .../adt/internal/build/PreCompilerBuilder.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java index 2ba0b0331..2f733fa9c 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java @@ -291,6 +291,9 @@ public class PreCompilerBuilder extends BaseBuilder { // This interrupts the build. The next builders will not run. stopBuild(msg); + + // TODO: document whether code below that uses manifest (which is now guaranteed + // to be null) will actually be executed or not. } // lets check the XML of the manifest first, if that hasn't been done by the @@ -342,7 +345,7 @@ public class PreCompilerBuilder extends BaseBuilder { } else if (minSdkValue < projectVersion.getApiLevel()) { // integer minSdk is not high enough for the target => warning String msg = String.format( - "Manifest min SDK version (%1$d) is lower than project target API level (%2$d)", + "Manifest min SDK version (%1$s) is lower than project target API level (%2$d)", minSdkVersion, projectVersion.getApiLevel()); AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg); BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg, @@ -383,11 +386,14 @@ public class PreCompilerBuilder extends BaseBuilder { // This interrupts the build. The next builders will not run. stopBuild(msg); + + // TODO: document whether code below that uses javaPackage (which is now guaranteed + // to be null) will actually be executed or not. } // at this point we have the java package. We need to make sure it's not a different // package than the previous one that were built. - if (javaPackage.equals(mManifestPackage) == false) { + if (javaPackage != null && javaPackage.equals(mManifestPackage) == false) { // The manifest package has changed, the user may want to update // the launch configuration if (mManifestPackage != null) { @@ -421,7 +427,7 @@ public class PreCompilerBuilder extends BaseBuilder { // get the file system path IPath outputLocation = mGenFolder.getLocation(); IPath resLocation = resFolder.getLocation(); - IPath manifestLocation = manifest.getLocation(); + IPath manifestLocation = manifest == null ? null : manifest.getLocation(); // those locations have to exist for us to do something! if (outputLocation != null && resLocation != null From d08cf83aace1c40952cc57fa1a12bc3891565250 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Fri, 31 Jul 2009 17:35:24 -0700 Subject: [PATCH 03/87] Minor fix to the plug-ins license. --- .../features/com.android.ide.eclipse.adt/feature.xml | 5 +---- .../features/com.android.ide.eclipse.ddms/feature.xml | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml index e739044cc..74002cbb3 100644 --- a/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml +++ b/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml @@ -15,11 +15,8 @@ - Note: jcommon-1.0.12.jar is under the BSD license rather than the APL. You can find a copy of the BSD License at http://www.opensource.org/licenses/bsd-license.php + Note: kxml2-2.3.0.jar is under the BSD license rather than the EPL. You can find a copy of the BSD License at http://www.opensource.org/licenses/bsd-license.php -jfreechart-1.0.9.jar and jfreechart-1.0.9-swt.jar are under the LGPL rather than the EPL. You can find a copy of the LGPL at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt. You can get the source code for these two components at http://android.git.kernel.org/pub/jfreechart-1.0.9.zip - - Eclipse Public License - v 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. diff --git a/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml index e70c1b98a..884669b86 100644 --- a/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml +++ b/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml @@ -16,9 +16,9 @@ Note: jcommon-1.0.12.jar is under the BSD license rather than the APL. You can find a copy of the BSD License at http://www.opensource.org/licenses/bsd-license.php - jfreechart-1.0.9.jar and jfreechart-1.0.9-swt.jar are under the LGPL rather than the EPL. You can find a copy of the LGPL at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt. You can get the source code for these two components at http://android.git.kernel.org/pub/jfreechart-1.0.9.zip - - + jfreechart-1.0.9.jar and jfreechart-1.0.9-swt.jar are under the LGPL rather than the APL. You can find a copy of the LGPL at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt. You can get the source code for these two components at http://android.git.kernel.org/pub/jfreechart-1.0.9.zip + + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ From bd133701171c4903041a47be982fec4a1fa98b42 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Mon, 3 Aug 2009 13:46:27 -0700 Subject: [PATCH 04/87] Fix PlatformTarget#compareTo(IAndroidTarget) again. --- .../libs/sdklib/src/com/android/sdklib/PlatformTarget.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java index 15e7e51f4..d0f009f51 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java @@ -242,7 +242,7 @@ final class PlatformTarget implements IAndroidTarget { int apiDiff = mVersion.getApiLevel() - target.getVersion().getApiLevel(); if (mVersion.getCodename() != null && apiDiff == 0) { - if (target.getVersionName() == null) { + if (target.getVersion().getCodename() == null) { return +1; // preview showed last } return mVersion.getCodename().compareTo(target.getVersion().getCodename()); From 2f39cedad3537a0afee5df59707be945ae70c8de Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Mon, 3 Aug 2009 14:23:16 -0700 Subject: [PATCH 05/87] Fix the DeviceChooserDialog table issues. On Linux, the gtk table seems to resize itself automatically when the layout is computed and forces the last column to resize itself at +18 pixels. This has a problematic impact on this dialog as it is not resizable and is made to match the size of the content. As the dialog is used time after time the last column grows by 18 pixels at every use up to a point where it doesn't fit the screen. Since storing the columns size is not that useful and I couldn't find a way to ignore this first resize, I'm just removing the width storage. --- .../internal/launch/DeviceChooserDialog.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java index 8b61e27dd..315f456ac 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java @@ -36,7 +36,6 @@ import com.android.sdkuilib.internal.widgets.AvdSelector.IAvdFilter; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; @@ -68,12 +67,6 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener 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_STATE = "deviceChooser.state"; //$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_DEBUG = "deviceChooser.debug"; //$NON-NLS-1$ - private Table mDeviceTable; private TableViewer mViewer; private AvdSelector mPreferredAvdSelector; @@ -334,7 +327,6 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener layout.marginLeft = 30; offsetComp.setLayout(layout); - IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); mDeviceTable = new Table(offsetComp, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER); GridData gd; mDeviceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH)); @@ -345,23 +337,23 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener TableHelper.createTableColumn(mDeviceTable, "Serial Number", SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$ - PREFS_COL_SERIAL, store); + null /* prefs name */, null /* prefs store */); TableHelper.createTableColumn(mDeviceTable, "AVD Name", - SWT.LEFT, "engineering", //$NON-NLS-1$ - PREFS_COL_AVD, store); + SWT.LEFT, "AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$ + null /* prefs name */, null /* prefs store */); TableHelper.createTableColumn(mDeviceTable, "Target", SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$ - PREFS_COL_TARGET, store); + null /* prefs name */, null /* prefs store */); TableHelper.createTableColumn(mDeviceTable, "Debug", SWT.LEFT, "Debug", //$NON-NLS-1$ - PREFS_COL_DEBUG, store); + null /* prefs name */, null /* prefs store */); TableHelper.createTableColumn(mDeviceTable, "State", SWT.LEFT, "bootloader", //$NON-NLS-1$ - PREFS_COL_STATE, store); + null /* prefs name */, null /* prefs store */); // create the viewer for it mViewer = new TableViewer(mDeviceTable); From 0c9bf956f008b1738b226644c21a63c206c6cdfd Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Mon, 3 Aug 2009 16:05:36 -0700 Subject: [PATCH 06/87] Import revised translations. DO NOT MERGE --- apps/Fallback/res/values-cs/strings.xml | 6 +++--- apps/Fallback/res/values-da/strings.xml | 6 +++--- apps/Fallback/res/values-de/strings.xml | 6 +++--- apps/Fallback/res/values-el/strings.xml | 6 +++--- apps/Fallback/res/values-es-rUS/strings.xml | 6 +++--- apps/Fallback/res/values-es/strings.xml | 6 +++--- apps/Fallback/res/values-fr/strings.xml | 6 +++--- apps/Fallback/res/values-it/strings.xml | 6 +++--- apps/Fallback/res/values-ja/strings.xml | 6 +++--- apps/Fallback/res/values-ko/strings.xml | 6 +++--- apps/Fallback/res/values-nb/strings.xml | 6 +++--- apps/Fallback/res/values-nl/strings.xml | 6 +++--- apps/Fallback/res/values-pl/strings.xml | 6 +++--- apps/Fallback/res/values-pt-rPT/strings.xml | 6 +++--- apps/Fallback/res/values-pt/strings.xml | 6 +++--- apps/Fallback/res/values-ru/strings.xml | 6 +++--- apps/Fallback/res/values-sv/strings.xml | 6 +++--- apps/Fallback/res/values-tr/strings.xml | 6 +++--- apps/Fallback/res/values-zh-rCN/strings.xml | 6 +++--- apps/Fallback/res/values-zh-rTW/strings.xml | 6 +++--- 20 files changed, 60 insertions(+), 60 deletions(-) diff --git a/apps/Fallback/res/values-cs/strings.xml b/apps/Fallback/res/values-cs/strings.xml index b9d34f940..1fc121cf0 100644 --- a/apps/Fallback/res/values-cs/strings.xml +++ b/apps/Fallback/res/values-cs/strings.xml @@ -15,7 +15,7 @@ --> - "Záloha" - "Akce není podporována" - "Tato akce není momentálně podporována." + "Záloha" + "Akce není podporována" + "Tato akce není momentálně podporována." diff --git a/apps/Fallback/res/values-da/strings.xml b/apps/Fallback/res/values-da/strings.xml index b3dfa6313..4584e6130 100644 --- a/apps/Fallback/res/values-da/strings.xml +++ b/apps/Fallback/res/values-da/strings.xml @@ -15,7 +15,7 @@ --> - "Reserve" - "Ikke understøttet handling" - "Handlingen er ikke understøttet i øjeblikket." + "Reserve" + "Ikke understøttet handling" + "Handlingen er ikke understøttet i øjeblikket." diff --git a/apps/Fallback/res/values-de/strings.xml b/apps/Fallback/res/values-de/strings.xml index 8d59ddf39..90bbb165e 100644 --- a/apps/Fallback/res/values-de/strings.xml +++ b/apps/Fallback/res/values-de/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Nicht unterstützte Aktion" - "Diese Aktion wird zurzeit nicht unterstützt." + "Fallback" + "Nicht unterstützte Aktion" + "Diese Aktion wird zurzeit nicht unterstützt." diff --git a/apps/Fallback/res/values-el/strings.xml b/apps/Fallback/res/values-el/strings.xml index fecaf4af4..b985af7be 100644 --- a/apps/Fallback/res/values-el/strings.xml +++ b/apps/Fallback/res/values-el/strings.xml @@ -15,7 +15,7 @@ --> - "Εναλλακτική" - "Ενέργεια που δεν υποστηρίζεται" - "Αυτή η ενέργεια δεν υποστηρίζεται αυτήν τη στιγμή." + "Εναλλακτική" + "Ενέργεια που δεν υποστηρίζεται" + "Αυτή η ενέργεια δεν υποστηρίζεται αυτήν τη στιγμή." diff --git a/apps/Fallback/res/values-es-rUS/strings.xml b/apps/Fallback/res/values-es-rUS/strings.xml index 0ce57511e..d15a287e4 100644 --- a/apps/Fallback/res/values-es-rUS/strings.xml +++ b/apps/Fallback/res/values-es-rUS/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Acción no admitida" - "Esa acción no se admite actualmente." + "Fallback" + "Acción no admitida" + "Esa acción no se admite actualmente." diff --git a/apps/Fallback/res/values-es/strings.xml b/apps/Fallback/res/values-es/strings.xml index 0ce57511e..d15a287e4 100644 --- a/apps/Fallback/res/values-es/strings.xml +++ b/apps/Fallback/res/values-es/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Acción no admitida" - "Esa acción no se admite actualmente." + "Fallback" + "Acción no admitida" + "Esa acción no se admite actualmente." diff --git a/apps/Fallback/res/values-fr/strings.xml b/apps/Fallback/res/values-fr/strings.xml index 024ae4203..df1e299cd 100644 --- a/apps/Fallback/res/values-fr/strings.xml +++ b/apps/Fallback/res/values-fr/strings.xml @@ -15,7 +15,7 @@ --> - "Application de secours" - "Action non prise en charge" - "Cette action n\'est actuellement pas prise en charge." + "Application de secours" + "Action non prise en charge" + "Cette action n\'est actuellement pas prise en charge." diff --git a/apps/Fallback/res/values-it/strings.xml b/apps/Fallback/res/values-it/strings.xml index d216e59d1..2d08c1bf4 100644 --- a/apps/Fallback/res/values-it/strings.xml +++ b/apps/Fallback/res/values-it/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Azione non supportata" - "L\'azione non è al momento supportata." + "Fallback" + "Azione non supportata" + "L\'azione non è al momento supportata." diff --git a/apps/Fallback/res/values-ja/strings.xml b/apps/Fallback/res/values-ja/strings.xml index 79aeb42ee..f22090929 100644 --- a/apps/Fallback/res/values-ja/strings.xml +++ b/apps/Fallback/res/values-ja/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "サポートされていない操作" - "現在サポートされていない操作です。" + "Fallback" + "サポートされていない操作" + "現在サポートされていない操作です。" diff --git a/apps/Fallback/res/values-ko/strings.xml b/apps/Fallback/res/values-ko/strings.xml index ec1c33046..2c2973fa9 100644 --- a/apps/Fallback/res/values-ko/strings.xml +++ b/apps/Fallback/res/values-ko/strings.xml @@ -15,7 +15,7 @@ --> - "폴백" - "지원되지 않는 작업" - "이 작업은 현재 지원되지 않습니다." + "폴백" + "지원되지 않는 작업" + "이 작업은 현재 지원되지 않습니다." diff --git a/apps/Fallback/res/values-nb/strings.xml b/apps/Fallback/res/values-nb/strings.xml index 6fed6609a..02814e606 100644 --- a/apps/Fallback/res/values-nb/strings.xml +++ b/apps/Fallback/res/values-nb/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Ustøttet handling" - "Denne handlingen er ikke støttet nå." + "Fallback" + "Ustøttet handling" + "Denne handlingen er ikke støttet nå." diff --git a/apps/Fallback/res/values-nl/strings.xml b/apps/Fallback/res/values-nl/strings.xml index f347964e4..8989efd80 100644 --- a/apps/Fallback/res/values-nl/strings.xml +++ b/apps/Fallback/res/values-nl/strings.xml @@ -15,7 +15,7 @@ --> - "Reserve" - "Niet-ondersteunde actie" - "Die actie wordt momenteel niet ondersteund." + "Reserve" + "Niet-ondersteunde actie" + "Die actie wordt momenteel niet ondersteund." diff --git a/apps/Fallback/res/values-pl/strings.xml b/apps/Fallback/res/values-pl/strings.xml index 73a176ae2..574049805 100644 --- a/apps/Fallback/res/values-pl/strings.xml +++ b/apps/Fallback/res/values-pl/strings.xml @@ -15,7 +15,7 @@ --> - "Wycofanie" - "Nieobsługiwana czynność" - "Ta czynność nie jest aktualnie obsługiwana." + "Wycofanie" + "Nieobsługiwana czynność" + "Ta czynność nie jest aktualnie obsługiwana." diff --git a/apps/Fallback/res/values-pt-rPT/strings.xml b/apps/Fallback/res/values-pt-rPT/strings.xml index 3c7ec9dcf..b226ea52f 100644 --- a/apps/Fallback/res/values-pt-rPT/strings.xml +++ b/apps/Fallback/res/values-pt-rPT/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Acção não suportada" - "Esta·acção·ainda·não·é·suportada." + "Fallback" + "Acção não suportada" + "Esta acção ainda não é suportada." diff --git a/apps/Fallback/res/values-pt/strings.xml b/apps/Fallback/res/values-pt/strings.xml index 08a3faaaf..395004cb6 100644 --- a/apps/Fallback/res/values-pt/strings.xml +++ b/apps/Fallback/res/values-pt/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Ação não suportada" - "Essa ação não é suportada no momento." + "Fallback" + "Ação não suportada" + "Essa ação não é suportada no momento." diff --git a/apps/Fallback/res/values-ru/strings.xml b/apps/Fallback/res/values-ru/strings.xml index 24c3480a2..084c3f3f9 100644 --- a/apps/Fallback/res/values-ru/strings.xml +++ b/apps/Fallback/res/values-ru/strings.xml @@ -15,7 +15,7 @@ --> - "Переход в обходной режим" - "Неподдерживаемое действие" - "В настоящее время это действие не поддерживается." + "Переход в обходной режим" + "Неподдерживаемое действие" + "В настоящее время это действие не поддерживается." diff --git a/apps/Fallback/res/values-sv/strings.xml b/apps/Fallback/res/values-sv/strings.xml index 9dae10ddf..224d946ae 100644 --- a/apps/Fallback/res/values-sv/strings.xml +++ b/apps/Fallback/res/values-sv/strings.xml @@ -15,7 +15,7 @@ --> - "Reserv" - "Åtgärden stöds inte" - "Den här åtgärden stöds inte för närvarande." + "Reserv" + "Åtgärden stöds inte" + "Den här åtgärden stöds inte för närvarande." diff --git a/apps/Fallback/res/values-tr/strings.xml b/apps/Fallback/res/values-tr/strings.xml index 27b860a5e..9c7ed152e 100644 --- a/apps/Fallback/res/values-tr/strings.xml +++ b/apps/Fallback/res/values-tr/strings.xml @@ -15,7 +15,7 @@ --> - "Fallback" - "Desteklenmeyen işlem" - "Bu işlem şu an desteklenmiyor." + "Fallback" + "Desteklenmeyen işlem" + "Bu işlem şu an desteklenmiyor." diff --git a/apps/Fallback/res/values-zh-rCN/strings.xml b/apps/Fallback/res/values-zh-rCN/strings.xml index e6cfde138..5b1fbf8b4 100644 --- a/apps/Fallback/res/values-zh-rCN/strings.xml +++ b/apps/Fallback/res/values-zh-rCN/strings.xml @@ -15,7 +15,7 @@ --> - "后备" - "不支持此操作" - "目前不支持该操作。" + "后备" + "不支持此操作" + "目前不支持该操作。" diff --git a/apps/Fallback/res/values-zh-rTW/strings.xml b/apps/Fallback/res/values-zh-rTW/strings.xml index 52afdbeb6..04d7f4f28 100644 --- a/apps/Fallback/res/values-zh-rTW/strings.xml +++ b/apps/Fallback/res/values-zh-rTW/strings.xml @@ -15,7 +15,7 @@ --> - "備用" - "不支援的操作" - "目前不支援此操作。" + "備用" + "不支援的操作" + "目前不支援此操作。" From 66f17e50dbb42bc529dd12b2f26729f114b1a1a9 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Mon, 3 Aug 2009 18:54:52 -0700 Subject: [PATCH 07/87] ApiDemos Clean up - Add missing @Override - Remove (some) unused imports - Add some missing headers BUG: 2031807 --- .../android/apis/ApiDemosApplication.java | 4 +- .../android/apis/app/IncomingMessageView.java | 3 +- .../appwidget/ExampleAppWidgetProvider.java | 8 +- .../appwidget/ExampleBroadcastReceiver.java | 13 +- .../apis/graphics/ColorPickerDialog.java | 3 +- .../android/apis/graphics/kube/GLColor.java | 55 ++++---- .../android/apis/graphics/kube/GLVertex.java | 125 +++++++++--------- .../apis/graphics/kube/KubeRenderer.java | 1 - .../android/apis/media/MediaPlayerDemo.java | 16 +++ .../apis/media/MediaPlayerDemo_Audio.java | 17 +++ .../apis/media/MediaPlayerDemo_Video.java | 22 ++- .../android/apis/media/VideoViewDemo.java | 19 ++- .../android/apis/view/BaselineNested1.java | 4 +- .../android/apis/view/BaselineNested2.java | 4 +- .../android/apis/view/BaselineNested3.java | 4 +- .../com/example/android/apis/view/Focus2.java | 1 + .../com/example/android/apis/view/Focus3.java | 1 + .../apis/view/InternalSelectionView.java | 1 + .../android/apis/view/LayoutAnimation2.java | 1 - .../android/apis/view/LayoutAnimation3.java | 2 - .../android/apis/view/LayoutAnimation5.java | 1 - .../android/apis/view/LayoutAnimation7.java | 13 -- .../com/example/android/apis/view/List5.java | 2 + 23 files changed, 177 insertions(+), 143 deletions(-) diff --git a/samples/ApiDemos/src/com/example/android/apis/ApiDemosApplication.java b/samples/ApiDemos/src/com/example/android/apis/ApiDemosApplication.java index 92460e50e..5ed171407 100644 --- a/samples/ApiDemos/src/com/example/android/apis/ApiDemosApplication.java +++ b/samples/ApiDemos/src/com/example/android/apis/ApiDemosApplication.java @@ -16,8 +16,6 @@ package com.example.android.apis; -import com.example.android.apis.app.DefaultValues; - import android.app.Application; import android.preference.PreferenceManager; @@ -33,6 +31,7 @@ import android.preference.PreferenceManager; */ public class ApiDemosApplication extends Application { + @Override public void onCreate() { /* * This populates the default values from the preferences XML file. See @@ -41,6 +40,7 @@ public class ApiDemosApplication extends Application { PreferenceManager.setDefaultValues(this, R.xml.default_values, false); } + @Override public void onTerminate() { } } diff --git a/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageView.java b/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageView.java index c3bead027..13ea3dae1 100644 --- a/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageView.java +++ b/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageView.java @@ -22,14 +22,13 @@ import android.app.Activity; import android.app.NotificationManager; import android.os.Bundle; -import java.util.Map; - /** * This activity is run as the click activity for {@link IncomingMessage}. * When it comes up, it also clears the notification, because the "message" * has been "read." */ public class IncomingMessageView extends Activity { + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.incoming_message_view); diff --git a/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java b/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java index 6977d3e6e..61aba6385 100644 --- a/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java +++ b/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java @@ -20,14 +20,11 @@ import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; import android.os.SystemClock; import android.util.Log; import android.widget.RemoteViews; -import java.util.ArrayList; - // Need the following import to get access to the app resources, since this // class is in a sub-package. import com.example.android.apis.R; @@ -51,6 +48,7 @@ public class ExampleAppWidgetProvider extends AppWidgetProvider { // log tag private static final String TAG = "ExampleAppWidgetProvider"; + @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Log.d(TAG, "onUpdate"); // For each widget that needs an update, get the text that we should display: @@ -65,6 +63,7 @@ public class ExampleAppWidgetProvider extends AppWidgetProvider { } } + @Override public void onDeleted(Context context, int[] appWidgetIds) { Log.d(TAG, "onDeleted"); // When the user deletes the widget, delete the preference associated with it. @@ -74,6 +73,7 @@ public class ExampleAppWidgetProvider extends AppWidgetProvider { } } + @Override public void onEnabled(Context context) { Log.d(TAG, "onEnabled"); // When the first widget is created, register for the TIMEZONE_CHANGED and TIME_CHANGED @@ -87,11 +87,11 @@ public class ExampleAppWidgetProvider extends AppWidgetProvider { PackageManager.DONT_KILL_APP); } + @Override public void onDisabled(Context context) { // When the first widget is created, stop listening for the TIMEZONE_CHANGED and // TIME_CHANGED broadcasts. Log.d(TAG, "onDisabled"); - Class clazz = ExampleBroadcastReceiver.class; PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting( new ComponentName("com.example.android.apis", ".appwidget.ExampleBroadcastReceiver"), diff --git a/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleBroadcastReceiver.java b/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleBroadcastReceiver.java index f6e01add1..cf23f3d45 100644 --- a/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleBroadcastReceiver.java +++ b/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleBroadcastReceiver.java @@ -17,21 +17,13 @@ package com.example.android.apis.appwidget; import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.os.SystemClock; import android.util.Log; -import android.widget.RemoteViews; import java.util.ArrayList; -// Need the following import to get access to the app resources, since this -// class is in a sub-package. -import com.example.android.apis.R; - /** * A BroadcastReceiver that listens for updates for the ExampleAppWidgetProvider. This * BroadcastReceiver starts off disabled, and we only enable it when there is a widget @@ -39,6 +31,7 @@ import com.example.android.apis.R; */ public class ExampleBroadcastReceiver extends BroadcastReceiver { + @Override public void onReceive(Context context, Intent intent) { Log.d("ExmampleBroadcastReceiver", "intent=" + intent); @@ -48,8 +41,8 @@ public class ExampleBroadcastReceiver extends BroadcastReceiver { if (action.equals(Intent.ACTION_TIMEZONE_CHANGED) || action.equals(Intent.ACTION_TIME_CHANGED)) { AppWidgetManager gm = AppWidgetManager.getInstance(context); - ArrayList appWidgetIds = new ArrayList(); - ArrayList texts = new ArrayList(); + ArrayList appWidgetIds = new ArrayList(); + ArrayList texts = new ArrayList(); ExampleAppWidgetConfigure.loadAllTitlePrefs(context, appWidgetIds, texts); diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.java b/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.java index cc4a0d431..7588180f4 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.java @@ -16,7 +16,6 @@ package com.example.android.apis.graphics; -import android.R; import android.os.Bundle; import android.app.Dialog; import android.content.Context; @@ -218,7 +217,7 @@ public class ColorPickerDialog extends Dialog { mInitialColor = initialColor; } - + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); OnColorChangedListener l = new OnColorChangedListener() { diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLColor.java b/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLColor.java index 7d4c7c1eb..7478cf420 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLColor.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLColor.java @@ -18,31 +18,34 @@ package com.example.android.apis.graphics.kube; public class GLColor { - public final int red; - public final int green; - public final int blue; - public final int alpha; - - public GLColor(int red, int green, int blue, int alpha) { - this.red = red; - this.green = green; - this.blue = blue; - this.alpha = alpha; - } + public final int red; + public final int green; + public final int blue; + public final int alpha; - public GLColor(int red, int green, int blue) { - this.red = red; - this.green = green; - this.blue = blue; - this.alpha = 0x10000; - } - - public boolean equals(Object other) { - if (other instanceof GLColor) { - GLColor color = (GLColor)other; - return (red == color.red && green == color.green && - blue == color.blue && alpha == color.alpha); - } - return false; - } + public GLColor(int red, int green, int blue, int alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + public GLColor(int red, int green, int blue) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = 0x10000; + } + + @Override + public boolean equals(Object other) { + if (other instanceof GLColor) { + GLColor color = (GLColor)other; + return (red == color.red && + green == color.green && + blue == color.blue && + alpha == color.alpha); + } + return false; + } } diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLVertex.java b/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLVertex.java index b5cd873f7..6e3bf68e1 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLVertex.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLVertex.java @@ -19,70 +19,71 @@ package com.example.android.apis.graphics.kube; import java.nio.IntBuffer; public class GLVertex { - - public float x; - public float y; - public float z; - final short index; // index in vertex table - GLColor color; - - GLVertex() { - this.x = 0; - this.y = 0; - this.z = 0; - this.index = -1; - } - GLVertex(float x, float y, float z, int index) { - this.x = x; - this.y = y; - this.z = z; - this.index = (short)index; - } + public float x; + public float y; + public float z; + final short index; // index in vertex table + GLColor color; - public boolean equals(Object other) { - if (other instanceof GLVertex) { - GLVertex v = (GLVertex)other; - return (x == v.x && y == v.y && z == v.z); - } - return false; - } - - static public int toFixed(float x) { - return (int)(x*65536.0f); + GLVertex() { + this.x = 0; + this.y = 0; + this.z = 0; + this.index = -1; } - public void put(IntBuffer vertexBuffer, IntBuffer colorBuffer) { - vertexBuffer.put(toFixed(x)); - vertexBuffer.put(toFixed(y)); - vertexBuffer.put(toFixed(z)); - if (color == null) { - colorBuffer.put(0); - colorBuffer.put(0); - colorBuffer.put(0); - colorBuffer.put(0); - } else { - colorBuffer.put(color.red); - colorBuffer.put(color.green); - colorBuffer.put(color.blue); - colorBuffer.put(color.alpha); - } - } - - public void update(IntBuffer vertexBuffer, M4 transform) { - // skip to location of vertex in mVertex buffer - vertexBuffer.position(index * 3); - - if (transform == null) { - vertexBuffer.put(toFixed(x)); - vertexBuffer.put(toFixed(y)); - vertexBuffer.put(toFixed(z)); - } else { - GLVertex temp = new GLVertex(); - transform.multiply(this, temp); - vertexBuffer.put(toFixed(temp.x)); - vertexBuffer.put(toFixed(temp.y)); - vertexBuffer.put(toFixed(temp.z)); - } - } + GLVertex(float x, float y, float z, int index) { + this.x = x; + this.y = y; + this.z = z; + this.index = (short)index; + } + + @Override + public boolean equals(Object other) { + if (other instanceof GLVertex) { + GLVertex v = (GLVertex)other; + return (x == v.x && y == v.y && z == v.z); + } + return false; + } + + static public int toFixed(float x) { + return (int)(x * 65536.0f); + } + + public void put(IntBuffer vertexBuffer, IntBuffer colorBuffer) { + vertexBuffer.put(toFixed(x)); + vertexBuffer.put(toFixed(y)); + vertexBuffer.put(toFixed(z)); + if (color == null) { + colorBuffer.put(0); + colorBuffer.put(0); + colorBuffer.put(0); + colorBuffer.put(0); + } else { + colorBuffer.put(color.red); + colorBuffer.put(color.green); + colorBuffer.put(color.blue); + colorBuffer.put(color.alpha); + } + } + + public void update(IntBuffer vertexBuffer, M4 transform) { + // skip to location of vertex in mVertex buffer + vertexBuffer.position(index * 3); + + if (transform == null) { + vertexBuffer.put(toFixed(x)); + vertexBuffer.put(toFixed(y)); + vertexBuffer.put(toFixed(z)); + } else { + GLVertex temp = new GLVertex(); + transform.multiply(this, temp); + vertexBuffer.put(toFixed(temp.x)); + vertexBuffer.put(toFixed(temp.y)); + vertexBuffer.put(toFixed(temp.z)); + } + } } diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/kube/KubeRenderer.java b/samples/ApiDemos/src/com/example/android/apis/graphics/kube/KubeRenderer.java index 9977041a2..58b03dae5 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/kube/KubeRenderer.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/kube/KubeRenderer.java @@ -18,7 +18,6 @@ package com.example.android.apis.graphics.kube; import android.opengl.GLSurfaceView; -import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; diff --git a/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo.java b/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo.java index 4b89167b4..1303d3598 100644 --- a/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo.java +++ b/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo.java @@ -1,3 +1,19 @@ +/* + * 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.media; import com.example.android.apis.R; diff --git a/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Audio.java b/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Audio.java index 39930f69e..b209ce9d5 100644 --- a/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Audio.java +++ b/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Audio.java @@ -1,3 +1,19 @@ +/* + * 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.media; import android.app.Activity; @@ -23,6 +39,7 @@ public class MediaPlayerDemo_Audio extends Activity { private TextView tx; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); tx = new TextView(this); diff --git a/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Video.java b/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Video.java index 601c5a30e..9853d675a 100644 --- a/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Video.java +++ b/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Video.java @@ -1,10 +1,24 @@ +/* + * 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.media; import com.example.android.apis.R; -import com.example.android.apis.app.AlarmController; import android.app.Activity; -import android.graphics.PixelFormat; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; @@ -15,9 +29,6 @@ import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; import android.widget.Toast; @@ -46,6 +57,7 @@ public class MediaPlayerDemo_Video extends Activity implements * * Called when the activity is first created. */ + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.mediaplayer_2); diff --git a/samples/ApiDemos/src/com/example/android/apis/media/VideoViewDemo.java b/samples/ApiDemos/src/com/example/android/apis/media/VideoViewDemo.java index a4fcf5f80..e72c077a6 100644 --- a/samples/ApiDemos/src/com/example/android/apis/media/VideoViewDemo.java +++ b/samples/ApiDemos/src/com/example/android/apis/media/VideoViewDemo.java @@ -1,11 +1,24 @@ +/* + * 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.media; import com.example.android.apis.R; import android.app.Activity; -import android.graphics.PixelFormat; -import android.net.Uri; import android.os.Bundle; -import android.util.Log; import android.widget.MediaController; import android.widget.Toast; import android.widget.VideoView; diff --git a/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested1.java b/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested1.java index d60e702c2..ab7898cb2 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested1.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested1.java @@ -20,8 +20,6 @@ import com.example.android.apis.R; import android.app.Activity; import android.os.Bundle; -import android.widget.LinearLayout; -import android.widget.TextView; /** * Baseline alignment includes elements within nested vertical @@ -29,7 +27,7 @@ import android.widget.TextView; */ public class BaselineNested1 extends Activity { - + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested2.java b/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested2.java index 32574d7d6..1b2c5857b 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested2.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested2.java @@ -20,8 +20,6 @@ import com.example.android.apis.R; import android.app.Activity; import android.os.Bundle; -import android.widget.LinearLayout; -import android.widget.TextView; /** * Baseline alignment includes an element within a nested horizontal @@ -29,7 +27,7 @@ import android.widget.TextView; */ public class BaselineNested2 extends Activity { - + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested3.java b/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested3.java index 33770416f..854a10fe2 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested3.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested3.java @@ -20,8 +20,6 @@ import com.example.android.apis.R; import android.app.Activity; import android.os.Bundle; -import android.widget.LinearLayout; -import android.widget.TextView; /** * Baseline alignment includes a {@link android.widget.LinearLayout} @@ -29,7 +27,7 @@ import android.widget.TextView; */ public class BaselineNested3 extends Activity { - + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Focus2.java b/samples/ApiDemos/src/com/example/android/apis/view/Focus2.java index 77bf8e021..5ffd847d3 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/Focus2.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/Focus2.java @@ -23,6 +23,7 @@ import android.os.Bundle; public class Focus2 extends Activity { + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/samples/ApiDemos/src/com/example/android/apis/view/Focus3.java b/samples/ApiDemos/src/com/example/android/apis/view/Focus3.java index fc3f6df31..c952a647f 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/Focus3.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/Focus3.java @@ -25,6 +25,7 @@ public class Focus3 extends Activity { private Button mTopButton; private Button mBottomButton; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionView.java b/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionView.java index 3ef84030c..fe415bdac 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionView.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionView.java @@ -199,6 +199,7 @@ public class InternalSelectionView extends View { /* (non-Javadoc) * @see android.view.KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent) */ + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch(event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_UP: diff --git a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation2.java b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation2.java index 1c0014556..9a240f97a 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation2.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation2.java @@ -17,7 +17,6 @@ package com.example.android.apis.view; import android.app.ListActivity; -import android.content.Context; import android.os.Bundle; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; diff --git a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation3.java b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation3.java index edc2926f8..59869361e 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation3.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation3.java @@ -21,8 +21,6 @@ import com.example.android.apis.R; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.view.View; public class LayoutAnimation3 extends ListActivity { @Override diff --git a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation5.java b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation5.java index 8ed8a36a3..ced28a730 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation5.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation5.java @@ -25,7 +25,6 @@ import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.Gallery; import android.widget.GridView; import android.widget.ImageView; diff --git a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation7.java b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation7.java index 6eeb42998..bfda4a550 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation7.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation7.java @@ -19,20 +19,7 @@ package com.example.android.apis.view; import com.example.android.apis.R; import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.GridLayoutAnimationController; -import android.widget.BaseAdapter; -import android.widget.Gallery; -import android.widget.GridView; -import android.widget.ImageView; - -import java.util.List; public class LayoutAnimation7 extends Activity { @Override diff --git a/samples/ApiDemos/src/com/example/android/apis/view/List5.java b/samples/ApiDemos/src/com/example/android/apis/view/List5.java index 72a8b8259..76b446926 100644 --- a/samples/ApiDemos/src/com/example/android/apis/view/List5.java +++ b/samples/ApiDemos/src/com/example/android/apis/view/List5.java @@ -49,10 +49,12 @@ public class List5 extends ListActivity { return mStrings.length; } + @Override public boolean areAllItemsEnabled() { return false; } + @Override public boolean isEnabled(int position) { return !mStrings[position].startsWith("-"); } From bf27d6e2f8e48730b2f55386314b3374902be6dd Mon Sep 17 00:00:00 2001 From: David Warren Date: Tue, 4 Aug 2009 16:03:59 -0700 Subject: [PATCH 08/87] Fixed bad link in intro text. --- pdk/docs/guide/stk.jd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdk/docs/guide/stk.jd b/pdk/docs/guide/stk.jd index 0ce0b4a04..55f914e42 100755 --- a/pdk/docs/guide/stk.jd +++ b/pdk/docs/guide/stk.jd @@ -16,7 +16,7 @@ pdk.version=1.0 -

This document offers a high-level overview of the SIM Toolkit Application for Android 1.0 and is primarily of interest for implementors of the Radio Interface Layer (RIL). The STK is R96 compatible (3GPP TS 11.14 v5.9.0) and complies partially with R99 (3GPP TS 101.267 v8.17.0). See the STK Feature List for the complete feature list.

+

This document offers a high-level overview of the SIM Toolkit Application for Android 1.0 and is primarily of interest for implementors of the Radio Interface Layer (RIL). The STK is R96 compatible (3GPP TS 11.14 v5.9.0) and complies partially with R99 (3GPP TS 101.267 v8.17.0). See the STK Feature List for the complete feature list.

.

The Android STK implementation includes three layers:

  • STK RIL: Low-level layer provided by the vendor plus libril.
  • From 6d673960b01f97a11eefb5c33979d4ffe6d31660 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Wed, 5 Aug 2009 17:09:35 -0700 Subject: [PATCH 09/87] Fix NPE that prevented any package w/o license to be installed. java.util.Properties#setProperty() doesn't like it when the value is null which was the case when a package had no license. Made sure it won't happen on other properties than the license as well. Also improved error display when an unexpected Throwable is thrown during install (Stack Call is now display if the Throwable has no message). BUG:2037085 --- .../internal/repository/AddonPackage.java | 8 ++++++-- .../sdklib/internal/repository/Package.java | 12 +++++++++--- .../internal/repository/PlatformPackage.java | 4 +++- .../internal/repository/UpdaterData.java | 17 ++++++++++++++++- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java index 4a19206d1..3c7b8c68e 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java @@ -126,8 +126,12 @@ public class AddonPackage extends Package { super.saveProperties(props); mVersion.saveProperties(props); - props.setProperty(PROP_NAME, mName); - props.setProperty(PROP_VENDOR, mVendor); + if (mName != null) { + props.setProperty(PROP_NAME, mName); + } + if (mVendor != null) { + props.setProperty(PROP_VENDOR, mVendor); + } } /** diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java index 1fcd6b10c..a637fdeaf 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java @@ -145,9 +145,15 @@ public abstract class Package implements IDescription { */ void saveProperties(Properties props) { props.setProperty(PROP_REVISION, Integer.toString(mRevision)); - props.setProperty(PROP_LICENSE, mLicense); - props.setProperty(PROP_DESC, mDescription); - props.setProperty(PROP_DESC_URL, mDescUrl); + if (mLicense != null) { + props.setProperty(PROP_LICENSE, mLicense); + } + if (mDescription != null) { + props.setProperty(PROP_DESC, mDescription); + } + if (mDescUrl != null) { + props.setProperty(PROP_DESC_URL, mDescUrl); + } if (mSource != null) { props.setProperty(PROP_SOURCE_URL, mSource.getUrl()); diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java index 324f51d73..c9a58f7f5 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java @@ -87,7 +87,9 @@ public class PlatformPackage extends Package { super.saveProperties(props); mVersion.saveProperties(props); - props.setProperty(PROP_VERSION, mVersionName); + if (mVersionName != null) { + props.setProperty(PROP_VERSION, mVersionName); + } } /** Returns the version, a string, for platform packages. */ diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java index 321f5ca97..a9e8afae3 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java @@ -36,6 +36,8 @@ import com.android.sdkuilib.repository.UpdaterWindow.ISdkListener; import org.eclipse.swt.widgets.Shell; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -304,8 +306,21 @@ class UpdaterData { } catch (Throwable t) { // Display anything unexpected in the monitor. - monitor.setResult("Unexpected Error: %1$s", t.getMessage()); + String msg = t.getMessage(); + if (msg != null) { + monitor.setResult("Unexpected Error installing '%1%s: %2$s", + archive.getParentPackage().getShortDescription(), msg); + } else { + // no error info? get the stack call to display it + // At least that'll give us a better bug report. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + t.printStackTrace(new PrintStream(baos)); + // and display it + monitor.setResult("Unexpected Error installing '%1$s\n%2$s", + archive.getParentPackage().getShortDescription(), + baos.toString()); + } } finally { // Always move the progress bar to the desired position. From f855c4e8469e31114fccca4c28aeb01a806a9a48 Mon Sep 17 00:00:00 2001 From: vchtchetkine Date: Wed, 5 Aug 2009 16:57:18 -0700 Subject: [PATCH 10/87] Split AdbWinApi.dll into two dlls to remove dependency on WINUSB.DLL Move all WINUSB-dependent functionality into AdbWinUsbApi.dll in order to enable ADB on condition that WINUSB has not been installed. --- host/windows/usb/api/AdbWinApi.cpp | 77 +++++++++++- host/windows/usb/api/SOURCES | 6 +- host/windows/usb/api/adb_api.cpp | 24 +++- host/windows/usb/api/adb_api.h | 26 ++++ host/windows/usb/api/adb_endpoint_object.h | 2 +- host/windows/usb/api/adb_interface.h | 15 ++- host/windows/usb/api/adb_io_completion.h | 2 +- host/windows/usb/api/adb_object_handle.h | 3 +- host/windows/usb/api/stdafx.h | 3 - host/windows/usb/winusb/AdbWinUsbApi.cpp | 62 ++++++++++ host/windows/usb/winusb/AdbWinUsbApi.def | 5 + host/windows/usb/winusb/AdbWinUsbApi.rc | 111 ++++++++++++++++++ host/windows/usb/winusb/BUILDME.TXT | 7 ++ host/windows/usb/winusb/MAKEFILE | 22 ++++ host/windows/usb/winusb/Resource.h | 34 ++++++ host/windows/usb/winusb/SOURCES | 93 +++++++++++++++ .../adb_winusb_endpoint_object.cpp | 12 +- .../adb_winusb_endpoint_object.h | 26 +++- .../{api => winusb}/adb_winusb_interface.cpp | 11 ++ .../{api => winusb}/adb_winusb_interface.h | 21 +++- .../adb_winusb_io_completion.cpp | 11 ++ .../adb_winusb_io_completion.h | 26 +++- host/windows/usb/winusb/stdafx.cpp | 21 ++++ host/windows/usb/winusb/stdafx.h | 78 ++++++++++++ 24 files changed, 674 insertions(+), 24 deletions(-) create mode 100755 host/windows/usb/winusb/AdbWinUsbApi.cpp create mode 100755 host/windows/usb/winusb/AdbWinUsbApi.def create mode 100755 host/windows/usb/winusb/AdbWinUsbApi.rc create mode 100755 host/windows/usb/winusb/BUILDME.TXT create mode 100755 host/windows/usb/winusb/MAKEFILE create mode 100755 host/windows/usb/winusb/Resource.h create mode 100755 host/windows/usb/winusb/SOURCES rename host/windows/usb/{api => winusb}/adb_winusb_endpoint_object.cpp (93%) rename host/windows/usb/{api => winusb}/adb_winusb_endpoint_object.h (81%) rename host/windows/usb/{api => winusb}/adb_winusb_interface.cpp (95%) rename host/windows/usb/{api => winusb}/adb_winusb_interface.h (84%) rename host/windows/usb/{api => winusb}/adb_winusb_io_completion.cpp (89%) rename host/windows/usb/{api => winusb}/adb_winusb_io_completion.h (75%) create mode 100755 host/windows/usb/winusb/stdafx.cpp create mode 100755 host/windows/usb/winusb/stdafx.h diff --git a/host/windows/usb/api/AdbWinApi.cpp b/host/windows/usb/api/AdbWinApi.cpp index 4d18d3793..e81c2c7ea 100644 --- a/host/windows/usb/api/AdbWinApi.cpp +++ b/host/windows/usb/api/AdbWinApi.cpp @@ -17,6 +17,7 @@ // AdbWinApi.cpp : Implementation of DLL Exports. #include "stdafx.h" +#include "adb_api.h" extern "C" { int _forceCRTManifest; @@ -24,8 +25,73 @@ int _forceMFCManifest; int _forceAtlDllManifest; }; +/// References InstantiateWinUsbInterface declared in adb_api.cpp +extern PFN_INSTWINUSBINTERFACE InstantiateWinUsbInterface; + class CAdbWinApiModule : public CAtlDllModuleT< CAdbWinApiModule > { -public: + public: + CAdbWinApiModule() + : CAtlDllModuleT< CAdbWinApiModule >(), + adbwinusbapi_handle_(NULL), + is_initialized_(false) { + } + + ~CAdbWinApiModule() { + // Unload AdbWinUsbApi.dll before we exit + if (NULL != adbwinusbapi_handle_) { + FreeLibrary(adbwinusbapi_handle_); + } + } + + /** \brief Loads AdbWinUsbApi.dll and caches its InstantiateWinUsbInterface + export. + + This method is called from DllMain on DLL_PROCESS_ATTACH event. In this + method we will check if WINUSB.DLL required by AdbWinUsbApi.dll is + installed, and if it is we will load AdbWinUsbApi.dll and cache address of + InstantiateWinUsbInterface routine exported from AdbWinUsbApi.dll + */ + void AttachToAdbWinUsbApi() { + // We only need to run this only once. + if (is_initialized_) { + return; + } + + // Just mark that we have ran initialization. + is_initialized_ = true; + + // Before we can load AdbWinUsbApi.dll we must make sure that WINUSB.DLL + // has been installed. Build path to the file. + wchar_t path_to_winusb_dll[MAX_PATH+1]; + if (!GetSystemDirectory(path_to_winusb_dll, MAX_PATH)) { + return; + } + wcscat(path_to_winusb_dll, L"\\WINUSB.DLL"); + + if (0xFFFFFFFF == GetFileAttributes(path_to_winusb_dll)) { + // WINUSB.DLL is not installed. We don't (in fact, can't) load + // AdbWinUsbApi.dll + return; + } + + // WINUSB.DLL is installed. Lets load AdbWinUsbApi.dll and cache its + // InstantiateWinUsbInterface export. + // We require that AdbWinUsbApi.dll is located in the same folder + // where AdbWinApi.dll and adb.exe are located, so by Windows + // conventions we can pass just module name, and not the full path. + adbwinusbapi_handle_ = LoadLibrary(L"AdbWinUsbApi.dll"); + if (NULL != adbwinusbapi_handle_) { + InstantiateWinUsbInterface = reinterpret_cast + (GetProcAddress(adbwinusbapi_handle_, "InstantiateWinUsbInterface")); + } + } + + protected: + /// Handle to the loaded AdbWinUsbApi.dll + HINSTANCE adbwinusbapi_handle_; + + /// Flags whether or not this module has been initialized. + bool is_initialized_; }; CAdbWinApiModule _AtlModule; @@ -34,5 +100,12 @@ CAdbWinApiModule _AtlModule; extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { - return _AtlModule.DllMain(reason, reserved); + // Lets see if we need to initialize InstantiateWinUsbInterface + // variable. We do that only once, on condition that this DLL is + // being attached to the process and InstantiateWinUsbInterface + // address has not been calculated yet. + if (DLL_PROCESS_ATTACH == reason) { + _AtlModule.AttachToAdbWinUsbApi(); + } + return _AtlModule.DllMain(reason, reserved); } diff --git a/host/windows/usb/api/SOURCES b/host/windows/usb/api/SOURCES index f6e66143c..35695217b 100755 --- a/host/windows/usb/api/SOURCES +++ b/host/windows/usb/api/SOURCES @@ -50,8 +50,7 @@ TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \ $(SDK_LIB_PATH)\wbemuuid.lib \ $(SDK_LIB_PATH)\uuid.lib \ $(SDK_LIB_PATH)\setupapi.lib \ - $(SDK_LIB_PATH)\usbd.lib \ - $(SDK_LIB_PATH)\winusb.lib + $(SDK_LIB_PATH)\usbd.lib !IF "$(DDKBUILDENV)" == "fre" # Libraries for release (free) builds @@ -87,15 +86,12 @@ PRECOMPILED_SOURCEFILE = stdafx.cpp # Define source files for AdbWinApi.dll SOURCES = adb_api.cpp \ adb_endpoint_object.cpp \ - adb_winusb_endpoint_object.cpp \ adb_legacy_endpoint_object.cpp \ adb_helper_routines.cpp \ adb_interface.cpp \ - adb_winusb_interface.cpp \ adb_legacy_interface.cpp \ adb_interface_enum.cpp \ adb_io_completion.cpp \ - adb_winusb_io_completion.cpp \ adb_legacy_io_completion.cpp \ adb_object_handle.cpp \ AdbWinApi.cpp \ diff --git a/host/windows/usb/api/adb_api.cpp b/host/windows/usb/api/adb_api.cpp index f9bd94e6c..493f62d86 100644 --- a/host/windows/usb/api/adb_api.cpp +++ b/host/windows/usb/api/adb_api.cpp @@ -24,12 +24,19 @@ #include "adb_object_handle.h" #include "adb_interface_enum.h" #include "adb_interface.h" -#include "adb_winusb_interface.h" #include "adb_legacy_interface.h" #include "adb_endpoint_object.h" #include "adb_io_completion.h" #include "adb_helper_routines.h" +/** \brief Points to InstantiateWinUsbInterface exported from AdbWinUsbApi.dll. + + This variable is initialized with the actual address in DllMain routine for + this DLL on DLL_PROCESS_ATTACH event. + @see PFN_INSTWINUSBINTERFACE for more information. +*/ +PFN_INSTWINUSBINTERFACE InstantiateWinUsbInterface = NULL; + ADBAPIHANDLE __cdecl AdbEnumInterfaces(GUID class_id, bool exclude_not_present, bool exclude_removed, @@ -101,11 +108,22 @@ ADBAPIHANDLE __cdecl AdbCreateInterfaceByName( ADBAPIHANDLE ret = NULL; try { - // Instantiate object + // Instantiate interface object, depending on the USB driver type. if (IsLegacyInterface(interface_name)) { + // We have legacy USB driver underneath us. obj = new AdbLegacyInterfaceObject(interface_name); } else { - obj = new AdbWinUsbInterfaceObject(interface_name); + // We have WinUsb driver underneath us. Make sure that AdbWinUsbApi.dll + // is loaded and its InstantiateWinUsbInterface routine address has + // been cached. + if (NULL != InstantiateWinUsbInterface) { + obj = InstantiateWinUsbInterface(interface_name); + if (NULL == obj) { + return NULL; + } + } else { + return NULL; + } } // Create handle for it diff --git a/host/windows/usb/api/adb_api.h b/host/windows/usb/api/adb_api.h index e2ad129ca..429a56d9a 100644 --- a/host/windows/usb/api/adb_api.h +++ b/host/windows/usb/api/adb_api.h @@ -110,6 +110,30 @@ typedef struct _AdbEndpointInformation { /// the driver in isolation from hardware. #define DEVICE_EMULATOR_PROD_ID 0xDDDD +/** \brief Function prototype for InstantiateWinUsbInterface routine exported + from AdbWinUsbApi.dll + + In order to provide backward compatibility with the systems that still run + legacy (custom) USB drivers, and have not installed WINUSB.DLL we need to + split functionality of our ADB API on Windows between two DLLs: AdbWinApi, + and AdbWinUsbApi. AdbWinApi is fully capable of working on top of the legacy + driver, but has no traces to WinUsb. AdbWinUsbApi is capable of working on + top of WinUsb API. We are forced to do this split, because we can have + dependency on WINUSB.DLL in the DLL that implements legacy API. The problem + is that customers may have a legacy driver that they don't want to upgrade + to WinUsb, so they may not have WINUSB.DLL installed on their machines, but + they still must be able to use ADB. So, the idea behind the split is as + such. When AdbWinApi.dll is loaded into a process, it will check WINUSB.DLL + installation (by checking existance of C:\Windows\System32\winusb.dll). If + WINUSB.DLL is installed, AdbWinApi will also load AdbWinUsbApi.dll (by + calling LoadLibrary), and will extract address of InstantiateWinUsbInterface + routine exported from AdbWinUsbApi.dll. Then this routine will be used to + instantiate AdbInterfaceObject instance on condition that it is confirmed + that USB driver underneath us is in deed WinUsb. +*/ +typedef class AdbInterfaceObject* \ + (__cdecl *PFN_INSTWINUSBINTERFACE)(const wchar_t*); + // The following ifdef block is the standard way of creating macros which make // exporting from a DLL simpler. All files within this DLL are compiled with // the ADBWIN_EXPORTS symbol defined on the command line. this symbol should @@ -119,8 +143,10 @@ typedef struct _AdbEndpointInformation { // as being exported. #ifdef ADBWIN_EXPORTS #define ADBWIN_API EXTERN_C __declspec(dllexport) +#define ADBWIN_API_CLASS __declspec(dllexport) #else #define ADBWIN_API EXTERN_C __declspec(dllimport) +#define ADBWIN_API_CLASS __declspec(dllimport) #endif /** \brief Handle to an API object. diff --git a/host/windows/usb/api/adb_endpoint_object.h b/host/windows/usb/api/adb_endpoint_object.h index 295eb46f2..d92aaad47 100644 --- a/host/windows/usb/api/adb_endpoint_object.h +++ b/host/windows/usb/api/adb_endpoint_object.h @@ -29,7 +29,7 @@ This class implement functionality that is common for both, WinUsb and legacy APIs. */ -class AdbEndpointObject : public AdbObjectHandle { +class ADBWIN_API_CLASS AdbEndpointObject : public AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/adb_interface.h b/host/windows/usb/api/adb_interface.h index 4afb17da0..0aa0d1d55 100644 --- a/host/windows/usb/api/adb_interface.h +++ b/host/windows/usb/api/adb_interface.h @@ -23,12 +23,17 @@ #include "adb_object_handle.h" +// 'AdbInterfaceObject::interface_name_' : class 'std::basic_string<_E,_Tr,_A>' +// needs to have dll-interface to be used by clients of class +// 'AdbInterfaceObject' We're ok with that, since interface_name_ will not +// be referenced by name from outside of this class. +#pragma warning(disable: 4251) /** \brief Encapsulates an interface on our USB device. This is an abstract class that implements functionality common for both, legacy, and WinUsb based interfaces. */ -class AdbInterfaceObject : public AdbObjectHandle { +class ADBWIN_API_CLASS AdbInterfaceObject : public AdbObjectHandle { public: /** \brief Constructs the object. @@ -180,9 +185,6 @@ class AdbInterfaceObject : public AdbObjectHandle { } protected: - /// Name of the USB interface (device name) for this object - std::wstring interface_name_; - /// Cached usb device descriptor USB_DEVICE_DESCRIPTOR usb_device_descriptor_; @@ -191,6 +193,11 @@ class AdbInterfaceObject : public AdbObjectHandle { /// Cached usb interface descriptor USB_INTERFACE_DESCRIPTOR usb_interface_descriptor_; + + private: + /// Name of the USB interface (device name) for this object + std::wstring interface_name_; }; +#pragma warning(default: 4251) #endif // ANDROID_USB_API_ADB_INTERFACE_H__ diff --git a/host/windows/usb/api/adb_io_completion.h b/host/windows/usb/api/adb_io_completion.h index 8a7c1d91d..ea4b4fbce 100644 --- a/host/windows/usb/api/adb_io_completion.h +++ b/host/windows/usb/api/adb_io_completion.h @@ -33,7 +33,7 @@ like all other handles this handle must be closed after it's no longer needed. */ -class AdbIOCompletion : public AdbObjectHandle { +class ADBWIN_API_CLASS AdbIOCompletion : public AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/adb_object_handle.h b/host/windows/usb/api/adb_object_handle.h index 29ac5e2f2..2fa4ad03b 100644 --- a/host/windows/usb/api/adb_object_handle.h +++ b/host/windows/usb/api/adb_object_handle.h @@ -22,6 +22,7 @@ of the API through a handle. */ +#include "adb_api.h" #include "adb_api_private_defines.h" /** \brief Defines types of internal API objects @@ -71,7 +72,7 @@ enum AdbObjectType { All API objects that have handles that are sent back to API client must be derived from this class. */ -class AdbObjectHandle { +class ADBWIN_API_CLASS AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/stdafx.h b/host/windows/usb/api/stdafx.h index 92b2652ea..d57bec74b 100644 --- a/host/windows/usb/api/stdafx.h +++ b/host/windows/usb/api/stdafx.h @@ -71,11 +71,8 @@ #include #pragma warning(default: 4201) #pragma warning(disable: 4200) -extern "C" { #include -#include #include -} #include "resource.h" diff --git a/host/windows/usb/winusb/AdbWinUsbApi.cpp b/host/windows/usb/winusb/AdbWinUsbApi.cpp new file mode 100755 index 000000000..4916eebd2 --- /dev/null +++ b/host/windows/usb/winusb/AdbWinUsbApi.cpp @@ -0,0 +1,62 @@ +/* + * 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. + */ + +// AdbWinUsbApi.cpp : Implementation of DLL Exports. + +#include "stdafx.h" +#include "adb_winusb_interface.h" + +class CAdbWinApiModule : public CAtlDllModuleT< CAdbWinApiModule > { +public: +}; + +CAdbWinApiModule _AtlModule; + +// DLL Entry Point +extern "C" BOOL WINAPI DllMain(HINSTANCE instance, + DWORD reason, + LPVOID reserved) { + return _AtlModule.DllMain(reason, reserved); +} + +/** \brief Instantiates interface instance that uses WinUsb API to communicate + with USB driver. + + This is the only exported routine from this DLL. This routine instantiates an + object of AdbWinUsbInterfaceObject on request from AdbWinApi.dll when it is + detected that underlying USB driver is WinUsb.sys. + @param[in] interface_name Name of the interface. + @return AdbInterfaceObject - casted instance of AdbWinUsbInterfaceObject + object on success, or NULL on failure with GetLastError providing + information on an error that occurred. +*/ +extern "C" __declspec(dllexport) +AdbInterfaceObject* __cdecl InstantiateWinUsbInterface( + const wchar_t* interface_name) { + // Validate parameter. + if (NULL == interface_name) { + return NULL; + } + + // Instantiate requested object. + try { + return new AdbWinUsbInterfaceObject(interface_name); + } catch (...) { + // We expect only OOM exceptions here. + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } +} diff --git a/host/windows/usb/winusb/AdbWinUsbApi.def b/host/windows/usb/winusb/AdbWinUsbApi.def new file mode 100755 index 000000000..9e616e91d --- /dev/null +++ b/host/windows/usb/winusb/AdbWinUsbApi.def @@ -0,0 +1,5 @@ +; AdbWinUsbApi.def : Declares the module parameters. + +LIBRARY "AdbWinUsbApi.DLL" + +EXPORTS diff --git a/host/windows/usb/winusb/AdbWinUsbApi.rc b/host/windows/usb/winusb/AdbWinUsbApi.rc new file mode 100755 index 000000000..44aa100f4 --- /dev/null +++ b/host/windows/usb/winusb/AdbWinUsbApi.rc @@ -0,0 +1,111 @@ +/* + * 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. + */ + +//Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Google, inc" + VALUE "FileDescription", "Android ADB API (WinUsb)" + VALUE "FileVersion", "2.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2006 The Android Open Source Project" + VALUE "InternalName", "AdbWinUsbApi.dll" + VALUE "OriginalFilename", "AdbWinUsbApi.dll" + VALUE "ProductName", "Android SDK" + VALUE "ProductVersion", "2.0.0.0" + VALUE "OLESelfRegister", "" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END + +#endif // !_MAC + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PROJNAME "AdbWinUsbApi" +END + +//////////////////////////////////////////////////////////////////////////// + + +#endif + +#ifndef APSTUDIO_INVOKED +#endif // not APSTUDIO_INVOKED diff --git a/host/windows/usb/winusb/BUILDME.TXT b/host/windows/usb/winusb/BUILDME.TXT new file mode 100755 index 000000000..2a459ef53 --- /dev/null +++ b/host/windows/usb/winusb/BUILDME.TXT @@ -0,0 +1,7 @@ +In order to build AdbWinUsbApi.dll you will need to install Windows Driver Kit, +which can be obtained from Microsoft. Assuming that WDK is installed, you +need to set one of the WDK's build environments, "cd" back into this directory, +and execute "build -cbeEIFZ" to clean and rebuild this project, or you can +execute "build -befEIF" to do a minimal build. +Note that you need to build AdbWinApi.dll (..\api) before you build +AdbWinUsbApi.dll, as it depends on AdbWinApi.lib library. diff --git a/host/windows/usb/winusb/MAKEFILE b/host/windows/usb/winusb/MAKEFILE new file mode 100755 index 000000000..fcd896d3f --- /dev/null +++ b/host/windows/usb/winusb/MAKEFILE @@ -0,0 +1,22 @@ +# +# 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. +# + +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/host/windows/usb/winusb/Resource.h b/host/windows/usb/winusb/Resource.h new file mode 100755 index 000000000..3ede761da --- /dev/null +++ b/host/windows/usb/winusb/Resource.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by AdbWinApi.rc +// + +#define IDS_PROJNAME 100 +#define IDR_ADBWINAPI 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/host/windows/usb/winusb/SOURCES b/host/windows/usb/winusb/SOURCES new file mode 100755 index 000000000..80d17ae1f --- /dev/null +++ b/host/windows/usb/winusb/SOURCES @@ -0,0 +1,93 @@ +# +# 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. +# + +TARGETNAME = AdbWinUsbApi +TARGETPATH = obj +TARGETTYPE = DYNLINK + +UMTYPE = windows +DLLDEF = AdbWinUsbApi.def + +# Use statically linked atl libraries: +# - atls.lib for free build +# - atlsd.lib for checked build +USE_STATIC_ATL = 1 +# Use ATL v. 7.1 +ATL_VER = 71 +# Use STL v. 6.0 +USE_STL = 1 +STL_VER = 60 +# Use multithreaded libraries +USE_LIBCMT = 1 + +# Include directories +INCLUDES = $(DDK_INC_PATH); \ + $(SDK_INC_PATH); \ + $(CRT_INC_PATH); \ + $(SDK_INC_PATH)\crt; \ + $(CRT_INC_PATH)\atl71; \ + $(SDK_INC_PATH)\crt\stl60 + +# Common target libraries +TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\Advapi32.lib \ + $(SDK_LIB_PATH)\Kernel32.lib \ + $(SDK_LIB_PATH)\User32.lib \ + $(SDK_LIB_PATH)\oleaut32.lib \ + $(SDK_LIB_PATH)\wbemuuid.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\setupapi.lib \ + $(SDK_LIB_PATH)\usbd.lib \ + $(SDK_LIB_PATH)\winusb.lib \ + ..\api\obj$(BUILD_ALT_DIR)\i386\AdbWinApi.lib + +!IF "$(DDKBUILDENV)" == "fre" +# Libraries for release (free) builds +TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atls.lib +!ELSE +# Libraries for debug (checked) builds +TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atlsd.lib +!ENDIF + +# Common C defines +C_DEFINES= $(C_DEFINES) -DADBWINUSB_EXPORTS -D_UNICODE \ + -DUNICODE -DWIN32 -D_WINDOWS -D_USRDLL -D_WINDLL + +!IF "$(DDKBUILDENV)" == "fre" +# C defines for release (free) builds +C_DEFINES = $(C_DEFINES) -DNDEBUG +!ELSE +# C defines for debug (checked) builds +C_DEFINES = $(C_DEFINES) -D_DEBUG +!ENDIF + +# Turn on all warnings, and treat warnings as errors +MSC_WARNING_LEVEL = /W4 /Wp64 /WX + +# Common C defines +USER_C_FLAGS = $(USER_C_FLAGS) /FD /EHsc /wd4100 /wd4200 /wd4702 /nologo + +# Set precompiled header information +PRECOMPILED_CXX = 1 +PRECOMPILED_INCLUDE = stdafx.h +PRECOMPILED_SOURCEFILE = stdafx.cpp + +# Define source files for AdbWinUsbApi.dll +SOURCES = adb_winusb_endpoint_object.cpp \ + adb_winusb_interface.cpp \ + adb_winusb_io_completion.cpp \ + AdbWinUsbApi.cpp \ + AdbWinUsbApi.rc diff --git a/host/windows/usb/api/adb_winusb_endpoint_object.cpp b/host/windows/usb/winusb/adb_winusb_endpoint_object.cpp similarity index 93% rename from host/windows/usb/api/adb_winusb_endpoint_object.cpp rename to host/windows/usb/winusb/adb_winusb_endpoint_object.cpp index 236de3b49..16f78370c 100755 --- a/host/windows/usb/api/adb_winusb_endpoint_object.cpp +++ b/host/windows/usb/winusb/adb_winusb_endpoint_object.cpp @@ -22,7 +22,6 @@ #include "stdafx.h" #include "adb_winusb_endpoint_object.h" #include "adb_winusb_io_completion.h" -#include "adb_helper_routines.h" AdbWinUsbEndpointObject::AdbWinUsbEndpointObject( AdbWinUsbInterfaceObject* parent_interf, @@ -34,6 +33,17 @@ AdbWinUsbEndpointObject::AdbWinUsbEndpointObject( AdbWinUsbEndpointObject::~AdbWinUsbEndpointObject() { } +LONG AdbWinUsbEndpointObject::Release() { + ATLASSERT(ref_count_ > 0); + LONG ret = InterlockedDecrement(&ref_count_); + ATLASSERT(ret >= 0); + if (0 == ret) { + LastReferenceReleased(); + delete this; + } + return ret; +} + ADBAPIHANDLE AdbWinUsbEndpointObject::CommonAsyncReadWrite( bool is_read, void* buffer, diff --git a/host/windows/usb/api/adb_winusb_endpoint_object.h b/host/windows/usb/winusb/adb_winusb_endpoint_object.h similarity index 81% rename from host/windows/usb/api/adb_winusb_endpoint_object.h rename to host/windows/usb/winusb/adb_winusb_endpoint_object.h index 26ef53b16..92b6e04fe 100755 --- a/host/windows/usb/api/adb_winusb_endpoint_object.h +++ b/host/windows/usb/winusb/adb_winusb_endpoint_object.h @@ -21,7 +21,7 @@ encapsulates a handle opened to a WinUsb endpoint on our device. */ -#include "adb_endpoint_object.h" +#include "..\api\adb_endpoint_object.h" #include "adb_winusb_interface.h" /** Class AdbWinUsbEndpointObject encapsulates a handle opened to an endpoint on @@ -48,6 +48,30 @@ class AdbWinUsbEndpointObject : public AdbEndpointObject { */ virtual ~AdbWinUsbEndpointObject(); + // + // Virtual overrides + // + + public: + /** \brief Releases the object. + + If refcount drops to zero as the result of this release, the object is + destroyed in this method. As a general rule, objects must not be touched + after this method returns even if returned value is not zero. We override + this method in order to make sure that objects of this class are deleted + in contect of the DLL they were created in. The problem is that since + objects of this class were created in context of AdbWinUsbApi module, they + are allocated from the heap assigned to that module. Now, if these objects + are deleted outside of AdbWinUsbApi module, this will lead to the heap + corruption in the module that deleted these objects. Since all objects of + this class are deleted in the Release method only, by overriding it we make + sure that we free memory in the context of the module where it was + allocated. + @return Value of the reference counter after object is released in this + method. + */ + virtual LONG Release(); + // // Abstract overrides // diff --git a/host/windows/usb/api/adb_winusb_interface.cpp b/host/windows/usb/winusb/adb_winusb_interface.cpp similarity index 95% rename from host/windows/usb/api/adb_winusb_interface.cpp rename to host/windows/usb/winusb/adb_winusb_interface.cpp index d09c1cbeb..9d0377a46 100755 --- a/host/windows/usb/api/adb_winusb_interface.cpp +++ b/host/windows/usb/winusb/adb_winusb_interface.cpp @@ -40,6 +40,17 @@ AdbWinUsbInterfaceObject::~AdbWinUsbInterfaceObject() { ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_); } +LONG AdbWinUsbInterfaceObject::Release() { + ATLASSERT(ref_count_ > 0); + LONG ret = InterlockedDecrement(&ref_count_); + ATLASSERT(ret >= 0); + if (0 == ret) { + LastReferenceReleased(); + delete this; + } + return ret; +} + ADBAPIHANDLE AdbWinUsbInterfaceObject::CreateHandle() { // Open USB device for this inteface Note that WinUsb API // requires the handle to be opened for overlapped I/O. diff --git a/host/windows/usb/api/adb_winusb_interface.h b/host/windows/usb/winusb/adb_winusb_interface.h similarity index 84% rename from host/windows/usb/api/adb_winusb_interface.h rename to host/windows/usb/winusb/adb_winusb_interface.h index 82f7f8985..2311fd170 100755 --- a/host/windows/usb/api/adb_winusb_interface.h +++ b/host/windows/usb/winusb/adb_winusb_interface.h @@ -22,7 +22,7 @@ via WinUsb API. */ -#include "adb_interface.h" +#include "..\api\adb_interface.h" /** \brief Encapsulates an interface on our USB device that is accessible via WinUsb API. @@ -48,6 +48,25 @@ class AdbWinUsbInterfaceObject : public AdbInterfaceObject { // public: + /** \brief Releases the object. + + If refcount drops to zero as the result of this release, the object is + destroyed in this method. As a general rule, objects must not be touched + after this method returns even if returned value is not zero. We override + this method in order to make sure that objects of this class are deleted + in contect of the DLL they were created in. The problem is that since + objects of this class were created in context of AdbWinUsbApi module, they + are allocated from the heap assigned to that module. Now, if these objects + are deleted outside of AdbWinUsbApi module, this will lead to the heap + corruption in the module that deleted these objects. Since all objects of + this class are deleted in the Release method only, by overriding it we make + sure that we free memory in the context of the module where it was + allocated. + @return Value of the reference counter after object is released in this + method. + */ + virtual LONG Release(); + /** \brief Creates handle to this object. In this call a handle for this object is generated and object is added diff --git a/host/windows/usb/api/adb_winusb_io_completion.cpp b/host/windows/usb/winusb/adb_winusb_io_completion.cpp similarity index 89% rename from host/windows/usb/api/adb_winusb_io_completion.cpp rename to host/windows/usb/winusb/adb_winusb_io_completion.cpp index baeb7bbb8..d98f87254 100755 --- a/host/windows/usb/api/adb_winusb_io_completion.cpp +++ b/host/windows/usb/winusb/adb_winusb_io_completion.cpp @@ -33,6 +33,17 @@ AdbWinUsbIOCompletion::AdbWinUsbIOCompletion( AdbWinUsbIOCompletion::~AdbWinUsbIOCompletion() { } +LONG AdbWinUsbIOCompletion::Release() { + ATLASSERT(ref_count_ > 0); + LONG ret = InterlockedDecrement(&ref_count_); + ATLASSERT(ret >= 0); + if (0 == ret) { + LastReferenceReleased(); + delete this; + } + return ret; +} + bool AdbWinUsbIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data, ULONG* bytes_transferred, bool wait) { diff --git a/host/windows/usb/api/adb_winusb_io_completion.h b/host/windows/usb/winusb/adb_winusb_io_completion.h similarity index 75% rename from host/windows/usb/api/adb_winusb_io_completion.h rename to host/windows/usb/winusb/adb_winusb_io_completion.h index a97a3a8b2..93a4c07eb 100755 --- a/host/windows/usb/api/adb_winusb_io_completion.h +++ b/host/windows/usb/winusb/adb_winusb_io_completion.h @@ -22,7 +22,7 @@ asynchronous I/O requests issued via WinUsb API. */ -#include "adb_io_completion.h" +#include "..\api\adb_io_completion.h" #include "adb_winusb_endpoint_object.h" /** \brief Encapsulates encapsulates a wrapper around OVERLAPPED Win32 @@ -56,6 +56,30 @@ class AdbWinUsbIOCompletion : public AdbIOCompletion { */ virtual ~AdbWinUsbIOCompletion(); + // + // Virtual overrides + // + + public: + /** \brief Releases the object. + + If refcount drops to zero as the result of this release, the object is + destroyed in this method. As a general rule, objects must not be touched + after this method returns even if returned value is not zero. We override + this method in order to make sure that objects of this class are deleted + in contect of the DLL they were created in. The problem is that since + objects of this class were created in context of AdbWinUsbApi module, they + are allocated from the heap assigned to that module. Now, if these objects + are deleted outside of AdbWinUsbApi module, this will lead to the heap + corruption in the module that deleted these objects. Since all objects of + this class are deleted in the Release method only, by overriding it we make + sure that we free memory in the context of the module where it was + allocated. + @return Value of the reference counter after object is released in this + method. + */ + virtual LONG Release(); + // // Abstract overrides // diff --git a/host/windows/usb/winusb/stdafx.cpp b/host/windows/usb/winusb/stdafx.cpp new file mode 100755 index 000000000..562765b81 --- /dev/null +++ b/host/windows/usb/winusb/stdafx.cpp @@ -0,0 +1,21 @@ +/* + * 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. + */ + +// stdafx.cpp : source file that includes just the standard includes +// AdbWinUsbApi.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/host/windows/usb/winusb/stdafx.h b/host/windows/usb/winusb/stdafx.h new file mode 100755 index 000000000..c2aa8dee6 --- /dev/null +++ b/host/windows/usb/winusb/stdafx.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/** \file + Visual Studio generated include file for standard system include files, or + project specific include files that are used frequently, but are changed + infrequently. +*/ + +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. +#define WINVER 0x0500 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. +#define _WIN32_WINNT 0x0500 // Change this to the appropriate value to target Windows 2000 or later. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0500 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. +#define _WIN32_IE 0x0501 // Change this to the appropriate value to target IE 5.0 or later. +#endif + +// These defines prevent the MS header files from ejecting #pragma comment +// statements with the manifest information of the used ATL, STL, and CRT +#define _ATL_NOFORCE_MANIFEST +#define _STL_NOFORCE_MANIFEST +#define _CRT_NOFORCE_MANIFEST + +#define _ATL_APARTMENT_THREADED +#define _ATL_NO_AUTOMATIC_NAMESPACE + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +// turns off ATL's hiding of some common and often safely ignored warning messages +#define _ATL_ALL_WARNINGS + +// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include +#pragma warning(disable: 4702) +#pragma warning(disable: 4201) +#include +#include +#include +#include +#include +#include +#pragma warning(default: 4201) +#pragma warning(disable: 4200) +#include + +#include "resource.h" + +using namespace ATL; From 2f6bd734c081c5ae96c724877ee86bfacc77a025 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Wed, 5 Aug 2009 19:25:35 -0700 Subject: [PATCH 11/87] Fix comparison of 2 doc packages that have the same codename/revision. This made the Donut_r1 doc show up as upgrade to the donut_r1 doc. BUG: 2037448 --- .../internal/repository/DocPackage.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java index abd42fb9c..3bd731b0a 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java @@ -166,22 +166,25 @@ public class DocPackage extends Package { AndroidVersion replacementVersion = replacementDoc.getVersion(); - // the new doc is an update if the api level is higher + // the new doc is an update if the api level is higher (no matter the codename on either) if (replacementVersion.getApiLevel() > mVersion.getApiLevel()) { return UpdateInfo.UPDATE; } - // if it's the exactly same (including codename), we check the revision - if (replacementVersion.equals(mVersion) && - replacementPackage.getRevision() > this.getRevision()) { - return UpdateInfo.UPDATE; - } - - // else we check if they have the same api level and the new one is a preview, in which - // case it's also an update (since preview have the api level of the _previous_ version. - if (replacementVersion.getApiLevel() == mVersion.getApiLevel() && - replacementVersion.isPreview()) { - return UpdateInfo.UPDATE; + // Check if they're the same exact (api and codename) + if (replacementVersion.equals(mVersion)) { + // exact same version, so check the revision level + if (replacementPackage.getRevision() > this.getRevision()) { + return UpdateInfo.UPDATE; + } + } else { + // not the same version? we check if they have the same api level and the new one + // is a preview, in which case it's also an update (since preview have the api level + // of the _previous_ version.) + if (replacementVersion.getApiLevel() == mVersion.getApiLevel() && + replacementVersion.isPreview()) { + return UpdateInfo.UPDATE; + } } // not an upgrade but not incompatible either. From 531749469d1befd28431b46c0c1279857f54c1b0 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 6 Aug 2009 11:39:39 -0700 Subject: [PATCH 12/87] SDK Updater: fix main window to resize. BUG 2038860 --- .../android/sdkuilib/internal/repository/UpdaterWindowImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java index 0fbcc41cd..20f1abbe8 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java @@ -109,7 +109,7 @@ public class UpdaterWindowImpl { * Create contents of the window. */ protected void createContents() { - mAndroidSdkUpdater = new Shell(mParentShell); + mAndroidSdkUpdater = new Shell(mParentShell, SWT.SHELL_TRIM); mAndroidSdkUpdater.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { onAndroidSdkUpdaterDispose(); //$hide$ (hide from SWT designer) From 26cdbb788a9137d04587bc678d7aa7f49e3671fc Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 6 Aug 2009 12:51:22 -0700 Subject: [PATCH 13/87] SDK Updater: Fix to allow install from directory URL (i.e. auto-guess the repository.xml correctly.) BUG 2039080 Also removed some misc Eclipse 3.5 warnings. --- .../com/android/sdklib/AndroidVersion.java | 2 +- .../sdklib/internal/repository/Archive.java | 8 +- .../sdklib/internal/repository/Package.java | 2 +- .../internal/repository/RepoSource.java | 86 +++++++++---------- 4 files changed, 47 insertions(+), 51 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java index 61b348a9a..ef62f6e8c 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java @@ -174,7 +174,7 @@ public class AndroidVersion { } else if (obj instanceof String) { // if we have a code name, this must match. if (mCodename != null) { - return mCodename.equals((String)obj); + return mCodename.equals(obj); } // else we try to convert to a int and compare to the api level diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java index 3757b7491..9fa614ad9 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java @@ -23,6 +23,7 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -572,6 +573,10 @@ public class Archive implements IDescription { return true; + } catch (FileNotFoundException e) { + // The FNF message is just the URL. Make it a bit more useful. + monitor.setResult("File not found: %1$s", e.getMessage()); + } catch (Exception e) { monitor.setResult(e.getMessage()); @@ -723,8 +728,7 @@ public class Archive implements IDescription { byte[] buf = new byte[65536]; - Enumeration entries = - (Enumeration)zipFile.getEntries(); + Enumeration entries = zipFile.getEntries(); while (entries.hasMoreElements()) { ZipArchiveEntry entry = entries.nextElement(); diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java index a637fdeaf..8d19c0f6d 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java @@ -332,7 +332,7 @@ public abstract class Package implements IDescription { * current one, it's not an update. * * @param replacementPackage The potential replacement package. - * @return + * @return One of the {@link UpdateInfo} values. * * @see #sameItemAs(Package) */ diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java index 5de2e9404..cd2bacb7d 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java @@ -47,7 +47,7 @@ import javax.xml.validation.Validator; */ public class RepoSource implements IDescription { - private final String mUrl; + private String mUrl; private final boolean mUserSource; private Package[] mPackages; @@ -132,55 +132,51 @@ public class RepoSource implements IDescription { monitor.setDescription("Fetching %1$s", url); monitor.incProgress(1); - ByteArrayInputStream xml = null; + mFetchError = null; + Exception[] exception = new Exception[] { null }; + ByteArrayInputStream xml = fetchUrl(url, exception); + boolean validated = false; + if (xml != null) { + monitor.setDescription("Validate XML"); + validated = validateXml(xml, url, monitor); + } - for (int tentative = 0; tentative < 2 && xml == null; tentative++) { + // If we failed the first time and the URL doesn't explicitly end with + // our filename, make another tentative after changing the URL. + if (!validated && !url.endsWith(SdkRepository.URL_DEFAULT_XML_FILE)) { + if (!url.endsWith("/")) { //$NON-NLS-1$ + url += "/"; //$NON-NLS-1$ + } + url += SdkRepository.URL_DEFAULT_XML_FILE; - // reset fetch error and fetch - mFetchError = null; - xml = fetchUrl(url, monitor); + xml = fetchUrl(url, exception); + if (xml != null) { + validated = validateXml(xml, url, monitor); + } - if (xml == null) { - mDescription += String.format("\nFailed to fetch URL %1$s", url); - mFetchError = "Failed to fetch URL"; - monitor.setResult("Failed to fetch URL %1$s", url); - } else { - // We got a document. It might not be XML or it might not be valid. + if (validated) { + // If the second tentative succeeded, indicate it in the console + // with the URL that worked. + monitor.setResult("Repository found at %1$s", url); - monitor.setDescription("Validate XML"); + // Keep the modified URL + mUrl = url; + } + } - if (validateXml(xml, url, monitor)) { - // We got a valid XML, keep it and use it. + if (!validated) { + mFetchError = "Failed to fetch URL"; - if (tentative > 0) { - // If the second tentative succeeded, indicate it in the console, - // otherwise the user will only see the first failure - // message and will think the whole thing failed. This also - // indicates we modifed the URL. - monitor.setResult("Repository found instead at %1$s", url); - } - break; - } else { - mDescription += String.format("\nFailed to validate XML at %1$s", url); - mFetchError = "Failed to validate XML"; - monitor.setResult("Failed to validate XML at %1$s", url); - - // forget this XML, it wasn't any good. - xml = null; + String reason = "Unknown"; + if (exception[0] != null) { + if (exception[0] instanceof FileNotFoundException) { + reason = "File not found"; + } else if (exception[0].getMessage() != null) { + reason = exception[0].getMessage(); } } - // If we failed the first time and the URL doesn't explicitly end with - // our filename, make another tentative. Otherwise abort. - if (tentative == 0 && !url.endsWith(SdkRepository.URL_DEFAULT_XML_FILE)) { - if (!url.endsWith("/")) { //$NON-NLS-1$ - url += "/"; //$NON-NLS-1$ - } - url += SdkRepository.URL_DEFAULT_XML_FILE; - } else { - break; - } - + monitor.setResult("Failed to fetch URL %1$s, reason:", url, reason); } monitor.incProgress(1); @@ -219,7 +215,7 @@ public class RepoSource implements IDescription { * Java URL Reader: http://java.sun.com/docs/books/tutorial/networking/urls/readingURL.html * Java set Proxy: http://java.sun.com/docs/books/tutorial/networking/urls/_setProxy.html */ - private ByteArrayInputStream fetchUrl(String urlString, ITaskMonitor monitor) { + private ByteArrayInputStream fetchUrl(String urlString, Exception[] outException) { URL url; try { url = new URL(urlString); @@ -255,12 +251,8 @@ public class RepoSource implements IDescription { } } - } catch (FileNotFoundException e) { - // The FNF message is just the URL. Make it a bit more useful. - monitor.setResult("File not found: %1$s", e.getMessage()); - } catch (IOException e) { - monitor.setResult(e.getMessage()); + outException[0] = e; } return null; From 48b3b5efc2287794a242bcbff5dfb8163b8890b0 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Thu, 6 Aug 2009 17:09:11 -0700 Subject: [PATCH 14/87] Make android.bat copy commons-compress to tmp with the other jar files. BUG: 2039759 --- tools/sdkmanager/app/etc/android.bat | 7 ++++--- .../android/sdkuilib/internal/repository/UpdaterData.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/sdkmanager/app/etc/android.bat b/tools/sdkmanager/app/etc/android.bat index b19ce0ab0..032985de4 100755 --- a/tools/sdkmanager/app/etc/android.bat +++ b/tools/sdkmanager/app/etc/android.bat @@ -43,9 +43,10 @@ if not "%1"=="" goto EndTempCopy set tmpdir=%TEMP%\temp-android-tool xcopy lib\x86 %tmpdir%\lib\x86 /I /E /C /G /R /O /Y /Q > nul - copy /B /D /Y lib\androidprefs.jar %tmpdir%\lib\ > nul - copy /B /D /Y lib\org.eclipse.* %tmpdir%\lib\ > nul - copy /B /D /Y lib\sdk* %tmpdir%\lib\ > nul + copy /B /D /Y lib\androidprefs.jar %tmpdir%\lib\ > nul + copy /B /D /Y lib\org.eclipse.* %tmpdir%\lib\ > nul + copy /B /D /Y lib\sdk* %tmpdir%\lib\ > nul + copy /B /D /Y lib\commons-compress* %tmpdir%\lib\ > nul rem jarpath and swt_path are relative to PWD so we don't need to adjust them, just change dirs. set toolsdir=%cd% diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java index a9e8afae3..6cae085ac 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java @@ -308,7 +308,7 @@ class UpdaterData { // Display anything unexpected in the monitor. String msg = t.getMessage(); if (msg != null) { - monitor.setResult("Unexpected Error installing '%1%s: %2$s", + monitor.setResult("Unexpected Error installing '%1$s: %2$s", archive.getParentPackage().getShortDescription(), msg); } else { // no error info? get the stack call to display it From 3a2c7273ee6a5d8561a82eff0d1ca57b003121ff Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Thu, 6 Aug 2009 17:59:52 -0700 Subject: [PATCH 15/87] Fix some minor typo BUG: 2039797 --- .../com/android/sdkuilib/internal/repository/UpdaterData.java | 4 ++-- .../com/android/sdkuilib/internal/widgets/AvdSelector.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java index 6cae085ac..486095ca7 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java @@ -308,7 +308,7 @@ class UpdaterData { // Display anything unexpected in the monitor. String msg = t.getMessage(); if (msg != null) { - monitor.setResult("Unexpected Error installing '%1$s: %2$s", + monitor.setResult("Unexpected Error installing '%1$s': %2$s", archive.getParentPackage().getShortDescription(), msg); } else { // no error info? get the stack call to display it @@ -317,7 +317,7 @@ class UpdaterData { t.printStackTrace(new PrintStream(baos)); // and display it - monitor.setResult("Unexpected Error installing '%1$s\n%2$s", + monitor.setResult("Unexpected Error installing '%1$s'\n%2$s", archive.getParentPackage().getShortDescription(), baos.toString()); } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java index a85c1b81e..96d1b65f5 100644 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java @@ -298,8 +298,8 @@ public final class AvdSelector { mRefreshButton = new Button(buttons, SWT.PUSH | SWT.FLAT); mRefreshButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mRefreshButton.setText("Resfresh"); - mRefreshButton.setToolTipText("Reloads the list of AVD.\nUse this if you create AVD from the command line."); + mRefreshButton.setText("Refresh"); + mRefreshButton.setToolTipText("Reloads the list of AVD.\nUse this if you create AVDs from the command line."); mRefreshButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { From 5ae5e3da1b96f206e4ce2409df2a81f9537cfa4f Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Thu, 6 Aug 2009 19:25:27 -0700 Subject: [PATCH 16/87] Fix some display string that contained an unused %s and an NPE This makes the android app crash when the XML cannot be validated. --- .../com/android/sdklib/internal/repository/RepoSource.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java index cd2bacb7d..cce65bd88 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java @@ -185,7 +185,7 @@ public class RepoSource implements IDescription { monitor.setDescription("Parse XML"); monitor.incProgress(1); parsePackages(xml, monitor); - if (mPackages.length == 0) { + if (mPackages == null || mPackages.length == 0) { mDescription += "\nNo packages found."; } else if (mPackages.length == 1) { mDescription += "\nOne package found."; @@ -370,10 +370,10 @@ public class RepoSource implements IDescription { } } catch (ParserConfigurationException e) { - monitor.setResult("Failed to create XML document builder for %1$s"); + monitor.setResult("Failed to create XML document builder"); } catch (SAXException e) { - monitor.setResult("Failed to parse XML document %1$s"); + monitor.setResult("Failed to parse XML document"); } catch (IOException e) { monitor.setResult("Failed to read XML document"); From 3e44f3b231c027f01290367049f2244514f22d16 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 6 Aug 2009 20:51:11 -0700 Subject: [PATCH 17/87] Revert "Split AdbWinApi.dll into two dlls to remove dependency on WINUSB.DLL" which breaks the Windows SDK on Donut. This reverts commit f855c4e8469e31114fccca4c28aeb01a806a9a48. --- host/windows/usb/api/AdbWinApi.cpp | 77 +----------- host/windows/usb/api/SOURCES | 6 +- host/windows/usb/api/adb_api.cpp | 24 +--- host/windows/usb/api/adb_api.h | 26 ---- host/windows/usb/api/adb_endpoint_object.h | 2 +- host/windows/usb/api/adb_interface.h | 15 +-- host/windows/usb/api/adb_io_completion.h | 2 +- host/windows/usb/api/adb_object_handle.h | 3 +- .../adb_winusb_endpoint_object.cpp | 12 +- .../adb_winusb_endpoint_object.h | 26 +--- .../{winusb => api}/adb_winusb_interface.cpp | 11 -- .../{winusb => api}/adb_winusb_interface.h | 21 +--- .../adb_winusb_io_completion.cpp | 11 -- .../adb_winusb_io_completion.h | 26 +--- host/windows/usb/api/stdafx.h | 3 + host/windows/usb/winusb/AdbWinUsbApi.cpp | 62 ---------- host/windows/usb/winusb/AdbWinUsbApi.def | 5 - host/windows/usb/winusb/AdbWinUsbApi.rc | 111 ------------------ host/windows/usb/winusb/BUILDME.TXT | 7 -- host/windows/usb/winusb/MAKEFILE | 22 ---- host/windows/usb/winusb/Resource.h | 34 ------ host/windows/usb/winusb/SOURCES | 93 --------------- host/windows/usb/winusb/stdafx.cpp | 21 ---- host/windows/usb/winusb/stdafx.h | 78 ------------ 24 files changed, 24 insertions(+), 674 deletions(-) rename host/windows/usb/{winusb => api}/adb_winusb_endpoint_object.cpp (93%) rename host/windows/usb/{winusb => api}/adb_winusb_endpoint_object.h (81%) rename host/windows/usb/{winusb => api}/adb_winusb_interface.cpp (95%) rename host/windows/usb/{winusb => api}/adb_winusb_interface.h (84%) rename host/windows/usb/{winusb => api}/adb_winusb_io_completion.cpp (89%) rename host/windows/usb/{winusb => api}/adb_winusb_io_completion.h (75%) delete mode 100755 host/windows/usb/winusb/AdbWinUsbApi.cpp delete mode 100755 host/windows/usb/winusb/AdbWinUsbApi.def delete mode 100755 host/windows/usb/winusb/AdbWinUsbApi.rc delete mode 100755 host/windows/usb/winusb/BUILDME.TXT delete mode 100755 host/windows/usb/winusb/MAKEFILE delete mode 100755 host/windows/usb/winusb/Resource.h delete mode 100755 host/windows/usb/winusb/SOURCES delete mode 100755 host/windows/usb/winusb/stdafx.cpp delete mode 100755 host/windows/usb/winusb/stdafx.h diff --git a/host/windows/usb/api/AdbWinApi.cpp b/host/windows/usb/api/AdbWinApi.cpp index e81c2c7ea..4d18d3793 100644 --- a/host/windows/usb/api/AdbWinApi.cpp +++ b/host/windows/usb/api/AdbWinApi.cpp @@ -17,7 +17,6 @@ // AdbWinApi.cpp : Implementation of DLL Exports. #include "stdafx.h" -#include "adb_api.h" extern "C" { int _forceCRTManifest; @@ -25,73 +24,8 @@ int _forceMFCManifest; int _forceAtlDllManifest; }; -/// References InstantiateWinUsbInterface declared in adb_api.cpp -extern PFN_INSTWINUSBINTERFACE InstantiateWinUsbInterface; - class CAdbWinApiModule : public CAtlDllModuleT< CAdbWinApiModule > { - public: - CAdbWinApiModule() - : CAtlDllModuleT< CAdbWinApiModule >(), - adbwinusbapi_handle_(NULL), - is_initialized_(false) { - } - - ~CAdbWinApiModule() { - // Unload AdbWinUsbApi.dll before we exit - if (NULL != adbwinusbapi_handle_) { - FreeLibrary(adbwinusbapi_handle_); - } - } - - /** \brief Loads AdbWinUsbApi.dll and caches its InstantiateWinUsbInterface - export. - - This method is called from DllMain on DLL_PROCESS_ATTACH event. In this - method we will check if WINUSB.DLL required by AdbWinUsbApi.dll is - installed, and if it is we will load AdbWinUsbApi.dll and cache address of - InstantiateWinUsbInterface routine exported from AdbWinUsbApi.dll - */ - void AttachToAdbWinUsbApi() { - // We only need to run this only once. - if (is_initialized_) { - return; - } - - // Just mark that we have ran initialization. - is_initialized_ = true; - - // Before we can load AdbWinUsbApi.dll we must make sure that WINUSB.DLL - // has been installed. Build path to the file. - wchar_t path_to_winusb_dll[MAX_PATH+1]; - if (!GetSystemDirectory(path_to_winusb_dll, MAX_PATH)) { - return; - } - wcscat(path_to_winusb_dll, L"\\WINUSB.DLL"); - - if (0xFFFFFFFF == GetFileAttributes(path_to_winusb_dll)) { - // WINUSB.DLL is not installed. We don't (in fact, can't) load - // AdbWinUsbApi.dll - return; - } - - // WINUSB.DLL is installed. Lets load AdbWinUsbApi.dll and cache its - // InstantiateWinUsbInterface export. - // We require that AdbWinUsbApi.dll is located in the same folder - // where AdbWinApi.dll and adb.exe are located, so by Windows - // conventions we can pass just module name, and not the full path. - adbwinusbapi_handle_ = LoadLibrary(L"AdbWinUsbApi.dll"); - if (NULL != adbwinusbapi_handle_) { - InstantiateWinUsbInterface = reinterpret_cast - (GetProcAddress(adbwinusbapi_handle_, "InstantiateWinUsbInterface")); - } - } - - protected: - /// Handle to the loaded AdbWinUsbApi.dll - HINSTANCE adbwinusbapi_handle_; - - /// Flags whether or not this module has been initialized. - bool is_initialized_; +public: }; CAdbWinApiModule _AtlModule; @@ -100,12 +34,5 @@ CAdbWinApiModule _AtlModule; extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { - // Lets see if we need to initialize InstantiateWinUsbInterface - // variable. We do that only once, on condition that this DLL is - // being attached to the process and InstantiateWinUsbInterface - // address has not been calculated yet. - if (DLL_PROCESS_ATTACH == reason) { - _AtlModule.AttachToAdbWinUsbApi(); - } - return _AtlModule.DllMain(reason, reserved); + return _AtlModule.DllMain(reason, reserved); } diff --git a/host/windows/usb/api/SOURCES b/host/windows/usb/api/SOURCES index 35695217b..f6e66143c 100755 --- a/host/windows/usb/api/SOURCES +++ b/host/windows/usb/api/SOURCES @@ -50,7 +50,8 @@ TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \ $(SDK_LIB_PATH)\wbemuuid.lib \ $(SDK_LIB_PATH)\uuid.lib \ $(SDK_LIB_PATH)\setupapi.lib \ - $(SDK_LIB_PATH)\usbd.lib + $(SDK_LIB_PATH)\usbd.lib \ + $(SDK_LIB_PATH)\winusb.lib !IF "$(DDKBUILDENV)" == "fre" # Libraries for release (free) builds @@ -86,12 +87,15 @@ PRECOMPILED_SOURCEFILE = stdafx.cpp # Define source files for AdbWinApi.dll SOURCES = adb_api.cpp \ adb_endpoint_object.cpp \ + adb_winusb_endpoint_object.cpp \ adb_legacy_endpoint_object.cpp \ adb_helper_routines.cpp \ adb_interface.cpp \ + adb_winusb_interface.cpp \ adb_legacy_interface.cpp \ adb_interface_enum.cpp \ adb_io_completion.cpp \ + adb_winusb_io_completion.cpp \ adb_legacy_io_completion.cpp \ adb_object_handle.cpp \ AdbWinApi.cpp \ diff --git a/host/windows/usb/api/adb_api.cpp b/host/windows/usb/api/adb_api.cpp index 493f62d86..f9bd94e6c 100644 --- a/host/windows/usb/api/adb_api.cpp +++ b/host/windows/usb/api/adb_api.cpp @@ -24,19 +24,12 @@ #include "adb_object_handle.h" #include "adb_interface_enum.h" #include "adb_interface.h" +#include "adb_winusb_interface.h" #include "adb_legacy_interface.h" #include "adb_endpoint_object.h" #include "adb_io_completion.h" #include "adb_helper_routines.h" -/** \brief Points to InstantiateWinUsbInterface exported from AdbWinUsbApi.dll. - - This variable is initialized with the actual address in DllMain routine for - this DLL on DLL_PROCESS_ATTACH event. - @see PFN_INSTWINUSBINTERFACE for more information. -*/ -PFN_INSTWINUSBINTERFACE InstantiateWinUsbInterface = NULL; - ADBAPIHANDLE __cdecl AdbEnumInterfaces(GUID class_id, bool exclude_not_present, bool exclude_removed, @@ -108,22 +101,11 @@ ADBAPIHANDLE __cdecl AdbCreateInterfaceByName( ADBAPIHANDLE ret = NULL; try { - // Instantiate interface object, depending on the USB driver type. + // Instantiate object if (IsLegacyInterface(interface_name)) { - // We have legacy USB driver underneath us. obj = new AdbLegacyInterfaceObject(interface_name); } else { - // We have WinUsb driver underneath us. Make sure that AdbWinUsbApi.dll - // is loaded and its InstantiateWinUsbInterface routine address has - // been cached. - if (NULL != InstantiateWinUsbInterface) { - obj = InstantiateWinUsbInterface(interface_name); - if (NULL == obj) { - return NULL; - } - } else { - return NULL; - } + obj = new AdbWinUsbInterfaceObject(interface_name); } // Create handle for it diff --git a/host/windows/usb/api/adb_api.h b/host/windows/usb/api/adb_api.h index 429a56d9a..e2ad129ca 100644 --- a/host/windows/usb/api/adb_api.h +++ b/host/windows/usb/api/adb_api.h @@ -110,30 +110,6 @@ typedef struct _AdbEndpointInformation { /// the driver in isolation from hardware. #define DEVICE_EMULATOR_PROD_ID 0xDDDD -/** \brief Function prototype for InstantiateWinUsbInterface routine exported - from AdbWinUsbApi.dll - - In order to provide backward compatibility with the systems that still run - legacy (custom) USB drivers, and have not installed WINUSB.DLL we need to - split functionality of our ADB API on Windows between two DLLs: AdbWinApi, - and AdbWinUsbApi. AdbWinApi is fully capable of working on top of the legacy - driver, but has no traces to WinUsb. AdbWinUsbApi is capable of working on - top of WinUsb API. We are forced to do this split, because we can have - dependency on WINUSB.DLL in the DLL that implements legacy API. The problem - is that customers may have a legacy driver that they don't want to upgrade - to WinUsb, so they may not have WINUSB.DLL installed on their machines, but - they still must be able to use ADB. So, the idea behind the split is as - such. When AdbWinApi.dll is loaded into a process, it will check WINUSB.DLL - installation (by checking existance of C:\Windows\System32\winusb.dll). If - WINUSB.DLL is installed, AdbWinApi will also load AdbWinUsbApi.dll (by - calling LoadLibrary), and will extract address of InstantiateWinUsbInterface - routine exported from AdbWinUsbApi.dll. Then this routine will be used to - instantiate AdbInterfaceObject instance on condition that it is confirmed - that USB driver underneath us is in deed WinUsb. -*/ -typedef class AdbInterfaceObject* \ - (__cdecl *PFN_INSTWINUSBINTERFACE)(const wchar_t*); - // The following ifdef block is the standard way of creating macros which make // exporting from a DLL simpler. All files within this DLL are compiled with // the ADBWIN_EXPORTS symbol defined on the command line. this symbol should @@ -143,10 +119,8 @@ typedef class AdbInterfaceObject* \ // as being exported. #ifdef ADBWIN_EXPORTS #define ADBWIN_API EXTERN_C __declspec(dllexport) -#define ADBWIN_API_CLASS __declspec(dllexport) #else #define ADBWIN_API EXTERN_C __declspec(dllimport) -#define ADBWIN_API_CLASS __declspec(dllimport) #endif /** \brief Handle to an API object. diff --git a/host/windows/usb/api/adb_endpoint_object.h b/host/windows/usb/api/adb_endpoint_object.h index d92aaad47..295eb46f2 100644 --- a/host/windows/usb/api/adb_endpoint_object.h +++ b/host/windows/usb/api/adb_endpoint_object.h @@ -29,7 +29,7 @@ This class implement functionality that is common for both, WinUsb and legacy APIs. */ -class ADBWIN_API_CLASS AdbEndpointObject : public AdbObjectHandle { +class AdbEndpointObject : public AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/adb_interface.h b/host/windows/usb/api/adb_interface.h index 0aa0d1d55..4afb17da0 100644 --- a/host/windows/usb/api/adb_interface.h +++ b/host/windows/usb/api/adb_interface.h @@ -23,17 +23,12 @@ #include "adb_object_handle.h" -// 'AdbInterfaceObject::interface_name_' : class 'std::basic_string<_E,_Tr,_A>' -// needs to have dll-interface to be used by clients of class -// 'AdbInterfaceObject' We're ok with that, since interface_name_ will not -// be referenced by name from outside of this class. -#pragma warning(disable: 4251) /** \brief Encapsulates an interface on our USB device. This is an abstract class that implements functionality common for both, legacy, and WinUsb based interfaces. */ -class ADBWIN_API_CLASS AdbInterfaceObject : public AdbObjectHandle { +class AdbInterfaceObject : public AdbObjectHandle { public: /** \brief Constructs the object. @@ -185,6 +180,9 @@ class ADBWIN_API_CLASS AdbInterfaceObject : public AdbObjectHandle { } protected: + /// Name of the USB interface (device name) for this object + std::wstring interface_name_; + /// Cached usb device descriptor USB_DEVICE_DESCRIPTOR usb_device_descriptor_; @@ -193,11 +191,6 @@ class ADBWIN_API_CLASS AdbInterfaceObject : public AdbObjectHandle { /// Cached usb interface descriptor USB_INTERFACE_DESCRIPTOR usb_interface_descriptor_; - - private: - /// Name of the USB interface (device name) for this object - std::wstring interface_name_; }; -#pragma warning(default: 4251) #endif // ANDROID_USB_API_ADB_INTERFACE_H__ diff --git a/host/windows/usb/api/adb_io_completion.h b/host/windows/usb/api/adb_io_completion.h index ea4b4fbce..8a7c1d91d 100644 --- a/host/windows/usb/api/adb_io_completion.h +++ b/host/windows/usb/api/adb_io_completion.h @@ -33,7 +33,7 @@ like all other handles this handle must be closed after it's no longer needed. */ -class ADBWIN_API_CLASS AdbIOCompletion : public AdbObjectHandle { +class AdbIOCompletion : public AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/adb_object_handle.h b/host/windows/usb/api/adb_object_handle.h index 2fa4ad03b..29ac5e2f2 100644 --- a/host/windows/usb/api/adb_object_handle.h +++ b/host/windows/usb/api/adb_object_handle.h @@ -22,7 +22,6 @@ of the API through a handle. */ -#include "adb_api.h" #include "adb_api_private_defines.h" /** \brief Defines types of internal API objects @@ -72,7 +71,7 @@ enum AdbObjectType { All API objects that have handles that are sent back to API client must be derived from this class. */ -class ADBWIN_API_CLASS AdbObjectHandle { +class AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/winusb/adb_winusb_endpoint_object.cpp b/host/windows/usb/api/adb_winusb_endpoint_object.cpp similarity index 93% rename from host/windows/usb/winusb/adb_winusb_endpoint_object.cpp rename to host/windows/usb/api/adb_winusb_endpoint_object.cpp index 16f78370c..236de3b49 100755 --- a/host/windows/usb/winusb/adb_winusb_endpoint_object.cpp +++ b/host/windows/usb/api/adb_winusb_endpoint_object.cpp @@ -22,6 +22,7 @@ #include "stdafx.h" #include "adb_winusb_endpoint_object.h" #include "adb_winusb_io_completion.h" +#include "adb_helper_routines.h" AdbWinUsbEndpointObject::AdbWinUsbEndpointObject( AdbWinUsbInterfaceObject* parent_interf, @@ -33,17 +34,6 @@ AdbWinUsbEndpointObject::AdbWinUsbEndpointObject( AdbWinUsbEndpointObject::~AdbWinUsbEndpointObject() { } -LONG AdbWinUsbEndpointObject::Release() { - ATLASSERT(ref_count_ > 0); - LONG ret = InterlockedDecrement(&ref_count_); - ATLASSERT(ret >= 0); - if (0 == ret) { - LastReferenceReleased(); - delete this; - } - return ret; -} - ADBAPIHANDLE AdbWinUsbEndpointObject::CommonAsyncReadWrite( bool is_read, void* buffer, diff --git a/host/windows/usb/winusb/adb_winusb_endpoint_object.h b/host/windows/usb/api/adb_winusb_endpoint_object.h similarity index 81% rename from host/windows/usb/winusb/adb_winusb_endpoint_object.h rename to host/windows/usb/api/adb_winusb_endpoint_object.h index 92b6e04fe..26ef53b16 100755 --- a/host/windows/usb/winusb/adb_winusb_endpoint_object.h +++ b/host/windows/usb/api/adb_winusb_endpoint_object.h @@ -21,7 +21,7 @@ encapsulates a handle opened to a WinUsb endpoint on our device. */ -#include "..\api\adb_endpoint_object.h" +#include "adb_endpoint_object.h" #include "adb_winusb_interface.h" /** Class AdbWinUsbEndpointObject encapsulates a handle opened to an endpoint on @@ -48,30 +48,6 @@ class AdbWinUsbEndpointObject : public AdbEndpointObject { */ virtual ~AdbWinUsbEndpointObject(); - // - // Virtual overrides - // - - public: - /** \brief Releases the object. - - If refcount drops to zero as the result of this release, the object is - destroyed in this method. As a general rule, objects must not be touched - after this method returns even if returned value is not zero. We override - this method in order to make sure that objects of this class are deleted - in contect of the DLL they were created in. The problem is that since - objects of this class were created in context of AdbWinUsbApi module, they - are allocated from the heap assigned to that module. Now, if these objects - are deleted outside of AdbWinUsbApi module, this will lead to the heap - corruption in the module that deleted these objects. Since all objects of - this class are deleted in the Release method only, by overriding it we make - sure that we free memory in the context of the module where it was - allocated. - @return Value of the reference counter after object is released in this - method. - */ - virtual LONG Release(); - // // Abstract overrides // diff --git a/host/windows/usb/winusb/adb_winusb_interface.cpp b/host/windows/usb/api/adb_winusb_interface.cpp similarity index 95% rename from host/windows/usb/winusb/adb_winusb_interface.cpp rename to host/windows/usb/api/adb_winusb_interface.cpp index 9d0377a46..d09c1cbeb 100755 --- a/host/windows/usb/winusb/adb_winusb_interface.cpp +++ b/host/windows/usb/api/adb_winusb_interface.cpp @@ -40,17 +40,6 @@ AdbWinUsbInterfaceObject::~AdbWinUsbInterfaceObject() { ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_); } -LONG AdbWinUsbInterfaceObject::Release() { - ATLASSERT(ref_count_ > 0); - LONG ret = InterlockedDecrement(&ref_count_); - ATLASSERT(ret >= 0); - if (0 == ret) { - LastReferenceReleased(); - delete this; - } - return ret; -} - ADBAPIHANDLE AdbWinUsbInterfaceObject::CreateHandle() { // Open USB device for this inteface Note that WinUsb API // requires the handle to be opened for overlapped I/O. diff --git a/host/windows/usb/winusb/adb_winusb_interface.h b/host/windows/usb/api/adb_winusb_interface.h similarity index 84% rename from host/windows/usb/winusb/adb_winusb_interface.h rename to host/windows/usb/api/adb_winusb_interface.h index 2311fd170..82f7f8985 100755 --- a/host/windows/usb/winusb/adb_winusb_interface.h +++ b/host/windows/usb/api/adb_winusb_interface.h @@ -22,7 +22,7 @@ via WinUsb API. */ -#include "..\api\adb_interface.h" +#include "adb_interface.h" /** \brief Encapsulates an interface on our USB device that is accessible via WinUsb API. @@ -48,25 +48,6 @@ class AdbWinUsbInterfaceObject : public AdbInterfaceObject { // public: - /** \brief Releases the object. - - If refcount drops to zero as the result of this release, the object is - destroyed in this method. As a general rule, objects must not be touched - after this method returns even if returned value is not zero. We override - this method in order to make sure that objects of this class are deleted - in contect of the DLL they were created in. The problem is that since - objects of this class were created in context of AdbWinUsbApi module, they - are allocated from the heap assigned to that module. Now, if these objects - are deleted outside of AdbWinUsbApi module, this will lead to the heap - corruption in the module that deleted these objects. Since all objects of - this class are deleted in the Release method only, by overriding it we make - sure that we free memory in the context of the module where it was - allocated. - @return Value of the reference counter after object is released in this - method. - */ - virtual LONG Release(); - /** \brief Creates handle to this object. In this call a handle for this object is generated and object is added diff --git a/host/windows/usb/winusb/adb_winusb_io_completion.cpp b/host/windows/usb/api/adb_winusb_io_completion.cpp similarity index 89% rename from host/windows/usb/winusb/adb_winusb_io_completion.cpp rename to host/windows/usb/api/adb_winusb_io_completion.cpp index d98f87254..baeb7bbb8 100755 --- a/host/windows/usb/winusb/adb_winusb_io_completion.cpp +++ b/host/windows/usb/api/adb_winusb_io_completion.cpp @@ -33,17 +33,6 @@ AdbWinUsbIOCompletion::AdbWinUsbIOCompletion( AdbWinUsbIOCompletion::~AdbWinUsbIOCompletion() { } -LONG AdbWinUsbIOCompletion::Release() { - ATLASSERT(ref_count_ > 0); - LONG ret = InterlockedDecrement(&ref_count_); - ATLASSERT(ret >= 0); - if (0 == ret) { - LastReferenceReleased(); - delete this; - } - return ret; -} - bool AdbWinUsbIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data, ULONG* bytes_transferred, bool wait) { diff --git a/host/windows/usb/winusb/adb_winusb_io_completion.h b/host/windows/usb/api/adb_winusb_io_completion.h similarity index 75% rename from host/windows/usb/winusb/adb_winusb_io_completion.h rename to host/windows/usb/api/adb_winusb_io_completion.h index 93a4c07eb..a97a3a8b2 100755 --- a/host/windows/usb/winusb/adb_winusb_io_completion.h +++ b/host/windows/usb/api/adb_winusb_io_completion.h @@ -22,7 +22,7 @@ asynchronous I/O requests issued via WinUsb API. */ -#include "..\api\adb_io_completion.h" +#include "adb_io_completion.h" #include "adb_winusb_endpoint_object.h" /** \brief Encapsulates encapsulates a wrapper around OVERLAPPED Win32 @@ -56,30 +56,6 @@ class AdbWinUsbIOCompletion : public AdbIOCompletion { */ virtual ~AdbWinUsbIOCompletion(); - // - // Virtual overrides - // - - public: - /** \brief Releases the object. - - If refcount drops to zero as the result of this release, the object is - destroyed in this method. As a general rule, objects must not be touched - after this method returns even if returned value is not zero. We override - this method in order to make sure that objects of this class are deleted - in contect of the DLL they were created in. The problem is that since - objects of this class were created in context of AdbWinUsbApi module, they - are allocated from the heap assigned to that module. Now, if these objects - are deleted outside of AdbWinUsbApi module, this will lead to the heap - corruption in the module that deleted these objects. Since all objects of - this class are deleted in the Release method only, by overriding it we make - sure that we free memory in the context of the module where it was - allocated. - @return Value of the reference counter after object is released in this - method. - */ - virtual LONG Release(); - // // Abstract overrides // diff --git a/host/windows/usb/api/stdafx.h b/host/windows/usb/api/stdafx.h index d57bec74b..92b2652ea 100644 --- a/host/windows/usb/api/stdafx.h +++ b/host/windows/usb/api/stdafx.h @@ -71,8 +71,11 @@ #include #pragma warning(default: 4201) #pragma warning(disable: 4200) +extern "C" { #include +#include #include +} #include "resource.h" diff --git a/host/windows/usb/winusb/AdbWinUsbApi.cpp b/host/windows/usb/winusb/AdbWinUsbApi.cpp deleted file mode 100755 index 4916eebd2..000000000 --- a/host/windows/usb/winusb/AdbWinUsbApi.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -// AdbWinUsbApi.cpp : Implementation of DLL Exports. - -#include "stdafx.h" -#include "adb_winusb_interface.h" - -class CAdbWinApiModule : public CAtlDllModuleT< CAdbWinApiModule > { -public: -}; - -CAdbWinApiModule _AtlModule; - -// DLL Entry Point -extern "C" BOOL WINAPI DllMain(HINSTANCE instance, - DWORD reason, - LPVOID reserved) { - return _AtlModule.DllMain(reason, reserved); -} - -/** \brief Instantiates interface instance that uses WinUsb API to communicate - with USB driver. - - This is the only exported routine from this DLL. This routine instantiates an - object of AdbWinUsbInterfaceObject on request from AdbWinApi.dll when it is - detected that underlying USB driver is WinUsb.sys. - @param[in] interface_name Name of the interface. - @return AdbInterfaceObject - casted instance of AdbWinUsbInterfaceObject - object on success, or NULL on failure with GetLastError providing - information on an error that occurred. -*/ -extern "C" __declspec(dllexport) -AdbInterfaceObject* __cdecl InstantiateWinUsbInterface( - const wchar_t* interface_name) { - // Validate parameter. - if (NULL == interface_name) { - return NULL; - } - - // Instantiate requested object. - try { - return new AdbWinUsbInterfaceObject(interface_name); - } catch (...) { - // We expect only OOM exceptions here. - SetLastError(ERROR_OUTOFMEMORY); - return NULL; - } -} diff --git a/host/windows/usb/winusb/AdbWinUsbApi.def b/host/windows/usb/winusb/AdbWinUsbApi.def deleted file mode 100755 index 9e616e91d..000000000 --- a/host/windows/usb/winusb/AdbWinUsbApi.def +++ /dev/null @@ -1,5 +0,0 @@ -; AdbWinUsbApi.def : Declares the module parameters. - -LIBRARY "AdbWinUsbApi.DLL" - -EXPORTS diff --git a/host/windows/usb/winusb/AdbWinUsbApi.rc b/host/windows/usb/winusb/AdbWinUsbApi.rc deleted file mode 100755 index 44aa100f4..000000000 --- a/host/windows/usb/winusb/AdbWinUsbApi.rc +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - */ - -//Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE 9, 1 -#pragma code_page(1252) -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#ifndef _MAC -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,0 - PRODUCTVERSION 2,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "Google, inc" - VALUE "FileDescription", "Android ADB API (WinUsb)" - VALUE "FileVersion", "2.0.0.0" - VALUE "LegalCopyright", "Copyright (C) 2006 The Android Open Source Project" - VALUE "InternalName", "AdbWinUsbApi.dll" - VALUE "OriginalFilename", "AdbWinUsbApi.dll" - VALUE "ProductName", "Android SDK" - VALUE "ProductVersion", "2.0.0.0" - VALUE "OLESelfRegister", "" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0409, 1252 - END -END - -#endif // !_MAC - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_PROJNAME "AdbWinUsbApi" -END - -//////////////////////////////////////////////////////////////////////////// - - -#endif - -#ifndef APSTUDIO_INVOKED -#endif // not APSTUDIO_INVOKED diff --git a/host/windows/usb/winusb/BUILDME.TXT b/host/windows/usb/winusb/BUILDME.TXT deleted file mode 100755 index 2a459ef53..000000000 --- a/host/windows/usb/winusb/BUILDME.TXT +++ /dev/null @@ -1,7 +0,0 @@ -In order to build AdbWinUsbApi.dll you will need to install Windows Driver Kit, -which can be obtained from Microsoft. Assuming that WDK is installed, you -need to set one of the WDK's build environments, "cd" back into this directory, -and execute "build -cbeEIFZ" to clean and rebuild this project, or you can -execute "build -befEIF" to do a minimal build. -Note that you need to build AdbWinApi.dll (..\api) before you build -AdbWinUsbApi.dll, as it depends on AdbWinApi.lib library. diff --git a/host/windows/usb/winusb/MAKEFILE b/host/windows/usb/winusb/MAKEFILE deleted file mode 100755 index fcd896d3f..000000000 --- a/host/windows/usb/winusb/MAKEFILE +++ /dev/null @@ -1,22 +0,0 @@ -# -# 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. -# - -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the components of NT OS/2 -# -!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/host/windows/usb/winusb/Resource.h b/host/windows/usb/winusb/Resource.h deleted file mode 100755 index 3ede761da..000000000 --- a/host/windows/usb/winusb/Resource.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by AdbWinApi.rc -// - -#define IDS_PROJNAME 100 -#define IDR_ADBWINAPI 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 201 -#define _APS_NEXT_COMMAND_VALUE 32768 -#define _APS_NEXT_CONTROL_VALUE 201 -#define _APS_NEXT_SYMED_VALUE 102 -#endif -#endif diff --git a/host/windows/usb/winusb/SOURCES b/host/windows/usb/winusb/SOURCES deleted file mode 100755 index 80d17ae1f..000000000 --- a/host/windows/usb/winusb/SOURCES +++ /dev/null @@ -1,93 +0,0 @@ -# -# 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. -# - -TARGETNAME = AdbWinUsbApi -TARGETPATH = obj -TARGETTYPE = DYNLINK - -UMTYPE = windows -DLLDEF = AdbWinUsbApi.def - -# Use statically linked atl libraries: -# - atls.lib for free build -# - atlsd.lib for checked build -USE_STATIC_ATL = 1 -# Use ATL v. 7.1 -ATL_VER = 71 -# Use STL v. 6.0 -USE_STL = 1 -STL_VER = 60 -# Use multithreaded libraries -USE_LIBCMT = 1 - -# Include directories -INCLUDES = $(DDK_INC_PATH); \ - $(SDK_INC_PATH); \ - $(CRT_INC_PATH); \ - $(SDK_INC_PATH)\crt; \ - $(CRT_INC_PATH)\atl71; \ - $(SDK_INC_PATH)\crt\stl60 - -# Common target libraries -TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \ - $(SDK_LIB_PATH)\Advapi32.lib \ - $(SDK_LIB_PATH)\Kernel32.lib \ - $(SDK_LIB_PATH)\User32.lib \ - $(SDK_LIB_PATH)\oleaut32.lib \ - $(SDK_LIB_PATH)\wbemuuid.lib \ - $(SDK_LIB_PATH)\uuid.lib \ - $(SDK_LIB_PATH)\setupapi.lib \ - $(SDK_LIB_PATH)\usbd.lib \ - $(SDK_LIB_PATH)\winusb.lib \ - ..\api\obj$(BUILD_ALT_DIR)\i386\AdbWinApi.lib - -!IF "$(DDKBUILDENV)" == "fre" -# Libraries for release (free) builds -TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atls.lib -!ELSE -# Libraries for debug (checked) builds -TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atlsd.lib -!ENDIF - -# Common C defines -C_DEFINES= $(C_DEFINES) -DADBWINUSB_EXPORTS -D_UNICODE \ - -DUNICODE -DWIN32 -D_WINDOWS -D_USRDLL -D_WINDLL - -!IF "$(DDKBUILDENV)" == "fre" -# C defines for release (free) builds -C_DEFINES = $(C_DEFINES) -DNDEBUG -!ELSE -# C defines for debug (checked) builds -C_DEFINES = $(C_DEFINES) -D_DEBUG -!ENDIF - -# Turn on all warnings, and treat warnings as errors -MSC_WARNING_LEVEL = /W4 /Wp64 /WX - -# Common C defines -USER_C_FLAGS = $(USER_C_FLAGS) /FD /EHsc /wd4100 /wd4200 /wd4702 /nologo - -# Set precompiled header information -PRECOMPILED_CXX = 1 -PRECOMPILED_INCLUDE = stdafx.h -PRECOMPILED_SOURCEFILE = stdafx.cpp - -# Define source files for AdbWinUsbApi.dll -SOURCES = adb_winusb_endpoint_object.cpp \ - adb_winusb_interface.cpp \ - adb_winusb_io_completion.cpp \ - AdbWinUsbApi.cpp \ - AdbWinUsbApi.rc diff --git a/host/windows/usb/winusb/stdafx.cpp b/host/windows/usb/winusb/stdafx.cpp deleted file mode 100755 index 562765b81..000000000 --- a/host/windows/usb/winusb/stdafx.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -// stdafx.cpp : source file that includes just the standard includes -// AdbWinUsbApi.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" diff --git a/host/windows/usb/winusb/stdafx.h b/host/windows/usb/winusb/stdafx.h deleted file mode 100755 index c2aa8dee6..000000000 --- a/host/windows/usb/winusb/stdafx.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - */ - -/** \file - Visual Studio generated include file for standard system include files, or - project specific include files that are used frequently, but are changed - infrequently. -*/ - -#pragma once - -#ifndef STRICT -#define STRICT -#endif - -// Modify the following defines if you have to target a platform prior to the ones specified below. -// Refer to MSDN for the latest info on corresponding values for different platforms. -#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. -#define WINVER 0x0500 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. -#endif - -#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. -#define _WIN32_WINNT 0x0500 // Change this to the appropriate value to target Windows 2000 or later. -#endif - -#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. -#define _WIN32_WINDOWS 0x0500 // Change this to the appropriate value to target Windows Me or later. -#endif - -#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. -#define _WIN32_IE 0x0501 // Change this to the appropriate value to target IE 5.0 or later. -#endif - -// These defines prevent the MS header files from ejecting #pragma comment -// statements with the manifest information of the used ATL, STL, and CRT -#define _ATL_NOFORCE_MANIFEST -#define _STL_NOFORCE_MANIFEST -#define _CRT_NOFORCE_MANIFEST - -#define _ATL_APARTMENT_THREADED -#define _ATL_NO_AUTOMATIC_NAMESPACE - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -// turns off ATL's hiding of some common and often safely ignored warning messages -#define _ATL_ALL_WARNINGS - -// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include -#pragma warning(disable: 4702) -#pragma warning(disable: 4201) -#include -#include -#include -#include -#include -#include -#pragma warning(default: 4201) -#pragma warning(disable: 4200) -#include - -#include "resource.h" - -using namespace ATL; From 74dca0efdcf15d0d59c3d8e4da0c51acc5437757 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Fri, 7 Aug 2009 10:40:24 -0700 Subject: [PATCH 18/87] Improve the comments in build.xml to help people customize their build. --- tools/scripts/build.template | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/scripts/build.template b/tools/scripts/build.template index 7939e6c63..1ed385345 100644 --- a/tools/scripts/build.template +++ b/tools/scripts/build.template @@ -49,13 +49,18 @@ classpathref="android.antlibs"/> From acc6f826433e639b1ba00c021ab5f9161eb56e59 Mon Sep 17 00:00:00 2001 From: vchtchetkine Date: Wed, 5 Aug 2009 16:57:18 -0700 Subject: [PATCH 19/87] Split AdbWinApi.dll into two dlls to remove dependency on WINUSB.DLL Move all WINUSB-dependent functionality into AdbWinUsbApi.dll in order to enable ADB on condition that WINUSB has not been installed. In this patch set new file (adb_winusb_api.h) has been added where I moved typedef that broke the build. Aso, adb_api.cpp and AdbWinApi.cpp were changed to include that new header file. BUG 2033924 --- host/windows/usb/api/AdbWinApi.cpp | 78 +++++++++++- host/windows/usb/api/SOURCES | 6 +- host/windows/usb/api/adb_api.cpp | 25 +++- host/windows/usb/api/adb_api.h | 2 + host/windows/usb/api/adb_endpoint_object.h | 2 +- host/windows/usb/api/adb_interface.h | 15 ++- host/windows/usb/api/adb_io_completion.h | 2 +- host/windows/usb/api/adb_object_handle.h | 3 +- host/windows/usb/api/adb_winusb_api.h | 48 ++++++++ host/windows/usb/api/stdafx.h | 3 - host/windows/usb/winusb/AdbWinUsbApi.cpp | 62 ++++++++++ host/windows/usb/winusb/AdbWinUsbApi.def | 5 + host/windows/usb/winusb/AdbWinUsbApi.rc | 111 ++++++++++++++++++ host/windows/usb/winusb/BUILDME.TXT | 7 ++ host/windows/usb/winusb/MAKEFILE | 22 ++++ host/windows/usb/winusb/Resource.h | 34 ++++++ host/windows/usb/winusb/SOURCES | 93 +++++++++++++++ .../adb_winusb_endpoint_object.cpp | 12 +- .../adb_winusb_endpoint_object.h | 26 +++- .../{api => winusb}/adb_winusb_interface.cpp | 11 ++ .../{api => winusb}/adb_winusb_interface.h | 21 +++- .../adb_winusb_io_completion.cpp | 11 ++ .../adb_winusb_io_completion.h | 26 +++- host/windows/usb/winusb/stdafx.cpp | 21 ++++ host/windows/usb/winusb/stdafx.h | 78 ++++++++++++ 25 files changed, 700 insertions(+), 24 deletions(-) create mode 100755 host/windows/usb/api/adb_winusb_api.h create mode 100755 host/windows/usb/winusb/AdbWinUsbApi.cpp create mode 100755 host/windows/usb/winusb/AdbWinUsbApi.def create mode 100755 host/windows/usb/winusb/AdbWinUsbApi.rc create mode 100755 host/windows/usb/winusb/BUILDME.TXT create mode 100755 host/windows/usb/winusb/MAKEFILE create mode 100755 host/windows/usb/winusb/Resource.h create mode 100755 host/windows/usb/winusb/SOURCES rename host/windows/usb/{api => winusb}/adb_winusb_endpoint_object.cpp (93%) rename host/windows/usb/{api => winusb}/adb_winusb_endpoint_object.h (81%) rename host/windows/usb/{api => winusb}/adb_winusb_interface.cpp (95%) rename host/windows/usb/{api => winusb}/adb_winusb_interface.h (84%) rename host/windows/usb/{api => winusb}/adb_winusb_io_completion.cpp (89%) rename host/windows/usb/{api => winusb}/adb_winusb_io_completion.h (75%) create mode 100755 host/windows/usb/winusb/stdafx.cpp create mode 100755 host/windows/usb/winusb/stdafx.h diff --git a/host/windows/usb/api/AdbWinApi.cpp b/host/windows/usb/api/AdbWinApi.cpp index 4d18d3793..507a2b59d 100644 --- a/host/windows/usb/api/AdbWinApi.cpp +++ b/host/windows/usb/api/AdbWinApi.cpp @@ -17,6 +17,8 @@ // AdbWinApi.cpp : Implementation of DLL Exports. #include "stdafx.h" +#include "adb_api.h" +#include "adb_winusb_api.h" extern "C" { int _forceCRTManifest; @@ -24,8 +26,73 @@ int _forceMFCManifest; int _forceAtlDllManifest; }; +/// References InstantiateWinUsbInterface declared in adb_api.cpp +extern PFN_INSTWINUSBINTERFACE InstantiateWinUsbInterface; + class CAdbWinApiModule : public CAtlDllModuleT< CAdbWinApiModule > { -public: + public: + CAdbWinApiModule() + : CAtlDllModuleT< CAdbWinApiModule >(), + adbwinusbapi_handle_(NULL), + is_initialized_(false) { + } + + ~CAdbWinApiModule() { + // Unload AdbWinUsbApi.dll before we exit + if (NULL != adbwinusbapi_handle_) { + FreeLibrary(adbwinusbapi_handle_); + } + } + + /** \brief Loads AdbWinUsbApi.dll and caches its InstantiateWinUsbInterface + export. + + This method is called from DllMain on DLL_PROCESS_ATTACH event. In this + method we will check if WINUSB.DLL required by AdbWinUsbApi.dll is + installed, and if it is we will load AdbWinUsbApi.dll and cache address of + InstantiateWinUsbInterface routine exported from AdbWinUsbApi.dll + */ + void AttachToAdbWinUsbApi() { + // We only need to run this only once. + if (is_initialized_) { + return; + } + + // Just mark that we have ran initialization. + is_initialized_ = true; + + // Before we can load AdbWinUsbApi.dll we must make sure that WINUSB.DLL + // has been installed. Build path to the file. + wchar_t path_to_winusb_dll[MAX_PATH+1]; + if (!GetSystemDirectory(path_to_winusb_dll, MAX_PATH)) { + return; + } + wcscat(path_to_winusb_dll, L"\\WINUSB.DLL"); + + if (0xFFFFFFFF == GetFileAttributes(path_to_winusb_dll)) { + // WINUSB.DLL is not installed. We don't (in fact, can't) load + // AdbWinUsbApi.dll + return; + } + + // WINUSB.DLL is installed. Lets load AdbWinUsbApi.dll and cache its + // InstantiateWinUsbInterface export. + // We require that AdbWinUsbApi.dll is located in the same folder + // where AdbWinApi.dll and adb.exe are located, so by Windows + // conventions we can pass just module name, and not the full path. + adbwinusbapi_handle_ = LoadLibrary(L"AdbWinUsbApi.dll"); + if (NULL != adbwinusbapi_handle_) { + InstantiateWinUsbInterface = reinterpret_cast + (GetProcAddress(adbwinusbapi_handle_, "InstantiateWinUsbInterface")); + } + } + + protected: + /// Handle to the loaded AdbWinUsbApi.dll + HINSTANCE adbwinusbapi_handle_; + + /// Flags whether or not this module has been initialized. + bool is_initialized_; }; CAdbWinApiModule _AtlModule; @@ -34,5 +101,12 @@ CAdbWinApiModule _AtlModule; extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { - return _AtlModule.DllMain(reason, reserved); + // Lets see if we need to initialize InstantiateWinUsbInterface + // variable. We do that only once, on condition that this DLL is + // being attached to the process and InstantiateWinUsbInterface + // address has not been calculated yet. + if (DLL_PROCESS_ATTACH == reason) { + _AtlModule.AttachToAdbWinUsbApi(); + } + return _AtlModule.DllMain(reason, reserved); } diff --git a/host/windows/usb/api/SOURCES b/host/windows/usb/api/SOURCES index f6e66143c..35695217b 100755 --- a/host/windows/usb/api/SOURCES +++ b/host/windows/usb/api/SOURCES @@ -50,8 +50,7 @@ TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \ $(SDK_LIB_PATH)\wbemuuid.lib \ $(SDK_LIB_PATH)\uuid.lib \ $(SDK_LIB_PATH)\setupapi.lib \ - $(SDK_LIB_PATH)\usbd.lib \ - $(SDK_LIB_PATH)\winusb.lib + $(SDK_LIB_PATH)\usbd.lib !IF "$(DDKBUILDENV)" == "fre" # Libraries for release (free) builds @@ -87,15 +86,12 @@ PRECOMPILED_SOURCEFILE = stdafx.cpp # Define source files for AdbWinApi.dll SOURCES = adb_api.cpp \ adb_endpoint_object.cpp \ - adb_winusb_endpoint_object.cpp \ adb_legacy_endpoint_object.cpp \ adb_helper_routines.cpp \ adb_interface.cpp \ - adb_winusb_interface.cpp \ adb_legacy_interface.cpp \ adb_interface_enum.cpp \ adb_io_completion.cpp \ - adb_winusb_io_completion.cpp \ adb_legacy_io_completion.cpp \ adb_object_handle.cpp \ AdbWinApi.cpp \ diff --git a/host/windows/usb/api/adb_api.cpp b/host/windows/usb/api/adb_api.cpp index f9bd94e6c..e58bcf17a 100644 --- a/host/windows/usb/api/adb_api.cpp +++ b/host/windows/usb/api/adb_api.cpp @@ -24,11 +24,19 @@ #include "adb_object_handle.h" #include "adb_interface_enum.h" #include "adb_interface.h" -#include "adb_winusb_interface.h" #include "adb_legacy_interface.h" #include "adb_endpoint_object.h" #include "adb_io_completion.h" #include "adb_helper_routines.h" +#include "adb_winusb_api.h" + +/** \brief Points to InstantiateWinUsbInterface exported from AdbWinUsbApi.dll. + + This variable is initialized with the actual address in DllMain routine for + this DLL on DLL_PROCESS_ATTACH event. + @see PFN_INSTWINUSBINTERFACE for more information. +*/ +PFN_INSTWINUSBINTERFACE InstantiateWinUsbInterface = NULL; ADBAPIHANDLE __cdecl AdbEnumInterfaces(GUID class_id, bool exclude_not_present, @@ -101,11 +109,22 @@ ADBAPIHANDLE __cdecl AdbCreateInterfaceByName( ADBAPIHANDLE ret = NULL; try { - // Instantiate object + // Instantiate interface object, depending on the USB driver type. if (IsLegacyInterface(interface_name)) { + // We have legacy USB driver underneath us. obj = new AdbLegacyInterfaceObject(interface_name); } else { - obj = new AdbWinUsbInterfaceObject(interface_name); + // We have WinUsb driver underneath us. Make sure that AdbWinUsbApi.dll + // is loaded and its InstantiateWinUsbInterface routine address has + // been cached. + if (NULL != InstantiateWinUsbInterface) { + obj = InstantiateWinUsbInterface(interface_name); + if (NULL == obj) { + return NULL; + } + } else { + return NULL; + } } // Create handle for it diff --git a/host/windows/usb/api/adb_api.h b/host/windows/usb/api/adb_api.h index e2ad129ca..20f0cd634 100644 --- a/host/windows/usb/api/adb_api.h +++ b/host/windows/usb/api/adb_api.h @@ -119,8 +119,10 @@ typedef struct _AdbEndpointInformation { // as being exported. #ifdef ADBWIN_EXPORTS #define ADBWIN_API EXTERN_C __declspec(dllexport) +#define ADBWIN_API_CLASS __declspec(dllexport) #else #define ADBWIN_API EXTERN_C __declspec(dllimport) +#define ADBWIN_API_CLASS __declspec(dllimport) #endif /** \brief Handle to an API object. diff --git a/host/windows/usb/api/adb_endpoint_object.h b/host/windows/usb/api/adb_endpoint_object.h index 295eb46f2..d92aaad47 100644 --- a/host/windows/usb/api/adb_endpoint_object.h +++ b/host/windows/usb/api/adb_endpoint_object.h @@ -29,7 +29,7 @@ This class implement functionality that is common for both, WinUsb and legacy APIs. */ -class AdbEndpointObject : public AdbObjectHandle { +class ADBWIN_API_CLASS AdbEndpointObject : public AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/adb_interface.h b/host/windows/usb/api/adb_interface.h index 4afb17da0..0aa0d1d55 100644 --- a/host/windows/usb/api/adb_interface.h +++ b/host/windows/usb/api/adb_interface.h @@ -23,12 +23,17 @@ #include "adb_object_handle.h" +// 'AdbInterfaceObject::interface_name_' : class 'std::basic_string<_E,_Tr,_A>' +// needs to have dll-interface to be used by clients of class +// 'AdbInterfaceObject' We're ok with that, since interface_name_ will not +// be referenced by name from outside of this class. +#pragma warning(disable: 4251) /** \brief Encapsulates an interface on our USB device. This is an abstract class that implements functionality common for both, legacy, and WinUsb based interfaces. */ -class AdbInterfaceObject : public AdbObjectHandle { +class ADBWIN_API_CLASS AdbInterfaceObject : public AdbObjectHandle { public: /** \brief Constructs the object. @@ -180,9 +185,6 @@ class AdbInterfaceObject : public AdbObjectHandle { } protected: - /// Name of the USB interface (device name) for this object - std::wstring interface_name_; - /// Cached usb device descriptor USB_DEVICE_DESCRIPTOR usb_device_descriptor_; @@ -191,6 +193,11 @@ class AdbInterfaceObject : public AdbObjectHandle { /// Cached usb interface descriptor USB_INTERFACE_DESCRIPTOR usb_interface_descriptor_; + + private: + /// Name of the USB interface (device name) for this object + std::wstring interface_name_; }; +#pragma warning(default: 4251) #endif // ANDROID_USB_API_ADB_INTERFACE_H__ diff --git a/host/windows/usb/api/adb_io_completion.h b/host/windows/usb/api/adb_io_completion.h index 8a7c1d91d..ea4b4fbce 100644 --- a/host/windows/usb/api/adb_io_completion.h +++ b/host/windows/usb/api/adb_io_completion.h @@ -33,7 +33,7 @@ like all other handles this handle must be closed after it's no longer needed. */ -class AdbIOCompletion : public AdbObjectHandle { +class ADBWIN_API_CLASS AdbIOCompletion : public AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/adb_object_handle.h b/host/windows/usb/api/adb_object_handle.h index 29ac5e2f2..2fa4ad03b 100644 --- a/host/windows/usb/api/adb_object_handle.h +++ b/host/windows/usb/api/adb_object_handle.h @@ -22,6 +22,7 @@ of the API through a handle. */ +#include "adb_api.h" #include "adb_api_private_defines.h" /** \brief Defines types of internal API objects @@ -71,7 +72,7 @@ enum AdbObjectType { All API objects that have handles that are sent back to API client must be derived from this class. */ -class AdbObjectHandle { +class ADBWIN_API_CLASS AdbObjectHandle { public: /** \brief Constructs the object diff --git a/host/windows/usb/api/adb_winusb_api.h b/host/windows/usb/api/adb_winusb_api.h new file mode 100755 index 000000000..268a99873 --- /dev/null +++ b/host/windows/usb/api/adb_winusb_api.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 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. + */ + +#ifndef ANDROID_USB_API_ADBWINUSBAPI_H__ +#define ANDROID_USB_API_ADBWINUSBAPI_H__ + +/** \file + Contains declarations required to link AdbWinApi and AdbWinUsbApi DLLs. +*/ + +/** \brief Function prototype for InstantiateWinUsbInterface routine exported + from AdbWinUsbApi.dll + + In order to provide backward compatibility with the systems that still run + legacy (custom) USB drivers, and have not installed WINUSB.DLL we need to + split functionality of our ADB API on Windows between two DLLs: AdbWinApi, + and AdbWinUsbApi. AdbWinApi is fully capable of working on top of the legacy + driver, but has no traces to WinUsb. AdbWinUsbApi is capable of working on + top of WinUsb API. We are forced to do this split, because we can have + dependency on WINUSB.DLL in the DLL that implements legacy API. The problem + is that customers may have a legacy driver that they don't want to upgrade + to WinUsb, so they may not have WINUSB.DLL installed on their machines, but + they still must be able to use ADB. So, the idea behind the split is as + such. When AdbWinApi.dll is loaded into a process, it will check WINUSB.DLL + installation (by checking existance of C:\Windows\System32\winusb.dll). If + WINUSB.DLL is installed, AdbWinApi will also load AdbWinUsbApi.dll (by + calling LoadLibrary), and will extract address of InstantiateWinUsbInterface + routine exported from AdbWinUsbApi.dll. Then this routine will be used to + instantiate AdbInterfaceObject instance on condition that it is confirmed + that USB driver underneath us is in deed WinUsb. +*/ +typedef class AdbInterfaceObject* \ + (__cdecl *PFN_INSTWINUSBINTERFACE)(const wchar_t*); + +#endif // ANDROID_USB_API_ADBWINUSBAPI_H__ diff --git a/host/windows/usb/api/stdafx.h b/host/windows/usb/api/stdafx.h index 92b2652ea..d57bec74b 100644 --- a/host/windows/usb/api/stdafx.h +++ b/host/windows/usb/api/stdafx.h @@ -71,11 +71,8 @@ #include #pragma warning(default: 4201) #pragma warning(disable: 4200) -extern "C" { #include -#include #include -} #include "resource.h" diff --git a/host/windows/usb/winusb/AdbWinUsbApi.cpp b/host/windows/usb/winusb/AdbWinUsbApi.cpp new file mode 100755 index 000000000..4916eebd2 --- /dev/null +++ b/host/windows/usb/winusb/AdbWinUsbApi.cpp @@ -0,0 +1,62 @@ +/* + * 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. + */ + +// AdbWinUsbApi.cpp : Implementation of DLL Exports. + +#include "stdafx.h" +#include "adb_winusb_interface.h" + +class CAdbWinApiModule : public CAtlDllModuleT< CAdbWinApiModule > { +public: +}; + +CAdbWinApiModule _AtlModule; + +// DLL Entry Point +extern "C" BOOL WINAPI DllMain(HINSTANCE instance, + DWORD reason, + LPVOID reserved) { + return _AtlModule.DllMain(reason, reserved); +} + +/** \brief Instantiates interface instance that uses WinUsb API to communicate + with USB driver. + + This is the only exported routine from this DLL. This routine instantiates an + object of AdbWinUsbInterfaceObject on request from AdbWinApi.dll when it is + detected that underlying USB driver is WinUsb.sys. + @param[in] interface_name Name of the interface. + @return AdbInterfaceObject - casted instance of AdbWinUsbInterfaceObject + object on success, or NULL on failure with GetLastError providing + information on an error that occurred. +*/ +extern "C" __declspec(dllexport) +AdbInterfaceObject* __cdecl InstantiateWinUsbInterface( + const wchar_t* interface_name) { + // Validate parameter. + if (NULL == interface_name) { + return NULL; + } + + // Instantiate requested object. + try { + return new AdbWinUsbInterfaceObject(interface_name); + } catch (...) { + // We expect only OOM exceptions here. + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } +} diff --git a/host/windows/usb/winusb/AdbWinUsbApi.def b/host/windows/usb/winusb/AdbWinUsbApi.def new file mode 100755 index 000000000..9e616e91d --- /dev/null +++ b/host/windows/usb/winusb/AdbWinUsbApi.def @@ -0,0 +1,5 @@ +; AdbWinUsbApi.def : Declares the module parameters. + +LIBRARY "AdbWinUsbApi.DLL" + +EXPORTS diff --git a/host/windows/usb/winusb/AdbWinUsbApi.rc b/host/windows/usb/winusb/AdbWinUsbApi.rc new file mode 100755 index 000000000..44aa100f4 --- /dev/null +++ b/host/windows/usb/winusb/AdbWinUsbApi.rc @@ -0,0 +1,111 @@ +/* + * 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. + */ + +//Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Google, inc" + VALUE "FileDescription", "Android ADB API (WinUsb)" + VALUE "FileVersion", "2.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2006 The Android Open Source Project" + VALUE "InternalName", "AdbWinUsbApi.dll" + VALUE "OriginalFilename", "AdbWinUsbApi.dll" + VALUE "ProductName", "Android SDK" + VALUE "ProductVersion", "2.0.0.0" + VALUE "OLESelfRegister", "" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END + +#endif // !_MAC + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PROJNAME "AdbWinUsbApi" +END + +//////////////////////////////////////////////////////////////////////////// + + +#endif + +#ifndef APSTUDIO_INVOKED +#endif // not APSTUDIO_INVOKED diff --git a/host/windows/usb/winusb/BUILDME.TXT b/host/windows/usb/winusb/BUILDME.TXT new file mode 100755 index 000000000..2a459ef53 --- /dev/null +++ b/host/windows/usb/winusb/BUILDME.TXT @@ -0,0 +1,7 @@ +In order to build AdbWinUsbApi.dll you will need to install Windows Driver Kit, +which can be obtained from Microsoft. Assuming that WDK is installed, you +need to set one of the WDK's build environments, "cd" back into this directory, +and execute "build -cbeEIFZ" to clean and rebuild this project, or you can +execute "build -befEIF" to do a minimal build. +Note that you need to build AdbWinApi.dll (..\api) before you build +AdbWinUsbApi.dll, as it depends on AdbWinApi.lib library. diff --git a/host/windows/usb/winusb/MAKEFILE b/host/windows/usb/winusb/MAKEFILE new file mode 100755 index 000000000..fcd896d3f --- /dev/null +++ b/host/windows/usb/winusb/MAKEFILE @@ -0,0 +1,22 @@ +# +# 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. +# + +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/host/windows/usb/winusb/Resource.h b/host/windows/usb/winusb/Resource.h new file mode 100755 index 000000000..3ede761da --- /dev/null +++ b/host/windows/usb/winusb/Resource.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by AdbWinApi.rc +// + +#define IDS_PROJNAME 100 +#define IDR_ADBWINAPI 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/host/windows/usb/winusb/SOURCES b/host/windows/usb/winusb/SOURCES new file mode 100755 index 000000000..80d17ae1f --- /dev/null +++ b/host/windows/usb/winusb/SOURCES @@ -0,0 +1,93 @@ +# +# 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. +# + +TARGETNAME = AdbWinUsbApi +TARGETPATH = obj +TARGETTYPE = DYNLINK + +UMTYPE = windows +DLLDEF = AdbWinUsbApi.def + +# Use statically linked atl libraries: +# - atls.lib for free build +# - atlsd.lib for checked build +USE_STATIC_ATL = 1 +# Use ATL v. 7.1 +ATL_VER = 71 +# Use STL v. 6.0 +USE_STL = 1 +STL_VER = 60 +# Use multithreaded libraries +USE_LIBCMT = 1 + +# Include directories +INCLUDES = $(DDK_INC_PATH); \ + $(SDK_INC_PATH); \ + $(CRT_INC_PATH); \ + $(SDK_INC_PATH)\crt; \ + $(CRT_INC_PATH)\atl71; \ + $(SDK_INC_PATH)\crt\stl60 + +# Common target libraries +TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\Advapi32.lib \ + $(SDK_LIB_PATH)\Kernel32.lib \ + $(SDK_LIB_PATH)\User32.lib \ + $(SDK_LIB_PATH)\oleaut32.lib \ + $(SDK_LIB_PATH)\wbemuuid.lib \ + $(SDK_LIB_PATH)\uuid.lib \ + $(SDK_LIB_PATH)\setupapi.lib \ + $(SDK_LIB_PATH)\usbd.lib \ + $(SDK_LIB_PATH)\winusb.lib \ + ..\api\obj$(BUILD_ALT_DIR)\i386\AdbWinApi.lib + +!IF "$(DDKBUILDENV)" == "fre" +# Libraries for release (free) builds +TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atls.lib +!ELSE +# Libraries for debug (checked) builds +TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atlsd.lib +!ENDIF + +# Common C defines +C_DEFINES= $(C_DEFINES) -DADBWINUSB_EXPORTS -D_UNICODE \ + -DUNICODE -DWIN32 -D_WINDOWS -D_USRDLL -D_WINDLL + +!IF "$(DDKBUILDENV)" == "fre" +# C defines for release (free) builds +C_DEFINES = $(C_DEFINES) -DNDEBUG +!ELSE +# C defines for debug (checked) builds +C_DEFINES = $(C_DEFINES) -D_DEBUG +!ENDIF + +# Turn on all warnings, and treat warnings as errors +MSC_WARNING_LEVEL = /W4 /Wp64 /WX + +# Common C defines +USER_C_FLAGS = $(USER_C_FLAGS) /FD /EHsc /wd4100 /wd4200 /wd4702 /nologo + +# Set precompiled header information +PRECOMPILED_CXX = 1 +PRECOMPILED_INCLUDE = stdafx.h +PRECOMPILED_SOURCEFILE = stdafx.cpp + +# Define source files for AdbWinUsbApi.dll +SOURCES = adb_winusb_endpoint_object.cpp \ + adb_winusb_interface.cpp \ + adb_winusb_io_completion.cpp \ + AdbWinUsbApi.cpp \ + AdbWinUsbApi.rc diff --git a/host/windows/usb/api/adb_winusb_endpoint_object.cpp b/host/windows/usb/winusb/adb_winusb_endpoint_object.cpp similarity index 93% rename from host/windows/usb/api/adb_winusb_endpoint_object.cpp rename to host/windows/usb/winusb/adb_winusb_endpoint_object.cpp index 236de3b49..16f78370c 100755 --- a/host/windows/usb/api/adb_winusb_endpoint_object.cpp +++ b/host/windows/usb/winusb/adb_winusb_endpoint_object.cpp @@ -22,7 +22,6 @@ #include "stdafx.h" #include "adb_winusb_endpoint_object.h" #include "adb_winusb_io_completion.h" -#include "adb_helper_routines.h" AdbWinUsbEndpointObject::AdbWinUsbEndpointObject( AdbWinUsbInterfaceObject* parent_interf, @@ -34,6 +33,17 @@ AdbWinUsbEndpointObject::AdbWinUsbEndpointObject( AdbWinUsbEndpointObject::~AdbWinUsbEndpointObject() { } +LONG AdbWinUsbEndpointObject::Release() { + ATLASSERT(ref_count_ > 0); + LONG ret = InterlockedDecrement(&ref_count_); + ATLASSERT(ret >= 0); + if (0 == ret) { + LastReferenceReleased(); + delete this; + } + return ret; +} + ADBAPIHANDLE AdbWinUsbEndpointObject::CommonAsyncReadWrite( bool is_read, void* buffer, diff --git a/host/windows/usb/api/adb_winusb_endpoint_object.h b/host/windows/usb/winusb/adb_winusb_endpoint_object.h similarity index 81% rename from host/windows/usb/api/adb_winusb_endpoint_object.h rename to host/windows/usb/winusb/adb_winusb_endpoint_object.h index 26ef53b16..92b6e04fe 100755 --- a/host/windows/usb/api/adb_winusb_endpoint_object.h +++ b/host/windows/usb/winusb/adb_winusb_endpoint_object.h @@ -21,7 +21,7 @@ encapsulates a handle opened to a WinUsb endpoint on our device. */ -#include "adb_endpoint_object.h" +#include "..\api\adb_endpoint_object.h" #include "adb_winusb_interface.h" /** Class AdbWinUsbEndpointObject encapsulates a handle opened to an endpoint on @@ -48,6 +48,30 @@ class AdbWinUsbEndpointObject : public AdbEndpointObject { */ virtual ~AdbWinUsbEndpointObject(); + // + // Virtual overrides + // + + public: + /** \brief Releases the object. + + If refcount drops to zero as the result of this release, the object is + destroyed in this method. As a general rule, objects must not be touched + after this method returns even if returned value is not zero. We override + this method in order to make sure that objects of this class are deleted + in contect of the DLL they were created in. The problem is that since + objects of this class were created in context of AdbWinUsbApi module, they + are allocated from the heap assigned to that module. Now, if these objects + are deleted outside of AdbWinUsbApi module, this will lead to the heap + corruption in the module that deleted these objects. Since all objects of + this class are deleted in the Release method only, by overriding it we make + sure that we free memory in the context of the module where it was + allocated. + @return Value of the reference counter after object is released in this + method. + */ + virtual LONG Release(); + // // Abstract overrides // diff --git a/host/windows/usb/api/adb_winusb_interface.cpp b/host/windows/usb/winusb/adb_winusb_interface.cpp similarity index 95% rename from host/windows/usb/api/adb_winusb_interface.cpp rename to host/windows/usb/winusb/adb_winusb_interface.cpp index d09c1cbeb..9d0377a46 100755 --- a/host/windows/usb/api/adb_winusb_interface.cpp +++ b/host/windows/usb/winusb/adb_winusb_interface.cpp @@ -40,6 +40,17 @@ AdbWinUsbInterfaceObject::~AdbWinUsbInterfaceObject() { ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_); } +LONG AdbWinUsbInterfaceObject::Release() { + ATLASSERT(ref_count_ > 0); + LONG ret = InterlockedDecrement(&ref_count_); + ATLASSERT(ret >= 0); + if (0 == ret) { + LastReferenceReleased(); + delete this; + } + return ret; +} + ADBAPIHANDLE AdbWinUsbInterfaceObject::CreateHandle() { // Open USB device for this inteface Note that WinUsb API // requires the handle to be opened for overlapped I/O. diff --git a/host/windows/usb/api/adb_winusb_interface.h b/host/windows/usb/winusb/adb_winusb_interface.h similarity index 84% rename from host/windows/usb/api/adb_winusb_interface.h rename to host/windows/usb/winusb/adb_winusb_interface.h index 82f7f8985..2311fd170 100755 --- a/host/windows/usb/api/adb_winusb_interface.h +++ b/host/windows/usb/winusb/adb_winusb_interface.h @@ -22,7 +22,7 @@ via WinUsb API. */ -#include "adb_interface.h" +#include "..\api\adb_interface.h" /** \brief Encapsulates an interface on our USB device that is accessible via WinUsb API. @@ -48,6 +48,25 @@ class AdbWinUsbInterfaceObject : public AdbInterfaceObject { // public: + /** \brief Releases the object. + + If refcount drops to zero as the result of this release, the object is + destroyed in this method. As a general rule, objects must not be touched + after this method returns even if returned value is not zero. We override + this method in order to make sure that objects of this class are deleted + in contect of the DLL they were created in. The problem is that since + objects of this class were created in context of AdbWinUsbApi module, they + are allocated from the heap assigned to that module. Now, if these objects + are deleted outside of AdbWinUsbApi module, this will lead to the heap + corruption in the module that deleted these objects. Since all objects of + this class are deleted in the Release method only, by overriding it we make + sure that we free memory in the context of the module where it was + allocated. + @return Value of the reference counter after object is released in this + method. + */ + virtual LONG Release(); + /** \brief Creates handle to this object. In this call a handle for this object is generated and object is added diff --git a/host/windows/usb/api/adb_winusb_io_completion.cpp b/host/windows/usb/winusb/adb_winusb_io_completion.cpp similarity index 89% rename from host/windows/usb/api/adb_winusb_io_completion.cpp rename to host/windows/usb/winusb/adb_winusb_io_completion.cpp index baeb7bbb8..d98f87254 100755 --- a/host/windows/usb/api/adb_winusb_io_completion.cpp +++ b/host/windows/usb/winusb/adb_winusb_io_completion.cpp @@ -33,6 +33,17 @@ AdbWinUsbIOCompletion::AdbWinUsbIOCompletion( AdbWinUsbIOCompletion::~AdbWinUsbIOCompletion() { } +LONG AdbWinUsbIOCompletion::Release() { + ATLASSERT(ref_count_ > 0); + LONG ret = InterlockedDecrement(&ref_count_); + ATLASSERT(ret >= 0); + if (0 == ret) { + LastReferenceReleased(); + delete this; + } + return ret; +} + bool AdbWinUsbIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data, ULONG* bytes_transferred, bool wait) { diff --git a/host/windows/usb/api/adb_winusb_io_completion.h b/host/windows/usb/winusb/adb_winusb_io_completion.h similarity index 75% rename from host/windows/usb/api/adb_winusb_io_completion.h rename to host/windows/usb/winusb/adb_winusb_io_completion.h index a97a3a8b2..93a4c07eb 100755 --- a/host/windows/usb/api/adb_winusb_io_completion.h +++ b/host/windows/usb/winusb/adb_winusb_io_completion.h @@ -22,7 +22,7 @@ asynchronous I/O requests issued via WinUsb API. */ -#include "adb_io_completion.h" +#include "..\api\adb_io_completion.h" #include "adb_winusb_endpoint_object.h" /** \brief Encapsulates encapsulates a wrapper around OVERLAPPED Win32 @@ -56,6 +56,30 @@ class AdbWinUsbIOCompletion : public AdbIOCompletion { */ virtual ~AdbWinUsbIOCompletion(); + // + // Virtual overrides + // + + public: + /** \brief Releases the object. + + If refcount drops to zero as the result of this release, the object is + destroyed in this method. As a general rule, objects must not be touched + after this method returns even if returned value is not zero. We override + this method in order to make sure that objects of this class are deleted + in contect of the DLL they were created in. The problem is that since + objects of this class were created in context of AdbWinUsbApi module, they + are allocated from the heap assigned to that module. Now, if these objects + are deleted outside of AdbWinUsbApi module, this will lead to the heap + corruption in the module that deleted these objects. Since all objects of + this class are deleted in the Release method only, by overriding it we make + sure that we free memory in the context of the module where it was + allocated. + @return Value of the reference counter after object is released in this + method. + */ + virtual LONG Release(); + // // Abstract overrides // diff --git a/host/windows/usb/winusb/stdafx.cpp b/host/windows/usb/winusb/stdafx.cpp new file mode 100755 index 000000000..562765b81 --- /dev/null +++ b/host/windows/usb/winusb/stdafx.cpp @@ -0,0 +1,21 @@ +/* + * 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. + */ + +// stdafx.cpp : source file that includes just the standard includes +// AdbWinUsbApi.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/host/windows/usb/winusb/stdafx.h b/host/windows/usb/winusb/stdafx.h new file mode 100755 index 000000000..c2aa8dee6 --- /dev/null +++ b/host/windows/usb/winusb/stdafx.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/** \file + Visual Studio generated include file for standard system include files, or + project specific include files that are used frequently, but are changed + infrequently. +*/ + +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. +#define WINVER 0x0500 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. +#define _WIN32_WINNT 0x0500 // Change this to the appropriate value to target Windows 2000 or later. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0500 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. +#define _WIN32_IE 0x0501 // Change this to the appropriate value to target IE 5.0 or later. +#endif + +// These defines prevent the MS header files from ejecting #pragma comment +// statements with the manifest information of the used ATL, STL, and CRT +#define _ATL_NOFORCE_MANIFEST +#define _STL_NOFORCE_MANIFEST +#define _CRT_NOFORCE_MANIFEST + +#define _ATL_APARTMENT_THREADED +#define _ATL_NO_AUTOMATIC_NAMESPACE + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +// turns off ATL's hiding of some common and often safely ignored warning messages +#define _ATL_ALL_WARNINGS + +// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include +#pragma warning(disable: 4702) +#pragma warning(disable: 4201) +#include +#include +#include +#include +#include +#include +#pragma warning(default: 4201) +#pragma warning(disable: 4200) +#include + +#include "resource.h" + +using namespace ATL; From a68dbdb1c31c486f489f38291eea05b3c621ae36 Mon Sep 17 00:00:00 2001 From: Bill Napier Date: Fri, 7 Aug 2009 11:34:12 -0700 Subject: [PATCH 20/87] Added in simple command scripting to monkey over a TCP socket. This allows a host program to talk to the monkey over TCP (via adb) and script up specific commands to run. --- cmds/monkey/Android.mk | 1 + cmds/monkey/README.NETWORK.txt | 86 ++++ cmds/monkey/example_script.txt | 57 +++ .../com/android/commands/monkey/Monkey.java | 171 ++++---- .../commands/monkey/MonkeySourceNetwork.java | 376 ++++++++++++++++++ .../commands/monkey/MonkeySourceRandom.java | 180 +++++---- 6 files changed, 711 insertions(+), 160 deletions(-) create mode 100644 cmds/monkey/README.NETWORK.txt create mode 100644 cmds/monkey/example_script.txt create mode 100644 cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java diff --git a/cmds/monkey/Android.mk b/cmds/monkey/Android.mk index 6bedc43e8..ba9cf0410 100644 --- a/cmds/monkey/Android.mk +++ b/cmds/monkey/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_MODULE := monkey include $(BUILD_JAVA_LIBRARY) +################################################################ include $(CLEAR_VARS) ALL_PREBUILT += $(TARGET_OUT)/bin/monkey $(TARGET_OUT)/bin/monkey : $(LOCAL_PATH)/monkey | $(ACP) diff --git a/cmds/monkey/README.NETWORK.txt b/cmds/monkey/README.NETWORK.txt new file mode 100644 index 000000000..ccf741b52 --- /dev/null +++ b/cmds/monkey/README.NETWORK.txt @@ -0,0 +1,86 @@ +MONKEY NETWORK SCRIPT + +The Monkey Network Script was designed to be a low-level way to +programmability inject KeyEvents and MotionEvents into the input +system. The idea is that a process will run on a host computer that +will support higher-level operations (like conditionals, etc.) and +will talk (via TCP over ADB) to the device in Monkey Network Script. +For security reasons, the Monkey only binds to localhost, so you will +need to use adb to setup port forwarding to actually talk to the +device. + +INITIAL SETUP + +Setup port forwarding from a local port on your machine to a port on +the device: + +$ adb forward tcp:1080 tcp:1080 + +Start the monkey server + +$ adb shell monkey --port 1080 + +Now you're ready to run commands + +COMMAND LIST + +Individual commands are separated by newlines. The Monkey will +respond to every command with a line starting with OK for commands +that executed without a problem, or a line starting with ERROR for +commands that had problems being run. The Monkey may decide to return +more information about command execution. That information would come +on the same line after the OK or ERROR. A possible example: + +key down menu +OK +touch monkey +ERROR: monkey not a number + +The complete list of commands follows: + +key [down|up] keycode + +This command injects KeyEvent's into the input system. The keycode +parameter refers to the KEYCODE list in the KeyEvent class +(http://developer.android.com/reference/android/view/KeyEvent.html). +The format of that parameter is quite flexible. Using the menu key as +an example, it can be 82 (the integer value of the keycode), +KEYCODE_MENU (the name of the keycode), or just menu (and the Monkey +will add the KEYCODE part). Do note that this last part doesn't work +for things like KEYCODE_1 for obvious reasons. + +Note that sending a full button press requires sending both the down +and the up event for that key + +touch [down|up|move] x y + +This command injects a MotionEvent into the input system that +simulates a user touching the touchscreen (or a pointer event). x and +y specify coordinates on the display (0 0 being the upper left) for +the touch event to happen. Just like key events, touch events at a +single location require both a down and an up. To simulate dragging, +send a "touch down", then a series of "touch move" events (to simulate +the drag), followed by a "touch up" at the final location. + +trackball dx dy + +This command injects a MotionEvent into the input system that +simulates a user using the trackball. dx and dy indicates the amount +of change in the trackball location (as opposed to exact coordinates +that the touch events use) + +flip [open|close] + +This simulates the opening or closing the keyboard (like on dream). + +OTHER NOTES + +There are some convenience features added to allow running without +needing a host process. + +Lines starting with a # character are considered comments. The Monkey +eats them and returns no indication that it did anything (no ERROR and +no OK). + +You can put the Monkey to sleep by using the "sleep" command with a +single argument, how many ms to sleep. diff --git a/cmds/monkey/example_script.txt b/cmds/monkey/example_script.txt new file mode 100644 index 000000000..5c1c61de2 --- /dev/null +++ b/cmds/monkey/example_script.txt @@ -0,0 +1,57 @@ +# Touch the android +touch down 160 200 +touch up 160 200 +sleep 1000 + +# Hit Next +touch down 300 450 +touch up 300 450 +sleep 1000 + +# Hit Next +touch down 300 450 +touch up 300 450 +sleep 1000 + +# Hit Next +touch down 300 450 +touch up 300 450 +sleep 1000 + +# Go down and select the account username +key down dpad_down +key up dpad_down +key down dpad_down +key up dpad_down +key down dpad_center +key up dpad_center +# account name: bill +key down b +key up b +key down i +key up i +key down l +key up l +key down l +key up l + +# Go down to the password field +key down dpad_down +key up dpad_down + +# password: bill +key down b +key up b +key down i +key up i +key down l +key up l +key down l +key up l + +# Select next +touch down 300 450 +touch up 300 450 + +# quit +quit diff --git a/cmds/monkey/src/com/android/commands/monkey/Monkey.java b/cmds/monkey/src/com/android/commands/monkey/Monkey.java index 7ebd7274f..6b10147a6 100644 --- a/cmds/monkey/src/com/android/commands/monkey/Monkey.java +++ b/cmds/monkey/src/com/android/commands/monkey/Monkey.java @@ -47,10 +47,10 @@ import java.util.List; * Application that injects random key events and other actions into the system. */ public class Monkey { - + /** * Monkey Debugging/Dev Support - * + * * All values should be zero when checking in. */ private final static int DEBUG_ALLOW_ANY_STARTS = 0; @@ -74,20 +74,20 @@ public class Monkey { /** Ignore any not responding timeouts while running? */ private boolean mIgnoreTimeouts; - + /** Ignore security exceptions when launching activities */ /** (The activity launch still fails, but we keep pluggin' away) */ private boolean mIgnoreSecurityExceptions; - + /** Monitor /data/tombstones and stop the monkey if new files appear. */ private boolean mMonitorNativeCrashes; - + /** Send no events. Use with long throttle-time to watch user operations */ private boolean mSendNoEvents; /** This is set when we would like to abort the running of the monkey. */ private boolean mAbort; - + /** This is set by the ActivityController thread to request collection of ANR trace files */ private boolean mRequestAnrTraces = false; @@ -96,7 +96,7 @@ public class Monkey { /** Kill the process after a timeout or crash. */ private boolean mKillProcessAfterError; - + /** Generate hprof reports before/after monkey runs */ private boolean mGenerateHprof; @@ -106,16 +106,16 @@ public class Monkey { ArrayList mMainCategories = new ArrayList(); /** Applications we can switch to. */ private ArrayList mMainApps = new ArrayList(); - + /** The delay between event inputs **/ long mThrottle = 0; - + /** The number of iterations **/ int mCount = 1000; - + /** The random number seed **/ long mSeed = 0; - + /** Dropped-event statistics **/ long mDroppedKeyEvents = 0; long mDroppedPointerEvents = 0; @@ -124,14 +124,17 @@ public class Monkey { /** a filename to the script (if any) **/ private String mScriptFileName = null; - + + /** a TCP port to listen on for remote commands. */ + private int mServerPort = -1; + private static final File TOMBSTONES_PATH = new File("/data/tombstones"); private HashSet mTombstones = null; - - float[] mFactors = new float[MonkeySourceRandom.FACTORZ_COUNT]; + + float[] mFactors = new float[MonkeySourceRandom.FACTORZ_COUNT]; MonkeyEventSource mEventSource; private MonkeyNetworkMonitor mNetworkMonitor = new MonkeyNetworkMonitor(); - + /** * Monitor operations happening in the system. */ @@ -144,7 +147,7 @@ public class Monkey { } return allow; } - + public boolean activityResuming(String pkg) { System.out.println(" // activityResuming(" + pkg + ")"); boolean allow = checkEnteringPackage(pkg) || (DEBUG_ALLOW_ANY_RESTARTS != 0); @@ -156,7 +159,7 @@ public class Monkey { } return allow; } - + private boolean checkEnteringPackage(String pkg) { if (pkg == null) { return true; @@ -168,7 +171,7 @@ public class Monkey { return mValidPackages.contains(pkg); } } - + public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, byte[] crashData) { System.err.println("// CRASH: " + processName + " (pid " + pid @@ -223,14 +226,14 @@ public class Monkey { return 1; } } - + /** * Run the procrank tool to insert system status information into the debug report. */ private void reportProcRank() { commandLineReport("procrank", "procrank"); } - + /** * Run "cat /data/anr/traces.txt". Wait about 5 seconds first, to let the asynchronous * report writing complete. @@ -238,21 +241,21 @@ public class Monkey { private void reportAnrTraces() { try { Thread.sleep(5 * 1000); - } catch (InterruptedException e) { + } catch (InterruptedException e) { } commandLineReport("anr traces", "cat /data/anr/traces.txt"); } - + /** * Run "dumpsys meminfo" - * + * * NOTE: You cannot perform a dumpsys call from the ActivityController callback, as it will * deadlock. This should only be called from the main loop of the monkey. */ private void reportDumpsysMemInfo() { commandLineReport("meminfo", "dumpsys meminfo"); } - + /** * Print report from a single command line. * @param reportName Simple tag that will print before the report and in various annotations. @@ -266,7 +269,7 @@ public class Monkey { try { // Process must be fully qualified here because android.os.Process is used elsewhere java.lang.Process p = Runtime.getRuntime().exec(command); - + // pipe everything from process stdout -> System.err InputStream inStream = p.getInputStream(); InputStreamReader inReader = new InputStreamReader(inStream); @@ -275,7 +278,7 @@ public class Monkey { while ((s = inBuffer.readLine()) != null) { System.err.println(s); } - + int status = p.waitFor(); System.err.println("// " + reportName + " status was " + status); } catch (Exception e) { @@ -307,26 +310,26 @@ public class Monkey { Debug.waitForDebugger(); } } - + // Default values for some command-line options mVerbose = 0; mCount = 1000; mSeed = 0; mThrottle = 0; - + // prepare for command-line processing mArgs = args; mNextArg = 0; - + //set a positive value, indicating none of the factors is provided yet for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) { mFactors[i] = 1.0f; } - + if (!processOptions()) { return -1; } - + // now set up additional data in preparation for launch if (mMainCategories.size() == 0) { mMainCategories.add(Intent.CATEGORY_LAUNCHER); @@ -348,11 +351,11 @@ public class Monkey { } } } - + if (!checkInternalConfiguration()) { return -2; } - + if (!getSystemInterfaces()) { return -3; } @@ -360,11 +363,14 @@ public class Monkey { if (!getMainApps()) { return -4; } - + if (mScriptFileName != null) { // script mode, ignore other options mEventSource = new MonkeySourceScript(mScriptFileName, mThrottle); mEventSource.setVerbose(mVerbose); + } else if (mServerPort != -1) { + mEventSource = new MonkeySourceNetwork(mServerPort); + mCount = Integer.MAX_VALUE; } else { // random source by default if (mVerbose >= 2) { // check seeding performance @@ -378,7 +384,7 @@ public class Monkey { ((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]); } } - + //in random mode, we start with a random activity ((MonkeySourceRandom) mEventSource).generateActivity(); } @@ -387,7 +393,7 @@ public class Monkey { if (!mEventSource.validate()) { return -5; } - + if (mScriptFileName != null) { // in random mode, count is the number of single events // while in script mode, count is the number of repetition @@ -396,12 +402,12 @@ public class Monkey { mCount = mCount * ((MonkeySourceScript) mEventSource) .getOneRoundEventCount(); } - + // If we're profiling, do it immediately before/after the main monkey loop if (mGenerateHprof) { signalPersistentProcesses(); } - + mNetworkMonitor.start(); int crashedAtCycle = runMonkeyCycles(); mNetworkMonitor.stop(); @@ -423,7 +429,7 @@ public class Monkey { System.out.println("// Generated profiling reports in /data/misc"); } } - + try { mAm.setActivityController(null); mNetworkMonitor.unregister(mAm); @@ -434,7 +440,7 @@ public class Monkey { crashedAtCycle = mCount - 1; } } - + // report dropped event stats if (mVerbose > 0) { System.out.print(":Dropped: keys="); @@ -446,7 +452,7 @@ public class Monkey { System.out.print(" flips="); System.out.println(mDroppedFlipEvents); } - + // report network stats mNetworkMonitor.dump(); @@ -461,10 +467,10 @@ public class Monkey { return 0; } } - + /** * Process the command-line options - * + * * @return Returns true if options were parsed with no apparent errors. */ private boolean processOptions() { @@ -498,28 +504,28 @@ public class Monkey { } else if (opt.equals("--hprof")) { mGenerateHprof = true; } else if (opt.equals("--pct-touch")) { - mFactors[MonkeySourceRandom.FACTOR_TOUCH] = + mFactors[MonkeySourceRandom.FACTOR_TOUCH] = -nextOptionLong("touch events percentage"); } else if (opt.equals("--pct-motion")) { - mFactors[MonkeySourceRandom.FACTOR_MOTION] = + mFactors[MonkeySourceRandom.FACTOR_MOTION] = -nextOptionLong("motion events percentage"); } else if (opt.equals("--pct-trackball")) { - mFactors[MonkeySourceRandom.FACTOR_TRACKBALL] = + mFactors[MonkeySourceRandom.FACTOR_TRACKBALL] = -nextOptionLong("trackball events percentage"); } else if (opt.equals("--pct-nav")) { - mFactors[MonkeySourceRandom.FACTOR_NAV] = + mFactors[MonkeySourceRandom.FACTOR_NAV] = -nextOptionLong("nav events percentage"); } else if (opt.equals("--pct-majornav")) { - mFactors[MonkeySourceRandom.FACTOR_MAJORNAV] = + mFactors[MonkeySourceRandom.FACTOR_MAJORNAV] = -nextOptionLong("major nav events percentage"); } else if (opt.equals("--pct-appswitch")) { - mFactors[MonkeySourceRandom.FACTOR_APPSWITCH] = + mFactors[MonkeySourceRandom.FACTOR_APPSWITCH] = -nextOptionLong("app switch events percentage"); } else if (opt.equals("--pct-flip")) { mFactors[MonkeySourceRandom.FACTOR_FLIP] = -nextOptionLong("keyboard flip percentage"); } else if (opt.equals("--pct-anyevent")) { - mFactors[MonkeySourceRandom.FACTOR_ANYTHING] = + mFactors[MonkeySourceRandom.FACTOR_ANYTHING] = -nextOptionLong("any events percentage"); } else if (opt.equals("--throttle")) { mThrottle = nextOptionLong("delay (in milliseconds) to wait between events"); @@ -527,7 +533,9 @@ public class Monkey { // do nothing - it's caught at the very start of run() } else if (opt.equals("--dbg-no-events")) { mSendNoEvents = true; - } else if (opt.equals("-f")) { + } else if (opt.equals("--port")) { + mServerPort = (int) nextOptionLong("Server port to listen on for commands"); + } else if (opt.equals("-f")) { mScriptFileName = nextOptionData(); } else if (opt.equals("-h")) { showUsage(); @@ -544,19 +552,23 @@ public class Monkey { return false; } - String countStr = nextArg(); - if (countStr == null) { - System.err.println("** Error: Count not specified"); - showUsage(); - return false; - } + // If a server port hasn't been specified, we need to specify + // a count + if (mServerPort == -1) { + String countStr = nextArg(); + if (countStr == null) { + System.err.println("** Error: Count not specified"); + showUsage(); + return false; + } - try { - mCount = Integer.parseInt(countStr); - } catch (NumberFormatException e) { - System.err.println("** Error: Count is not a number"); - showUsage(); - return false; + try { + mCount = Integer.parseInt(countStr); + } catch (NumberFormatException e) { + System.err.println("** Error: Count is not a number"); + showUsage(); + return false; + } } return true; @@ -564,7 +576,7 @@ public class Monkey { /** * Check for any internal configuration (primarily build-time) errors. - * + * * @return Returns true if ready to rock. */ private boolean checkInternalConfiguration() { @@ -585,7 +597,7 @@ public class Monkey { /** * Attach to the required system interfaces. - * + * * @return Returns true if all system interfaces were available. */ private boolean getSystemInterfaces() { @@ -621,7 +633,7 @@ public class Monkey { /** * Using the restrictions provided (categories & packages), generate a list of activities * that we can actually switch to. - * + * * @return Returns true if it could successfully build a list of target activities */ private boolean getMainApps() { @@ -644,7 +656,7 @@ public class Monkey { final int NA = mainApps.size(); for (int a = 0; a < NA; a++) { ResolveInfo r = mainApps.get(a); - if (mValidPackages.size() == 0 || + if (mValidPackages.size() == 0 || mValidPackages.contains(r.activityInfo.applicationInfo.packageName)) { if (mVerbose >= 2) { // very verbose System.out.println("// + Using main activity " @@ -676,15 +688,15 @@ public class Monkey { System.out.println("** No activities found to run, monkey aborted."); return false; } - + return true; } /** * Run mCount cycles and see if we hit any crashers. - * + * * TODO: Meta state on keys - * + * * @return Returns the last cycle which executed. If the value == mCount, no errors detected. */ private int runMonkeyCycles() { @@ -749,9 +761,11 @@ public class Monkey { } else if (injectCode == MonkeyEvent.INJECT_ERROR_SECURITY_EXCEPTION) { systemCrashed = !mIgnoreSecurityExceptions; } + } else { + // Event Source has signaled that we have no more events to process + break; } } - // If we got this far, we succeeded! return mCount; } @@ -775,18 +789,18 @@ public class Monkey { /** * Watch for appearance of new tombstone files, which indicate native crashes. - * + * * @return Returns true if new files have appeared in the list */ private boolean checkNativeCrashes() { String[] tombstones = TOMBSTONES_PATH.list(); - + // shortcut path for usually empty directory, so we don't waste even more objects if ((tombstones == null) || (tombstones.length == 0)) { mTombstones = null; return false; } - + // use set logic to look for new files HashSet newStones = new HashSet(); for (String x : tombstones) { @@ -804,14 +818,14 @@ public class Monkey { /** * Return the next command line option. This has a number of special cases which * closely, but not exactly, follow the POSIX command line options patterns: - * + * * -- means to stop processing additional options * -z means option z * -z ARGS means option z with (non-optional) arguments ARGS * -zARGS means option z with (optional) arguments ARGS * --zz means option zz * --zz ARGS means option zz with (non-optional) arguments ARGS - * + * * Note that you cannot combine single letter options; -abc != -a -b -c * * @return Returns the option string, or null if there are no more options. @@ -857,10 +871,10 @@ public class Monkey { mNextArg++; return data; } - + /** * Returns a long converted from the next data argument, with error handling if not available. - * + * * @param opt The name of the option. * @return Returns a long converted from the argument. */ @@ -904,6 +918,7 @@ public class Monkey { System.err.println(" [--pct-appswitch PERCENT] [--pct-flip PERCENT]"); System.err.println(" [--pct-anyevent PERCENT]"); System.err.println(" [--wait-dbg] [--dbg-no-events] [-f scriptfile]"); + System.err.println(" [--port port]"); System.err.println(" [-s SEED] [-v [-v] ...] [--throttle MILLISEC]"); System.err.println(" COUNT"); } diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java new file mode 100644 index 000000000..de784d0ae --- /dev/null +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java @@ -0,0 +1,376 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.commands.monkey; + +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.lang.Integer; +import java.lang.NumberFormatException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.StringTokenizer; + +/** + * An Event source for getting Monkey Network Script commands from + * over the network. + */ +public class MonkeySourceNetwork implements MonkeyEventSource { + private static final String TAG = "MonkeyStub"; + + private interface MonkeyCommand { + MonkeyEvent translateCommand(List command); + } + + /** + * Command to simulate closing and opening the keyboard. + */ + private static class FlipCommand implements MonkeyCommand { + // flip open + // flip closed + public MonkeyEvent translateCommand(List command) { + if (command.size() > 1) { + String direction = command.get(1); + if ("open".equals(direction)) { + return new MonkeyFlipEvent(true); + } else if ("close".equals(direction)) { + return new MonkeyFlipEvent(false); + } + } + return null; + } + } + + /** + * Command to send touch events to the input system. + */ + private static class TouchCommand implements MonkeyCommand { + // touch [down|up|move] [x] [y] + // touch down 120 120 + // touch move 140 140 + // touch up 140 140 + public MonkeyEvent translateCommand(List command) { + if (command.size() == 4) { + String actionName = command.get(1); + int x = 0; + int y = 0; + try { + x = Integer.parseInt(command.get(2)); + y = Integer.parseInt(command.get(3)); + } catch (NumberFormatException e) { + // Ok, it wasn't a number + Log.e(TAG, "Got something that wasn't a number", e); + return null; + } + + // figure out the action + int action = -1; + if ("down".equals(actionName)) { + action = MotionEvent.ACTION_DOWN; + } else if ("up".equals(actionName)) { + action = MotionEvent.ACTION_UP; + } else if ("move".equals(actionName)) { + action = MotionEvent.ACTION_MOVE; + } + if (action == -1) { + Log.e(TAG, "Got a bad action: " + actionName); + return null; + } + + return new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + -1, action, x, y, 0); + } + return null; + + } + } + + /** + * Command to send Trackball events to the input system. + */ + private static class TrackballCommand implements MonkeyCommand { + // trackball [dx] [dy] + // trackball 1 0 -- move right + // trackball -1 0 -- move left + public MonkeyEvent translateCommand(List command) { + if (command.size() == 3) { + int dx = 0; + int dy = 0; + try { + dx = Integer.parseInt(command.get(1)); + dy = Integer.parseInt(command.get(2)); + } catch (NumberFormatException e) { + // Ok, it wasn't a number + Log.e(TAG, "Got something that wasn't a number", e); + return null; + } + return new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1, + MotionEvent.ACTION_MOVE, dx, dy, 0); + + } + return null; + } + } + + /** + * Command to send Key events to the input system. + */ + private static class KeyCommand implements MonkeyCommand { + // key [down|up] [keycode] + // key down 82 + // key up 82 + public MonkeyEvent translateCommand(List command) { + if (command.size() == 3) { + int keyCode = -1; + String keyName = command.get(2); + try { + keyCode = Integer.parseInt(keyName); + } catch (NumberFormatException e) { + // Ok, it wasn't a number, see if we have a + // keycode name for it + keyCode = MonkeySourceRandom.getKeyCode(keyName); + if (keyCode == -1) { + // OK, one last ditch effort to find a match. + // Build the KEYCODE_STRING from the string + // we've been given and see if that key + // exists. This would allow you to do "key + // down menu", for example. + keyCode = MonkeySourceRandom.getKeyCode("KEYCODE_" + keyName.toUpperCase()); + if (keyCode == -1) { + // Ok, you gave us something bad. + Log.e(TAG, "Can't find keyname: " + keyName); + return null; + } + } + } + Log.d(TAG, "keycode: " + keyCode); + int action = -1; + if ("down".equals(command.get(1))) { + action = KeyEvent.ACTION_DOWN; + } else if ("up".equals(command.get(1))) { + action = KeyEvent.ACTION_UP; + } + if (action == -1) { + Log.e(TAG, "got unknown action."); + return null; + } + return new MonkeyKeyEvent(action, keyCode); + } + return null; + } + } + + /** + * Command to put the Monkey to sleep. + */ + private static class SleepCommand implements MonkeyCommand { + // sleep 2000 + public MonkeyEvent translateCommand(List command) { + if (command.size() == 2) { + int sleep = -1; + String sleepStr = command.get(1); + try { + sleep = Integer.parseInt(sleepStr); + } catch (NumberFormatException e) { + Log.e(TAG, "Not a number: " + sleepStr, e); + } + return new MonkeyThrottleEvent(sleep); + } + return null; + } + } + + // This maps from command names to command implementations. + private static final Map COMMAND_MAP = new HashMap(); + + static { + // Add in all the commands we support + COMMAND_MAP.put("flip", new FlipCommand()); + COMMAND_MAP.put("touch", new TouchCommand()); + COMMAND_MAP.put("trackball", new TrackballCommand()); + COMMAND_MAP.put("key", new KeyCommand()); + COMMAND_MAP.put("sleep", new SleepCommand()); + } + + // QUIT command + private static final String QUIT = "quit"; + + // command response strings + private static final String OK = "OK"; + private static final String ERROR = "ERROR"; + + + private final int port; + private BufferedReader input; + private PrintWriter output; + private boolean started = false; + + public MonkeySourceNetwork(int port) { + this.port = port; + } + + /** + * Start a network server listening on the specified port. The + * network protocol is a line oriented protocol, where each line + * is a different command that can be run. + * + * @param port the port to listen on + */ + private void startServer() throws IOException { + // Only bind this to local host. This means that you can only + // talk to the monkey locally, or though adb port forwarding. + ServerSocket server = new ServerSocket(port, + 0, // default backlog + InetAddress.getLocalHost()); + Socket s = server.accept(); + input = new BufferedReader(new InputStreamReader(s.getInputStream())); + // auto-flush + output = new PrintWriter(s.getOutputStream(), true); + } + + /** + * This function splits the given line into String parts. It obey's quoted + * strings and returns them as a single part. + * + * "This is a test" -> returns only one element + * This is a test -> returns four elements + * + * @param line the line to parse + * @return the List of elements + */ + private static List commandLineSplit(String line) { + ArrayList result = new ArrayList(); + StringTokenizer tok = new StringTokenizer(line); + + boolean insideQuote = false; + StringBuffer quotedWord = new StringBuffer(); + while (tok.hasMoreTokens()) { + String cur = tok.nextToken(); + if (!insideQuote && cur.startsWith("\"")) { + // begin quote + quotedWord.append(cur); + insideQuote = true; + } else if (insideQuote) { + // end quote + if (cur.endsWith("\"")) { + insideQuote = false; + quotedWord.append(cur); + String word = quotedWord.toString(); + + // trim off the quotes + result.add(word.substring(1, word.length() - 1)); + } else { + quotedWord.append(cur); + } + } else { + result.add(cur); + } + } + return result; + } + + /** + * Translate the given command line into a MonkeyEvent. + * + * @param commandLine the full command line given. + * @returns the MonkeyEvent corresponding to the command, or null + * if there was an issue. + */ + private MonkeyEvent translateCommand(String commandLine) { + Log.d(TAG, "translateCommand: " + commandLine); + List parts = commandLineSplit(commandLine); + if (parts.size() > 0) { + MonkeyCommand command = COMMAND_MAP.get(parts.get(0)); + if (command != null) { + return command.translateCommand(parts); + } + return null; + } + return null; + } + + public MonkeyEvent getNextEvent() { + if (!started) { + try { + startServer(); + } catch (IOException e) { + Log.e(TAG, "Got IOException from server", e); + return null; + } + started = true; + } + + // Now, get the next command. This call may block, but that's OK + try { + while (true) { + String command = input.readLine(); + if (command == null) { + Log.d(TAG, "Connection dropped."); + return null; + } + // Do quit checking here + if (QUIT.equals(command)) { + // then we're done + Log.d(TAG, "Quit requested"); + // let the host know the command ran OK + output.println(OK); + return null; + } + + // Do comment checking here. Comments aren't a + // command, so we don't echo anything back to the + // user. + if (command.startsWith("#")) { + // keep going + continue; + } + + // Translate the command line + MonkeyEvent event = translateCommand(command); + if (event != null) { + // let the host know the command ran OK + output.println(OK); + return event; + } + // keep going. maybe the next command will make more sense + Log.e(TAG, "Got unknown command! \"" + command + "\""); + output.println(ERROR); + } + } catch (IOException e) { + Log.e(TAG, "Exception: ", e); + return null; + } + } + + public void setVerbose(int verbose) { + // We're not particualy verbose + } + + public boolean validate() { + // we have no pre-conditions to validate + return true; + } +} diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java index 5f9c10f03..27c8a5171 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java @@ -31,7 +31,7 @@ import java.util.Random; /** * monkey event queue */ -public class MonkeySourceRandom implements MonkeyEventSource { +public class MonkeySourceRandom implements MonkeyEventSource { /** Key events that move around the UI. */ private static final int[] NAV_KEYS = { KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN, @@ -55,7 +55,7 @@ public class MonkeySourceRandom implements MonkeyEventSource { /** Nice names for all key events. */ private static final String[] KEY_NAMES = { "KEYCODE_UNKNOWN", - "KEYCODE_MENU", + "KEYCODE_SOFT_LEFT", "KEYCODE_SOFT_RIGHT", "KEYCODE_HOME", "KEYCODE_BACK", @@ -146,7 +146,7 @@ public class MonkeySourceRandom implements MonkeyEventSource { "KEYCODE_REWIND", "KEYCODE_FORWARD", "KEYCODE_MUTE", - + "TAG_LAST_KEYCODE" // EOL. used to keep the lists in sync }; @@ -158,34 +158,50 @@ public class MonkeySourceRandom implements MonkeyEventSource { public static final int FACTOR_SYSOPS = 5; public static final int FACTOR_APPSWITCH = 6; public static final int FACTOR_FLIP = 7; - public static final int FACTOR_ANYTHING = 8; + public static final int FACTOR_ANYTHING = 8; public static final int FACTORZ_COUNT = 9; // should be last+1 - - + + /** percentages for each type of event. These will be remapped to working * values after we read any optional values. - **/ + **/ private float[] mFactors = new float[FACTORZ_COUNT]; private ArrayList mMainApps; private int mEventCount = 0; //total number of events generated so far private MonkeyEventQueue mQ; - private Random mRandom; + private Random mRandom; private int mVerbose = 0; private long mThrottle = 0; private boolean mKeyboardOpen = false; - /** + /** * @return the last name in the key list */ public static String getLastKeyName() { return KEY_NAMES[KeyEvent.getMaxKeyCode() + 1]; } - + public static String getKeyName(int keycode) { return KEY_NAMES[keycode]; } - + + /** + * Looks up the keyCode from a given KEYCODE_NAME. NOTE: This may + * be an expensive operation. + * + * @param keyName the name of the KEYCODE_VALUE to lookup. + * @returns the intenger keyCode value, or -1 if not found + */ + public static int getKeyCode(String keyName) { + for (int x = 0; x < KEY_NAMES.length; x++) { + if (KEY_NAMES[x].equals(keyName)) { + return x; + } + } + return -1; + } + public MonkeySourceRandom(long seed, ArrayList MainApps, long throttle) { // default values for random distributions // note, these are straight percentages, to match user input (cmd line args) @@ -199,7 +215,7 @@ public class MonkeySourceRandom implements MonkeyEventSource { mFactors[FACTOR_APPSWITCH] = 2.0f; mFactors[FACTOR_FLIP] = 1.0f; mFactors[FACTOR_ANYTHING] = 15.0f; - + mRandom = new SecureRandom(); mRandom.setSeed((seed == 0) ? -1 : seed); mMainApps = MainApps; @@ -220,25 +236,25 @@ public class MonkeySourceRandom implements MonkeyEventSource { } else { defaultSum += mFactors[i]; ++defaultCount; - } + } } - + // if the user request was > 100%, reject it if (userSum > 100.0f) { System.err.println("** Event weights > 100%"); return false; } - + // if the user specified all of the weights, then they need to be 100% if (defaultCount == 0 && (userSum < 99.9f || userSum > 100.1f)) { System.err.println("** Event weights != 100%"); return false; } - + // compute the adjustment necessary float defaultsTarget = (100.0f - userSum); float defaultsAdjustment = defaultsTarget / defaultSum; - + // fix all values, by adjusting defaults, or flipping user values back to >0 for (int i = 0; i < FACTORZ_COUNT; ++i) { if (mFactors[i] <= 0.0f) { // user values are zero or negative @@ -247,46 +263,46 @@ public class MonkeySourceRandom implements MonkeyEventSource { mFactors[i] *= defaultsAdjustment; } } - + // if verbose, show factors - + if (mVerbose > 0) { System.out.println("// Event percentages:"); for (int i = 0; i < FACTORZ_COUNT; ++i) { System.out.println("// " + i + ": " + mFactors[i] + "%"); } - } - + } + // finally, normalize and convert to running sum float sum = 0.0f; for (int i = 0; i < FACTORZ_COUNT; ++i) { sum += mFactors[i] / 100.0f; mFactors[i] = sum; - } + } return true; } - + /** * set the factors - * + * * @param factors: percentages for each type of event */ public void setFactors(float factors[]) { int c = FACTORZ_COUNT; if (factors.length < c) { c = factors.length; - } + } for (int i = 0; i < c; i++) mFactors[i] = factors[i]; } - + public void setFactors(int index, float v) { mFactors[index] = v; } - + /** * Generates a random motion event. This method counts a down, move, and up as multiple events. - * + * * TODO: Test & fix the selectors when non-zero percentages * TODO: Longpress. * TODO: Fling. @@ -294,13 +310,13 @@ public class MonkeySourceRandom implements MonkeyEventSource { * TODO: More useful than the random walk here would be to pick a single random direction * and distance, and divvy it up into a random number of segments. (This would serve to * generate fling gestures, which are important). - * + * * @param random Random number source for positioning - * @param motionEvent If false, touch/release. If true, touch/move/release. - * + * @param motionEvent If false, touch/release. If true, touch/move/release. + * */ private void generateMotionEvent(Random random, boolean motionEvent){ - + Display display = WindowManagerImpl.getDefault().getDefaultDisplay(); float x = Math.abs(random.nextInt() % display.getWidth()); @@ -310,12 +326,12 @@ public class MonkeySourceRandom implements MonkeyEventSource { if (downAt == -1) { downAt = eventTime; } - - MonkeyMotionEvent e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, - downAt, MotionEvent.ACTION_DOWN, x, y, 0); - e.setIntermediateNote(false); + + MonkeyMotionEvent e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + downAt, MotionEvent.ACTION_DOWN, x, y, 0); + e.setIntermediateNote(false); mQ.addLast(e); - + // sometimes we'll move during the touch if (motionEvent) { int count = random.nextInt(10); @@ -323,34 +339,34 @@ public class MonkeySourceRandom implements MonkeyEventSource { // generate some slop in the up event x = (x + (random.nextInt() % 10)) % display.getWidth(); y = (y + (random.nextInt() % 10)) % display.getHeight(); - - e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, - downAt, MotionEvent.ACTION_MOVE, x, y, 0); - e.setIntermediateNote(true); + + e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + downAt, MotionEvent.ACTION_MOVE, x, y, 0); + e.setIntermediateNote(true); mQ.addLast(e); } } // TODO generate some slop in the up event - e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, - downAt, MotionEvent.ACTION_UP, x, y, 0); - e.setIntermediateNote(false); + e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + downAt, MotionEvent.ACTION_UP, x, y, 0); + e.setIntermediateNote(false); mQ.addLast(e); } - + /** * Generates a random trackball event. This consists of a sequence of small moves, followed by * an optional single click. - * + * * TODO: Longpress. * TODO: Meta state * TODO: Parameterize the % clicked * TODO: More useful than the random walk here would be to pick a single random direction * and distance, and divvy it up into a random number of segments. (This would serve to * generate fling gestures, which are important). - * + * * @param random Random number source for positioning - * + * */ private void generateTrackballEvent(Random random) { Display display = WindowManagerImpl.getDefault().getDefaultDisplay(); @@ -362,47 +378,47 @@ public class MonkeySourceRandom implements MonkeyEventSource { // generate a small random step int dX = random.nextInt(10) - 5; int dY = random.nextInt(10) - 5; - - - e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1, - MotionEvent.ACTION_MOVE, dX, dY, 0); - e.setIntermediateNote(i > 0); + + + e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1, + MotionEvent.ACTION_MOVE, dX, dY, 0); + e.setIntermediateNote(i > 0); mQ.addLast(e); } - + // 10% of trackball moves end with a click if (0 == random.nextInt(10)) { long downAt = SystemClock.uptimeMillis(); - - - e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt, - MotionEvent.ACTION_DOWN, 0, 0, 0); - e.setIntermediateNote(true); + + + e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt, + MotionEvent.ACTION_DOWN, 0, 0, 0); + e.setIntermediateNote(true); mQ.addLast(e); - - - e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt, - MotionEvent.ACTION_UP, 0, 0, 0); - e.setIntermediateNote(false); + + + e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt, + MotionEvent.ACTION_UP, 0, 0, 0); + e.setIntermediateNote(false); mQ.addLast(e); - } + } } - - /** + + /** * generate a random event based on mFactor */ - private void generateEvents() { + private void generateEvents() { float cls = mRandom.nextFloat(); int lastKey = 0; boolean touchEvent = cls < mFactors[FACTOR_TOUCH]; boolean motionEvent = !touchEvent && (cls < mFactors[FACTOR_MOTION]); - if (touchEvent || motionEvent) { + if (touchEvent || motionEvent) { generateMotionEvent(mRandom, motionEvent); return; } - - if (cls < mFactors[FACTOR_TRACKBALL]) { + + if (cls < mFactors[FACTOR_TRACKBALL]) { generateTrackballEvent(mRandom); return; } @@ -427,23 +443,23 @@ public class MonkeySourceRandom implements MonkeyEventSource { } else { lastKey = 1 + mRandom.nextInt(KeyEvent.getMaxKeyCode() - 1); } - + MonkeyKeyEvent e = new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, lastKey); mQ.addLast(e); - + e = new MonkeyKeyEvent(KeyEvent.ACTION_UP, lastKey); mQ.addLast(e); } - + public boolean validate() { //check factors return adjustEventFactors(); } - + public void setVerbose(int verbose) { mVerbose = verbose; } - + /** * generate an activity event */ @@ -452,18 +468,18 @@ public class MonkeySourceRandom implements MonkeyEventSource { mRandom.nextInt(mMainApps.size()))); mQ.addLast(e); } - + /** * if the queue is empty, we generate events first - * @return the first event in the queue + * @return the first event in the queue */ public MonkeyEvent getNextEvent() { if (mQ.isEmpty()) { generateEvents(); - } - mEventCount++; - MonkeyEvent e = mQ.getFirst(); - mQ.removeFirst(); + } + mEventCount++; + MonkeyEvent e = mQ.getFirst(); + mQ.removeFirst(); return e; } } From 3c1404268adef92f1c3b2a2da3b212e44e54a4bd Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Fri, 7 Aug 2009 12:05:09 -0700 Subject: [PATCH 21/87] Fix template for java test file to not use deprecated class. bug: http://code.google.com/p/android/issues/detail?id=3350 --- tools/scripts/java_tests_file.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/scripts/java_tests_file.template b/tools/scripts/java_tests_file.template index 7781a33c3..c6fa8736f 100644 --- a/tools/scripts/java_tests_file.template +++ b/tools/scripts/java_tests_file.template @@ -1,6 +1,6 @@ package PACKAGE; -import android.test.ActivityInstrumentationTestCase; +import android.test.ActivityInstrumentationTestCase2; /** * This is a simple framework for a test of an Application. See @@ -12,7 +12,7 @@ import android.test.ActivityInstrumentationTestCase; * -e class PACKAGE.ACTIVITY_NAMETest \ * PACKAGE.tests/android.test.InstrumentationTestRunner */ -public class ACTIVITY_NAMETest extends ActivityInstrumentationTestCase { +public class ACTIVITY_NAMETest extends ActivityInstrumentationTestCase2 { public ACTIVITY_NAMETest() { super("PACKAGE", ACTIVITY_NAME.class); From 904ef4d8a4c223d4558c97fbf5d5dece4bc1b6f7 Mon Sep 17 00:00:00 2001 From: Raphael Date: Fri, 7 Aug 2009 14:19:16 -0700 Subject: [PATCH 22/87] BUG 2041688 : SDK Updater: better description of extra packages --- .../internal/repository/ExtraPackage.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java index 86d650b02..e308a0f6d 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java @@ -112,7 +112,31 @@ public class ExtraPackage extends Package { /** Returns a short description for an {@link IDescription}. */ @Override public String getShortDescription() { - return String.format("Extra %1$s package, revision %2$d", getPath(), getRevision()); + String name = getPath(); + if (name != null) { + // Uniformize all spaces in the name and upper case words. + + name = name.replaceAll("[ _\t\f-]+", " "); //$NON-NLS-1$ //$NON-NLS-2$ + + // Look at all lower case characters in range [1..n-1] and replace them by an upper + // case if they are preceded by a space. Also upper cases the first character of the + // string. + boolean changed = false; + char[] chars = name.toCharArray(); + for (int n = chars.length - 1, i = 0; i < n; i++) { + if (Character.isLowerCase(chars[i]) && (i == 0 || chars[i - 1] == ' ')) { + chars[i] = Character.toUpperCase(chars[i]); + changed = true; + } + } + if (changed) { + name = new String(chars); + } + } + + return String.format("%1$s package, revision %2$d", + name, + getRevision()); } /** Returns a long description for an {@link IDescription}. */ From 18499b9160a031fc0b6e6c94e3de505824cfc21c Mon Sep 17 00:00:00 2001 From: Scott Main Date: Fri, 7 Aug 2009 14:32:41 -0700 Subject: [PATCH 23/87] fix release notes redirect for the SDK package to point to the correct page --- docs/SDK_RELEASE_NOTES | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/SDK_RELEASE_NOTES b/docs/SDK_RELEASE_NOTES index e117528e3..381c5da66 100644 --- a/docs/SDK_RELEASE_NOTES +++ b/docs/SDK_RELEASE_NOTES @@ -1,8 +1,8 @@ - + -click here if you are not redirected +click here if you are not redirected - \ No newline at end of file + From bd7dfac5a51bd6e7c552ced63e03c2b1833e04f0 Mon Sep 17 00:00:00 2001 From: Raphael Date: Fri, 7 Aug 2009 15:44:00 -0700 Subject: [PATCH 24/87] BUG 2039647 : support customization from calling wrapper script. --- build/tools/make_windows_sdk.sh | 37 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh index 7b6a17b0b..2a6433ad1 100755 --- a/build/tools/make_windows_sdk.sh +++ b/build/tools/make_windows_sdk.sh @@ -19,25 +19,26 @@ DIST_DIR="$2" TEMP_DIR="$3" [ -z "$TEMP_DIR" ] && TEMP_DIR=${TMP:-/tmp} - function die() { - echo "Error:" $* - echo "Aborting" - exit 1 + echo "Error:" $* + echo "Aborting" + exit 1 } function usage() { - echo "Usage: ${PROG_NAME} linux_or_mac_sdk.zip output_dir [temp_dir]" - echo "If temp_dir is not given, \$TMP is used. If that's missing, /tmp is used." - status - exit 2 + local NAME + NAME=`basename ${PROG_NAME}` + echo "Usage: ${NAME} linux_or_mac_sdk.zip output_dir [temp_dir]" + echo "If temp_dir is not given, \$TMP is used. If that's missing, /tmp is used." + status + exit 2 } function status() { - echo "Current values:" - echo "- Input SDK: ${SDK_ZIP:-missing}" - echo "- Output dir: ${DIST_DIR:-missing}" - echo "- Temp dir: ${TEMP_DIR:-missing}" + echo "Current values:" + echo "- Input SDK: ${SDK_ZIP:-missing}" + echo "- Output dir: ${DIST_DIR:-missing}" + echo "- Temp dir: ${TEMP_DIR:-missing}" } function check() { @@ -114,6 +115,10 @@ function package() { "Instead found " $THE_PLATFORM [[ -d "$PLATFORM_TOOLS" ]] || die "Missing folder $PLATFORM_TOOLS." + # Package USB Driver + if type package_usb_driver 2>&1 | grep -q function ; then + package_usb_driver $TEMP_SDK_DIR + fi # Remove obsolete stuff from tools & platform TOOLS="$TEMP_SDK_DIR/tools" @@ -190,14 +195,14 @@ function package() { # Now move the final zip from the temp dest to the final dist dir mv -v "$TEMP_DIR/$DEST_NAME_ZIP" "$DIST_DIR/$DEST_NAME_ZIP" - echo "Done" - echo - echo "Resulting SDK is in $DIST_DIR/$DEST_NAME_ZIP" - # We want fastboot and adb next to the new SDK for i in fastboot.exe adb.exe AdbWinApi.dll; do mv -vf out/host/windows-x86/bin/$i "$DIST_DIR"/$i done + + echo "Done" + echo + echo "Resulting SDK is in $DIST_DIR/$DEST_NAME_ZIP" } check From 1cf0c7fe0ecc5d412910669520a7ab19988bcdee Mon Sep 17 00:00:00 2001 From: Raphael Date: Fri, 7 Aug 2009 16:36:19 -0700 Subject: [PATCH 25/87] BUG 2042088 : SDK Updater: we want to keep getenv(TEMP_SDK_URL) Renamed the getenv and added one for user sources. Added a (naive) check to prevent duplicate URLs. Also fixed the repositoy.xml download error message, it was not displaying the reason of failure correctly. --- .../internal/repository/RepoSource.java | 22 ++++++++++++++- .../internal/repository/RepoSources.java | 19 ++++++++++++- .../repository/UpdaterWindowImpl.java | 27 +++++++++++++++++-- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java index cce65bd88..1d76655bd 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java @@ -56,6 +56,9 @@ public class RepoSource implements IDescription { /** * Constructs a new source for the given repository URL. + * @param url The source URL. Cannot be null. If the URL ends with a /, the default + * repository.xml filename will be appended automatically. + * @param userSource True if this a user source (add-ons & packages only.) */ public RepoSource(String url, boolean userSource) { @@ -72,6 +75,23 @@ public class RepoSource implements IDescription { setDefaultDescription(); } + /** + * Two repo source are equal if they have the same userSource flag and the same URL. + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof RepoSource) { + RepoSource rs = (RepoSource) obj; + return rs.isUserSource() == this.isUserSource() && rs.getUrl().equals(this.getUrl()); + } + return false; + } + + @Override + public int hashCode() { + return mUrl.hashCode() ^ Boolean.valueOf(mUserSource).hashCode(); + } + /** Returns true if this is a user source. We only load addon and extra packages * from a user source and ignore the rest. */ public boolean isUserSource() { @@ -176,7 +196,7 @@ public class RepoSource implements IDescription { } } - monitor.setResult("Failed to fetch URL %1$s, reason:", url, reason); + monitor.setResult("Failed to fetch URL %1$s, reason: %2$s", url, reason); } monitor.incProgress(1); diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java index 7af6657ae..e0452b8e4 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java @@ -95,7 +95,10 @@ public class RepoSources { for (int i = 0; i < count; i++) { String url = props.getProperty(String.format("%s%02d", KEY_SRC, i)); //$NON-NLS-1$ if (url != null) { - mSources.add(new RepoSource(url, true /*userSource*/)); + RepoSource s = new RepoSource(url, true /*userSource*/); + if (!hasSource(s)) { + mSources.add(s); + } } } } @@ -119,6 +122,20 @@ public class RepoSources { } } + /** + * Returns true if there's already a similar source in the sources list. + *

    + * The search is O(N), which should be acceptable on the expectedly small source list. + */ + public boolean hasSource(RepoSource source) { + for (RepoSource s : mSources) { + if (s.equals(source)) { + return true; + } + } + return false; + } + /** * Saves all the user sources. * @param log diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java index 20f1abbe8..b9cf0a494 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java @@ -335,17 +335,40 @@ public class UpdaterWindowImpl { RepoSources sources = mUpdaterData.getSources(); sources.add(new RepoSource(SdkRepository.URL_GOOGLE_SDK_REPO_SITE, false /*userSource*/)); - String str = System.getenv("TEMP_SDK_URL"); // TODO STOPSHIP temporary remove before shipping + // SDK_UPDATER_URLS is a semicolon-separated list of URLs that can be used to + // seed the SDK Updater list for full repositories. + String str = System.getenv("SDK_UPDATER_URLS"); if (str != null) { String[] urls = str.split(";"); for (String url : urls) { - sources.add(new RepoSource(url, false /*userSource*/)); + if (url != null && url.length() > 0) { + RepoSource s = new RepoSource(url, false /*userSource*/); + if (!sources.hasSource(s)) { + sources.add(s); + } + } } } // Load user sources sources.loadUserSources(mUpdaterData.getSdkLog()); + // SDK_UPDATER_USER_URLS is a semicolon-separated list of URLs that can be used to + // seed the SDK Updater list for user-only repositories. User sources can only provide + // add-ons and extra packages. + str = System.getenv("SDK_UPDATER_USER_URLS"); + if (str != null) { + String[] urls = str.split(";"); + for (String url : urls) { + if (url != null && url.length() > 0) { + RepoSource s = new RepoSource(url, true /*userSource*/); + if (!sources.hasSource(s)) { + sources.add(s); + } + } + } + } + mRemotePackagesPage.onSdkChange(); } From 0b1f5a9484d03fd2ca7fd986842cf8b593c71e8c Mon Sep 17 00:00:00 2001 From: Bill Napier Date: Mon, 10 Aug 2009 09:56:08 -0700 Subject: [PATCH 26/87] Update monkey network readme. --- cmds/monkey/README.NETWORK.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cmds/monkey/README.NETWORK.txt b/cmds/monkey/README.NETWORK.txt index ccf741b52..f3f69d440 100644 --- a/cmds/monkey/README.NETWORK.txt +++ b/cmds/monkey/README.NETWORK.txt @@ -1,13 +1,13 @@ -MONKEY NETWORK SCRIPT +SIMPLE PROTOCOL FOR AUTOMATED NETWORK CONTROL -The Monkey Network Script was designed to be a low-level way to -programmability inject KeyEvents and MotionEvents into the input -system. The idea is that a process will run on a host computer that -will support higher-level operations (like conditionals, etc.) and -will talk (via TCP over ADB) to the device in Monkey Network Script. -For security reasons, the Monkey only binds to localhost, so you will -need to use adb to setup port forwarding to actually talk to the -device. +The Simple Protocol for Automated Network Control was designed to be a +low-level way to programmability inject KeyEvents and MotionEvents +into the input system. The idea is that a process will run on a host +computer that will support higher-level operations (like conditionals, +etc.) and will talk (via TCP over ADB) to the device in Simple +Protocol for Automated Network Control. For security reasons, the +Monkey only binds to localhost, so you will need to use adb to setup +port forwarding to actually talk to the device. INITIAL SETUP From 7a3e95aeba5109ef6aa4c9488be9416e7355067c Mon Sep 17 00:00:00 2001 From: Karl Rosaen Date: Fri, 7 Aug 2009 15:45:17 -0700 Subject: [PATCH 27/87] Add a "Searchable Dictionary" app to the sample apps that demonstrates being a part of global search. updated: makefile adjusted so app is part of sdk, and the manifest refers to the correct sdk version. updated: brushed up docs and formatting per feedback. --- build/sdk.atree | 1 + samples/SearchableDictionary/Android.mk | 12 + .../SearchableDictionary/AndroidManifest.xml | 58 + .../res/drawable/ic_dictionary.gif | Bin 0 -> 1132 bytes .../SearchableDictionary/res/layout/main.xml | 37 + .../SearchableDictionary/res/layout/word.xml | 39 + .../res/raw/definitions.txt | 997 ++++++++++++++++++ .../res/values/strings.xml | 38 + .../res/xml/searchable.xml | 40 + .../android/searchabledict/Dictionary.java | 130 +++ .../searchabledict/DictionaryProvider.java | 160 +++ .../searchabledict/SearchableDictionary.java | 155 +++ .../android/searchabledict/WordActivity.java | 49 + 13 files changed, 1716 insertions(+) create mode 100755 samples/SearchableDictionary/Android.mk create mode 100644 samples/SearchableDictionary/AndroidManifest.xml create mode 100644 samples/SearchableDictionary/res/drawable/ic_dictionary.gif create mode 100644 samples/SearchableDictionary/res/layout/main.xml create mode 100644 samples/SearchableDictionary/res/layout/word.xml create mode 100644 samples/SearchableDictionary/res/raw/definitions.txt create mode 100644 samples/SearchableDictionary/res/values/strings.xml create mode 100644 samples/SearchableDictionary/res/xml/searchable.xml create mode 100644 samples/SearchableDictionary/src/com/example/android/searchabledict/Dictionary.java create mode 100644 samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java create mode 100644 samples/SearchableDictionary/src/com/example/android/searchabledict/SearchableDictionary.java create mode 100644 samples/SearchableDictionary/src/com/example/android/searchabledict/WordActivity.java diff --git a/build/sdk.atree b/build/sdk.atree index 4b7b4a90f..9136e5e6b 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -78,6 +78,7 @@ development/samples/SkeletonApp platforms/${PLATFORM_NAME}/samples/SkeletonApp development/samples/Snake platforms/${PLATFORM_NAME}/samples/Snake development/samples/SoftKeyboard platforms/${PLATFORM_NAME}/samples/SoftKeyboard development/samples/JetBoy platforms/${PLATFORM_NAME}/samples/JetBoy +development/samples/SearchableDictionary platforms/${PLATFORM_NAME}/samples/SearchableDictionary # dx bin/dx platforms/${PLATFORM_NAME}/tools/dx diff --git a/samples/SearchableDictionary/Android.mk b/samples/SearchableDictionary/Android.mk new file mode 100755 index 000000000..8c5fdf489 --- /dev/null +++ b/samples/SearchableDictionary/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := samples + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_SDK_VERSION := current + +LOCAL_PACKAGE_NAME := SearchableDictionary + +include $(BUILD_PACKAGE) diff --git a/samples/SearchableDictionary/AndroidManifest.xml b/samples/SearchableDictionary/AndroidManifest.xml new file mode 100644 index 000000000..93cd47beb --- /dev/null +++ b/samples/SearchableDictionary/AndroidManifest.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/SearchableDictionary/res/drawable/ic_dictionary.gif b/samples/SearchableDictionary/res/drawable/ic_dictionary.gif new file mode 100644 index 0000000000000000000000000000000000000000..47cdfc2bb7a032dcc99ef823eb21c9ed2e2f1fc7 GIT binary patch literal 1132 zcmV-y1e5zmNk%w1VITk?0OkMyuqh0Sz1CQw%&$i;=j-g`ql%fUt|?AcCvlkeka9bU zyZu%$agLNKe6klqP)&fBm&M)(I!tM##W8`j;Lf@HQ!SE+e$8S?5KCnzc&*Tnce>*E z|7u6Q*x)57D(~pk*j6{Ey1mia+gyEwdbQS&#^v^NQ$>@)S#)=YD;98}wfp<~VX4tb zjI`e5? zdtQ>K$j{0-C?&?w(!_pdMNU!cQ!%a4@5x_^90AzM(dX&XOg$fJC zxVaW4!iXejoREM3Ax#kl7*K3tfF#d?3LK^Y96<+72Nops=t&bqL69R3zC4nF+I=(!8eW^V8d(`xG{hb4&()f1pd_o-~>7xVMRTSWbp!mWAtH!2U}Fp zf(imixZVUPX0SsDjxZqGNgP~Ygb+tm5d;_lsHX#a6Ex6(MUI5<#7QVEVT2J5FcpKz z1Sgz`qK^#-Mnoeb?4SV*3%D`G3?F6?#1>$jz+;aMWYEA7NN86G0agqELjrJKVZ<78 z1fjzNKA=dZnP}diQz2~4SAiEW5VJ-E3g{q(5(+?RrW|72z(|WvfPfMVAiRKt6$t2% z!2^w&nE?i3Fz}}%1UNuRA5C}=fdO2|QKl3Mh#CPB?``5jD?3=hhb}cZAVCXrw2;AN yTu8NxAaRJm%pV~jVOJS3pm~6r%Q~{c2x9CIK?Gv(@kX|)7*N9jHRS3@AOJfzP~GVO literal 0 HcmV?d00001 diff --git a/samples/SearchableDictionary/res/layout/main.xml b/samples/SearchableDictionary/res/layout/main.xml new file mode 100644 index 000000000..d0dd52274 --- /dev/null +++ b/samples/SearchableDictionary/res/layout/main.xml @@ -0,0 +1,37 @@ + + + + + + + + + diff --git a/samples/SearchableDictionary/res/layout/word.xml b/samples/SearchableDictionary/res/layout/word.xml new file mode 100644 index 000000000..ba1a3daf6 --- /dev/null +++ b/samples/SearchableDictionary/res/layout/word.xml @@ -0,0 +1,39 @@ + + + + + + diff --git a/samples/SearchableDictionary/res/raw/definitions.txt b/samples/SearchableDictionary/res/raw/definitions.txt new file mode 100644 index 000000000..e4e1cbda6 --- /dev/null +++ b/samples/SearchableDictionary/res/raw/definitions.txt @@ -0,0 +1,997 @@ +abbey - n. a monastery ruled by an abbot +abide - v. dwell; inhabit or live in +abound - v. be abundant or plentiful; exist in large quantities +absence - n. the state of being absent +absorb - v. assimilate or take in +abstinence - n. practice of refraining from indulging an appetite especially alcohol +absurd - j. inconsistent with reason or logic or common sense +abundant - j. present in great quantity +abusive - j. characterized by physical or psychological maltreatment +academic - j. associated with school or learning +academy - n. a school for special training +accept - v. consider or hold as true +access - v. reach or gain access to +accessible - j. easily obtained +acclaim - n. enthusiastic approval +accommodate - v. provide with something desired or needed +accompany - v. go or travel along with +accomplish - v. to gain with effort +account - v. furnish a justifying analysis or explanation +accurate - j. conforming exactly or almost exactly to fact or to a standard or performing with total accuracy +accusation - n. an assertion that someone is guilty of a fault or offence +accuse - v. blame for, make a claim of wrongdoing or misbehavior against +acid - j. biting, sarcastic, or scornful +acknowledge - v. declare to be true or admit the existence or reality or truth of +acquire - v. come into the possession of something concrete or abstract +acquisition - n. something acquired or received +adamant - j. impervious to pleas, persuasion, requests, reason +adjacent - j. having a common boundary or edge; abutting; touching +administrator - n. someone who manages a government agency or department +advent - n. arrival that has been awaited (especially of something momentous) +adverse - j. contrary to your interests or welfare +advisory - n. an announcement that usually advises or warns the public of some threat +advocacy - n. active support of an idea or cause etc.; especially the act of pleading or arguing for something +advocate - v. speak, plead, or argue in favor of +affect - n. the conscious subjective aspect of feeling or emotion +affirmative - j. affirming or giving assent +aggression - n. violent action that is hostile and usually unprovoked +airy - j. not practical or realizable; speculative +album - n. a book of blank pages with pockets or envelopes; for organizing photographs or stamp collections etc +alcohol - n. a liquor or brew containing alcohol as the active agent +alien - j. being or from or characteristic of another place or part of the world +allegiance - n. the loyalty that citizens owe to their country (or subjects to their sovereign) +alley - n. a narrow street with walls on both sides +alliance - n. a formal agreement establishing an association or alliance between nations or other groups to achieve a particular aim +ally - n. an associate who provides cooperation or assistance +altar - n. a raised structure on which gifts or sacrifices to a god are made +alter - v. cause to change; make different; cause a transformation +alternate - j. serving or used in place of another +alternative - j. serving or used in place of another +altitude - n. elevation especially above sea level or above the earth's surface +amateur - j. lacking professional skill or expertise +ambiguous - j. having more than one possible meaning +ambitious - j. having a strong desire for success or achievement +ambivalent - j. uncertain or unable to decide about what course to follow +analogy - n. drawing a comparison in order to show a similarity in some respect +analyst - n. someone who is skilled at analyzing data +analyze - v. break down into components or essential features +anchor - v. fix firmly and stably +annual - j. occurring or payable every year +anonymous - j. having no known name or identity or known source +antichrist - n. the adversary of Christ (or Christianity) mentioned in the New Testament +antique - j. made in or typical of earlier times and valued for its age +anxious - j. causing or fraught with or showing anxiety +apartheid - n. a social policy or racial segregation involving political and economic and legal discrimination against people who are not Whites +apocalyptic - j. prophetic of devastation or ultimate doom +apology - n. an expression of regret at having caused trouble for someone +apparel - n. clothing in general +apparent - j. clearly revealed to the mind or the senses or judgment +appease - v. make peace with +appropriate - j. suitable for a particular person or place or condition etc +apt - j. being of striking appropriateness and pertinence +arbitrary - j. based on or subject to individual discretion or preference or sometimes impulse or caprice +arcade - n. a covered passageway with shops and stalls on either side +arrange - v. put into a proper or systematic order +arrangement - n. an orderly grouping (of things or persons) considered as a unit; the result of arranging +arrival - n. the act of arriving at a certain place +arrogance - n. overbearing pride evidenced by a superior manner toward inferiors +arrogant - j. having or showing feelings of unwarranted importance out of overbearing pride +articulate - j. expressing yourself easily or characterized by clear expressive language +assassination - n. murder of a public figure by surprise attack +assess - v. set or determine the amount of (a payment such as a fine) +assets - n. anything of material value or usefulness that is owned by a person or company +asylum - n. a shelter from danger or hardship +auburn - j. (of hair) colored a moderate reddish-brown +august - j. profoundly honored +aura - n. a distinctive but intangible quality surrounding a person or thing +austere - j. of a stern or strict bearing or demeanor; forbidding in aspect +authentic - j. not counterfeit or copied +authenticity - n. undisputed credibility +authoritarian - n. a person who behaves in a tyrannical manner +autobiography - n. a biography of yourself +autonomous - j. existing as an independent entity +autonomy - n. immunity from arbitrary exercise of authority: political independence +avid - j. marked by active interest and enthusiasm +banal - j. repeated too often; over familiar through overuse +barring - n. the act of excluding someone by a negative vote or veto +bass - n. the lowest adult male singing voice +batter - n. a liquid or semiliquid mixture, as of flour, eggs, and milk, used in cooking +belle - n. a young woman who is the most charming and beautiful of several rivals +beneficial - j. promoting or enhancing well-being +benefit - n. something that aids or promotes well-being +benign - j. not dangerous to health; not recurrent or progressive (especially of a tumor) +bid - n. a formal proposal to buy at a specified price +biography - n. an account of the series of events making up a person's life +biology - n. the science that studies living organisms +blaze - n. a strong flame that burns brightly +bleak - j. unpleasantly cold and damp +bogus - j. fraudulent; having a misleading appearance +bolster - v. support and strengthen +bomb - n. an explosive device fused to explode under specific conditions +bore - n. a person who evokes boredom +botanical - j. of or relating to plants or botany +boycott - n. a group's refusal to have commercial dealings with some organization in protest against its policies +brass - n. an alloy of copper and zinc +breach - n. an opening (especially a gap in a dike or fortification) +broadcast - n. message that is transmitted by radio or television +brokerage - n. the business of a broker; charges a fee to arrange a contract between two parties +buffet - n. a meal set out on a buffet at which guests help themselves +bumper - n. a mechanical device consisting of bars at either end of a vehicle to absorb shock and prevent serious damage +bureau - n. an administrative unit of government +bureaucracy - n. non elected government officials +butt - v. to strike, thrust or shove against +cabinet - n. persons appointed by a head of state to head executive departments of government and act as official advisers +caliber - n. a degree or grade of excellence or worth +campaign - n. a series of actions advancing a principle or tending toward a particular end +canon - n. a rule or especially body of rules or principles generally established as valid and fundamental in a field or art or philosophy +cardinal - j. serving as an essential component +caricature - n. a representation of a person that is exaggerated for comic effect +casual - j. without or seeming to be without plan or method; offhand +catastrophe - n. an event resulting in great loss and misfortune +caucus - n. a closed political meeting +causal - j. involving or constituting a cause; causing +censure - n. harsh criticism or disapproval +census - n. a periodic count of the population +cereal - n. grass whose starchy grains are used as food: wheat; rice; rye; oats; maize; buckwheat; millet +ceremonial - j. marked by pomp or ceremony or formality +chaos - n. a state of extreme confusion and disorder +characteristic - n. a distinguishing quality +chronic - j. being long-lasting and recurrent or characterized by long suffering +citadel - n. a stronghold into which people could go for shelter during a battle +cite - v. refer to for illustration or proof +clumsy - j. not elegant or graceful in expression +coalition - n. an organization of people (or countries) involved in a pact or treaty +coherent - j. marked by an orderly, logical, and aesthetically consistent relation of parts +coincidence - n. the temporal property of two things happening at the same time +collapse - v. break down, literally or metaphorically +colleague - n. an associate that one works with +collective - j. set up on the principle of collectivism or ownership and production by the workers involved usually under the supervision of a government +collector - n. a person who collects things +collision - n. an accident resulting from violent impact of a moving object +commemorate - v. mark by some ceremony or observation +commentary - n. a written explanation or criticism or illustration that is added to a book or other textual material +commission - n. a special group delegated to consider some matter +commitment - n. the act of binding yourself (intellectually or emotionally) to a course of action +commodity - n. articles of commerce +commute - n. a regular journey of some distance to and from your place of work +comparable - j. able to be compared or worthy of comparison +comparison - n. the act of examining resemblances +compassionate - j. showing or having compassion +compensate - v. make payment to; compensate +competence - n. the quality of being adequately or well qualified physically and intellectually +competent - j. properly or sufficiently qualified or capable or efficient +competitive - j. involving competition or competitiveness +competitor - n. the contestant you hope to defeat +complex - j. complicated in structure; consisting of interconnected parts +component - n. an artifact that is one of the individual parts of which a composite entity is made up; especially a part that can be separated from or attached to a system +composer - n. someone who composes music as a profession +comprehensive - j. broad in scope +concede - v. admit (to a wrongdoing) +conceive - v. have the idea for +concession - n. a point conceded or yielded +confederate - j. united in a group or league +confidence - n. a state of confident hopefulness that events will be favorable +confident - j. having or marked by confidence or assurance +confront - v. oppose, as in hostility or a competition +conscience - n. a feeling of shame when you do something immoral +conscious - j. knowing and perceiving; having awareness of surroundings and sensations and thoughts +consecutive - j. one after the other +consensus - n. agreement in the judgment or opinion reached by a group as a whole +conservatism - n. a political or theological orientation advocating the preservation of the best in society and opposing radical changes +conservative - j. avoiding excess +consistency - n. a harmonious uniformity or agreement among things or parts +conspicuous - j. obvious to the eye or mind +conspiracy - n. a plot to carry out some harmful or illegal act (especially a political plot) +constituency - n. the body of voters who elect a representative for their area +consume - v. use up (resources or materials) +consumer - n. a person who uses goods or services +consumption - n. the process of taking food into the body through the mouth +contemplate - v. look at thoughtfully; observe deep in thought +contemporary - j. belonging to the present time +contender - n. the contestant you hope to defeat +contentious - j. inclined or showing an inclination to dispute or disagree, even to engage in law suits +contingent - j. possible but not certain to occur +continuous - j. continuing in time or space without interruption +contradiction - n. opposition between two conflicting forces or ideas +contradictory - j. unable for both to be true at the same time +contribution - n. a voluntary gift (as of money or service or ideas) made to some worthwhile cause +contributor - n. someone who contributes (or promises to contribute) a sum of money +convenience - n. the quality of being useful and convenient +conversion - n. the act of changing from one use or function or purpose to another +convertible - j. designed to be changed from one use or form to another +conviction - n. an unshakable belief in something without need for proof or evidence +corporate - j. of or belonging to a corporation +corps - n. a body of people associated together +corruption - n. destroying someone's (or some group's) honesty or loyalty; undermining moral integrity +cosmetic - j. serving an esthetic rather than a useful purpose +cosmopolitan - j. of worldwide scope or applicability +counsel - n. something that provides direction or advice as to a decision or course of action +counterpart - n. a person or thing having the same function or characteristics as another +courageous - j. able to face and deal with danger or fear without flinching +course - n. a connected series of events or actions or developments +courtesy - n. a courteous or respectful or considerate act +credible - j. appearing to merit belief or acceptance +critique - n. a serious examination and judgment of something +crusade - v. exert oneself continuously, vigorously, or obtrusively to gain an end or engage in a crusade for a certain cause or person; be an advocate for +crush - v. to compress with violence, out of natural shape or condition +curator - n. the custodian of a collection (as a museum or library) +curriculum - n. an integrated course of academic studies +cynical - j. believing the worst of human nature and motives; having a sneering disbelief in e.g. selflessness of others +cynicism - n. a cynical feeling of distrust +daring - n. the trait of being willing to undertake things that involve risk or danger +debacle - n. a sudden and violent collapse +debut - v. appear for the first time in public +decay - n. the organic phenomenon of rotting +decency - n. the quality of conforming to standards of propriety and morality +decent - j. socially or conventionally correct; refined or virtuous +decisive - j. characterized by decision and firmness +decree - n. a legally binding command or decision entered on the court record (as if issued by a court or judge) +dedication - n. complete and wholehearted fidelity +default - n. loss due to not showing up +defendant - n. a person or institution against whom an action is brought in a court of law; the person being sued or accused +defensive - j. attempting to justify or defend in speech or writing +defiance - n. a hostile challenge +definite - j. known for certain +delicacy - n. something considered choice to eat +demise - v. transfer by a lease or by a will +demonstrate - v. establish the validity of something, as by an example, explanation or experiment +denominator - n. the divisor of a fraction +deposition - n. (law) a pretrial interrogation of a witness; usually conducted in a lawyer's office +depression - n. a long-term economic state characterized by unemployment and low prices and low levels of trade and investment +depth - n. the attribute or quality of being deep, strong, or intense +derive - v. come from +descent - n. properties attributable to your ancestry +desert - n. arid land with little or no vegetation +designate - v. give an assignment to (a person) to a post, or assign a task to (a person) +despair - n. a state in which all hope is lost or absent +desperate - j. showing extreme urgency or intensity especially because of great need or desire +detect - v. discover or determine the existence, presence, or fact of +deter - v. try to prevent; show opposition to +determination - n. the quality of being determined to do or achieve something; firmness of purpose +deterrent - j. tending to deter +diagnosis - n. identifying the nature or cause of some phenomenon +dialogue - n. a discussion intended to produce an agreement +difference - n. the quality of being unlike or dissimilar +dignity - n. the quality of being worthy of esteem or respect +dilemma - n. state of uncertainty or perplexity especially as requiring a choice between equally unfavorable options +diplomacy - n. subtly skillful handling of a situation +diplomat - n. a person who deals tactfully with others +diplomatic - j. using or marked by tact in dealing with sensitive matters or people +disagree - v. be of different opinions +disappear - v. become invisible or unnoticeable +discern - v. detect with the senses +discipline - n. a system of rules of conduct or method of practice +discomfort - n. the state of being tense and feeling pain +discourse - n. extended verbal expression in speech or writing +discover - v. see for the first time; make a discovery +discriminate - v. treat differently on the basis of sex or race +discussion - n. an exchange of views on some topic +disdain - n. lack of respect accompanied by a feeling of intense dislike +dishonest - j. deceptive or fraudulent; disposed to cheat or defraud or deceive +dismal - j. causing dejection +dismay - v. fill with apprehension or alarm; cause to be unpleasantly surprised +dismissal - n. the termination of someone's employment (leaving them free to depart) +disparity - n. inequality or difference in some respect +disregard - n. willful lack of care and attention +dissent - n. a difference of opinion +distant - j. separated in space or coming from or going to a distance +distinction - n. a distinguishing difference +distress - n. extreme physical pain +distrust - v. regard as untrustworthy; regard with suspicion; have no faith or confidence in +diverse - j. many and different +diversion - n. an activity that diverts or amuses or stimulates +diversity - n. noticeable heterogeneity +divert - v. turn aside; turn away from +document - n. writing that provides information (especially information of an official nature) +doe - n. mature female of mammals of which the male is called 'buck' +domain - n. territory over which rule or control is exercised +dominance - n. the state that exists when one person or group has power over another +dominant - j. exercising influence or control +dominate - v. be in control +domination - n. social control by dominating +donate - v. give to a charity or good cause +donor - n. person who makes a gift of property +drastic - j. forceful and extreme and rigorous +drought - n. a shortage of rainfall +dubious - j. open to doubt or suspicion +dynamics - n. the branch of mechanics concerned with the forces that cause motions of bodies +earnest - j. characterized by a firm and humorless belief in the validity of your opinions +eccentric - n. a person with an unusual or odd personality +eclectic - j. selecting what seems best of various styles or ideas +editorial - n. an article giving opinions or perspectives +effect - n. a phenomenon that follows and is caused by some previous phenomenon +effective - j. works well as a means or remedy +efficiency - n. skillfulness in avoiding wasted time and effort +efficient - j. able to accomplish a purpose; functioning effectively +elaborate - v. add details, as to an account or idea; clarify the meaning of and discourse in a learned way, usually in writing +element - n. any of the more than 100 known substances (of which 92 occur naturally) that cannot be separated into simpler substances and that singly or in combination constitute all matter +eligible - j. qualified for or allowed or worthy of being chosen +eliminate - v. terminate, end, or take out +embargo - n. a government order imposing a trade barrier +emblem - n. a visible symbol representing an abstract idea +embrace - n. the act of clasping another person in the arms (as in greeting or affection) +emerge - v. come out into view, as from concealment +emergence - n. the gradual beginning or coming forth +eminent - j. of imposing height; especially standing out above others +emphasis - n. intensity or forcefulness of expression +emphasize - v. to stress, single out as important +employee - n. a worker who is hired to perform a job +employer - n. a person or firm that employs workers +emulate - v. imitate the function of (another system), as by modifying the hardware or the software +enact - v. order by virtue of superior authority; decree +encourage - v. inspire with confidence; give hope or courage to +encyclopedia - n. a reference work (often in several volumes) containing articles on various topics +endorse - v. be behind; approve of +enduring - j. patiently bearing continual wrongs or trouble +energetic - j. possessing or exerting or displaying energy +enhance - v. make better or more attractive +enormous - j. extraordinarily large in size or extent or amount or power or degree +enthusiastic - j. having or showing great excitement and interest +entity - n. that which is perceived or known or inferred to have its own distinct existence (living or nonliving) +epic - j. very imposing or impressive; surpassing the ordinary (especially in size or scale) +epidemic - n. a widespread outbreak of an infectious disease; many people are infected at the same time +episode - n. a brief section of a literary or dramatic work that forms part of a connected series +equilibrium - n. a stable situation in which forces cancel one another +equity - n. the difference between the market value of a property and the claims held against it +equivalent - j. being essentially equal to something +error - n. a wrong action attributable to bad judgment or ignorance or inattention +esquire - n. a title of respect for a member of the English gentry ranking just below a knight; placed after the name +essence - n. the central meaning or theme of a speech or literary work +evangelical - j. relating to or being a Christian church believing in personal conversion and the inerrancy of the Bible especially the 4 Gospels +evoke - v. call to mind +evolution - n. a process in which something passes by degrees to a different stage (especially a more advanced or mature stage) +exceed - v. be greater in scope or size than some standard +excellent - j. very good; of the highest quality +excerpt - n. a passage selected from a larger work +excess - j. more than is needed, desired, or required +exclude - v. prevent from being included or considered or accepted +excursion - n. a journey taken for pleasure +exempt - v. grant relief or an exemption from a rule or requirement to +existence - n. everything that exists anywhere +exit - v. move out of or depart from +exotic - j. strikingly strange or unusual +expand - v. become larger in size or volume or quantity +expansion - n. the act of increasing (something) in size or volume or quantity or scope +expect - v. regard something as probable or likely +expectancy - n. something expected (as on the basis of a norm) +expense - n. money spent to perform work and usually reimbursed by an employer +expertise - n. skillfulness by virtue of possessing special knowledge +explicit - j. precisely and clearly expressed or readily observable; leaving nothing to implication +explode - v. drive from the stage by noisy disapproval +exploit - v. use or manipulate to one's advantage +explosion - n. the act of exploding or bursting +explosive - n. a chemical substance that undergoes a rapid chemical change (with the production of gas) on being heated or struck +exposure - n. vulnerability to the elements; to the action of heat or cold or wind or rain +expressive - j. characterized by expression +extension - n. an addition to the length of something +extensive - j. large in spatial extent or range or scope or quantity +exterior - n. the outer side or surface of something +external - j. happening or arising or located outside or beyond some limits or especially surface +extradition - n. the surrender of an accused or convicted person by one state or country to another (usually under the provisions of a statute or treaty) +extraordinary - j. beyond what is ordinary or usual; highly unusual or exceptional or remarkable +extravagant - j. unrestrained, especially with regard to feelings +exuberant - j. joyously unrestrained +fabulous - j. extremely pleasing +facial - j. of or concerning the face +facility - n. something designed and created to serve a particular function and to afford a particular convenience or service +faction - n. a dissenting clique +faulty - j. characterized by errors; not agreeing with a model or not following established rules +feasible - j. capable of being done with means at hand and circumstances as they are +felony - n. a serious crime (such as murder or arson) +feminine - j. associated with women and not with men +fervor - n. the state of being emotionally aroused and worked up +fetus - n. an unborn or unhatched vertebrate in the later stages of development showing the main recognizable features of the mature animal +feud - n. a bitter quarrel between two parties +feudal - j. of or relating to or characteristic of feudalism +fidelity - n. the quality of being faithful +finale - n. the concluding part of any performance +finite - j. bounded or limited in magnitude or spatial or temporal extent +fiscal - j. involving financial matters +flag - n. emblem usually consisting of a rectangular piece of cloth of distinctive design +flamboyant - j. marked by ostentation but often tasteless +fleet - n. a group of warships organized as a tactical unit +flexible - j. able to flex; able to bend easily +flop - n. a complete failure +flourish - n. a showy gesture +foil - n. anything that serves by contrast to call attention to another thing's good qualities +ford - v. cross a river where it's shallow +forecast - n. a prediction about how something (as the weather) will develop +foreign - j. relating to or originating in or characteristic of another place or part of the world +foresee - v. act in advance of; deal with ahead of time +formation - n. an arrangement of people or things acting as a unit +formidable - j. extremely impressive in strength or excellence +formula - n. directions for making something +forte - n. an asset of special worth or utility +forth - a. forward in time or order or degree +foster - v. promote the growth of +fragile - j. easily broken or damaged or destroyed +frantic - j. excessively agitated; distraught with fear or other violent emotion +fray - v. wear away by rubbing +frequency - n. the number of occurrences within a given time period +fringe - n. a social group holding marginal or extreme views +frivolous - j. not serious in content or attitude or behavior +frontier - n. a wilderness at the edge of a settled area of a country +fundamental - j. being or involving basic facts or principles +further - v. promote the growth of +futile - j. producing no result or effect +galaxy - n. (astronomy) a collection of star systems; any of the billions of systems each having many stars and nebulae and dust +gamble - v. take a risk in the hope of a favorable outcome +gauge - n. a measuring instrument for measuring and indicating a quantity such as the thickness of wire or the amount of rain etc. +generate - v. bring into existence +generic - j. applicable to an entire class or group +generosity - n. the trait of being willing to give your money or time +genesis - n. the first book of the Old Testament: tells of Creation; Adam and Eve; Cain and Abel +gesture - n. motion of hands or body to emphasize or help to express a thought or feeling +gigantic - j. so exceedingly large or extensive as to suggest a giant or mammoth +gist - n. the choicest or most essential or most vital part of some idea or experience +glimpse - n. a brief or incomplete view +glorious - j. having great beauty and splendor +grandeur - n. the quality of being magnificent or splendid or grand +grandiose - j. impressive because of unnecessary largeness or grandeur; used to show disapproval +grave - j. of great gravity or crucial import; requiring serious thought +gravity - n. a manner that is serious and solemn +grief - n. something that causes great unhappiness +grotesque - j. distorted and unnatural in shape or size; abnormal and hideous +grove - n. a small growth of trees without underbrush +guise - n. an artful or simulated semblance +hack - n. a mediocre and disdained writer +hale - j. exhibiting or restored to vigorous good health +handwriting - n. something written by hand +harbor - v. hold back a thought or feeling about +hazard - n. a source of danger; a possibility of incurring loss or misfortune +heir - n. a person who is entitled by law or by the terms of a will to inherit the estate of another +heritage - n. practices that are handed down from the past by tradition +hilarious - j. marked by or causing boisterous merriment or convulsive laughter +hollow - j. not solid; having a space or gap or cavity +homage - n. respectful deference +hostility - n. violent action that is hostile and usually unprovoked +humane - j. marked or motivated by concern with the alleviation of suffering +humanitarian - n. someone devoted to the promotion of human welfare and to social reforms +hush - v. become quiet or still; fall silent +hybrid - n. (genetics) an organism that is the offspring of genetically dissimilar parents or stock; especially offspring produced by breeding plants or animals of different varieties or breeds or species +hypocrisy - n. insincerity by virtue of pretending to have qualities or beliefs that you do not really have +hypothesis - n. a tentative insight into the natural world; a concept that is not yet verified but that if true would explain certain facts or phenomena +hysteria - n. excessive or uncontrollable fear +icon - n. a conventional religious painting in oil on a small wooden panel; venerated in the Eastern Church +ideology - n. an orientation that characterizes the thinking of a group or nation +illusion - n. an erroneous mental representation +imaginary - j. not based on fact; unreal +imitation - n. something copied or derived from an original +immense - j. unusually great in size or amount or degree or especially extent or scope +immigrant - n. a person who comes to a country where they were not born in order to settle there +imminent - j. close in time; about to occur +immoral - j. not adhering to ethical or moral principles +immune - j. (usually followed by 'to') not affected by a given influence +impending - j. close in time; about to occur +implausible - j. having a quality that provokes disbelief +implicit - j. implied though not directly expressed; inherent in the nature of something +imply - v. express or state indirectly +impose - v. compel to behave in a certain way +improper - j. not suitable or right or appropriate +impulse - n. a sudden desire +inadequate - j. not sufficient to meet a need +incentive - n. a positive motivational influence +incidence - n. the relative frequency of occurrence of something +incident - n. a public disturbance +incidentally - a. of a minor or subordinate nature +inclined - j. at an angle to the horizontal or vertical position +incompetence - n. lack of physical or intellectual ability or qualifications +inconsistent - j. displaying a lack of consistency +inconvenient - j. not suited to your comfort, purpose or needs +indefinitely - a. to an indefinite extent; for an indefinite time +indicator - n. a device for showing the operating condition of some system +indifferent - j. showing no care or concern in attitude or action +indigenous - j. originating where it is found +indulge - v. enjoy to excess +inefficient - j. not producing desired results; wasteful +inept - j. generally incompetent and ineffectual +inevitable - j. incapable of being avoided or prevented +inexpensive - j. relatively low in price or charging low prices +infamous - j. known widely and usually unfavorably +infinite - j. having no limits or boundaries in time or space or extent or magnitude +influence - n. a power to affect persons or events especially power based on prestige etc +influential - j. having or exercising influence or power +influx - n. the process of flowing in +ingenious - j. showing inventiveness and skill +inherent - j. in the nature of something though not readily apparent +injunction - n. (law) a judicial remedy issued in order to prohibit a party from doing or continuing to do a certain activity +inland - a. towards or into the interior of a region +insight - n. the clear (and often sudden) understanding of a complex situation +insistence - n. the state of demanding notice or attention +inspector - n. a high ranking police officer +instance - n. an occurrence of something +instant - n. a very short time +insufficient - j. of a quantity not able to fulfill a need or requirement +integral - j. essential to completeness; lacking nothing +integrity - n. moral soundness +intellectual - j. appealing to or using the intellect +intelligence - n. the ability to comprehend; to understand and profit from experience +intensive - j. characterized by a high degree or intensity; often used as a combining form +intention - n. an act of intending; a volition that you intend to carry out +interact - v. act together or towards others or with others +interim - n. the time between one event, process, or period and another +intermediate - j. lying between two extremes in time or space or state +intervene - v. get involved, so as to alter or hinder an action, or through force or threat of force +intervention - n. the act of intervening (as to mediate a dispute, etc.) +intimacy - n. close or warm friendship +intricate - j. having many complexly arranged elements; elaborate +invasion - n. any entry into an area not previously occupied +inventive - j. (used of persons or artifacts) marked by independence and creativity in thought or action +investigator - n. a police officer who investigates crimes +investor - n. someone who commits capital in order to gain financial returns +invincible - j. incapable of being overcome or subdued +invoke - v. cite as an authority; resort to +involuntary - j. not subject to the control of the will +involve - v. engage as a participant +irony - n. incongruity between what might be expected and what actually occurs +irrational - j. not consistent with or using reason +irrelevant - j. having no bearing on or connection with the subject at issue +irresistible - j. impossible to resist; overpowering +irresponsible - j. showing lack of care for consequences +judgment - n. the capacity to assess situations or circumstances shrewdly and to draw sound conclusions +judicial - j. belonging or appropriate to the office of a judge +juicy - j. lucrative +junction - n. something that joins or connects +jurisdiction - n. (law) the right and power to interpret and apply the law +juror - n. someone who serves (or waits to be called to serve) on a jury +justification - n. something (such as a fact or circumstance) that shows an action to be reasonable or necessary +juvenile - j. of or relating to or characteristic of or appropriate for children or young people +ken - n. range of what one can know or understand +knight - n. originally a person of noble birth trained to arms and chivalry; today in Great Britain a person honored by the sovereign for personal merit +knit - n. needlework created by interlacing yarn in a series of connected loops using straight eyeless needles or by machine +lament - v. regret strongly +landmark - n. the position of a prominent or well-known object in a particular landscape +landscape - n. an expanse of scenery that can be seen in a single view +lapse - n. a break or intermission in the occurrence of something +laureate - n. someone honored for great achievements; figuratively someone crowned with a laurel wreath +lavish - j. very generous +lax - j. lacking in rigor or strictness +legacy - n. (law) a gift of personal property by will +legislative - j. relating to a legislature or composed of members of a legislature +legitimacy - n. lawfulness by virtue of being authorized or in accordance with law +legitimate - j. in accordance with recognized or accepted standards or principles +leisure - n. time available for ease and relaxation +lenient - j. not strict +levy - v. impose and collect +liable - j. held legally responsible +liberalism - n. a political orientation that favors social progress by reform and by changing laws rather than by revolution +lifelong - j. continuing through life +lifetime - n. the period during which something is functional (as between birth and death) +likelihood - n. the probability of a specified outcome +liking - n. a feeling of pleasure and enjoyment +liquor - n. an alcoholic beverage that is distilled rather than fermented +literacy - n. the ability to read and write +literal - j. avoiding embellishment or exaggeration (used for emphasis) +literature - n. creative writing of recognized artistic value +logic - n. the principles that guide reasoning within a given field or situation +logical - j. capable of thinking and expressing yourself in a clear and consistent manner +lovable - j. having characteristics that attract love or affection +lucrative - j. producing a sizeable profit +ludicrous - j. broadly or extravagantly humorous; resembling farce +lying - n. the deliberate act of deviating from the truth +machinery - n. machines or machine systems collectively +magnet - n. (physics) a device that attracts iron and produces a magnetic field +magnificent - j. characterized by grandeur +magnitude - n. the property of relative size or extent (whether large or small) +maintain - v. state or assert +maintenance - n. activity involved in maintaining something in good working order +makeup - n. the way in which someone or something is composed +mandate - n. an authorization to act given to a representative +mandatory - j. required by rule +maneuver - v. act in order to achieve a certain goal +manifesto - n. a public declaration of intentions (as issued by a political party or government) +marine - j. native to or inhabiting the sea +maritime - j. relating to or involving ships or shipping or navigation or seamen +martial - j. suggesting war or military life +marvel - v. be amazed at +massacre - n. the savage and excessive killing of many people +massive - j. imposing in size or bulk or solidity +masterpiece - n. the most outstanding work of a creative artist or craftsman +material - j. concerned with worldly rather than spiritual interests +maternal - j. relating to or derived from one's mother +maze - n. complex system of paths or tunnels in which it is easy to get lost +mechanics - n. the technical aspects of doing something +medicine - n. something that treats or prevents or alleviates the symptoms of disease +medieval - j. as if belonging to the Middle Ages; old-fashioned and unenlightened +mediocre - j. moderate to inferior in quality +meditation - n. continuous and profound contemplation or musing on a subject or series of subjects of a deep or abstruse nature +melodrama - n. an extravagant comedy in which action is more salient than characterization +memorable - j. worth remembering +menace - v. act in a threatening manner +mentality - n. a habitual or characteristic mental attitude that determines how you will interpret and respond to situations +mentor - v. serve as a teacher or trusted counselor +metal - n. any of several chemical elements that are usually shiny solids +metaphor - n. a figure of speech in which an expression is used to refer to something that it does not literally denote in order to suggest a similarity +metric - j. based on the meter as a standard of measurement +metropolis - n. a large and densely populated urban area; may include several independent administrative districts +metropolitan - j. relating to or characteristic of a densely populated urban area +mileage - n. the ratio of the number of miles traveled to the number of gallons of gasoline burned; miles per gallon +militant - j. disposed to warfare or hard-line policies +militia - n. civilians trained as soldiers but not part of the regular army +miniature - j. being on a very small scale +minimize - v. make small or insignificant +ministry - n. a government department under the direction of a minister +minority - n. being or relating to the smaller in number of two parts +minute - j. infinitely or immeasurably small +misdemeanor - n. a crime less serious than a felony +missile - n. a rocket carrying a warhead of conventional or nuclear explosives +momentum - n. an impelling force or strength +monarchy - n. an autocracy governed by a monarch who usually inherits the authority +monastery - n. the residence of a religious community +monetary - j. relating to or involving money +monopoly - n. (economics) a market in which there are many buyers but only one seller +morale - n. the spirit of a group that makes the members want the group to succeed +morality - n. concern with the distinction between good and evil or right and wrong; right or good conduct +motto - n. a favorite saying of a sect or political group +mundane - j. concerned with the world or worldly matters; ordinary +municipal - j. relating to city government +muster - v. gather or bring together +myriad - n. a large indefinite number +myth - n. a traditional story accepted as history; serves to explain the world view of a people +mythology - n. myths collectively; the body of stories associated with a culture or institution or person +narrative - n. a message that tells the particulars of an act or occurrence or course of events; presented in writing or drama or cinema or as a radio or television program +narrator - n. someone who tells a story +naturally - a. according to nature; by natural means; without artificial help +naval - j. connected with or belonging to or used in a navy +necessary - j. absolutely essential +necessity - n. anything indispensable +network - n. an interconnected system of things or people +neutral - j. having no personal preference +nevertheless - a. despite anything to the contrary (usually following a concession) +noisy - j. full of or characterized by loud and nonmusical sounds +nomination - n. the condition of having been proposed as a suitable candidate for appointment or election +nominee - n. a politician who is running for public office +norm - n. a standard or model or pattern regarded as typical +notorious - j. known widely and usually unfavorably +nude - n. without clothing (especially in the phrase 'in the nude') +obesity - n. more than average fatness +objective - j. undistorted by emotion or personal bias; based on observable phenomena +observatory - n. a building designed and equipped to observe astronomical phenomena +obsolete - j. no longer in use +obstruction - n. something that stands in the way and must be circumvented or surmounted +obtain - v. come into possession of +occasion - n. a vaguely specified social event +odor - n. the sensation that results when olfactory receptors in the nose are stimulated by particular chemicals in gaseous form +ominous - j. threatening or foreshadowing evil or tragic developments +operate - v. handle and cause to function +operator - n. an agent that operates some apparatus or machine +opinion - n. a personal belief or judgment that is not founded on proof or certainty +opponent - n. a contestant that you are matched against +opportunity - n. a possibility due to a favorable combination of circumstances +optimism - n. a general disposition to expect the best in all things +option - n. one of a number of things from which only one can be chosen +oral - j. of or relating to or affecting or for use in the mouth +ordeal - n. a severe or trying experience +ornate - j. marked by elaborate rhetoric and elaborated with decorative details +orthodox - j. adhering to what is commonly accepted +outbreak - n. a sudden violent spontaneous occurrence (usually of some undesirable condition) +outcry - n. a loud utterance; often in protest or opposition +outrage - n. a feeling of righteous anger +outrageous - j. grossly offensive to decency or morality; causing horror +outright - a. without reservation or concealment +overhaul - v. make repairs, renovations, revisions or adjustments to +oversee - v. watch and direct +overthrow - n. the termination of a ruler or institution (especially by force) +overweight - n. the property of excessive fatness +pact - n. a written agreement between two states or sovereigns +pageant - n. a rich and spectacular ceremony +panic - n. an overwhelming feeling of fear and anxiety +pantheon - n. all the gods of a religion +paradox - n. (logic) a statement that contradicts itself +parallel - j. being everywhere equidistant and not intersecting +parish - n. a local church community +parliament - n. a legislative assembly in certain countries +parody - v. make a spoof of or make fun of +participant - n. someone who takes part in an activity +participate - v. become a participant; be involved in +partisan - n. an ardent and enthusiastic supporter of some person or activity +partition - v. divide into parts, pieces, or sections +passive - j. lacking in energy or will +patriotism - n. love of country and willingness to sacrifice for it +patron - n. someone who supports or champions something +pavilion - n. large and often sumptuous tent +peaceful - j. not disturbed by strife or turmoil or war +pedestrian - j. lacking wit or imagination +penalty - n. a punishment for a crime or offense +penchant - n. a strong liking +pennant - n. a long flag; often tapering +pension - n. a regular payment to a person that is intended to allow them to subsist without working +pentagon - n. a five-sided polygon +perceive - v. to become aware of or conscious of +perception - n. becoming aware of something via the senses +perennial - j. lasting an indefinitely long time; suggesting self-renewal +perform - v. carry out or perform an action +perjury - n. criminal offense of making false statements under oath +permanent - j. continuing or enduring without marked change in status or condition or place +perpetual - j. continuing forever or indefinitely +persist - v. be persistent, refuse to stop +personal - j. concerning or affecting a particular person or his or her private life and personality +personality - n. the complex of all the attributes--behavioral, temperamental, emotional and mental--that characterize a unique individual +personnel - n. persons collectively in the employ of a business +perspective - n. the appearance of things relative to one another as determined by their distance from the viewer +persuade - v. cause somebody to adopt a certain position, belief, or course of action; twist somebody's arm +pervasive - j. spreading or spread throughout +petty - j. contemptibly narrow in outlook +phenomenal - j. exceedingly or unbelievably great +phenomenon - n. any state or process known through the senses rather than by intuition or reasoning +philharmonic - j. composing or characteristic of an orchestral group +philosophy - n. any personal belief about how to live or how to deal with a situation +physicist - n. a scientist trained in physics +physics - n. the science of matter and energy and their interactions +pinch - n. a squeeze with the fingers +pine - n. straight-grained white to yellowish tree +pioneer - v. open up and explore a new area +pivotal - j. being of crucial importance +plausible - j. apparently reasonable and valid, and truthful +playful - j. full of fun and high spirits +playwright - n. someone who writes plays +plea - n. a humble request for help from someone in authority +plead - v. appeal or request earnestly +pleasant - j. affording pleasure; being in harmony with your taste or likings +plunge - v. fall abruptly +poetic - j. of or relating to poetry +poignant - j. arousing emotions; touching +poised - j. in full control of your faculties +portfolio - n. a set of pieces of creative work collected to be shown to potential customers or employers +positive - j. characterized by or displaying affirmation or acceptance or certainty etc. +possess - v. have as an attribute, knowledge, or skill +possession - n. the act of having and controlling property +potent - j. having a strong physiological or chemical effect +potential - j. existing in possibility +precedent - n. an example that is used to justify similar occurrences at a later time +precise - j. sharply exact or accurate or delimited +precision - n. the quality of being reproducible in amount or performance +predecessor - n. one who precedes you in time (as in holding a position or office) +predict - v. make a prediction about; tell in advance +prediction - n. a statement made about the future +prefer - v. like better; value more highly +preference - n. a strong liking +prejudice - n. a partiality that prevents objective consideration of an issue or situation +premature - j. too soon or too hasty +premier - v. be performed for the first time +premise - v. set forth beforehand, often as an explanation +preparation - n. the activity of putting or setting in order in advance of some act or purpose +preposterous - j. incongruous; inviting ridicule +prescription - n. written instructions from a physician or dentist to a druggist concerning the form and dosage of a drug to be issued to a given patient +preservation - n. the activity of protecting something from loss or danger +pretentious - j. making claim to or creating an appearance of (often undeserved) importance or distinction +prevalent - j. most frequent or common +prevention - n. the act of preventing +primer - n. an introductory textbook +primitive - j. belonging to an early stage of technical development; characterized by simplicity and (often) crudeness +principal - n. the educator who has executive authority for a school +principle - n. a basic truth or law or assumption +principled - j. based on or manifesting objectively defined standards of rightness or morality +pristine - j. completely free from dirt or contamination +privilege - n. a special advantage or immunity or benefit not enjoyed by all +probation - n. (law) a way of dealing with offenders without imprisoning them; a defendant found guilty of a crime is released by the court without imprisonment subject to conditions imposed by the court +probe - v. question or examine thoroughly and closely +procedure - n. a process or series of acts especially of a practical or mechanical nature involved in a particular form of work +proceed - v. move ahead; travel onward in time or space +productive - j. producing or capable of producing (especially abundantly) +profession - n. an occupation requiring special education (especially in the liberal arts or sciences) +professor - n. someone who is a member of the faculty at a college or university +profile - n. an outline of something (especially a human face as seen from one side) +progressive - j. favoring or promoting progress +prohibition - n. the action of prohibiting or inhibiting or forbidding (or an instance thereof) +prolific - j. bearing in abundance especially offspring +promenade - n. a public area set aside as a pedestrian walk +prominence - n. relative importance +prominent - j. having a quality that thrusts itself into attention +promoter - n. someone who is an active supporter and advocate +prone - j. having a tendency (to); often used in combination +propaganda - n. information that is spread for the purpose of promoting some cause +prophet - n. someone who speaks by divine inspiration; someone who is an interpreter of the will of God +protagonist - n. the principal character in a work of fiction +protection - n. the activity of protecting someone or something +protective - j. intended or adapted to afford protection of some kind +protestant - j. of or relating to Protestants or Protestantism +provincial - j. characteristic of the provinces or their people +provoke - v. evoke or provoke to appear or occur +proxy - n. a person authorized to act for another +prudence - n. knowing how to avoid embarrassment or distress +psychic - j. outside the sphere of physical science +pundit - n. someone who has been admitted to membership in a scholarly field +quake - v. shake with fast, tremulous movements +qualify - v. make fit or prepared +quarterly - a. in three month intervals +radical - j. markedly new or introducing extreme change +rampant - j. unrestrained and violent +rapid - j. characterized by speed; moving with or capable of moving with high speed +rave - v. praise enthusiastically +reaction - n. a response that reveals a person's feelings or attitude +readily - a. without much difficulty +realism - n. the attribute of accepting the facts of life and favoring practicality and literal truth +recipient - n. a person who receives something +reckless - j. characterized by careless unconcern +recognize - v. detect with the senses +reconcile - v. come to terms +reconsider - v. consider again; give new consideration to; usually with a view to changing +recover - v. get or find back; recover the use of +recruit - v. cause to assemble or enlist in the military +redemption - n. (theology) the act of delivering from sin or saving from evil +refer - v. send or direct for treatment, information, or a decision +reflection - n. the image of something as reflected by a mirror (or other reflective material) +reform - v. make changes for improvement in order to remove abuse and injustices +refuge - n. a shelter from danger or hardship +refusal - n. the act of not accepting something that is offered +regime - n. the government or governing authority of a political unit +regional - j. related or limited to a particular region +reign - v. have sovereign power +relevant - j. having a bearing on or connection with the subject at issue +reliant - j. depending on another for support +reluctance - n. a certain degree of unwillingness +reluctant - j. not eager +reminiscent - j. serving to bring to mind +renaissance - n. the period of European history at the close of the Middle Ages and the rise of the modern world; a cultural rebirth from the 14th through the middle of the 17th centuries +render - v. give or supply +renowned - j. widely known and esteemed +repeal - n. cancel officially +reproduction - n. the act of making copies +requisite - n. anything indispensable +resemblance - n. similarity in appearance or external or superficial details +resent - v. feel bitter or indignant about +resist - v. withstand the force of something +resistance - n. the action of opposing something that you disapprove or disagree with +resistant - j. impervious to being affected +resort - v. have recourse to +resource - n. a source of aid or support that may be drawn upon when needed +restore - v. bring back into original existence, use, function, or position +resurrection - n. (New Testament) the rising of Christ on the third day after the Crucifixion +retrospect - n. contemplation of things past +retrospective - j. concerned with or related to the past +revelation - n. communication of knowledge to man by a divine or supernatural agency +revive - v. be brought back to life, consciousness, or strength +rhetoric - n. using language effectively to please or persuade +ridiculous - j. incongruous; absurd; nonsensical +rigorous - j. demanding strict attention to rules and procedures +robust - j. sturdy and strong in form, constitution, or construction +rue - n. sadness associated with some wrong done or some disappointment +rural - j. living in or characteristic of farming or country life +rustic - j. characteristic of the fields or country +sacrifice - v. kill or destroy +savage - v. criticize harshly or violently +scholarly - j. characteristic of learning or studying +scope - n. an area in which something acts or operates or has power or control +script - n. a written version of a play or other dramatic composition; used in preparing for a performance +secession - n. formal separation from an alliance or federation +secondary - j. not of major importance +secrecy - n. the trait of keeping things secret +secular - j. not concerned with or devoted to religion +seize - v. take hold of; grab +selective - j. characterized by very careful or fastidious choices +seminar - n. any meeting for an exchange of ideas +sensation - n. a perception associated with stimulation of a sensory organ +sensibility - n. refined sensitivity to pleasurable or painful impressions +sensitive - j. responsive to physical stimuli +sentence - n. the period of time a prisoner is imprisoned +sentinel - n. a person employed to keep watch for some anticipated event +sequel - n. a part added to a book or play that continues and extends it +sequence - n. serial arrangement in which things follow in logical order or a recurrent pattern +sergeant - n. any of several noncommissioned officer ranks in the Army or Air Force or Marines ranking above a corporal +servitude - n. state of subjection to an owner or master or forced labor imposed as punishment +severely - a. with sternness; in a severe manner +shallow - j. lacking depth of intellect or knowledge; concerned only with what is obvious +sheer - j. complete and without restriction or qualification +shrewd - j. marked by practical hardheaded intelligence +siege - n. the action of an armed force that surrounds a fortified place and isolates it while continuing to attack +significance - n. the quality of being important in effect or meaning +significant - j. important in effect or meaning +similar - j. having close to the same characteristics +sinister - j. stemming from evil characteristics or forces; wicked or dishonorable +skepticism - n. the disbelief in any claims of ultimate knowledge +slack - j. not tense or taut +slight - n. a deliberate discourteous act (usually as an expression of anger or disapproval) +sober - v. become more realistic +socialism - n. a political theory advocating state ownership of industry +socialist - j. advocating or following the socialist principles of state ownership +sociology - n. the study and classification of human societies +solar - j. relating to or derived from the sun or utilizing the energies of the sun +soldier - n. an enlisted man or woman who serves in an army +somber - j. grave or even gloomy in character +sophisticated - j. having or appealing to those having worldly knowledge and refinement +souvenir - n. a reminder of past events +specialty - n. an asset of special worth or utility +species - n. (biology) taxonomic group whose members can interbreed +spectator - n. a close observer; someone who looks at something (such as an exhibition of some kind) +specter - n. a ghostly appearing figure +spectrum - n. a broad range of related objects or ideas or activities +speculate - v. consider in an idle or casual way and with an element of doubt or without sufficient reason to reach a conclusion +spontaneous - j. said or done without having been planned or written in advance +static - j. showing little if any change +stature - n. high level of respect gained by impressive development or achievement +statute - n. an act passed by a legislative body +stealth - n. avoiding detection by moving carefully +stimulate - v. cause to be alert and energetic +stringent - j. demanding strict attention to rules and procedures +submission - n. something (manuscripts or architectural plans and models or estimates or works of art of all genres etc.) submitted for the judgment of others (as in a competition) +subsequent - j. following in time or order +subsidiary - j. functioning in a supporting capacity +substantive - j. having a firm basis in reality and being therefore important, meaningful, or considerable +subtle - j. difficult to detect or grasp by the mind or analyze +successor - n. a person who follows next in order +summary - n. a brief statement that presents the main points in a concise form +superb - j. of surpassing excellence +superficial - j. concerned with or comprehending only what is apparent or obvious; not deep or penetrating emotionally or intellectually +suppress - v. reduce the incidence or severity of or stop +surround - v. extend on all sides of simultaneously; encircle +suspense - n. excited anticipation of an approaching climax +suspension - n. an interruption in the intensity or amount of something +suspicious - j. openly distrustful and unwilling to confide +sympathetic - j. expressing or feeling or resulting from sympathy or compassion or friendly fellow feelings; disposed toward +symphony - n. a large orchestra; can perform symphonies +systematic - j. characterized by order and planning +tactics - n. the branch of military science dealing with detailed maneuvers to achieve objectives set by strategy +tangible - j. perceptible by the senses especially the sense of touch +taxation - n. the imposition of taxes; the practice of the government in levying taxes on the subjects of a state +technique - n. skillfulness in the command of fundamentals deriving from practice and familiarity +technology - n. the practical application of science to commerce or industry +telescope - n. a magnifier of images of distant objects +temporary - j. not permanent; not lasting +tendency - n. a characteristic likelihood of or natural disposition toward a certain condition or character or effect +tense - j. taut or rigid; stretched tight +tentative - j. unsettled in mind or opinion +tenure - v. give life-time employment to +terminal - j. being or situated at an end +territorial - j. displaying territoriality; defending an area from intruders +testament - n. a profession of belief +theological - j. of or relating to or concerning the study of religion +theology - n. the rational and systematic study of religion and its influences and of the nature of religious truth +theoretical - j. concerned with theories rather than their practical applications +theorist - n. someone who theorizes (especially in science or art) +thesis - n. a formal paper advancing a new point of view resulting from research; usually a requirement for an advanced academic degree +titanic - j. of great force or power +tolerance - n. willingness to recognize and respect the beliefs or practices of others +tolerant - j. showing respect for the rights or opinions or practices of others +tolerate - v. recognize and respect (rights and beliefs of others) +transcript - n. something that has been transcribed; a written record (usually typewritten) of dictated or recorded speech +transfer - v. move from one place to another +transition - v. make or undergo a transition (from one state or system to another) +translate - v. restate (words) from one language into another language +transmission - n. the act of sending a message; causing a message to be transmitted +transparent - j. transmitting light; able to be seen through with clarity +transplant - n. the act of removing something from one location and introducing it in another location +tremendous - j. extraordinarily large in size or extent or amount or power or degree +tribune - n. a protector of the people +trinity - n. the union of the Father and Son and Holy Ghost in one Godhead +triple - v. increase threefold +trivial - j. of little substance or significance +truthful - j. expressing or given to expressing the truth +turmoil - n. a violent disturbance +typical - j. exhibiting the qualities or characteristics that identify a group or kind or category +ubiquitous - j. being present everywhere at once +ultimate - j. furthest or highest in degree or order; utmost or extreme +unanimous - j. acting together as a single undiversified whole +uncommon - j. not common or ordinarily encountered; unusually great in amount or remarkable in character or kind +unconscious - j. not conscious; lacking awareness and the capacity for sensory perception as if asleep or dead +undermine - v. destroy property or hinder normal operations +unique - j. the single one of its kind +unlimited - j. having no limits in range or scope +unprecedented - j. having no previous example; novel +urban - j. located in or characteristic of a city or city life +urgency - n. an urgent situation calling for prompt action +usage - n. the act of using +utility - n. the quality of being of practical use +vacuum - n. a region that is devoid of matter +valid - j. well grounded in logic or truth or having legal force +variation - n. an artifact that deviates from a norm or standard +vegetarian - n. eater of fruits and grains and nuts; someone who eats no meat or fish or (often) any animal products +vegetation - n. all the plant life in a particular region or period +venerable - j. impressive by reason of age +verify - v. confirm the truth of +version - n. something a little different from others of the same type +vertical - j. at right angles to the plane of the horizon or a base line +veto - n. the power or right to prohibit or reject a proposed or intended act (especially the power of a chief executive to reject a bill passed by the legislature) +vigorous - j. strong and active physically or mentally +violation - n. an act that disregards an agreement or a right +vista - n. the visual percept of a region +visual - j. relating to or using sight +vitality - n. an energetic style +vogue - n. the popular taste at a given time +volatile - j. liable to lead to sudden change or violence +vulnerable - j. capable of being wounded or hurt +warrant - v. stand behind and guarantee the quality, accuracy, or condition of +wherever - a. where in the world +wholly - a. to a complete degree or to the full or entire extent ('whole' is often used informally for 'wholly') +woo - v. seek someone's favor +zeal - n. excessive fervor to do something or accomplish some end diff --git a/samples/SearchableDictionary/res/values/strings.xml b/samples/SearchableDictionary/res/values/strings.xml new file mode 100644 index 000000000..a39ba75b9 --- /dev/null +++ b/samples/SearchableDictionary/res/values/strings.xml @@ -0,0 +1,38 @@ + + + + + + Searchable Dictionary + + + Dictionary + + + Search + + + Definitions of words + + + Press the search key to look up a word + + + Search results for \'%s\': + diff --git a/samples/SearchableDictionary/res/xml/searchable.xml b/samples/SearchableDictionary/res/xml/searchable.xml new file mode 100644 index 000000000..1edb57c94 --- /dev/null +++ b/samples/SearchableDictionary/res/xml/searchable.xml @@ -0,0 +1,40 @@ + + + + + + diff --git a/samples/SearchableDictionary/src/com/example/android/searchabledict/Dictionary.java b/samples/SearchableDictionary/src/com/example/android/searchabledict/Dictionary.java new file mode 100644 index 000000000..59e735b3d --- /dev/null +++ b/samples/SearchableDictionary/src/com/example/android/searchabledict/Dictionary.java @@ -0,0 +1,130 @@ +/* + * 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.searchabledict; + +import android.content.res.Resources; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Contains logic to load the word of words and definitions and find a list of matching words + * given a query. Everything is held in memory; this is not a robust way to serve lots of + * words and is only for demo purposes. + * + * You may want to consider using an SQLite database. In practice, you'll want to make sure your + * suggestion provider is as efficient as possible, as the system will be taxed while performing + * searches across many sources for each keystroke the user enters into Quick Search Box. + */ +public class Dictionary { + + public static class Word { + public final String word; + public final String definition; + + public Word(String word, String definition) { + this.word = word; + this.definition = definition; + } + } + + private static final Dictionary sInstance = new Dictionary(); + + public static Dictionary getInstance() { + return sInstance; + } + + private final Map> mDict = new ConcurrentHashMap>(); + + private Dictionary() { + } + + private boolean mLoaded = false; + + /** + * Loads the words and definitions if they haven't been loaded already. + * + * @param resources Used to load the file containing the words and definitions. + */ + public synchronized void ensureLoaded(final Resources resources) { + if (mLoaded) return; + + new Thread(new Runnable() { + public void run() { + try { + loadWords(resources); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }).start(); + } + + private synchronized void loadWords(Resources resources) throws IOException { + if (mLoaded) return; + + Log.d("dict", "loading words"); + InputStream inputStream = resources.openRawResource(R.raw.definitions); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + + try { + String line; + while((line = reader.readLine()) != null) { + String[] strings = TextUtils.split(line, "-"); + if (strings.length < 2) continue; + addWord(strings[0].trim(), strings[1].trim()); + } + } finally { + reader.close(); + } + mLoaded = true; + } + + + public List getMatches(String query) { + List list = mDict.get(query); + return list == null ? Collections.EMPTY_LIST : list; + } + + private void addWord(String word, String definition) { + final Word theWord = new Word(word, definition); + + final int len = word.length(); + for (int i = 0; i < len; i++) { + final String prefix = word.substring(0, len - i); + addMatch(prefix, theWord); + } + } + + private void addMatch(String query, Word word) { + List matches = mDict.get(query); + if (matches == null) { + matches = new ArrayList(); + mDict.put(query, matches); + } + matches.add(word); + } +} diff --git a/samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java b/samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java new file mode 100644 index 000000000..db626e84e --- /dev/null +++ b/samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java @@ -0,0 +1,160 @@ +/* + * 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.searchabledict; + +import android.app.SearchManager; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.content.res.Resources; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.text.TextUtils; + +import java.util.List; + +/** + * Provides search suggestions for a list of words and their definitions. + */ +public class DictionaryProvider extends ContentProvider { + + public static String AUTHORITY = "dictionary"; + + private static final int SEARCH_SUGGEST = 0; + private static final int SHORTCUT_REFRESH = 1; + private static final UriMatcher sURIMatcher = buildUriMatcher(); + + /** + * The columns we'll include in our search suggestions. There are others that could be used + * to further customize the suggestions, see the docs in {@link SearchManager} for the details + * on additional columns that are supported. + */ + private static final String[] COLUMNS = { + "_id", // must include this column + SearchManager.SUGGEST_COLUMN_TEXT_1, + SearchManager.SUGGEST_COLUMN_TEXT_2, + SearchManager.SUGGEST_COLUMN_INTENT_DATA, + }; + + + /** + * Sets up a uri matcher for search suggestion and shortcut refresh queries. + */ + private static UriMatcher buildUriMatcher() { + UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); + matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST); + matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST); + matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, SHORTCUT_REFRESH); + matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", SHORTCUT_REFRESH); + return matcher; + } + + @Override + public boolean onCreate() { + Resources resources = getContext().getResources(); + Dictionary.getInstance().ensureLoaded(resources); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + if (!TextUtils.isEmpty(selection)) { + throw new IllegalArgumentException("selection not allowed for " + uri); + } + if (selectionArgs != null && selectionArgs.length != 0) { + throw new IllegalArgumentException("selectionArgs not allowed for " + uri); + } + if (!TextUtils.isEmpty(sortOrder)) { + throw new IllegalArgumentException("sortOrder not allowed for " + uri); + } + switch (sURIMatcher.match(uri)) { + case SEARCH_SUGGEST: + String query = null; + if (uri.getPathSegments().size() > 1) { + query = uri.getLastPathSegment().toLowerCase(); + } + return getSuggestions(query, projection); + case SHORTCUT_REFRESH: + String shortcutId = null; + if (uri.getPathSegments().size() > 1) { + shortcutId = uri.getLastPathSegment(); + } + return refreshShortcut(shortcutId, projection); + default: + throw new IllegalArgumentException("Unknown URL " + uri); + } + } + + private Cursor getSuggestions(String query, String[] projection) { + String processedQuery = query == null ? "" : query.toLowerCase(); + List words = Dictionary.getInstance().getMatches(processedQuery); + + MatrixCursor cursor = new MatrixCursor(COLUMNS); + for (Dictionary.Word word : words) { + cursor.addRow(columnValuesOfWord(word)); + } + + return cursor; + } + + private Object[] columnValuesOfWord(Dictionary.Word word) { + return new String[] { + word.word, // _id + word.word, // text1 + word.definition, // text2 + word.word, // intent_data (included when clicking on item) + }; + } + + /** + * Note: this is unused as is, but if we included + * {@link SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} as a column in our results, we + * could expect to receive refresh queries on this uri for the id provided, in which case we + * would return a cursor with a single item representing the refreshed suggestion data. + */ + private Cursor refreshShortcut(String shortcutId, String[] projection) { + return null; + } + + /** + * All queries for this provider are for the search suggestion and shortcut refresh mime type. + */ + public String getType(Uri uri) { + switch (sURIMatcher.match(uri)) { + case SEARCH_SUGGEST: + return SearchManager.SUGGEST_MIME_TYPE; + case SHORTCUT_REFRESH: + return SearchManager.SHORTCUT_MIME_TYPE; + default: + throw new IllegalArgumentException("Unknown URL " + uri); + } + } + + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException(); + } + + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException(); + } + + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException(); + } +} diff --git a/samples/SearchableDictionary/src/com/example/android/searchabledict/SearchableDictionary.java b/samples/SearchableDictionary/src/com/example/android/searchabledict/SearchableDictionary.java new file mode 100644 index 000000000..4d2747025 --- /dev/null +++ b/samples/SearchableDictionary/src/com/example/android/searchabledict/SearchableDictionary.java @@ -0,0 +1,155 @@ +/* + * 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.searchabledict; + +import android.app.Activity; +import android.app.SearchManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.TwoLineListItem; + +import java.util.List; + +/** + * The main activity for the dictionary. Also displays search results triggered by the search + * dialog. + */ +public class SearchableDictionary extends Activity { + + private static final int MENU_SEARCH = 1; + + private TextView mTextView; + private ListView mList; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + + setContentView(R.layout.main); + mTextView = (TextView) findViewById(R.id.textField); + mList = (ListView) findViewById(R.id.list); + + if (Intent.ACTION_VIEW.equals(intent.getAction())) { + // from click on search results + Dictionary.getInstance().ensureLoaded(getResources()); + String word = intent.getDataString(); + Dictionary.Word theWord = Dictionary.getInstance().getMatches(word).get(0); + launchWord(theWord); + finish(); + } else if (Intent.ACTION_SEARCH.equals(intent.getAction())) { + String query = intent.getStringExtra(SearchManager.QUERY); + mTextView.setText(getString(R.string.search_results, query)); + WordAdapter wordAdapter = new WordAdapter(Dictionary.getInstance().getMatches(query)); + mList.setAdapter(wordAdapter); + mList.setOnItemClickListener(wordAdapter); + } + + Log.d("dict", intent.toString()); + if (intent.getExtras() != null) { + Log.d("dict", intent.getExtras().keySet().toString()); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, MENU_SEARCH, 0, R.string.menu_search) + .setIcon(android.R.drawable.ic_search_category_default) + .setAlphabeticShortcut(SearchManager.MENU_KEY); + + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_SEARCH: + onSearchRequested(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void launchWord(Dictionary.Word theWord) { + Intent next = new Intent(); + next.setClass(this, WordActivity.class); + next.putExtra("word", theWord.word); + next.putExtra("definition", theWord.definition); + startActivity(next); + } + + class WordAdapter extends BaseAdapter implements AdapterView.OnItemClickListener { + + private final List mWords; + private final LayoutInflater mInflater; + + public WordAdapter(List words) { + mWords = words; + mInflater = (LayoutInflater) SearchableDictionary.this.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + } + + public int getCount() { + return mWords.size(); + } + + public Object getItem(int position) { + return position; + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + TwoLineListItem view = (convertView != null) ? (TwoLineListItem) convertView : + createView(parent); + bindView(view, mWords.get(position)); + return view; + } + + private TwoLineListItem createView(ViewGroup parent) { + TwoLineListItem item = (TwoLineListItem) mInflater.inflate( + android.R.layout.simple_list_item_2, parent, false); + item.getText2().setSingleLine(); + item.getText2().setEllipsize(TextUtils.TruncateAt.END); + return item; + } + + private void bindView(TwoLineListItem view, Dictionary.Word word) { + view.getText1().setText(word.word); + view.getText2().setText(word.definition); + } + + public void onItemClick(AdapterView parent, View view, int position, long id) { + launchWord(mWords.get(position)); + } + } +} diff --git a/samples/SearchableDictionary/src/com/example/android/searchabledict/WordActivity.java b/samples/SearchableDictionary/src/com/example/android/searchabledict/WordActivity.java new file mode 100644 index 000000000..1c4b8b4aa --- /dev/null +++ b/samples/SearchableDictionary/src/com/example/android/searchabledict/WordActivity.java @@ -0,0 +1,49 @@ +/* + * 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.searchabledict; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; +import android.content.Intent; + +/** + * Displays a word and its definition. + */ +public class WordActivity extends Activity { + + private TextView mWord; + private TextView mDefinition; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.word); + + mWord = (TextView) findViewById(R.id.word); + mDefinition = (TextView) findViewById(R.id.definition); + + Intent intent = getIntent(); + + String word = intent.getStringExtra("word"); + String definition = intent.getStringExtra("definition"); + + mWord.setText(word); + mDefinition.setText(definition); + } +} From 5c0fcdca734bf1e020d6e4691cf17f4ea3a9d87e Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Fri, 7 Aug 2009 17:59:45 -0700 Subject: [PATCH 28/87] Fix IAndroidTarget#isCompatibleBaseFor() for add-ons BUG: 2042277 --- .../src/com/android/sdklib/AddOnTarget.java | 31 ++++++++++++++----- .../internal/widgets/AvdSelector.java | 29 ++++++++++------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java index 293d66a95..d72cd9430 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java @@ -218,15 +218,32 @@ final class AddOnTarget implements IAndroidTarget { return true; } - // if the receiver has optional libraries, then the target is only compatible if the - // vendor and name are the same - if (mLibraries.length != 0 && - (mVendor.equals(target.getVendor()) == false || - mName.equals(target.getName()) == false)) { - return false; + /* + * The method javadoc indicates: + * Returns whether the given target is compatible with the receiver. + *

    A target is considered compatible if applications developed for the receiver can + * run on the given target. + */ + + // The receiver is an add-on. There are 2 big use cases: The add-on has libraries + // or the add-on doesn't (in which case we consider it a platform). + if (mLibraries.length == 0) { + return mBasePlatform.isCompatibleBaseFor(target); + } else { + // the only targets that can run the receiver are the same add-on in the same or later + // versions. + // first check: vendor/name + if (mVendor.equals(target.getVendor()) == false || + mName.equals(target.getName()) == false) { + return false; + } + + // now check the version. At this point since we checked the add-on part, + // we can revert to the basic check on version/codename which are done by the + // base platform already. + return mBasePlatform.isCompatibleBaseFor(target); } - return mBasePlatform.equals(target); } public String hashString() { diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java index 96d1b65f5..ba1bb4c0c 100644 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java @@ -81,7 +81,7 @@ public final class AvdSelector { private Button mNewButton; private Button mRefreshButton; private Button mManagerButton; - private Button mUpdateButton; + private Button mRepairButton; private Button mStartButton; private SelectionListener mSelectionListener; @@ -256,14 +256,14 @@ public final class AvdSelector { } }); - mUpdateButton = new Button(buttons, SWT.PUSH | SWT.FLAT); - mUpdateButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mUpdateButton.setText("Update..."); - mUpdateButton.setToolTipText("Updates the path of the selected AVD."); - mUpdateButton.addSelectionListener(new SelectionAdapter() { + mRepairButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + mRepairButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mRepairButton.setText("Repair..."); + mRepairButton.setToolTipText("Repairs the selected AVD."); + mRepairButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - onUpdate(); + onRepair(); } }); @@ -775,8 +775,8 @@ public final class AvdSelector { if (mDeleteButton != null) { mDeleteButton.setEnabled(false); } - if (mUpdateButton != null) { - mUpdateButton.setEnabled(false); + if (mRepairButton != null) { + mRepairButton.setEnabled(false); } } else { AvdInfo selection = getTableSelection(); @@ -790,8 +790,8 @@ public final class AvdSelector { if (mDeleteButton != null) { mDeleteButton.setEnabled(hasSelection); } - if (mUpdateButton != null) { - mUpdateButton.setEnabled(hasSelection && + if (mRepairButton != null) { + mRepairButton.setEnabled(hasSelection && selection.getStatus() == AvdStatus.ERROR_IMAGE_DIR); } } @@ -851,7 +851,12 @@ public final class AvdSelector { } } - private void onUpdate() { + /** + * Repairs the selected AVD. + *

    + * For now this only supports fixing the wrong value in image.sysdir.* + */ + private void onRepair() { final AvdInfo avdInfo = getTableSelection(); // get the current Display From ad904291499650e3d3aadc0aef617e06d71d3672 Mon Sep 17 00:00:00 2001 From: Bill Napier Date: Mon, 10 Aug 2009 13:22:32 -0700 Subject: [PATCH 29/87] Add "wake" command to wake device up. Run wake command at first connection. --- cmds/monkey/README.NETWORK.txt | 4 ++ .../android/commands/monkey/MonkeyEvent.java | 25 +++++------ .../commands/monkey/MonkeyNoopEvent.java | 42 +++++++++++++++++++ .../commands/monkey/MonkeySourceNetwork.java | 40 ++++++++++++++++++ 4 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java diff --git a/cmds/monkey/README.NETWORK.txt b/cmds/monkey/README.NETWORK.txt index f3f69d440..3ec6298f0 100644 --- a/cmds/monkey/README.NETWORK.txt +++ b/cmds/monkey/README.NETWORK.txt @@ -73,6 +73,10 @@ flip [open|close] This simulates the opening or closing the keyboard (like on dream). +wake + +This command will wake the device up from sleep and allow user input. + OTHER NOTES There are some convenience features added to allow running without diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java index d926be8e4..2783dde21 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java @@ -22,7 +22,7 @@ import android.view.IWindowManager; /** * abstract class for monkey event */ -public abstract class MonkeyEvent { +public abstract class MonkeyEvent { protected int eventType; public static final int EVENT_TYPE_KEY = 0; public static final int EVENT_TYPE_POINTER = 1; @@ -30,41 +30,42 @@ public abstract class MonkeyEvent { public static final int EVENT_TYPE_ACTIVITY = 3; public static final int EVENT_TYPE_FLIP = 4; // Keyboard flip public static final int EVENT_TYPE_THROTTLE = 5; - + public static final int EVENT_TYPE_NOOP = 6; + public static final int INJECT_SUCCESS = 1; public static final int INJECT_FAIL = 0; // error code for remote exception during injection - public static final int INJECT_ERROR_REMOTE_EXCEPTION = -1; + public static final int INJECT_ERROR_REMOTE_EXCEPTION = -1; // error code for security exception during injection public static final int INJECT_ERROR_SECURITY_EXCEPTION = -2; - + public MonkeyEvent(int type) { eventType = type; } - - /** + + /** * @return event type - */ + */ public int getEventType() { return eventType; } - + /** * @return true if it is safe to throttle after this event, and false otherwise. */ public boolean isThrottlable() { return true; } - - + + /** * a method for injecting event * @param iwm wires to current window manager * @param iam wires to current activity manager - * @param verbose a log switch + * @param verbose a log switch * @return INJECT_SUCCESS if it goes through, and INJECT_FAIL if it fails * in the case of exceptions, return its corresponding error code */ - public abstract int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose); + public abstract int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose); } diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java new file mode 100644 index 000000000..ea9273576 --- /dev/null +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.commands.monkey; + +import java.util.List; + +import android.app.IActivityManager; +import android.view.IWindowManager; + + +/** + * monkey noop event (don't do anything). + */ +public class MonkeyNoopEvent extends MonkeyEvent { + + public MonkeyNoopEvent() { + super(MonkeyEvent.EVENT_TYPE_NOOP); + } + + @Override + public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) { + // No real work to do + if (verbose > 1) { + System.out.println("NOOP"); + } + return MonkeyEvent.INJECT_SUCCESS; + } +} diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java index de784d0ae..b444dd340 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java @@ -15,6 +15,11 @@ */ package com.android.commands.monkey; +import android.content.Context; +import android.os.IPowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; @@ -203,6 +208,36 @@ public class MonkeySourceNetwork implements MonkeyEventSource { } } + /** + * Command to wake the device up + */ + private static class WakeCommand implements MonkeyCommand { + // wake + public MonkeyEvent translateCommand(List command) { + if (wake()) { + return null; + } + return new MonkeyNoopEvent(); + } + } + + /** + * Force the device to wake up. + * + * @return true if woken up OK. + */ + private static final boolean wake() { + IPowerManager pm = + IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); + try { + pm.userActivityWithForce(SystemClock.uptimeMillis(), true, true); + } catch (RemoteException e) { + Log.e(TAG, "Got remote exception", e); + return false; + } + return true; + } + // This maps from command names to command implementations. private static final Map COMMAND_MAP = new HashMap(); @@ -213,6 +248,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { COMMAND_MAP.put("trackball", new TrackballCommand()); COMMAND_MAP.put("key", new KeyCommand()); COMMAND_MAP.put("sleep", new SleepCommand()); + COMMAND_MAP.put("wake", new WakeCommand()); } // QUIT command @@ -246,6 +282,10 @@ public class MonkeySourceNetwork implements MonkeyEventSource { 0, // default backlog InetAddress.getLocalHost()); Socket s = server.accept(); + // At this point, we have a client connected. Wake the device + // up in preparation for doing some commands. + wake(); + input = new BufferedReader(new InputStreamReader(s.getInputStream())); // auto-flush output = new PrintWriter(s.getOutputStream(), true); From fd6f01eb6999c79d21844a117d27bf2c5f469de3 Mon Sep 17 00:00:00 2001 From: vchtchetkine Date: Mon, 10 Aug 2009 13:34:28 -0700 Subject: [PATCH 30/87] Update ignore file to include new ignoring patterns --- host/windows/.gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/host/windows/.gitignore b/host/windows/.gitignore index dc7a154e8..434a0faf9 100755 --- a/host/windows/.gitignore +++ b/host/windows/.gitignore @@ -1,9 +1,12 @@ *.sln *.vcproj* +*.aps usb/api.* usb/Debug usb/Release usb/api/obj* usb/api/*.log usb/adb_winapi_test/obj* -usb/adb_winapi_test/*.log \ No newline at end of file +usb/adb_winapi_test/*.log +usb/winusb/obj* +usb/winusb/*.log \ No newline at end of file From 78ce46361bf91b21c2d4769c062af96d4fde98fd Mon Sep 17 00:00:00 2001 From: vchtchetkine Date: Mon, 10 Aug 2009 14:21:51 -0700 Subject: [PATCH 31/87] Complete AdbWinApi split: submit prebuild binaries. As the result of the split, now we have two DLLs that deal with USB driver connection on Windows. AdbWinApi.dll deals with legacy driver and LoadLibrary AdbWinUsbApi.dll on condition that WINUSB.DLL is installed on user's machine. When both DLLs must be installed in the same location in SDK. BUG 2033924 --- host/windows/prebuilt/usb/AdbWinApi.dll | Bin 95232 -> 96256 bytes host/windows/prebuilt/usb/AdbWinUsbApi.dll | Bin 0 -> 60928 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 host/windows/prebuilt/usb/AdbWinUsbApi.dll diff --git a/host/windows/prebuilt/usb/AdbWinApi.dll b/host/windows/prebuilt/usb/AdbWinApi.dll index 1fcfaa9343877823583543c4239f0716e01f7178..b5586eb50d853881b02681362b24ec7548b2c7e8 100755 GIT binary patch delta 36260 zcmd?SeLz&z)(3pfIKZf*j0(t?fPjjMf&vNxG6;jHpra^=3TTRrL`phiTIygU#(1Qx zZH<+cgmtakE&G(L48z2XTUOq(w4&nHMyRmNsK|ML>zo-ttLJ&%f8KxI(KY*P?X}ll zd+oK?-e;eol6zEkdhAIN`8}x_*8A(t|NP*Sz%Dlo`DkX>CvrNd>j{KEhu+xLD2KOp z?UuvkT_4J!xvNbMSG&?T$l-!DD@{a8xb9;#2ttmi7F1Q0v)x54f@;{vfucqb^r9db zmF%=zS-3cHLZd|`sN{ULAn2$FUvj7fooS+Q+*=TKOcezq+bV{7WFytUYQ<17iX9h+ zsmjHBMh3D@Q8VQ^;L3HW8IbGy2@{0n6IZP;uR!Li3HUMsXDGrTZY(7$bK6CC=W)s?1gQrJ4ALsrL*o!6@}s?QCJJu0@w|B1n?B#Wk56FQ$Q!6 z3!s}O3Q+((U@^c9*bR6D@C@Jt;8Q>c;5UFSSrifhvjIy0s{!i)+W_|_i&o(PBF_Mh z0!{%w0C2!>fB`9@;13uF&;ynL)&q6}o&dZEcoT32a1rnuK!*;E155`j0IUV<20R9M z25{pLlttmtGLLwj@5DSO`=m6bA^g;)~{YjXt7pj-)g?)fo ztM$U`tMoz>;vdY?3lGNqeObaLy+H6rhF-V=2+Y(A(*Y%b`{MOse@m1qoi5a~FFfPe zY0tUVr~U^9+>KE9f>AI0G!Km;Gz0vzuVwD1nZ1mE2qrSJ{+c;6@a|vGQ+K@ZCK7#n z{ZO7>_473R`{HES1b zxM9{>bLslkD^`{YLb|X@xIrio)(C5bMZyNe(}fD8CL+Ha|L}E2rsVD3%{B4!T^NtPQr*Fym<}F?;k#;HAXM2Ez=9ZcVUnbx<9L8^+HX#Ubr1_ zzCte?MtbngN_x~S?3w-{g9T8!f1Q#g+`>NXKW)HjyIz#af* zA{qc6rx#8E4g#tHs{omRV1NMV9E%14t$?$D!+=A8{eazo3V;z11rPw|qR=Q{51<^7 z4G0EwLNsRqB(}U#_Cff)qXdk2_eAs!a2e1EXa$@DoB_}$8zv+ftr;sc0fH%Er5x?AYDFR)4^Y~w85L?JjL6M`ka(LQ#O^|^F9f0fq98mo8cP5`H3rrjun=GdJPJ4s zP(_JCDqsuXAm9X`6`&p~3Xy;ufElnK@EYJxA1Phk*xYPwZf=&+HHhI8*N~L1_P(z{ zNlDH{QipV0%GERpn}+HIX};QSR7>+UcB4j`rL|{ki{4ZVa>ZWM{|)JiL8B^=el?HE zH*JA!sp1ObJj*(;xSWeP%}bh5bJhkK88XBY5>sg&JR($j2Bdc2!) zy%MQO4|hk#_vuBSR@3IARk_j30auCF-r3#6@@0_hU3z3Ox}dF~yG2_ntZ*|T)JX8KfT`RtnMTb<=w z!jA3tvl7~UK>Lew$fidKvh4eG@D8kfN(cQ5_)zr8EmfA$Bh|xj?v(5TzI4i;q$+m{ znjxh}y1Ns3eRs3nnnAC3;YJHKy6Pv=iWy0Z)T z@`UR;Ulv*a%;VZ+%w7VoHTSpJNZ8&Sn=ox)%Ati)87jx?=WHC}<=D=XqeLk*&)f9>`}4g6)L1$Th??jQQ03 zgc!DdOt`3K_l=pX`e-71drY`Wtz$;h@P2&XMCKLMn_M!H8G4f5Ja{58jt2cC&$51O zew5z;5{sg(Y*3QF=BLT%aM7C@_H2~z7%H3GP}C^5dWtk1buH@24efz>PKyqmwrKh0 zFcvyC%;&DY#Xfn`yZq}=DiHTE{n%(Qdui-&F%R(o_Q=>_uJmAbdhBRd{5{rxoIAdU zW%tDAvpdI)1oe+V-hbAPd zR!?C6nJ}imwq7*`T2!CLQj;RW*8Jv#258#DFu|Y+WrD3iW#oBEZvD(uR+$tz1fC`h zt5mEh6CtLtPWDn#=~9_kGgrscQS6>$r^mDBvVFqxq#|v8nV1LjHP-2L z?r1QF7SyB!6+pL~8`WIP9-B5wo2w}k_#G&Q8DOtY8|ASb@nSZzEOK%s3_!m09)B7+ zCB=P34;$0oKcC-@0^7;RWQ*4Fqs$lUEcMqkPk{2h$M>*#Ib(dPu0We^)j$qq!uX$v z+JLKUSI)?EFz(za^RXCIh@VB{1PpPZJxguR(%7@KeOr_aTJ%Pfl%av){&j-~A3K2^ z&j}k8Np&q+={KdZ|}FH~-FUfnPjQh$%9cBB0abyb7Kqn?WFGu6@@jeVX* znxnPP(_Ym(+f&O#;wuWhg@|ILrRu8lz-9AteO14uu+_N{n(ZBjux!_!VNXt+Wtuz~ z+w+E+nq}0qAHN5Jk86-}yGx4W{=JlsN*08-8~KEvolZ0wZ2CfnUR_bll2V74poVm^ zy}5F0n9~yGeZ&xK#FxLZrfLgFni7Y>U*oX`wj^eRrW2Oi$OjsjHD;O$OuZTtpz5E= zK8hKmo%NH`Stxb3MW7P1=7w7DBZGbYf>h=#BfG~pp|Ho&m#OQ=kvjj7grWMxUet*J z&F2|E&~WOY(@p&x#}C$2jIX(U{Ns(y*|E$m%Ne0wPO(ENLPS)f;P&BEknH=WqMWVdvdskoQFAnY<|;S>>f zRc}{kCHw3$=x8a&D9_bl^)`D*q7#nNN&Yh`zNuBFjhoodi7sMPg{_MX@H#bI5ctbU z?C#h=O#Y{0Uu6HDuN`;*qh*`x4=3Re`#df<@(?6r_A)wsHDpoWEpB@e2(no!3$9;C zQoS&hg~a>!S4W3)CplvVVUY<7ct%Mgx0%_ zfhL@c0oyTk1gJkYb)A0M5SY^Qc{PS^V;;=A7E2*ngpbIvfXUBO8nboXX1N4Y(amST zVo6=ezZY5t$ZHy#pEzC>Hl1xtyffs3Fl8B0+V5i`Y#lzBE?v_?tsh>7dKiK+L8RYn zEFGj#CB^oPFq$lLCu6d_>F*jCO}&}KSA|SlX@^i_=rDpkQr@i)G3MqN$S(}i z4QeCb1kz4R2md97R_|OLxy>55&HM^TV7!Ul09m}tXZQF6>iS2i6+VeQn;a2CHerFS zLnn2EFQfF%FAEcw+oT0OMw{p>}Q`~gX+tKU{w$O7*B z2Roda9=Pa7Z~>dRV1yvtJ{(*$kP~Vo0pvN5kRJ1--_t>Je7seK3rou%p{Lbi1}ox2Qg z@GN)`Z-(_zD_e&@26UT#$!JnVsS|3l5Q;=jO}=8?Fv7bG?TQtwie^{!fng+js8l#P z+f|TA8R@K&Hz>d679C4W507wVg#HE603eagVbjxt-NgP5Z#;V?Jz|uL*o{(piax1G zlW#Uklao8w&rU4TNwX3yBa`1b3Q37GMv}lHXM{~qDip&DcG(9BYo5HO#y5GA739Wt zj1T5{*Z_e!W{k*Q27$?D*0m114ayH#zZB~v@|XIP4#R3121185HFMp>4v}`9NVP?2L_#qUqaz7NxJ+F5R z$GjdfFfs0Ya$|wKy0K5P$7gpcQ^lWL27fe$X``jMUXEJ^Ru?&y2`-((V2}-~I&b#E zXp$f*w>ky$Gn3CJ7RRuhSyKkaR2Tie{%zE*AIfTG`HN@R6SJaRBiMEsOQNJtOm0*f z|9Vyd3|I2(U6T}%!i48`(B766KVM2u%#XX0eA31EmDzc+h3nxd`E!LQ zRy-%#Z)2bUCO0M(NZa77^!uH<aT&zSH%hC=r4$)UG3#TV4%Uf}03+NNMw1tgjb-E>yK zAu`w*4HYjyOfs~%{0WvcH+0Mo|3y|)TNz4vCRt>DkG=7)KS->#Fzeh{D~X0?-UWUa zYJsx_;25$o#ValHe}0Skmo>B6(6K8ktKH8O=E`SszCq5X@ABZvJwGp=<`JKFd#Gz3_3=*g%P<}IR-EcId1kXaj8Wd%=nQZ8 z2JB!unN;i*WAIe3A!NJzcrEVflo;WjPW|{*9Gk$r!V9EH)#TYclxgRO&G`l>ZpCs} z`zG8~jj;5BG&fQbsgl#Ep<#yVybfa6JPNK2BF*;%HM@0wEDOxj4voPu?lSn;R!0lf zS+Px?t9)2u-UKY2tMkS|zwgO=ZP+U6#-ct`@zP*gVh71bG`8hxfsSd|_JzY$2p(Lx ze4uhFgF*9M#s)4LDK29Z7LCVu;iAR(etyvee77u07+5_q9Tr1l|<^*t~u6UzMgMfOv{1kFd}Lr$$-#-bJn`-n)`4PCYdjTCD) zbk^iL`S)z`;{C})%Hk!JsOLHg&VHDW8XEsGNmvm?varWAO>Vy{*Mv_c{1#9iTo;OILC5nan5Nfw`N z6j70zxeJBz;>SmLvK2+4Ai2G0iFlq}C>kGlf@b`Wa3^U!XpubQ&Q}-x09VwM$wn3j z`No5YQF@P-=))vBLu;}}BAZ`4QMM2DGfFW%B}+@YpWB3y=C*6xDN`ouJAD&jOI+s( zy9__@E;Oe&U}c*6R$^c>a%5cEf5Zcubc?*ISBL>ST)X~q>m6tv8Rjr4rb0&)?XV(7 zb^DMWbM~Rak*06UC;6Sj*@TkSlht@U#aH`LXO-5lz))*R+te0=(<7GJ+S)CpQbcK; zy;U+&>FSfKsjFK%(78~>TK8?DiT?v+`*@YxJ9IE7wRA8Y_ma(dOqD)VxmF^X9FVW~ye+Tn*FxbD3x1Yz6z+DNJVLPmeo& zb5Oz7g`I~v!gLUsPTy>qggqnLJj7H@XincuWYy8Bk85qy_`)(W@8vfSUx*TEg9a)w zya1k?(+`VPKA+9l@^sbrm)S?lON(t=wPOCU3e?8jd6$oY1%cg$Ta?dVMI1Zmo<$N% zK2Jk&nfS_%n;_oTP!1#M76o}If>QDrmB5@XVfGbc*{dtUyt~0_nOI=b!~8jYSFwvL zCT5YFYts5sALjQxEe0VeE4r$o$+HC*^0sC%bp!+_p!sWe75`?5H-z7i1j}jL1|#Pg z40@Kqwrv{0qN$CUyT?J!L0CNs^J{W1^D*eYsfUT-I7?djqE{rTx@riU zv}%Ux>P^hDDol0H5aw7FJ2eERtJkK|_~2AV+vFKfoWA55BWa{t80k9MgD|qIt0r4> zi0TR0H?kHTHHJ=O6M!m~V0(o=$ev^mwSPm^n>;g74o7k`tev~vCXq7RjMopGg3J?< z@0OPqGs3;@!pIK< zvF}PVRi(pN-0Gd8ksVzfi0}Wbo-l-%mvXiF{f--*x2n0XHyd{2Y^9%$L4VQD$r$55 z_45E4Lk}0g(7JnwMSedqy1+%GlMeCuBGe`>ZB5#OUZJm0st@a_&Ysvmcv3lX;n&N; z>pi+}5-F$c6wF~CWhJ+}f(4o4#0oagG%{Ned2g+<*m_xPw_r_{#kR#Iwi#H``igB5 ziLHE+OKfLZz3JJQLvpg!$b)c@(MP{+9l`T!a$EUxq?1Y=AYEa%tnu@HhVm5gBkz6o z>YA~t8Cv$unvK?GsI=2}8Ro97OJx~odQnd6k#^e*^1EvZt)NU*0^c#W+cL<7M%KE$ zqN*Y9RjOvmEfY<>^q{CwrUTFn>=Bj&krbDg!Ywv^aSK%RF*xUic55nCXdji_WYO7` zI8HsCzEQ-GoEFVLB*_sAZ8oUIrIMk$)8wp3YclP@DvCTIHhinW&abXc21ob^f-rlhfox$Grg`38T zCidA)ldRonLaHHEkuDwoM$_-dGSQx(UI7C)NJHPgT71_D_~LV86zlRBZ7};rF`$Z#)CuWAc`lYCW0Fb%x=tuq^&y3T3(F`{MS%? z>4>2s(u*Aa3NlPSSVYT2{^cl4#m?kk3Jbk=v_Q4;oe8G-P@{~5Z0edHPz#-Bu!s&Q z$mc&&s(pAqe|jh)ZKR&Iu6`D;0=}JWW?X}wwhM9pF6Ixx?RuL%x6WsR3Jn*vB>`1d z@G`CG6ttc<`=H%iEvncJt?1Ev7H{;3?YTKnT+aS^^FHxSmbrGOcpKZjwg5S;Yj@y# z&ALqSbN0--;no9?Sy3B3o$8&dMQvwsVxqL-V@jNiR+fNInuN|=-KJ^SJdDrP+H*C| zMLzA{;TQ=m!|jp;yP*YJsqKj?H{9G}9@u2K09gx?;X)&CL^Dz;#~u*;JGl|$-qc~H zTG0x6vY6WV1yiDCbEw!!a}@m)03F(A_U!b7){zr&w+&tiO7e#``)rtbuoyozokwUFqI8o zU#>bcmQ}6KP)TFi>GcubH)AqMl{7c7tn(7qy*@xRFux7aOK6(mz&QCZ6>Do?7qxu=#U%7>b^8asBdDA&?cWfpirmaz z-w=+rS~dg>B3I9%`l+#P!xWsDOgE44Qk*{{J7AuK^N3}*R(6It%+s{4d^^Urls#$= zWWSixSV)s{HkIwGezspV z>&L+vjJz+>%F=He9+J2XK2&5)ycJg~5Y{8PCmUa8z`kv4<85P9zO16ly*wlUA!vwet;HGZHdL~REm0~2xm#jKQC(0sBiI7i0oV=L3)l}h2sl#79@~=b zqp)-a8Rq~T&|S%{ZpmSvZjSwXvHvmo@5R3N4q5Dnw#&UZc!whPC<^P5*9y?wA&VWD zB=)^j^tWQCQW6w`O@Io339uZn7+?fs-yw^gFeT?fd_N7S2Q=Ryi#>KnkJwvme=GKQ z6hZ8SyeAWJ6JQVEe-wM{4q5C7NbFP>ytblN2jDWG8=ywE7T^OIvqKiU!jc{t*?`4> z@*NQS{2_R9Q`G?9^JJD*uvqvDIyTqhzvxr}_I5+1L9O}eLREGJR;Y8+FsVJIEOoL6 zUxY$GDNEB^uHgl7@}x)Z6@7)u5^l?`P=Th{?q5s9?4Grpy=qAwDy0ZQK7E=5KLI8! zGKFb2-ZFFn$a^2@BuCc!h?kMin8u`ync@L{@~81Y$?jRm$D$pVsn(kIQOh5Q?j=E!oS;R^w}zwPlSEf( zc=`gRVfSKylVU75t^9LT%xMJfk!<3j*D}(L4%^ih?>lROnO7jCn!%GTmG~1Z{(NOV z7V{AP!9pzTP8tOjmY2f9+Ax;Ad5Tr;#mDkvq=`u$@nz{knYP&MOUuk24{|xMO9K5i zdX&q*OGK|?`8RSw2Htde@A)Z*(rMX&YV!!v|w2AP8v+h_w#CA!^&6jhh@eS;g@+8bpXJ){$lIf$;CLJM1F3q{!$TkxoCxNPu+ z^9#Ip`~&^9rDh^S@ZRwt5=MRs-iPCq+^J!5-W(Mhs(b?wG2o_hrBD2n?x*jHG^54F%@OHQC}W zoqop$mS4vouh}FP@GpO3aaHMrxv?rjwfQ&pP*utrs$lN#yhY7t|B4-*Yh2RNZyXFa zps>$K!7%WX7-sh#@W=DLd%)iD#9-E4hDX_VjGYOWnSQ69j<|Mi@-o6llu{Sod#Aq= z9f9$^^HcAGb0HY0)zDlL&~m1!4jtYK4xGN5d_;%AXjd-xlF?o zAYm8xNM-2R_Uh!2Z)2}D6_rTaPWY7hEp8uF+s!_$j<7y)9ZFg+%Fv_)^5f0tCBOrjeIfNwQHHR{$=bF zcsu-FQ{%m$>P>`B1lKKxQuG{8$rqRsR*{}0RAQLrXUijNX>)-SHuG?!Q!aFVB=0UX zQe_wV&>mzGFmrp<#oyHFQWr&i@L)sZWTn!mS^qBxcmE|}9omugaETOXb^7i=1MU+B z7iYf2HYQO37b5tRXy#Y7k1a9xbetMT`eJDrft*4Bg#d>B?b?g|dz zaZTZYnix<2IP~&8_HNB^YZi(MrK~9Q2>wB$lEN`0rN$|#SS1y#q~ev-U?r8Jqy#0U zS5iO1q=ROrl4?~_*-GjoCABP-glYED8u?q4Q#ObvCbNpWf@Im5v6tOP+3rbF0GU7< zPI5Ak2T2Rkw(=^cIii67XAClvQ)S=EXS=f#zLi;POT)=-0sk2L>K-E4kHg#06J6ek z)eMS;aYf4~;6fDQm|ue?to3rD*9zNGWl5Un*tX(ybqsdq*D3w5YsLW+3D?nz$!&3s z0I6aqjl-O4B( zADQAQtka_fB%AOVls=o zPEJ#EatoZvY2v3&KIO0>ZHqaflUw22r_w558Nl!QojPA!(rEhmKFl0CdQ)abj7^;%(1#C3&rDrd)bdb2hVutM_R=aFYr#Ta|Ne>IL zpC#^H;6=oozI)j{djoV+am&K(yyO=g)3c*{Cl5};B^vlrxR0#fepSzY+Z#AI2TLi= zy>7vZCMC48@cWke(n(v5I>eq3Mx(qC2=;_v#_mg2eHhNp+~+@BK8l-;Yd5x06cvah zwC)AxeJfQlL@*!s68Okqm{xkObj%1k`FYhN7RpXoo z4~+8C0neW5!(tu?%vcOu99!ZJT*8Z}P!M+>O3-MT==_N8Qkk_)9)tnvLVJY!#?>a= zuu?6qqk?vi+Qn@51B)^z;ck+Ks!9?q8AW+p%N4jTGlP|+>0Wlm2){*{N zB28U5o8S!-N$UzNzV7{0J*wd;Dr(VbW`o{kf!v$4g1or%Nh8#tfPD__y|%?cfEuK6 zG0`Mc!XV=sT({GAK?4f$!UCqIvc<8T^vOt;Yi>DL?3AnY7M3jii}u~x1#blxz-rI1 zw;u|fauy3jdtN?u-06D;ZAg~xIGnNhHX|O_>Ga*>3Qx%)?QxyHCs@dSzeqZO`sE{g z0+A^0nOquEB~7k5kUr13#G0QB8(NhDc}7)yZMoHF^4_-NT4StdZXEUkBkj}_6$1jIH_m&LoDShj!R5^{4{v}qr5`Q8>(`9#{P#d2>iYPFR% z<7Ja>yWs+^bjpv?etjP@$0R?;*Aex~YLK-X&hiySVgVB-#jAC%jptZ?pb@aT)ViPJyM&lYCglhtPS#N zAQpf6ob`LmIBY)cJ_@TEym$Nv!g=sq(%9<95{CBg$$v`8?_&RY%wJ{w4{LgCP`eZZ}sPErnA(#;c<_4^^6)$LfQwz zF396G3Hi7qb@DU!R4LP#T8PK#)=k}b}&Wt^J%vAV0hqCD7LM>5fk%< z^Mk{OU!}Y3mSD0Cba@spAcPh0E6q&%_#t%~%2@s58G0w|wXL3{j3a~Buy^F&(S;{@ z)NrqYe?h5A8Z}%yw;ObP6P#^%7wN%Y!xn%gKQTJ&UPSm_nUbQ6oA^$uC#xpE{TsIZ ziOA`D;RtcBPvv{&gR*Rmy5y-_zHa*pK0Kbhp`}02)xtv4GR*Iq+-80Y?JpD^Z8q`( z_Vp7+)xS@_knj(cIJ^;7haaP_SMcRhv1eM@+(SX)Y*uzCXLKg=duK)ruAbu-k;{RQ z4{vZ@!b91GLtnDer%YDUO00x~R?)Zba{3;zjJ^{V(|77Ze6QZ^TPX*F%yKZoCnJ;G52}ppVj3x1D9hA6Y!<5kp)9d+eXNs)3W)rGNT}4b1cDbbsZU1YJ}q zsHx&`5}}=Hr*A7Od3vrY7dMcf9;>n^vrnH6QI#aI-=2<8O-o{-|9a9o>4ekicF(k? zFly0?dCV)J%TiaZe3U!0!aTxeEf>tgrCUwdfN9FY_`g2JnB$?j1IUfoWGoE8#3b_o z6uYH0IYB<}oq}`GK&a2Y zUbTK08yq%qAROA?{#zANCDdbi7w`J|;a$t`42D<+eEaflt|+ zhsUb^+swW@oHan{vyngZ4oiJ5$VxI5y{kT>nK_7G#l;>)a2e{lz38r#p{d&^huXUR z2;&;CL$`H#Y}Kunax!$Q?OH=Mvi0p;E=i?6Y#p>K$3M8bx+RYa+LQtk+*aML-TosG zsjlV=sq7o)D0ygl#$;G6jZ~_e$DdDQTwa#ui}5`E#%UJ)yno2jf4j}2EtQ;C z0asuD;PbJj!l}(+H#|Q^jAgr?kFchIi1X#w&_R9{`<%i;Y3GYb;03nfN&c2$xQft= zutr93zI>Rl`}O8`y$!Oc*q~I*L`A){^8`{8uHwtcKL&!dvl;O>D)BYG$;eO0S!b-S z#}5K>Y}Hy(A&gyZYZ&ZcZzlg^pzrLi>S^Q5=g^Do>Wa`xPd z@od(MH_EXxXkqY6K}pL=T|&@X9{Lfw(Wy+dtO|3uZ5t+9FxOCaMY(IX&4jl>vu)C8 zR`HULc#2iMG)t9rf}MG3s>+eX`oA2f3QA(rU#16@6)$h~?}l-)SGB^sar$;Z;pIzY z{K`@0ab&c3jzu2{5-+gqBO&3N;f!Ende-X;;p5@{rOQ)X;m*%w)kpNIm`ry1NNMPv zWsrqt`_;n;Ew})sS1~3(@kidsNkF?8{@d$g{n%S!JBguDpCkDZW1@!y)zrt?f;;cDCK9azq9v;;%c{xwxEB4NZ;&TPUu z+w?-&@hVX@FqK_;bA_1mLSAF8sA@`LkDYix^~@2L`c|2B!P8_0s+;se*;{yS3HTL| zbrNrT03HB5i87ZfoL>-k<&9IAy|$E}7eeBqC9+2Svk@^9v`uYKl<&VdV{J|T+%}wc zMtHVi)@IqRMsC5o+IqYkXN#2aVHVmifodY&*>&bgBlH;M{9{C^K$?!d?l9b(6U~DP zoF5kO1204Q<;^U{u3`!H(HD*xS@B7KtDN|zcxfN+9)|$V__v6Va`DscO>0e+q_fZ0 z!&AZ`;nr5#KgpXifBpz=N#V)RAT3O)6CL5HZ_tp!2d#;hxlIbeo6$|}YjOMcTQE~d z+e3>tXFs2eoPK}|AY3}j@B)6~B^2^0ILlCuE8xPm542Bj$642tROI%w+>f$m*Rz7A z5dp-lZMr~~Wdu~76jD<*gohtvHBBS) z)amdI!#Ri!K$<*!@U25v-1|n^^^gV;YOQ9=3*xCPl`mB%2lgEBq(S~Dk`fx&veN-p ziq}%{Q502vc(K1xBPS)jPC>LCtUiGv1qr!VvojQgY+dE%48hXhwp@Kx&avUjv86N* zenW-U`H`IEtkCuBIOXStF21P2o8I=3e67^W@uzBXhIGuY$@ZCV zD$~_xcs)+v%Mdc|4Oy{IZ{K87gs4=L1%J~OpMG)$(+NntOyjObV}pxgSvqr5nc5_T zL5=A5hH%Kx=_=7$hB`OudfKT#cKbuNxf-W^x_z74=|P-HSvs2r7x_wx*^lom6FXm+ z*Zg?D!E#Bi2F&*J&}?C#*X_=3e0%Q* z0+OjC7(WB!gHwuvV_~44&)0jhxgYwEO*LWO)49*9Nyw%l_N5~qOoh>=v#4YG9bSDN zpXABz{xDc&9?t&tVL<;gD8MbL1;g2U9|q4cV>Tl-p~qGXlAmq!W!RG9SjD6Z69v;D zRLSStqGfy1KBerk(^okd!|_lQ9gamvK0lk;l(W$RAL9ZUbrB$avjuoS1}~woG>`@qv>5p;c(I) zCV~zp^Y{aDj9yal-th>Say<*5m7kGkCEG^KoFO;P}|(eE`Ku8%Vj@U@TY+Tvk1j$Y2jl!S^B5rm8aga z+Dl#SL+N%_kp}Fg;S2#s?ps@{oZeM$fGeDo;)%F9I-lQw{tqLo(C*n@LUnDZ%Rf+%%qGPsw%-C-iCOtjn4Z%vnt1YQdOn`L-+O+9btme$ zAEWal5OgEofULGHWFP5m;!>n~8`U9&YX-2<%1tSZSPP9y+%1xgr zvfbJ$nn#*qN6@BGz*AP}?@*HlNo*PEp$T2Dw0Ioz{g$TsgQR11Mz;QoX+CNc+Dcp8 zR|0XXg@?0-FEacVf|HG**qlWHqh=?EeMW`|Shs=D)g-ZU4F;KM#`&^eBsfIkr`hAn8I`aU_{ALXD%D;(I?cT>~ zzX?*U+sBT5bC*gzgw6eSx@zY>cGtIQD#JeZ-nVg-spivE-`&sjeAFm48k0J0ThG!Z z49i*m^8M(tWH?3MVUi)39%t6w&vx-})l-Z;!)F+K4g_kKp>KKl^2?jjua;?asDy{^ z`LZN1`aW(UBoJbId>Kd#VLH@L{z>Yh zP5ongiL0iX(hi*2D0_}a*~1qDR0r;1&s+*(A6|^LMga#ejqxx!)N+40)N!30`f!aL z`g4K8Dg0MP=wbYl97ggsIgH|8%3(DBL=IzdN1gEEvGhqb3)Le9(NkH}#*zh4e>_+4^nSs4i}^-5T*lYR;c~uO4p;GFIW*yfnc6Jp zbLFstXUUMKX-ERPS6qjYS?o%a#~9c%N; za&#|6+vMmziheFf_fzykIeLJir{w5CioPyK4^i}aL~SRcS!GASq}XLxi=Z;QkcTJP zxSbd8%Go66Y{ZSSL^&s)ucjQ-!mF$up4Jo>UYb%kqwS6yWI@m1BxuZy#1M>4$ORD)#aZhgDDC%}kwXG-aRcOjkwS%{n@ZREwL~ zoJ%8V&aAx@se1Ab_Q*wl)l<7L5tfWF!GNun)ak1u@XX){4tToT^{^c^xg9)i7aR5C zy4l{?pf(BeKBr0gxP3P6ZP(;>&zB#|`3BRRYr@?(%P?iSg46!^@ebP5w!bHxRGx+6 zp{S(BiDl7HNiEst%n_wpS4N@yoPjY@d$5&MY zsYEe-#oV~L_k>Vq+DAk1$WCP+)^*hq#1AV~`5u`XjWwvWJ&X|ER?`+djCYOBoj}0o znA~^)F2_qG0w;Xh-|iV6R`h#%x`!K2;6vq_w%pd9hZOFua|k$*#r)>bYsKvJFtIOw zUy@z+x?2eJNKJl;zK5k?o`X`CNQol>9ORp*LC=0|j z$G8t(saS^9%A=OB?OK)Xc$n=?_4Z#oi*dSfvFvIwFe-sjApK_hHuR=}&PeG^_k0Nb zBdD+iWn11Y>A5S(H~3(qo=TVA=z-ig$i$gIw0RSLrl_wLVvj7hoqT+~f9e@Dck7Vx z$Lan-gU-l(n;H8fO4a@jd;O2_AY$<^(N3Rczx@$4-~i75;J4t?6m$L&5Gacn?sfjF zJ)$M&l>cy)m0TS)H1xXc`lIart6?}SJ90HbENADhhCuCqyP7TEq~JeZz1Qi-N}Qpp ztw&jN&&1t_h~5>@>x_Zh?){x5FmQBc{vvz-#--cIr;zwc2oUA6J{`@Rxa z!G1ZiMKM7&y53=>5b2jiF-^7NHpefb_={NK_(3K5EzKT7o@qCnJNazKE3Tof5LVN5 zqbCKWxY2{d(r=CYKX*d0)REDYS62b+>io#a87V0Wd#q48hb>|l&zp!o#a%<^JvUDb&G~b+*Q0ZvsCyo>= z9bfem$Exms(J@FZhKOcIv|98RH#rPyF%n%WQ;RX9JFuN^kE*4>K1fak@hdN0J2rQ} zc;pSWI9#09v$T|X(#xbKH4cwp#7-K1gIN4!AIsuFMq+^cuIV^6CY|CTjbGa{2=b1= z))8NO#xcrMOdLYbDr$21eEIf~lnT+W^%QriLN+_Dc#2P}?6*1&dWqwG%ge8)unZJh zy~Ie>1BV?0G-6OdtjvM;jt(f4WN5}uiPabm!W)lvOxK8^fwZr%Z|&^aT11&DCMsJC z$E_N1rw<*&V2!~eZx7|)l=u;I*i?Cvjq zT+|~U+g2YZ-2JVjAwNPxYAZ3zqy%z9>E=oXc9?PGqvpv=v3&ak9{LEvY7e>2Ih8X# zYB8n*#K%?tGCOV@C~j3vG&{Z-DCUHaXS#a(wyUt6hRbHZ)!V1z4vKdHw(mHxEO!{S z;yBgu8|7vB&2^6Zwc^ZZvbP)XGiI&@j^=euN|n6mdG$MqgKW{9U`uqGV{szl=s!pd zwZ@|n$;+no#5TFzmzU!-*tO7YM%3<)A*WwK=(CK`F&ti{(s6wcE|7{EZCDcq@C;;P zIcfh=F}O38HDE*9bw(9@_B#%KtfFNk*HKHc{1SG3eNFN%q-k~Vli<7XcBFvRj6h)! zjk@pG<7Q|*txktv4{*&~Y9dqliy{QNQH9oAFP2@&(x@#-*!SHDYlO#Ej?sg~j4(o| z$xPHjq2kE`;3b1nkir27Z4r}?I_!h-tKxdclY_+&`SyzZPCa^Mz?JW9W8oR33onX37&)ffnQ1{U*oR*@1nc~CR5tM@hSB_}uI6yzMq zWzc#!68JsGR=mqN@F+TtOHgI~O6*%(l2d7o+FBs}a{L=rZL6c+TO2)-)(uJRX=?}r zD|9d~uTsu<+#gwo%0P2^iva`Pz6Bxz#mDL$;X3g|OcyovT!rfZz`peY%AUq?JDs4= zb-9*gc|r89p+g}M@f{+Di>;2tA>v#FcMcJw224h6B02Dgq;5gde$ZtBW=u_P zCqHI#JUC2@PWcQaO#*&|2uD+h;;F2J?S$*Oto*b-`6u(l3`w|D%qK05Qo&Pj!P#Jx<>+?t8$o2b9Lju3aF%{HS|ADu-P)NYkV}qquY_ zHG0SU0pgUXY-KJCRHgt9FzH9VT9b-e%>jHL>foWZUBfp%>WB#xgT?zDIe}t?>f05L zTLQ(mF!QDciF!zVQxHrRje6n9%viO6A8g_iA3?uqVZsA8{N|$~GbsLY;{4N6h4Xiv z$tNv={DX(x%13mjX^e^{2ZVncs#Q~0qf#L{poTENi9Iwj0!SUZ<@sg@s=P-td z%SIlU0-~ew6Om0>SZ;COH%n8AUNvQDDd792IQ|_XM GKmv`@!bnZc46QV~Iqnoc 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 J<@zpb{tF#RlY;;N delta 34761 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 Y?gaf!5)3j9_|<%W+I82o@NVt?3r0OBQ~&?~ diff --git a/host/windows/prebuilt/usb/AdbWinUsbApi.dll b/host/windows/prebuilt/usb/AdbWinUsbApi.dll new file mode 100755 index 0000000000000000000000000000000000000000..0c9e00bd9f48b0ae5c5ed6d7dbbc609420b22971 GIT binary patch literal 60928 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

    SeXOG&{oluT-DQ8CRHq>h%8I$BOX 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 Date: Mon, 10 Aug 2009 17:12:27 -0700 Subject: [PATCH 32/87] Fix runtest launchperf test definition. BUG 2045435 --- testrunner/test_defs.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml index 9d03558d2..44db464e9 100644 --- a/testrunner/test_defs.xml +++ b/testrunner/test_defs.xml @@ -72,7 +72,7 @@ See test_defs.xsd for more information. From 3b0146057889eaf6eb1a6ebc86553a95885f074f Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 10 Aug 2009 18:12:32 -0700 Subject: [PATCH 33/87] Add density demo. This is basically just a copy of DpiTest, but it seems like this stuff would be useful to have in sample code. --- samples/ApiDemos/AndroidManifest.xml | 7 + .../ApiDemos/res/drawable-hdpi/logo240dpi.png | Bin 0 -> 13388 bytes .../res/drawable-hdpi/npatch240dpi.9.png | Bin 0 -> 17331 bytes .../res/drawable-hdpi/reslogo240dpi.png | Bin 0 -> 13388 bytes .../res/drawable-hdpi/smlnpatch240dpi.9.png | Bin 0 -> 946 bytes .../res/drawable-hdpi/stylogo240dpi.png | Bin 0 -> 13388 bytes .../ApiDemos/res/drawable-ldpi/logo120dpi.png | Bin 0 -> 5178 bytes .../res/drawable-ldpi/npatch120dpi.9.png | Bin 0 -> 6299 bytes .../res/drawable-ldpi/reslogo120dpi.png | Bin 0 -> 5178 bytes .../res/drawable-ldpi/smlnpatch120dpi.9.png | Bin 0 -> 804 bytes .../res/drawable-ldpi/stylogo120dpi.png | Bin 0 -> 5178 bytes .../res/drawable-nodpi/logonodpi120.png | Bin 0 -> 5178 bytes .../res/drawable-nodpi/logonodpi160.png | Bin 0 -> 8114 bytes .../res/drawable-nodpi/logonodpi240.png | Bin 0 -> 13388 bytes samples/ApiDemos/res/drawable/logo160dpi.png | Bin 0 -> 8114 bytes .../ApiDemos/res/drawable/npatch160dpi.9.png | Bin 0 -> 9978 bytes .../ApiDemos/res/drawable/reslogo160dpi.png | Bin 0 -> 8114 bytes .../res/drawable/smlnpatch160dpi.9.png | Bin 0 -> 855 bytes .../ApiDemos/res/drawable/stylogo160dpi.png | Bin 0 -> 8114 bytes .../res/layout/density_image_views.xml | 37 +++ .../res/layout/density_styled_image_views.xml | 26 ++ .../res/values-large-long/strings.xml | 19 ++ .../res/values-large-notlong/strings.xml | 19 ++ samples/ApiDemos/res/values-large/strings.xml | 19 ++ samples/ApiDemos/res/values-long/strings.xml | 19 ++ .../res/values-normal-long/strings.xml | 19 ++ .../res/values-normal-notlong/strings.xml | 19 ++ .../ApiDemos/res/values-normal/strings.xml | 19 ++ .../ApiDemos/res/values-notlong/strings.xml | 19 ++ .../res/values-small-long/strings.xml | 19 ++ .../res/values-small-notlong/strings.xml | 19 ++ samples/ApiDemos/res/values-small/strings.xml | 19 ++ samples/ApiDemos/res/values/strings.xml | 2 + samples/ApiDemos/res/values/styles.xml | 17 ++ .../apis/graphics/DensityActivity.java | 223 ++++++++++++++++++ 35 files changed, 521 insertions(+) create mode 100644 samples/ApiDemos/res/drawable-hdpi/logo240dpi.png create mode 100644 samples/ApiDemos/res/drawable-hdpi/npatch240dpi.9.png create mode 100644 samples/ApiDemos/res/drawable-hdpi/reslogo240dpi.png create mode 100644 samples/ApiDemos/res/drawable-hdpi/smlnpatch240dpi.9.png create mode 100644 samples/ApiDemos/res/drawable-hdpi/stylogo240dpi.png create mode 100644 samples/ApiDemos/res/drawable-ldpi/logo120dpi.png create mode 100644 samples/ApiDemos/res/drawable-ldpi/npatch120dpi.9.png create mode 100644 samples/ApiDemos/res/drawable-ldpi/reslogo120dpi.png create mode 100644 samples/ApiDemos/res/drawable-ldpi/smlnpatch120dpi.9.png create mode 100644 samples/ApiDemos/res/drawable-ldpi/stylogo120dpi.png create mode 100644 samples/ApiDemos/res/drawable-nodpi/logonodpi120.png create mode 100644 samples/ApiDemos/res/drawable-nodpi/logonodpi160.png create mode 100644 samples/ApiDemos/res/drawable-nodpi/logonodpi240.png create mode 100644 samples/ApiDemos/res/drawable/logo160dpi.png create mode 100644 samples/ApiDemos/res/drawable/npatch160dpi.9.png create mode 100644 samples/ApiDemos/res/drawable/reslogo160dpi.png create mode 100644 samples/ApiDemos/res/drawable/smlnpatch160dpi.9.png create mode 100644 samples/ApiDemos/res/drawable/stylogo160dpi.png create mode 100644 samples/ApiDemos/res/layout/density_image_views.xml create mode 100644 samples/ApiDemos/res/layout/density_styled_image_views.xml create mode 100644 samples/ApiDemos/res/values-large-long/strings.xml create mode 100644 samples/ApiDemos/res/values-large-notlong/strings.xml create mode 100644 samples/ApiDemos/res/values-large/strings.xml create mode 100644 samples/ApiDemos/res/values-long/strings.xml create mode 100644 samples/ApiDemos/res/values-normal-long/strings.xml create mode 100644 samples/ApiDemos/res/values-normal-notlong/strings.xml create mode 100644 samples/ApiDemos/res/values-normal/strings.xml create mode 100644 samples/ApiDemos/res/values-notlong/strings.xml create mode 100644 samples/ApiDemos/res/values-small-long/strings.xml create mode 100644 samples/ApiDemos/res/values-small-notlong/strings.xml create mode 100644 samples/ApiDemos/res/values-small/strings.xml create mode 100644 samples/ApiDemos/src/com/example/android/apis/graphics/DensityActivity.java diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml index fb34afa9f..032f5c273 100644 --- a/samples/ApiDemos/AndroidManifest.xml +++ b/samples/ApiDemos/AndroidManifest.xml @@ -1627,6 +1627,13 @@ + + + + + + + diff --git a/samples/ApiDemos/res/drawable-hdpi/logo240dpi.png b/samples/ApiDemos/res/drawable-hdpi/logo240dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..4d717a86143dd680bbdd9f6f54c6623d5a33b03b GIT binary patch literal 13388 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 U$N{&z)Bpeg07*qoM6N<$f`>4}{r~^~ literal 0 HcmV?d00001 diff --git a/samples/ApiDemos/res/drawable-hdpi/stylogo240dpi.png b/samples/ApiDemos/res/drawable-hdpi/stylogo240dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..4d717a86143dd680bbdd9f6f54c6623d5a33b03b GIT binary patch literal 13388 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 RfP?@5002ovPDHLkV1kkjBE0|r literal 0 HcmV?d00001 diff --git a/samples/ApiDemos/res/drawable-ldpi/reslogo120dpi.png b/samples/ApiDemos/res/drawable-ldpi/reslogo120dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..46bbd5bd3d485ba132f14fd5b04a7c6b69004d0c GIT binary patch literal 5178 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 Eg4ZI2KmY&$ literal 0 HcmV?d00001 diff --git a/samples/ApiDemos/res/drawable/reslogo160dpi.png b/samples/ApiDemos/res/drawable/reslogo160dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..c23b2ce83b43d984173a16be7fc25b46bf4fbd50 GIT binary patch literal 8114 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 literal 0 HcmV?d00001 diff --git a/samples/ApiDemos/res/drawable/stylogo160dpi.png b/samples/ApiDemos/res/drawable/stylogo160dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..c23b2ce83b43d984173a16be7fc25b46bf4fbd50 GIT binary patch literal 8114 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 + + + + + + + + + + + diff --git a/samples/ApiDemos/res/layout/density_styled_image_views.xml b/samples/ApiDemos/res/layout/density_styled_image_views.xml new file mode 100644 index 000000000..86c63bf23 --- /dev/null +++ b/samples/ApiDemos/res/layout/density_styled_image_views.xml @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/samples/ApiDemos/res/values-large-long/strings.xml b/samples/ApiDemos/res/values-large-long/strings.xml new file mode 100644 index 000000000..7c392d8b7 --- /dev/null +++ b/samples/ApiDemos/res/values-large-long/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Large Long + diff --git a/samples/ApiDemos/res/values-large-notlong/strings.xml b/samples/ApiDemos/res/values-large-notlong/strings.xml new file mode 100644 index 000000000..40328eab4 --- /dev/null +++ b/samples/ApiDemos/res/values-large-notlong/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Large NotLong + diff --git a/samples/ApiDemos/res/values-large/strings.xml b/samples/ApiDemos/res/values-large/strings.xml new file mode 100644 index 000000000..c9fb18993 --- /dev/null +++ b/samples/ApiDemos/res/values-large/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Large + diff --git a/samples/ApiDemos/res/values-long/strings.xml b/samples/ApiDemos/res/values-long/strings.xml new file mode 100644 index 000000000..5d15048e4 --- /dev/null +++ b/samples/ApiDemos/res/values-long/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Long + diff --git a/samples/ApiDemos/res/values-normal-long/strings.xml b/samples/ApiDemos/res/values-normal-long/strings.xml new file mode 100644 index 000000000..01a048763 --- /dev/null +++ b/samples/ApiDemos/res/values-normal-long/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Normal Long + diff --git a/samples/ApiDemos/res/values-normal-notlong/strings.xml b/samples/ApiDemos/res/values-normal-notlong/strings.xml new file mode 100644 index 000000000..bea3f8dcb --- /dev/null +++ b/samples/ApiDemos/res/values-normal-notlong/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Normal NotLong + diff --git a/samples/ApiDemos/res/values-normal/strings.xml b/samples/ApiDemos/res/values-normal/strings.xml new file mode 100644 index 000000000..16ff46fc8 --- /dev/null +++ b/samples/ApiDemos/res/values-normal/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Normal + diff --git a/samples/ApiDemos/res/values-notlong/strings.xml b/samples/ApiDemos/res/values-notlong/strings.xml new file mode 100644 index 000000000..a3e78dbb6 --- /dev/null +++ b/samples/ApiDemos/res/values-notlong/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: NotLong + diff --git a/samples/ApiDemos/res/values-small-long/strings.xml b/samples/ApiDemos/res/values-small-long/strings.xml new file mode 100644 index 000000000..8526f61db --- /dev/null +++ b/samples/ApiDemos/res/values-small-long/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Small Long + diff --git a/samples/ApiDemos/res/values-small-notlong/strings.xml b/samples/ApiDemos/res/values-small-notlong/strings.xml new file mode 100644 index 000000000..bc8a67687 --- /dev/null +++ b/samples/ApiDemos/res/values-small-notlong/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Small NotLong + diff --git a/samples/ApiDemos/res/values-small/strings.xml b/samples/ApiDemos/res/values-small/strings.xml new file mode 100644 index 000000000..56db73056 --- /dev/null +++ b/samples/ApiDemos/res/values-small/strings.xml @@ -0,0 +1,19 @@ + + + + + Density: Small + diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml index 29bbcec69..c2c98295b 100644 --- a/samples/ApiDemos/res/values/strings.xml +++ b/samples/ApiDemos/res/values/strings.xml @@ -423,6 +423,8 @@ Hide Me! + Density: Unknown Screen + diff --git a/samples/ApiDemos/res/values/styles.xml b/samples/ApiDemos/res/values/styles.xml index 40e934e78..3c9c68185 100644 --- a/samples/ApiDemos/res/values/styles.xml +++ b/samples/ApiDemos/res/values/styles.xml @@ -63,4 +63,21 @@ normal + + + + + diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/DensityActivity.java b/samples/ApiDemos/src/com/example/android/apis/graphics/DensityActivity.java new file mode 100644 index 000000000..10c42a716 --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/DensityActivity.java @@ -0,0 +1,223 @@ +/* + * 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.example.android.apis.graphics; + +//Need the following import to get access to the app resources, since this +//class is in a sub-package. +import com.example.android.apis.R; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.ScrollView; +import android.view.LayoutInflater; +import android.view.View; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.util.DisplayMetrics; +import android.util.Log; + +/** + * This activity demonstrates various ways density can cause the scaling of + * bitmaps and drawables. + */ +public class DensityActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final LayoutInflater li = (LayoutInflater)getSystemService( + LAYOUT_INFLATER_SERVICE); + + this.setTitle(R.string.density_title); + LinearLayout root = new LinearLayout(this); + root.setOrientation(LinearLayout.VERTICAL); + + LinearLayout layout = new LinearLayout(this); + addBitmapDrawable(layout, R.drawable.logo120dpi, true); + addBitmapDrawable(layout, R.drawable.logo160dpi, true); + addBitmapDrawable(layout, R.drawable.logo240dpi, true); + addLabelToRoot(root, "Prescaled bitmap in drawable"); + addChildToRoot(root, layout); + + layout = new LinearLayout(this); + addBitmapDrawable(layout, R.drawable.logo120dpi, false); + addBitmapDrawable(layout, R.drawable.logo160dpi, false); + addBitmapDrawable(layout, R.drawable.logo240dpi, false); + addLabelToRoot(root, "Autoscaled bitmap in drawable"); + addChildToRoot(root, layout); + + layout = new LinearLayout(this); + addResourceDrawable(layout, R.drawable.logo120dpi); + addResourceDrawable(layout, R.drawable.logo160dpi); + addResourceDrawable(layout, R.drawable.logo240dpi); + addLabelToRoot(root, "Prescaled resource drawable"); + addChildToRoot(root, layout); + + layout = (LinearLayout)li.inflate(R.layout.density_image_views, null); + addLabelToRoot(root, "Inflated layout"); + addChildToRoot(root, layout); + + layout = (LinearLayout)li.inflate(R.layout.density_styled_image_views, null); + addLabelToRoot(root, "Inflated styled layout"); + addChildToRoot(root, layout); + + layout = new LinearLayout(this); + addCanvasBitmap(layout, R.drawable.logo120dpi, true); + addCanvasBitmap(layout, R.drawable.logo160dpi, true); + addCanvasBitmap(layout, R.drawable.logo240dpi, true); + addLabelToRoot(root, "Prescaled bitmap"); + addChildToRoot(root, layout); + + layout = new LinearLayout(this); + addCanvasBitmap(layout, R.drawable.logo120dpi, false); + addCanvasBitmap(layout, R.drawable.logo160dpi, false); + addCanvasBitmap(layout, R.drawable.logo240dpi, false); + addLabelToRoot(root, "Autoscaled bitmap"); + addChildToRoot(root, layout); + + layout = new LinearLayout(this); + addResourceDrawable(layout, R.drawable.logonodpi120); + addResourceDrawable(layout, R.drawable.logonodpi160); + addResourceDrawable(layout, R.drawable.logonodpi240); + addLabelToRoot(root, "No-dpi resource drawable"); + addChildToRoot(root, layout); + + layout = new LinearLayout(this); + addNinePatchResourceDrawable(layout, R.drawable.smlnpatch120dpi); + addNinePatchResourceDrawable(layout, R.drawable.smlnpatch160dpi); + addNinePatchResourceDrawable(layout, R.drawable.smlnpatch240dpi); + addLabelToRoot(root, "Prescaled 9-patch resource drawable"); + addChildToRoot(root, layout); + + setContentView(scrollWrap(root)); + } + + private View scrollWrap(View view) { + ScrollView scroller = new ScrollView(this); + scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.FILL_PARENT, + ScrollView.LayoutParams.FILL_PARENT)); + return scroller; + } + + private void addLabelToRoot(LinearLayout root, String text) { + TextView label = new TextView(this); + label.setText(text); + root.addView(label, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT)); + } + + private void addChildToRoot(LinearLayout root, LinearLayout layout) { + root.addView(layout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT)); + } + + private void addBitmapDrawable(LinearLayout layout, int resource, boolean scale) { + Bitmap bitmap; + bitmap = loadAndPrintDpi(resource, scale); + + View view = new View(this); + + final BitmapDrawable d = new BitmapDrawable(getResources(), bitmap); + if (!scale) d.setTargetDensity(getResources().getDisplayMetrics()); + view.setBackgroundDrawable(d); + + view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(), + d.getIntrinsicHeight())); + layout.addView(view); + } + + private void addResourceDrawable(LinearLayout layout, int resource) { + View view = new View(this); + + final Drawable d = getResources().getDrawable(resource); + view.setBackgroundDrawable(d); + + view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(), + d.getIntrinsicHeight())); + layout.addView(view); + } + + private void addCanvasBitmap(LinearLayout layout, int resource, boolean scale) { + Bitmap bitmap; + bitmap = loadAndPrintDpi(resource, scale); + + ScaledBitmapView view = new ScaledBitmapView(this, bitmap); + + view.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT)); + layout.addView(view); + } + + private void addNinePatchResourceDrawable(LinearLayout layout, int resource) { + View view = new View(this); + + final Drawable d = getResources().getDrawable(resource); + view.setBackgroundDrawable(d); + + Log.i("foo", "9-patch #" + Integer.toHexString(resource) + + " w=" + d.getIntrinsicWidth() + " h=" + d.getIntrinsicHeight()); + view.setLayoutParams(new LinearLayout.LayoutParams( + d.getIntrinsicWidth()*2, d.getIntrinsicHeight()*2)); + layout.addView(view); + } + + private Bitmap loadAndPrintDpi(int id, boolean scale) { + Bitmap bitmap; + if (scale) { + bitmap = BitmapFactory.decodeResource(getResources(), id); + } else { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inScaled = false; + bitmap = BitmapFactory.decodeResource(getResources(), id, opts); + } + return bitmap; + } + + private class ScaledBitmapView extends View { + private Bitmap mBitmap; + + public ScaledBitmapView(Context context, Bitmap bitmap) { + super(context); + mBitmap = bitmap; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + final DisplayMetrics metrics = getResources().getDisplayMetrics(); + setMeasuredDimension( + mBitmap.getScaledWidth(metrics), + mBitmap.getScaledHeight(metrics)); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null); + } + } +} From bdc2220af4536d45300dc08d259ca90455373d53 Mon Sep 17 00:00:00 2001 From: Bill Napier Date: Mon, 10 Aug 2009 20:50:30 -0700 Subject: [PATCH 34/87] Add press/tap and also a command queue for returning multiple events. --- cmds/monkey/README.NETWORK.txt | 10 + .../commands/monkey/MonkeySourceNetwork.java | 179 +++++++++++++++--- 2 files changed, 159 insertions(+), 30 deletions(-) diff --git a/cmds/monkey/README.NETWORK.txt b/cmds/monkey/README.NETWORK.txt index 3ec6298f0..1a1ad9c3c 100644 --- a/cmds/monkey/README.NETWORK.txt +++ b/cmds/monkey/README.NETWORK.txt @@ -77,6 +77,16 @@ wake This command will wake the device up from sleep and allow user input. +tap x y +The tap command is a shortcut for the touch command. It will +automatically send both the up and the down event. + +press keycode + +The press command is a shortcut for the key command. The keycode +paramter works just like the key command and will automatically send +both the up and the down event. + OTHER NOTES There are some convenience features added to allow running without diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java index b444dd340..63e226c7d 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java @@ -36,7 +36,9 @@ import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.LinkedList; import java.util.List; +import java.util.Queue; import java.util.StringTokenizer; /** @@ -47,7 +49,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { private static final String TAG = "MonkeyStub"; private interface MonkeyCommand { - MonkeyEvent translateCommand(List command); + MonkeyEvent translateCommand(List command, CommandQueue queue); } /** @@ -56,7 +58,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { private static class FlipCommand implements MonkeyCommand { // flip open // flip closed - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() > 1) { String direction = command.get(1); if ("open".equals(direction)) { @@ -77,7 +80,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // touch down 120 120 // touch move 140 140 // touch up 140 140 - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 4) { String actionName = command.get(1); int x = 0; @@ -120,7 +124,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // trackball [dx] [dy] // trackball 1 0 -- move right // trackball -1 0 -- move left - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 3) { int dx = 0; int dy = 0; @@ -147,29 +152,14 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // key [down|up] [keycode] // key down 82 // key up 82 - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 3) { - int keyCode = -1; - String keyName = command.get(2); - try { - keyCode = Integer.parseInt(keyName); - } catch (NumberFormatException e) { - // Ok, it wasn't a number, see if we have a - // keycode name for it - keyCode = MonkeySourceRandom.getKeyCode(keyName); - if (keyCode == -1) { - // OK, one last ditch effort to find a match. - // Build the KEYCODE_STRING from the string - // we've been given and see if that key - // exists. This would allow you to do "key - // down menu", for example. - keyCode = MonkeySourceRandom.getKeyCode("KEYCODE_" + keyName.toUpperCase()); - if (keyCode == -1) { - // Ok, you gave us something bad. - Log.e(TAG, "Can't find keyname: " + keyName); - return null; - } - } + int keyCode = getKeyCode(command.get(2)); + if (keyCode < 0) { + // Ok, you gave us something bad. + Log.e(TAG, "Can't find keyname: " + command.get(2)); + return null; } Log.d(TAG, "keycode: " + keyCode); int action = -1; @@ -188,12 +178,39 @@ public class MonkeySourceNetwork implements MonkeyEventSource { } } + /** + * Get an integer keycode value from a given keyname. + * + * @param keyName the key name to get the code for + * @returns the integer keycode value, or -1 on error. + */ + private static int getKeyCode(String keyName) { + int keyCode = -1; + try { + keyCode = Integer.parseInt(keyName); + } catch (NumberFormatException e) { + // Ok, it wasn't a number, see if we have a + // keycode name for it + keyCode = MonkeySourceRandom.getKeyCode(keyName); + if (keyCode == -1) { + // OK, one last ditch effort to find a match. + // Build the KEYCODE_STRING from the string + // we've been given and see if that key + // exists. This would allow you to do "key + // down menu", for example. + keyCode = MonkeySourceRandom.getKeyCode("KEYCODE_" + keyName.toUpperCase()); + } + } + return keyCode; + } + /** * Command to put the Monkey to sleep. */ private static class SleepCommand implements MonkeyCommand { // sleep 2000 - public MonkeyEvent translateCommand(List command) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { if (command.size() == 2) { int sleep = -1; String sleepStr = command.get(1); @@ -213,14 +230,71 @@ public class MonkeySourceNetwork implements MonkeyEventSource { */ private static class WakeCommand implements MonkeyCommand { // wake - public MonkeyEvent translateCommand(List command) { - if (wake()) { + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { + if (!wake()) { return null; } return new MonkeyNoopEvent(); } } + /** + * Command to "tap" at a location (Sends a down and up touch + * event). + */ + private static class TapCommand implements MonkeyCommand { + // tap x y + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { + if (command.size() == 3) { + int x = 0; + int y = 0; + try { + x = Integer.parseInt(command.get(1)); + y = Integer.parseInt(command.get(2)); + } catch (NumberFormatException e) { + // Ok, it wasn't a number + Log.e(TAG, "Got something that wasn't a number", e); + return null; + } + + queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + -1, MotionEvent.ACTION_DOWN, + x, y, 0)); + queue.enqueueEvent(new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, + -1, MotionEvent.ACTION_UP, + x, y, 0)); + return new MonkeyNoopEvent(); + } + return null; + } + } + + /** + * Command to "press" a buttons (Sends an up and down key event.) + */ + private static class PressCommand implements MonkeyCommand { + // press keycode + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { + if (command.size() == 2) { + int keyCode = getKeyCode(command.get(1)); + if (keyCode < 0) { + // Ok, you gave us something bad. + Log.e(TAG, "Can't find keyname: " + command.get(1)); + return null; + } + + queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, keyCode)); + queue.enqueueEvent(new MonkeyKeyEvent(KeyEvent.ACTION_UP, keyCode)); + return new MonkeyNoopEvent(); + + } + return null; + } + } + /** * Force the device to wake up. * @@ -249,6 +323,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { COMMAND_MAP.put("key", new KeyCommand()); COMMAND_MAP.put("sleep", new SleepCommand()); COMMAND_MAP.put("wake", new WakeCommand()); + COMMAND_MAP.put("tap", new TapCommand()); + COMMAND_MAP.put("press", new PressCommand()); } // QUIT command @@ -258,6 +334,39 @@ public class MonkeySourceNetwork implements MonkeyEventSource { private static final String OK = "OK"; private static final String ERROR = "ERROR"; + private static interface CommandQueue { + /** + * Enqueue an event to be returned later. This allows a + * command to return multiple events. Commands using the + * command queue still have to return a valid event from their + * translateCommand method. The returned command will be + * executed before anything put into the queue. + * + * @param e the event to be enqueued. + */ + public void enqueueEvent(MonkeyEvent e); + }; + + // Queue of Events to be processed. This allows commands to push + // multiple events into the queue to be processed. + private static class CommandQueueImpl implements CommandQueue{ + private final Queue queuedEvents = new LinkedList(); + + public void enqueueEvent(MonkeyEvent e) { + queuedEvents.offer(e); + } + + /** + * Get the next queued event to excecute. + * + * @returns the next event, or null if there aren't any more. + */ + public MonkeyEvent getNextQueuedEvent() { + return queuedEvents.poll(); + } + }; + + private final CommandQueueImpl commandQueue = new CommandQueueImpl(); private final int port; private BufferedReader input; @@ -345,7 +454,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource { if (parts.size() > 0) { MonkeyCommand command = COMMAND_MAP.get(parts.get(0)); if (command != null) { - return command.translateCommand(parts); + return command.translateCommand(parts, + commandQueue); } return null; } @@ -366,6 +476,15 @@ public class MonkeySourceNetwork implements MonkeyEventSource { // Now, get the next command. This call may block, but that's OK try { while (true) { + // Check to see if we have any events queued up. If + // we do, use those until we have no more. Then get + // more input from the user. + MonkeyEvent queuedEvent = commandQueue.getNextQueuedEvent(); + if (queuedEvent != null) { + // dispatch the event + return queuedEvent; + } + String command = input.readLine(); if (command == null) { Log.d(TAG, "Connection dropped."); From 5dfeb0e195c79915d47ebc61ec1b1e2375264a22 Mon Sep 17 00:00:00 2001 From: Wu-cheng Li Date: Tue, 11 Aug 2009 17:26:35 +0800 Subject: [PATCH 35/87] Release the camera in surfaceDestroyed(). If the camera is not released, the new client will fail to connect to camera next time. b2042350 --- .../src/com/example/android/apis/graphics/CameraPreview.java | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java b/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java index ceff15042..e3cf97696 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java @@ -78,6 +78,7 @@ class Preview extends SurfaceView implements SurfaceHolder.Callback { // Because the CameraDevice object is not a shared resource, it's very // important to release it when the activity is paused. mCamera.stopPreview(); + mCamera.release(); mCamera = null; } From 1620a180c2f56573d4f9446c54acc126175f6775 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 11 Aug 2009 11:08:36 -0700 Subject: [PATCH 36/87] BUG 2033924: Add AdbWinUsbApi.dll to prebuilt for Windows SDK --- build/tools/make_windows_sdk.sh | 6 +++--- host/windows/prebuilt/usb/Android.mk | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh index 2a6433ad1..11ab3976d 100755 --- a/build/tools/make_windows_sdk.sh +++ b/build/tools/make_windows_sdk.sh @@ -195,9 +195,9 @@ function package() { # Now move the final zip from the temp dest to the final dist dir mv -v "$TEMP_DIR/$DEST_NAME_ZIP" "$DIST_DIR/$DEST_NAME_ZIP" - # We want fastboot and adb next to the new SDK - for i in fastboot.exe adb.exe AdbWinApi.dll; do - mv -vf out/host/windows-x86/bin/$i "$DIST_DIR"/$i + # We want fastboot and adb (and its DLLs) next to the new SDK + for i in fastboot.exe adb.exe AdbWinApi.dll AdbWinUsbApi.dll; do + cp -vf out/host/windows-x86/bin/$i "$DIST_DIR"/$i done echo "Done" diff --git a/host/windows/prebuilt/usb/Android.mk b/host/windows/prebuilt/usb/Android.mk index 180610109..9cf4e61f3 100644 --- a/host/windows/prebuilt/usb/Android.mk +++ b/host/windows/prebuilt/usb/Android.mk @@ -6,7 +6,8 @@ LOCAL_PREBUILT_LIBS := \ AdbWinApi.a LOCAL_PREBUILT_EXECUTABLES := \ - AdbWinApi.dll + AdbWinApi.dll \ + AdbWinUsbApi.dll .PHONY : kill-adb From 609b375a03b48dd4a155aba7bcc5424e2e924d0a Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 11 Aug 2009 13:46:21 -0700 Subject: [PATCH 37/87] BUG 2041701: Release notes content/link in SDK Updater schema --- .../sdklib/internal/repository/Package.java | 89 ++++++++++++++++--- .../sdklib/repository/SdkRepository.java | 10 ++- .../sdklib/repository/sdk-repository.xsd | 20 +++++ .../sdklib/repository/repository_sample.xml | 4 + 4 files changed, 107 insertions(+), 16 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java index 8d19c0f6d..5afe73cd1 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java @@ -42,16 +42,20 @@ import java.util.Properties; */ public abstract class Package implements IDescription { - private static final String PROP_REVISION = "Pkg.Revision"; //$NON-NLS-1$ - private static final String PROP_LICENSE = "Pkg.License"; //$NON-NLS-1$ - private static final String PROP_DESC = "Pkg.Desc"; //$NON-NLS-1$ - private static final String PROP_DESC_URL = "Pkg.DescUrl"; //$NON-NLS-1$ - private static final String PROP_SOURCE_URL = "Pkg.SourceUrl"; //$NON-NLS-1$ - private static final String PROP_USER_SOURCE = "Pkg.UserSrc"; //$NON-NLS-1$ + private static final String PROP_REVISION = "Pkg.Revision"; //$NON-NLS-1$ + private static final String PROP_LICENSE = "Pkg.License"; //$NON-NLS-1$ + private static final String PROP_DESC = "Pkg.Desc"; //$NON-NLS-1$ + private static final String PROP_DESC_URL = "Pkg.DescUrl"; //$NON-NLS-1$ + private static final String PROP_RELEASE_NOTE = "Pkg.RelNote"; //$NON-NLS-1$ + private static final String PROP_RELEASE_URL = "Pkg.RelNoteUrl"; //$NON-NLS-1$ + private static final String PROP_SOURCE_URL = "Pkg.SourceUrl"; //$NON-NLS-1$ + private static final String PROP_USER_SOURCE = "Pkg.UserSrc"; //$NON-NLS-1$ private final int mRevision; private final String mLicense; private final String mDescription; private final String mDescUrl; + private final String mReleaseNote; + private final String mReleaseUrl; private final Archive[] mArchives; private final RepoSource mSource; @@ -80,6 +84,8 @@ public abstract class Package implements IDescription { mRevision = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_REVISION, 0); mDescription = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_DESCRIPTION); mDescUrl = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_DESC_URL); + mReleaseNote = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_RELEASE_NOTE); + mReleaseUrl = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_RELEASE_URL); mLicense = parseLicense(packageNode, licenses); mArchives = parseArchives(XmlParserUtils.getFirstChild( @@ -104,10 +110,19 @@ public abstract class Package implements IDescription { Arch archiveArch, String archiveOsPath) { + if (description == null) { + description = ""; + } + if (descUrl == null) { + descUrl = ""; + } + mRevision = Integer.parseInt(getProperty(props, PROP_REVISION, Integer.toString(revision))); - mLicense = getProperty(props, PROP_LICENSE, license); - mDescription = getProperty(props, PROP_DESC, description); - mDescUrl = getProperty(props, PROP_DESC_URL, descUrl); + mLicense = getProperty(props, PROP_LICENSE, license); + mDescription = getProperty(props, PROP_DESC, description); + mDescUrl = getProperty(props, PROP_DESC_URL, descUrl); + mReleaseNote = getProperty(props, PROP_RELEASE_NOTE, ""); + mReleaseUrl = getProperty(props, PROP_RELEASE_URL, ""); // If source is null and we can find a source URL in the properties, generate // a dummy source just to store the URL. This allows us to easily remember where @@ -145,16 +160,24 @@ public abstract class Package implements IDescription { */ void saveProperties(Properties props) { props.setProperty(PROP_REVISION, Integer.toString(mRevision)); - if (mLicense != null) { + if (mLicense != null && mLicense.length() > 0) { props.setProperty(PROP_LICENSE, mLicense); } - if (mDescription != null) { + + if (mDescription != null && mDescription.length() > 0) { props.setProperty(PROP_DESC, mDescription); } - if (mDescUrl != null) { + if (mDescUrl != null && mDescUrl.length() > 0) { props.setProperty(PROP_DESC_URL, mDescUrl); } + if (mReleaseNote != null && mReleaseNote.length() > 0) { + props.setProperty(PROP_RELEASE_NOTE, mReleaseNote); + } + if (mReleaseUrl != null && mReleaseUrl.length() > 0) { + props.setProperty(PROP_RELEASE_URL, mReleaseUrl); + } + if (mSource != null) { props.setProperty(PROP_SOURCE_URL, mSource.getUrl()); props.setProperty(PROP_USER_SOURCE, Boolean.toString(mSource.isUserSource())); @@ -258,6 +281,22 @@ public abstract class Package implements IDescription { return mDescUrl; } + /** + * Returns the optional release note for all packages (platform, add-on, tool, doc) or + * for a lib. Can be empty but not null. + */ + public String getReleaseNote() { + return mReleaseNote; + } + + /** + * Returns the optional release note URL for all packages (platform, add-on, tool, doc). + * Can be empty but not null. + */ + public String getReleaseNoteUrl() { + return mReleaseUrl; + } + /** * Returns the archives defined in this package. * Can be an empty array but not null. @@ -291,7 +330,31 @@ public abstract class Package implements IDescription { * Can be empty but not null. */ public String getLongDescription() { - return String.format("%1$s\nRevision %2$d", getDescription(), getRevision()); + StringBuilder sb = new StringBuilder(); + + String s = getDescription(); + if (s != null) { + sb.append(s); + } + + sb.append(String.format("\nRevision %1$d", getRevision())); + + s = getDescUrl(); + if (s != null && s.length() > 0) { + sb.append(String.format("\n\nMore information at %1$s", s)); + } + + s = getReleaseNote(); + if (s != null && s.length() > 0) { + sb.append("\n\nRelease note:\n").append(s); + } + + s = getReleaseNoteUrl(); + if (s != null && s.length() > 0) { + sb.append("\nRelease note URL: ").append(s); + } + + return sb.toString(); } /** diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java index 88d18dbfd..4b12d597b 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java @@ -53,11 +53,15 @@ public class SdkRepository { /** The optional uses-license for all packages (platform, add-on, tool, doc) or for a lib. */ public static final String NODE_USES_LICENSE = "uses-license"; //$NON-NLS-1$ /** The revision, an int > 0, for all packages (platform, add-on, tool, doc). */ - public static final String NODE_REVISION = "revision"; //$NON-NLS-1$ + public static final String NODE_REVISION = "revision"; //$NON-NLS-1$ /** The optional description for all packages (platform, add-on, tool, doc) or for a lib. */ - public static final String NODE_DESCRIPTION = "description"; //$NON-NLS-1$ + public static final String NODE_DESCRIPTION = "description"; //$NON-NLS-1$ /** The optional description URL for all packages (platform, add-on, tool, doc). */ - public static final String NODE_DESC_URL = "desc-url"; //$NON-NLS-1$ + public static final String NODE_DESC_URL = "desc-url"; //$NON-NLS-1$ + /** The optional release note for all packages (platform, add-on, tool, doc). */ + public static final String NODE_RELEASE_NOTE = "release-note"; //$NON-NLS-1$ + /** The optional release note URL for all packages (platform, add-on, tool, doc). */ + public static final String NODE_RELEASE_URL = "release-url"; //$NON-NLS-1$ /** The version, a string, for platform packages. */ public static final String NODE_VERSION = "version"; //$NON-NLS-1$ diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd index a697c83a3..7ca089298 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd @@ -65,6 +65,10 @@ + + + + @@ -99,6 +103,10 @@ + + + + @@ -143,6 +151,10 @@ + + + + @@ -173,6 +185,10 @@ + + + + @@ -219,6 +235,10 @@ + + + + diff --git a/tools/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml b/tools/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml index 73405498a..20b85717c 100755 --- a/tools/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml +++ b/tools/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml @@ -39,6 +39,10 @@ Some optional description http://www.example.com/platform1.html + This is an optional release note + for this package. It's a free multi-line text. + + http://some/url/for/the/release/note.html From 8585e68b4072583e84bac8ade8d8f74718e719c3 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 11 Aug 2009 14:26:29 -0700 Subject: [PATCH 38/87] BUG 2039245 : Need to show something in the source if there are no available package Also moves the "Show updates only" checkbox around. --- .../repository/RemotePackagesPage.java | 23 ++- .../repository/RepoSourcesAdapter.java | 142 +++++++++++++----- .../repository/icons/ImageFactory.java | 21 +-- .../repository/icons/nopkg_icon16.png | Bin 0 -> 397 bytes 4 files changed, 123 insertions(+), 63 deletions(-) create mode 100755 tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java index a7c1a83a1..6ea040c34 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java @@ -62,7 +62,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener { private Group mDescriptionContainer; private Button mAddSiteButton; private Button mDeleteSiteButton; - private Label mPlaceholder3; private Button mRefreshButton; private Button mInstallSelectedButton; private Label mDescriptionLabel; @@ -118,16 +117,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener { spacer.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); gd.heightHint = 0; - mUpdateOnlyCheckBox = new Button(composite, SWT.CHECK); - mUpdateOnlyCheckBox.setText("Display updates only"); - mUpdateOnlyCheckBox.setSelection(mUpdaterData.getSettingsController().getShowUpdateOnly()); - mUpdateOnlyCheckBox.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - onShowUpdateOnly(); //$hide$ - } - }); - mDescriptionContainer = new Group(parent, SWT.NONE); mDescriptionContainer.setLayout(new GridLayout(1, false)); mDescriptionContainer.setText("Description"); @@ -155,8 +144,16 @@ public class RemotePackagesPage extends Composite implements ISdkListener { }); mDeleteSiteButton.setText("Delete Site..."); - mPlaceholder3 = new Label(parent, SWT.NONE); - mPlaceholder3.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1)); + mUpdateOnlyCheckBox = new Button(parent, SWT.CHECK); + mUpdateOnlyCheckBox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1)); + mUpdateOnlyCheckBox.setText("Display updates only"); + mUpdateOnlyCheckBox.setSelection(mUpdaterData.getSettingsController().getShowUpdateOnly()); + mUpdateOnlyCheckBox.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + onShowUpdateOnly(); //$hide$ + } + }); mRefreshButton = new Button(parent, SWT.NONE); mRefreshButton.addSelectionListener(new SelectionAdapter() { diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java index dbf46f593..de12666e2 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java @@ -43,6 +43,11 @@ public class RepoSourcesAdapter { private final UpdaterData mUpdaterData; + /** + * A dummy RepoSource entry returned for sources which had load errors. + * It displays a summary of the error as its short description or + * it displays the source's long description. + */ public static class RepoSourceError implements IDescription { private final RepoSource mSource; @@ -60,6 +65,33 @@ public class RepoSourcesAdapter { } } + /** + * A dummy RepoSource entry returned for sources with no packages. + * We need that to force the SWT tree to display an open/close triangle + * even for empty sources. + */ + public static class RepoSourceEmpty implements IDescription { + + private final RepoSource mSource; + private final boolean mEmptyBecauseOfUpdateOnly; + + public RepoSourceEmpty(RepoSource source, boolean emptyBecauseOfUpdateOnly) { + mSource = source; + mEmptyBecauseOfUpdateOnly = emptyBecauseOfUpdateOnly; + } + + public String getLongDescription() { + return mSource.getLongDescription(); + } + + public String getShortDescription() { + if (mEmptyBecauseOfUpdateOnly) { + return "Some packages were found but are not compatible updates."; + } else { + return "No packages found"; + } + } + } public RepoSourcesAdapter(UpdaterData updaterData) { mUpdaterData = updaterData; @@ -137,50 +169,78 @@ public class RepoSourcesAdapter { return mUpdaterData.getSources().getSources(); } else if (parentElement instanceof RepoSource) { - final RepoSource source = (RepoSource) parentElement; - Package[] packages = source.getPackages(); - - if (packages == null && source.getFetchError() == null) { - final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp(); - - mUpdaterData.getTaskFactory().start("Loading Source", new ITask() { - public void run(ITaskMonitor monitor) { - source.load(monitor, forceHttp); - } - }); - - packages = source.getPackages(); - } - if (packages != null) { - // filter out only the packages that are new/upgrade. - if (mUpdaterData.getSettingsController().getShowUpdateOnly()) { - return filteredPackages(packages); - } - return packages; - } else if (source.getFetchError() != null) { - // Return a dummy entry to display the fetch error - return new Object[] { new RepoSourceError(source) }; - } + return getRepoSourceChildren((RepoSource) parentElement); } else if (parentElement instanceof Package) { - Archive[] archives = ((Package) parentElement).getArchives(); - if (mUpdaterData.getSettingsController().getShowUpdateOnly()) { - for (Archive archive : archives) { - // if we only want the compatible archives, then we just take the first - // one. it's unlikely there are 2 compatible archives for the same - // package - if (archive.isCompatible()) { - return new Object[] { archive }; - } - } - } - - return archives; + return getPackageChildren((Package) parentElement); } return new Object[0]; } + /** + * Returns the list of packages for this repo source, eventually filtered to display + * only update packages. If the list is empty, returns a specific empty node. If there's + * an error, returns a specific error node. + */ + private Object[] getRepoSourceChildren(final RepoSource source) { + Package[] packages = source.getPackages(); + + if (packages == null && source.getFetchError() == null) { + final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp(); + + mUpdaterData.getTaskFactory().start("Loading Source", new ITask() { + public void run(ITaskMonitor monitor) { + source.load(monitor, forceHttp); + } + }); + + packages = source.getPackages(); + } + + boolean wasEmptyBeforeFilter = (packages == null || packages.length == 0); + + // filter out only the packages that are new/upgrade. + if (packages != null && mUpdaterData.getSettingsController().getShowUpdateOnly()) { + packages = filteredPackages(packages); + } + if (packages != null && packages.length == 0) { + packages = null; + } + + if (packages != null && source.getFetchError() != null) { + // Return a dummy entry to display the fetch error + return new Object[] { new RepoSourceError(source) }; + } + + // Either return a non-null package list or create a new empty node + if (packages != null) { + return packages; + } else { + return new Object[] { new RepoSourceEmpty(source, !wasEmptyBeforeFilter) } ; + } + } + + /** + * Returns the list of archives for the given package, eventually filtering it + * to only show the compatible archives. + */ + private Object[] getPackageChildren(Package pkg) { + Archive[] archives = pkg.getArchives(); + if (mUpdaterData.getSettingsController().getShowUpdateOnly()) { + for (Archive archive : archives) { + // if we only want the compatible archives, then we just take the first + // one. it's unlikely there are 2 compatible archives for the same + // package + if (archive.isCompatible()) { + return new Object[] { archive }; + } + } + } + + return archives; + } + /** * Returns the parent of a given element. * The input {@link RepoSourcesAdapter} is the parent of all {@link RepoSource} elements. @@ -213,7 +273,7 @@ public class RepoSourcesAdapter { * @param remotePackages the list of packages to filter. * @return a non null (but maybe empty) list of new or update packages. */ - private Object[] filteredPackages(Package[] remotePackages) { + private Package[] filteredPackages(Package[] remotePackages) { // get the installed packages Package[] installedPackages = mUpdaterData.getInstalledPackage(); @@ -233,10 +293,10 @@ public class RepoSourcesAdapter { if (info == UpdateInfo.UPDATE) { filteredList.add(remotePkg); newPkg = false; - break; // there shouldn't be 2 revision of the same package + break; // there shouldn't be 2 revisions of the same package } else if (info != UpdateInfo.INCOMPATIBLE) { newPkg = false; - break; // there shouldn't be 2 revision of the same package + break; // there shouldn't be 2 revisions of the same package } } @@ -247,6 +307,6 @@ public class RepoSourcesAdapter { } } - return filteredList.toArray(); + return filteredList.toArray(new Package[filteredList.size()]); } } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java index bd39c5e82..cbd846e42 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java @@ -91,31 +91,34 @@ public class ImageFactory { */ public Image getImageForObject(Object object) { if (object instanceof RepoSource) { - return getImageByName("source_icon16.png"); + return getImageByName("source_icon16.png"); //$NON-NLS-1$ } else if (object instanceof RepoSourcesAdapter.RepoSourceError) { - return getImageByName("error_icon16.png"); + return getImageByName("error_icon16.png"); //$NON-NLS-1$ + + } else if (object instanceof RepoSourcesAdapter.RepoSourceEmpty) { + return getImageByName("nopkg_icon16.png"); //$NON-NLS-1$ } else if (object instanceof PlatformPackage) { - return getImageByName("android_icon_16.png"); + return getImageByName("android_icon_16.png"); //$NON-NLS-1$ } else if (object instanceof AddonPackage) { - return getImageByName("addon_icon16.png"); + return getImageByName("addon_icon16.png"); //$NON-NLS-1$ } else if (object instanceof ToolPackage) { - return getImageByName("tool_icon16.png"); + return getImageByName("tool_icon16.png"); //$NON-NLS-1$ } else if (object instanceof DocPackage) { - return getImageByName("doc_icon16.png"); + return getImageByName("doc_icon16.png"); //$NON-NLS-1$ } else if (object instanceof ExtraPackage) { - return getImageByName("extra_icon16.png"); + return getImageByName("extra_icon16.png"); //$NON-NLS-1$ } else if (object instanceof Archive) { if (((Archive) object).isCompatible()) { - return getImageByName("archive_icon16.png"); + return getImageByName("archive_icon16.png"); //$NON-NLS-1$ } else { - return getImageByName("incompat_icon16.png"); + return getImageByName("incompat_icon16.png"); //$NON-NLS-1$ } } return null; diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png new file mode 100755 index 0000000000000000000000000000000000000000..147837fd64f0fa22c37cce6f79ce9a8c0d512355 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgga4sKCl6Bnib)<9EuJzX3_EKXmY zZ0ODGDA2m!vR@-Td%n?B7RM&v4V>G;o}G`psTO*{?ah%x-L4+0D}&gMoO+XY?(><5 zHBNfdSryIvEZ_XD_?#9NGBsB#>GZGY11|z!omcjB?th=BBKu{j9Lt-xm%N3dHm?k6 zs;m-Ndo|;z;ohtJ*0fv9?o#7CV!fe$0h57b_byfm=C^(CSs59=U3H$roV@o#E}y%4 zYM}swLA{`^-F`(jsk5sj6!=)vbVOL6SU!<|sGCy))aNFsGd*t3^Lr Date: Tue, 11 Aug 2009 15:34:04 -0700 Subject: [PATCH 39/87] Change ADT/DDMS plug-ins version to 0.9.3 --- .../features/com.android.ide.eclipse.adt/feature.xml | 2 +- .../features/com.android.ide.eclipse.ddms/feature.xml | 2 +- .../features/com.android.ide.eclipse.tests/feature.xml | 2 +- .../com.android.ide.eclipse.adt/META-INF/MANIFEST.MF | 2 +- .../com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF | 2 +- .../com.android.ide.eclipse.tests/META-INF/MANIFEST.MF | 2 +- tools/eclipse/sites/external/site.xml | 4 ++-- tools/eclipse/sites/internal/site.xml | 6 +++--- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml index 74002cbb3..6dd3ee79d 100644 --- a/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml +++ b/tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml @@ -2,7 +2,7 @@ diff --git a/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml index 884669b86..e67f96089 100644 --- a/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml +++ b/tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml @@ -2,7 +2,7 @@ diff --git a/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml b/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml index d2778feb9..cc34045f9 100644 --- a/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml +++ b/tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml @@ -2,7 +2,7 @@ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index f9c1e9c17..32c939b37 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Android Development Toolkit Bundle-SymbolicName: com.android.ide.eclipse.adt;singleton:=true -Bundle-Version: 0.9.2.qualifier +Bundle-Version: 0.9.3.qualifier Bundle-ClassPath: ., jarutils.jar, androidprefs.jar, diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF index ebdec6d45..9f021aee4 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF +++ b/tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Dalvik Debug Monitor Service Bundle-SymbolicName: com.android.ide.eclipse.ddms;singleton:=true -Bundle-Version: 0.9.2.qualifier +Bundle-Version: 0.9.3.qualifier Bundle-Activator: com.android.ide.eclipse.ddms.DdmsPlugin Bundle-Vendor: The Android Open Source Project Bundle-Localization: plugin diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF index 61bfbe47a..a8ec3da31 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Android Plugin Tests Bundle-SymbolicName: com.android.ide.eclipse.tests -Bundle-Version: 0.9.2.qualifier +Bundle-Version: 0.9.3.qualifier Bundle-Activator: com.android.ide.eclipse.tests.AndroidTestPlugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, diff --git a/tools/eclipse/sites/external/site.xml b/tools/eclipse/sites/external/site.xml index 7dee775fe..a00d1a4fe 100644 --- a/tools/eclipse/sites/external/site.xml +++ b/tools/eclipse/sites/external/site.xml @@ -3,10 +3,10 @@ Update Site for Android Development Toolkit - + - + diff --git a/tools/eclipse/sites/internal/site.xml b/tools/eclipse/sites/internal/site.xml index 4fd533337..e19c119be 100644 --- a/tools/eclipse/sites/internal/site.xml +++ b/tools/eclipse/sites/internal/site.xml @@ -3,13 +3,13 @@ Update Site for Android Development Toolkit - + - + - + From f6abec3376d6e9eea2a44ec9ff92b4aa9c4b33bd Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 11 Aug 2009 15:37:00 -0700 Subject: [PATCH 40/87] BUG 1993354 : Add zipalign to SDK --- build/sdk.atree | 1 + build/tools/make_windows_sdk.sh | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build/sdk.atree b/build/sdk.atree index 9136e5e6b..40a2876ef 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -31,6 +31,7 @@ bin/sqlite3 tools/sqlite3 bin/dmtracedump tools/dmtracedump bin/hprof-conv tools/hprof-conv bin/mksdcard tools/mksdcard +bin/zipalign tools/zipalign # the uper-jar file that apps link against out/target/common/obj/PACKAGING/android_jar_intermediates/android.jar platforms/${PLATFORM_NAME}/android.jar diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh index 11ab3976d..68e6c804a 100755 --- a/build/tools/make_windows_sdk.sh +++ b/build/tools/make_windows_sdk.sh @@ -83,7 +83,14 @@ function build() { make -j 4 emulator || die "Build failed" # Disable parallel build: it generates "permission denied" issues when # multiple "ar.exe" are running in parallel. - make prebuilt adb fastboot aidl aapt dexdump dmtracedump hprof-conv mksdcard sqlite3 \ + make aapt adb aidl \ + prebuilt \ + dexdump dmtracedump \ + fastboot \ + hprof-conv \ + mksdcard \ + sqlite3 \ + zipalign \ || die "Build failed" } @@ -124,7 +131,7 @@ function package() { TOOLS="$TEMP_SDK_DIR/tools" LIB="$TEMP_SDK_DIR/tools/lib" rm -v "$TOOLS"/{adb,android,apkbuilder,ddms,dmtracedump,draw9patch,emulator} - rm -v "$TOOLS"/{hierarchyviewer,hprof-conv,mksdcard,sqlite3,traceview} + rm -v "$TOOLS"/{hierarchyviewer,hprof-conv,mksdcard,sqlite3,traceview,zipalign} rm -v "$LIB"/*/swt.jar rm -v "$PLATFORM_TOOLS"/{aapt,aidl,dx,dexdump} From 3faef17986da97e97a394601f87af423f5e50c08 Mon Sep 17 00:00:00 2001 From: Bill Napier Date: Tue, 11 Aug 2009 16:07:38 -0700 Subject: [PATCH 41/87] Add "type" command to allow strings to be more easily typed. --- cmds/monkey/README.NETWORK.txt | 5 ++ .../commands/monkey/MonkeyKeyEvent.java | 54 +++++++++++-------- .../commands/monkey/MonkeySourceNetwork.java | 51 ++++++++++++++++-- 3 files changed, 83 insertions(+), 27 deletions(-) diff --git a/cmds/monkey/README.NETWORK.txt b/cmds/monkey/README.NETWORK.txt index 1a1ad9c3c..b80cea9f7 100644 --- a/cmds/monkey/README.NETWORK.txt +++ b/cmds/monkey/README.NETWORK.txt @@ -87,6 +87,11 @@ The press command is a shortcut for the key command. The keycode paramter works just like the key command and will automatically send both the up and the down event. +type string + +This command will simulate a user typing the given string on the +keyboard by generating the proper KeyEvents. + OTHER NOTES There are some convenience features added to allow running without diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java b/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java index 877ebb576..d9c68af50 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeyKeyEvent.java @@ -23,7 +23,7 @@ import android.view.KeyEvent; /** * monkey key event */ -public class MonkeyKeyEvent extends MonkeyEvent { +public class MonkeyKeyEvent extends MonkeyEvent { private long mDownTime = -1; private int mMetaState = -1; private int mAction = -1; @@ -32,18 +32,25 @@ public class MonkeyKeyEvent extends MonkeyEvent { private int mRepeatCount = -1; private int mDeviceId = -1; private long mEventTime = -1; - + + private KeyEvent keyEvent = null; + public MonkeyKeyEvent(int action, int keycode) { super(EVENT_TYPE_KEY); mAction = action; mKeyCode = keycode; } - + + public MonkeyKeyEvent(KeyEvent e) { + super(EVENT_TYPE_KEY); + keyEvent = e; + } + public MonkeyKeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int device, int scancode) { super(EVENT_TYPE_KEY); - + mAction = action; mKeyCode = code; mMetaState = metaState; @@ -53,49 +60,52 @@ public class MonkeyKeyEvent extends MonkeyEvent { mDownTime = downTime; mEventTime = eventTime; } - + public int getKeyCode() { return mKeyCode; } - + public int getAction() { return mAction; } - + public long getDownTime() { return mDownTime; } - + public long getEventTime() { return mEventTime; } - + public void setDownTime(long downTime) { mDownTime = downTime; } - + public void setEventTime(long eventTime) { mEventTime = eventTime; } - - /** + + /** * @return the key event - */ + */ private KeyEvent getEvent() { - if (mDeviceId < 0) { - return new KeyEvent(mAction, mKeyCode); - } - - // for scripts - return new KeyEvent(mDownTime, mEventTime, mAction, - mKeyCode, mRepeatCount, mMetaState, mDeviceId, mScancode); + if (keyEvent == null) { + if (mDeviceId < 0) { + keyEvent = new KeyEvent(mAction, mKeyCode); + } else { + // for scripts + keyEvent = new KeyEvent(mDownTime, mEventTime, mAction, + mKeyCode, mRepeatCount, mMetaState, mDeviceId, mScancode); + } + } + return keyEvent; } @Override public boolean isThrottlable() { return (getAction() == KeyEvent.ACTION_UP); } - + @Override public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) { if (verbose > 1) { @@ -124,7 +134,7 @@ public class MonkeyKeyEvent extends MonkeyEvent { } catch (RemoteException ex) { return MonkeyEvent.INJECT_ERROR_REMOTE_EXCEPTION; } - + return MonkeyEvent.INJECT_SUCCESS; } } diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java index 63e226c7d..5937f09c1 100644 --- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java +++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java @@ -21,6 +21,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.util.Log; +import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; @@ -217,7 +218,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { try { sleep = Integer.parseInt(sleepStr); } catch (NumberFormatException e) { - Log.e(TAG, "Not a number: " + sleepStr, e); + Log.e(TAG, "Not a number: " + sleepStr, e); } return new MonkeyThrottleEvent(sleep); } @@ -225,6 +226,34 @@ public class MonkeySourceNetwork implements MonkeyEventSource { } } + /** + * Command to type a string + */ + private static class TypeCommand implements MonkeyCommand { + // wake + public MonkeyEvent translateCommand(List command, + CommandQueue queue) { + if (command.size() == 2) { + String str = command.get(1); + + char[] chars = str.toString().toCharArray(); + + // Convert the string to an array of KeyEvent's for + // the built in keymap. + KeyCharacterMap keyCharacterMap = KeyCharacterMap. + load(KeyCharacterMap.BUILT_IN_KEYBOARD); + KeyEvent[] events = keyCharacterMap.getEvents(chars); + + // enqueue all the events we just got. + for (KeyEvent event : events) { + queue.enqueueEvent(new MonkeyKeyEvent(event)); + } + return new MonkeyNoopEvent(); + } + return null; + } + } + /** * Command to wake the device up */ @@ -325,6 +354,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource { COMMAND_MAP.put("wake", new WakeCommand()); COMMAND_MAP.put("tap", new TapCommand()); COMMAND_MAP.put("press", new PressCommand()); + COMMAND_MAP.put("type", new TypeCommand()); } // QUIT command @@ -400,6 +430,17 @@ public class MonkeySourceNetwork implements MonkeyEventSource { output = new PrintWriter(s.getOutputStream(), true); } + /** + * Helper function for commandLineSplit that replaces quoted + * charaters with their real values. + * + * @param input the string to do replacement on. + * @returns the results with the characters replaced. + */ + private static String replaceQuotedChars(String input) { + return input.replace("\\\"", "\""); + } + /** * This function splits the given line into String parts. It obey's quoted * strings and returns them as a single part. @@ -420,22 +461,22 @@ public class MonkeySourceNetwork implements MonkeyEventSource { String cur = tok.nextToken(); if (!insideQuote && cur.startsWith("\"")) { // begin quote - quotedWord.append(cur); + quotedWord.append(replaceQuotedChars(cur)); insideQuote = true; } else if (insideQuote) { // end quote if (cur.endsWith("\"")) { insideQuote = false; - quotedWord.append(cur); + quotedWord.append(" ").append(replaceQuotedChars(cur)); String word = quotedWord.toString(); // trim off the quotes result.add(word.substring(1, word.length() - 1)); } else { - quotedWord.append(cur); + quotedWord.append(" ").append(replaceQuotedChars(cur)); } } else { - result.add(cur); + result.add(replaceQuotedChars(cur)); } } return result; From ae60bdab1554b0ddafb2c89ae1a6626c8995f33e Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 11 Aug 2009 17:50:54 -0700 Subject: [PATCH 42/87] Make the res qualifiers aware of the project target to handle differnt behavior. First behavior change: \d{3}dpi replaced with hdpi/mdpi/ldpi/nodpi --- .../editors/layout/GraphicalLayoutEditor.java | 314 +++++++++--------- .../editors/layout/LayoutCreatorDialog.java | 27 +- .../extractstring/ExtractStringInputPage.java | 2 +- .../configurations/CountryCodeQualifier.java | 37 ++- .../configurations/FolderConfiguration.java | 119 +++---- .../KeyboardStateQualifier.java | 41 +-- .../configurations/LanguageQualifier.java | 35 +- .../NavigationMethodQualifier.java | 41 +-- .../configurations/NetworkCodeQualifier.java | 31 +- .../configurations/PixelDensityQualifier.java | 200 +++++++---- .../configurations/RegionQualifier.java | 31 +- .../configurations/ResourceQualifier.java | 22 +- .../ScreenDimensionQualifier.java | 25 +- .../ScreenOrientationQualifier.java | 37 ++- .../TextInputMethodQualifier.java | 35 +- .../configurations/TouchScreenQualifier.java | 35 +- .../ide/eclipse/adt/internal/sdk/Sdk.java | 14 + .../internal/ui/ConfigurationSelector.java | 252 +++++++------- .../newxmlfile/NewXmlFileCreationPage.java | 44 ++- .../resources/manager/ConfigMatchTest.java | 55 ++- 20 files changed, 757 insertions(+), 640 deletions(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java index c940b9f71..225d5bda1 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java @@ -4,7 +4,7 @@ * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.eclipse.org/org/documents/epl-v10.php * * Unless required by applicable law or agreed to in writing, software @@ -43,6 +43,7 @@ import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMe import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier; import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier.KeyboardState; import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier.NavigationMethod; +import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density; import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation; import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier.TextInputMethod; import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier.TouchScreenType; @@ -55,7 +56,6 @@ import com.android.ide.eclipse.adt.internal.sdk.LoadStatus; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData.LayoutBridge; import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener; -import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.DensityVerifier; import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.DimensionVerifier; import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.LanguageRegionVerifier; import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.MobileCodeVerifier; @@ -143,7 +143,7 @@ import java.util.Set; */ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor implements ILayoutReloadListener { - + private final static String THEME_SEPARATOR = "----------"; //$NON-NLS-1$ /** Reference to the layout editor */ @@ -161,7 +161,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor private Combo mLanguage; private Combo mRegion; private Combo mOrientation; - private Text mDensity; + private Combo mDensity; private Combo mTouch; private Combo mKeyboard; private Combo mTextInput; @@ -216,7 +216,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor public void onTargetsLoaded() { // because the SDK changed we must reset the configured framework resource. mConfiguredFrameworkRes = null; - + updateUIFromResources(); mThemeCombo.getParent().layout(); @@ -383,19 +383,19 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor new Label(topParent, SWT.NONE).setText("Density"); mDensityIcon = createControlComposite(topParent, true /* grab_horizontal */); - mDensity = new Text(mDensityIcon.getParent(), SWT.BORDER); + mDensity = new Combo(mDensityIcon.getParent(), SWT.DROP_DOWN | SWT.READ_ONLY); + Density[] dValues = Density.values(); + mDensity.add("(Default)"); + for (Density value : dValues) { + mDensity.add(value.getDisplayValue()); + } + mDensity.select(0); mDensity.setLayoutData(new GridData( GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mDensity.addVerifyListener(new DensityVerifier()); mDensity.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent e) { - onDensityChange(); - } - }); - mDensity.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onDensityChange(); + @Override + public void widgetSelected(SelectionEvent e) { + onDensityChange(); } }); @@ -468,7 +468,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor @Override public void widgetSelected(SelectionEvent e) { onNavigationChange(); - } + } }); Composite labelParent = new Composite(topParent, SWT.NONE); @@ -512,7 +512,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor mSize1.addSelectionListener(sl); mSize2.addSelectionListener(sl); - + ModifyListener sizeModifyListener = new ModifyListener() { public void modifyText(ModifyEvent e) { onSizeChange(); @@ -551,11 +551,12 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor @Override public void widgetSelected(SelectionEvent e) { LayoutCreatorDialog dialog = new LayoutCreatorDialog(mCreateButton.getShell(), - mEditedFile.getName(), mCurrentConfig); + mEditedFile.getName(), + Sdk.getCurrent().getTarget(mEditedFile.getProject()), mCurrentConfig); if (dialog.open() == Dialog.OK) { final FolderConfiguration config = new FolderConfiguration(); dialog.getConfiguration(config); - + createAlternateLayout(config); } } @@ -591,7 +592,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor @Override protected PaletteRoot getPaletteRoot() { mPaletteRoot = PaletteFactory.createPaletteRoot(mPaletteRoot, - mLayoutEditor.getTargetData()); + mLayoutEditor.getTargetData()); return mPaletteRoot; } @@ -618,7 +619,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor getCommandStack().markSaveLocation(); firePropertyChange(PROP_DIRTY); } - + @Override protected void configurePaletteViewer() { super.configurePaletteViewer(); @@ -628,7 +629,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // the PaletteTemplateEntry held in the PaletteRoot. TemplateTransferDragSourceListener dragSource = new TemplateTransferDragSourceListener(getPaletteViewer()); - + // Create a drag source on the palette viewer. // See the drag target associated with the GraphicalViewer in configureGraphicalViewer. getPaletteViewer().addDragSourceListener(dragSource); @@ -645,12 +646,12 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor viewer.setEditPartFactory(new UiElementsEditPartFactory(mParent.getDisplay())); viewer.setRootEditPart(new ScalableFreeformRootEditPart()); - // Disable the following -- we don't drag *from* the GraphicalViewer yet: + // Disable the following -- we don't drag *from* the GraphicalViewer yet: // viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer)); - + viewer.addDropTargetListener(new DropListener(viewer)); } - + class DropListener extends TemplateTransferDropTargetListener { public DropListener(EditPartViewer viewer) { super(viewer); @@ -670,7 +671,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor public Object getObjectType() { return template; } - + }; } } @@ -698,7 +699,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor input.toString()); } } - + /* (non-javadoc) * Sets the graphicalViewer for this EditorPart. * @param viewer the graphical viewer @@ -714,18 +715,18 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor /** * Used by LayoutEditor.UiEditorActions.selectUiNode to select a new UI Node * created by {@link ElementCreateCommand#execute()}. - * + * * @param uiNodeModel The {@link UiElementNode} to select. */ @Override void selectModel(UiElementNode uiNodeModel) { GraphicalViewer viewer = getGraphicalViewer(); - + // Give focus to the graphical viewer (in case the outline has it) viewer.getControl().forceFocus(); - + Object editPart = viewer.getEditPartRegistry().get(uiNodeModel); - + if (editPart instanceof EditPart) { viewer.select((EditPart)editPart); } @@ -745,7 +746,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor MenuManager menuManager = new MenuManager(); menuManager.setRemoveAllWhenShown(true); menuManager.addMenuListener(new ActionMenuListener(viewer)); - + return menuManager; } @@ -775,13 +776,13 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor } } } - + if (selected.size() > 0) { doCreateMenuAction(manager, mViewer, selected); } } } - + private void doCreateMenuAction(IMenuManager manager, final GraphicalViewer viewer, final ArrayList selected) { @@ -820,7 +821,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // Append "add" and "remove" actions. They do the same thing as the add/remove // buttons on the side. IconFactory factory = IconFactory.getInstance(); - + final UiEditorActions uiActions = mLayoutEditor.getUiEditorActions(); // "Add" makes sense only if there's 0 or 1 item selected since the @@ -845,7 +846,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor }); manager.add(new Separator()); - + manager.add(new Action("Up", factory.getImageDescriptor("up")) { //$NON-NLS-2$ @Override public void run() { @@ -859,8 +860,8 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor } }); } - - } + + } /** * Sets the UI for the edition of a new file. @@ -870,11 +871,11 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor void editNewFile(FolderConfiguration configuration) { // update the configuration UI setConfiguration(configuration, true /*force*/); - + // enable the create button if the current and edited config are not equals mCreateButton.setEnabled(mEditedConfig.equals(mCurrentConfig) == false); } - + public Rectangle getBounds() { ScreenOrientation orientation = null; if (mOrientation.getSelectionIndex() == 0) { @@ -916,7 +917,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor return new Rectangle(0, 0, s1, s1); } } - + /** * Renders an Android View described by a {@link ViewElementDescriptor}. *

    This uses the wrap_content mode for both layout_width and @@ -928,17 +929,17 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor if (mEditedFile == null) { return null; } - + IAndroidTarget target = Sdk.getCurrent().getTarget(mEditedFile.getProject()); if (target == null) { return null; } - + AndroidTargetData data = Sdk.getCurrent().getTargetData(target); if (data == null) { return null; } - + LayoutBridge bridge = data.getLayoutBridge(); if (bridge.bridge != null) { // bridge can never be null. @@ -961,7 +962,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // get the project resource values based on the current config mConfiguredProjectRes = projectRes.getConfiguredResources(mCurrentConfig); } - + configuredProjectResources = mConfiguredProjectRes; } else { // we absolutely need a Map of configured project resources. @@ -998,12 +999,12 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor int height = result.getRootView().getBottom(); Raster raster = largeImage.getData(new java.awt.Rectangle(width, height)); int[] imageDataBuffer = ((DataBufferInt)raster.getDataBuffer()).getData(); - + ImageData imageData = new ImageData(width, height, 32, new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); imageData.setPixels(0, 0, imageDataBuffer.length, imageDataBuffer, 0); - + return imageData; } } @@ -1046,7 +1047,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor mNeedsXmlReload = true; } } - + /** * Actually performs the XML reload * @see #onXmlModelChanged() @@ -1054,17 +1055,17 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor private void doXmlReload(boolean force) { if (force || mNeedsXmlReload) { GraphicalViewer viewer = getGraphicalViewer(); - + // try to preserve the selection before changing the content SelectionManager selMan = viewer.getSelectionManager(); ISelection selection = selMan.getSelection(); - + try { viewer.setContents(getModel()); } finally { selMan.setSelection(selection); } - + mNeedsXmlReload = false; } } @@ -1148,12 +1149,13 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor mDensityIcon.setImage(mMatchImage); PixelDensityQualifier densityQualifier = config.getPixelDensityQualifier(); if (densityQualifier != null) { - mDensity.setText(String.format("%1$d", densityQualifier.getValue())); + mDensity.select( + Density.getIndex(densityQualifier.getValue()) + 1); mCurrentConfig.setPixelDensityQualifier(densityQualifier); } else if (force) { - mDensity.setText(""); //$NON-NLS-1$ + mOrientation.select(0); mCurrentConfig.setPixelDensityQualifier(null); - } else if (mDensity.getText().length() > 0) { + } else if (mDensity.getSelectionIndex() != 0) { mDensityIcon.setImage(mWarningImage); } @@ -1223,10 +1225,10 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // update the string showing the folder name String current = config.toDisplayString(); mCurrentLayoutLabel.setText(current != null ? current : "(Default)"); - + mDisableUpdates = false; } - + /** * Displays an error icon in front of all the non-null qualifiers. */ @@ -1236,44 +1238,44 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor if (countryQualifier != null) { mCountryIcon.setImage(mErrorImage); } - + mNetworkIcon.setImage(mMatchImage); NetworkCodeQualifier networkQualifier = mCurrentConfig.getNetworkCodeQualifier(); if (networkQualifier != null) { mNetworkIcon.setImage(mErrorImage); } - + mLanguageIcon.setImage(mMatchImage); LanguageQualifier languageQualifier = mCurrentConfig.getLanguageQualifier(); if (languageQualifier != null) { mLanguageIcon.setImage(mErrorImage); } - + mRegionIcon.setImage(mMatchImage); RegionQualifier regionQualifier = mCurrentConfig.getRegionQualifier(); if (regionQualifier != null) { mRegionIcon.setImage(mErrorImage); } - + mOrientationIcon.setImage(mMatchImage); ScreenOrientationQualifier orientationQualifier = mCurrentConfig.getScreenOrientationQualifier(); if (orientationQualifier != null) { mOrientationIcon.setImage(mErrorImage); } - + mDensityIcon.setImage(mMatchImage); PixelDensityQualifier densityQualifier = mCurrentConfig.getPixelDensityQualifier(); if (densityQualifier != null) { mDensityIcon.setImage(mErrorImage); } - + mTouchIcon.setImage(mMatchImage); TouchScreenQualifier touchQualifier = mCurrentConfig.getTouchTypeQualifier(); if (touchQualifier != null) { mTouchIcon.setImage(mErrorImage); } - + mKeyboardIcon.setImage(mMatchImage); KeyboardStateQualifier keyboardQualifier = mCurrentConfig.getKeyboardStateQualifier(); if (keyboardQualifier != null) { @@ -1285,20 +1287,20 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor if (inputQualifier != null) { mTextInputIcon.setImage(mErrorImage); } - + mNavigationIcon.setImage(mMatchImage); NavigationMethodQualifier navigationQualifiter = mCurrentConfig.getNavigationMethodQualifier(); if (navigationQualifiter != null) { mNavigationIcon.setImage(mErrorImage); } - + mSizeIcon.setImage(mMatchImage); ScreenDimensionQualifier sizeQualifier = mCurrentConfig.getScreenDimensionQualifier(); if (sizeQualifier != null) { mSizeIcon.setImage(mErrorImage); } - + // update the string showing the folder name String current = mCurrentConfig.toDisplayString(); mCurrentLayoutLabel.setText(current != null ? current : "(Default)"); @@ -1308,7 +1310,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor UiDocumentNode getModel() { return mLayoutEditor.getUiRootNode(); } - + @Override void reloadPalette() { PaletteFactory.createPaletteRoot(mPaletteRoot, mLayoutEditor.getTargetData()); @@ -1474,36 +1476,12 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor } private void onDensityChange() { - // because mDensity triggers onDensityChange at each modification, calling setText() - // will trigger notifications, and we don't want that. - if (mDisableUpdates == true) { - return; - } - - // update the current config - String value = mDensity.getText(); - - // empty string, means no qualifier. - if (value.length() == 0) { - mCurrentConfig.setPixelDensityQualifier(null); + int index = mDensity.getSelectionIndex(); + if (index != 0) { + mCurrentConfig.setPixelDensityQualifier((new PixelDensityQualifier( + Density.getByIndex(index-1)))); } else { - try { - PixelDensityQualifier qualifier = PixelDensityQualifier.getQualifier( - PixelDensityQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mCurrentConfig.setPixelDensityQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - // We do nothing in this case. - return; - } - } catch (NumberFormatException e) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - // We do nothing in this case. - mDensityIcon.setImage(mErrorImage); - return; - } + mCurrentConfig.setPixelDensityQualifier(null); } // look for a file to open/create @@ -1612,11 +1590,11 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor if (mEditedFile == null || mEditedConfig == null) { return; } - + // get the resources of the file's project. ProjectResources resources = ResourceManager.getInstance().getProjectResources( mEditedFile.getProject()); - + // from the resources, look for a matching file ResourceFile match = null; if (resources != null) { @@ -1643,7 +1621,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // update the configuration icons with the new edited config. setConfiguration(mEditedConfig, false /*force*/); - + // enable the create button if the current and edited config are not equals mCreateButton.setEnabled(mEditedConfig.equals(mCurrentConfig) == false); @@ -1653,7 +1631,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor } else { // update the configuration icons with the new edited config. displayConfigError(); - + // enable the Create button mCreateButton.setEnabled(true); @@ -1661,7 +1639,8 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor String message = String.format( "No resources match the configuration\n \n\t%1$s\n \nChange the configuration or create:\n \n\tres/%2$s/%3$s\n \nYou can also click the 'Create' button above.", mCurrentConfig.toDisplayString(), - mCurrentConfig.getFolderName(ResourceFolderType.LAYOUT), + mCurrentConfig.getFolderName(ResourceFolderType.LAYOUT, + Sdk.getCurrent().getTarget(mEditedFile.getProject())), mEditedFile.getName()); showErrorInEditor(message); } @@ -1671,7 +1650,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor int themeIndex = mThemeCombo.getSelectionIndex(); if (themeIndex != -1) { String theme = mThemeCombo.getItem(themeIndex); - + if (theme.equals(THEME_SEPARATOR)) { mThemeCombo.select(0); } @@ -1745,7 +1724,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor showErrorInEditor("The project target is not set."); return; } - + AndroidTargetData data = currentSdk.getTargetData(target); if (data == null) { // It can happen that the workspace refreshes while the SDK is loading its @@ -1774,67 +1753,77 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor if (bridge.bridge != null) { // bridge can never be null. ResourceManager resManager = ResourceManager.getInstance(); - + ProjectResources projectRes = resManager.getProjectResources(iProject); if (projectRes == null) { return; } - + // get the resources of the file's project. if (mConfiguredProjectRes == null) { // make sure they are loaded projectRes.loadAll(); - + // get the project resource values based on the current config mConfiguredProjectRes = projectRes.getConfiguredResources(mCurrentConfig); } - + // get the framework resources Map> frameworkResources = getConfiguredFrameworkResources(); - + if (mConfiguredProjectRes != null && frameworkResources != null) { if (mProjectCallback == null) { mProjectCallback = new ProjectCallback( bridge.classLoader, projectRes, iProject); } - + if (mLogger == null) { mLogger = new ILayoutLog() { public void error(String message) { AdtPlugin.printErrorToConsole(mEditedFile.getName(), message); } - + public void error(Throwable error) { String message = error.getMessage(); if (message == null) { message = error.getClass().getName(); } - + PrintStream ps = new PrintStream(AdtPlugin.getErrorStream()); error.printStackTrace(ps); } - + public void warning(String message) { AdtPlugin.printToConsole(mEditedFile.getName(), message); } }; } - + // get the selected theme int themeIndex = mThemeCombo.getSelectionIndex(); if (themeIndex != -1) { String theme = mThemeCombo.getItem(themeIndex); - + // Compute the layout UiElementPullParser parser = new UiElementPullParser(getModel()); Rectangle rect = getBounds(); boolean isProjectTheme = themeIndex >= mPlatformThemeCount; // FIXME pass the density/dpi from somewhere (resource config or skin). + // For now, get it from the config + int density = Density.MEDIUM.getDpiValue(); + PixelDensityQualifier qual = mCurrentConfig.getPixelDensityQualifier(); + if (qual != null) { + int d = qual.getValue().getDpiValue(); + if (d > 0) { + density = d; + } + } + ILayoutResult result = computeLayout(bridge, parser, iProject /* projectKey */, - rect.width, rect.height, 160, 160.f, 160.f, + rect.width, rect.height, density, density, density, theme, isProjectTheme, mConfiguredProjectRes, frameworkResources, mProjectCallback, mLogger); @@ -1842,20 +1831,20 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // update the UiElementNode with the layout info. if (result.getSuccess() == ILayoutResult.SUCCESS) { model.setEditData(result.getImage()); - + updateNodeWithBounds(result.getRootView()); } else { String message = result.getErrorMessage(); - + // Reset the edit data for all the nodes. resetNodeBounds(model); - + if (message != null) { // set the error in the top element. model.setEditData(message); } } - + model.refreshUi(); } } @@ -1951,11 +1940,11 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // clear the cache in the bridge in case a bitmap/9-patch changed. IAndroidTarget target = Sdk.getCurrent().getTarget(mEditedFile.getProject()); if (target != null) { - + AndroidTargetData data = Sdk.getCurrent().getTargetData(target); if (data != null) { LayoutBridge bridge = data.getLayoutBridge(); - + if (bridge.bridge != null) { bridge.bridge.clearCaches(mEditedFile.getProject()); } @@ -2007,28 +1996,28 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor ProjectResources frameworkProject = getFrameworkResources(); mDisableUpdates = true; - + // Reset stuff int selection = mThemeCombo.getSelectionIndex(); mThemeCombo.removeAll(); mPlatformThemeCount = 0; mLanguage.removeAll(); - + Set languages = new HashSet(); ArrayList themes = new ArrayList(); - + // get the themes, and languages from the Framework. if (frameworkProject != null) { // get the configured resources for the framework Map> frameworResources = getConfiguredFrameworkResources(); - + if (frameworResources != null) { // get the styles. Map styles = frameworResources.get( ResourceType.STYLE.getName()); - - + + // collect the themes out of all the styles. for (IResourceValue value : styles.values()) { String name = value.getName(); @@ -2040,11 +2029,11 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // sort them and add them to the combo Collections.sort(themes); - + for (String theme : themes) { mThemeCombo.add(theme); } - + mPlatformThemeCount = themes.size(); themes.clear(); } @@ -2054,7 +2043,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor languages.addAll(frameworkLanguages); } } - + // now get the themes and languages from the project. ProjectResources project = null; if (mEditedFile != null) { @@ -2062,7 +2051,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // in cases where the opened file is not linked to a project, this could be null. if (project != null) { - // get the configured resources for the project + // get the configured resources for the project if (mConfiguredProjectRes == null) { // make sure they are loaded project.loadAll(); @@ -2070,12 +2059,12 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // get the project resource values based on the current config mConfiguredProjectRes = project.getConfiguredResources(mCurrentConfig); } - + if (mConfiguredProjectRes != null) { // get the styles. Map styleMap = mConfiguredProjectRes.get( ResourceType.STYLE.getName()); - + if (styleMap != null) { // collect the themes out of all the styles, ie styles that extend, // directly or indirectly a platform theme. @@ -2089,9 +2078,9 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor if (mPlatformThemeCount > 0 && themes.size() > 0) { mThemeCombo.add(THEME_SEPARATOR); } - + Collections.sort(themes); - + for (String theme : themes) { mThemeCombo.add(theme); } @@ -2110,7 +2099,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor for (String language : languages) { mLanguage.add(language); } - + mDisableUpdates = false; // and update the Region UI based on the current language @@ -2143,7 +2132,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor private boolean isTheme(IResourceValue value, Map styleMap) { if (value instanceof IStyleResourceValue) { IStyleResourceValue style = (IStyleResourceValue)value; - + boolean frameworkStyle = false; String parentStyle = style.getParentStyle(); if (parentStyle == null) { @@ -2160,13 +2149,13 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor if (parentStyle.startsWith("@")) { parentStyle = parentStyle.substring(1); } - + // check for framework identifier. if (parentStyle.startsWith("android:")) { frameworkStyle = true; parentStyle = parentStyle.substring("android:".length()); } - + // at this point we could have the format style/. we want only the name if (parentStyle.startsWith("style/")) { parentStyle = parentStyle.substring("style/".length()); @@ -2232,7 +2221,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor mDisableUpdates = false; } } - + private Map> getConfiguredFrameworkResources() { if (mConfiguredFrameworkRes == null) { ProjectResources frameworkRes = getFrameworkResources(); @@ -2244,7 +2233,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // get the framework resource values based on the current config mConfiguredFrameworkRes = frameworkRes.getConfiguredResources(mCurrentConfig); } - + return mConfiguredFrameworkRes; } @@ -2256,14 +2245,15 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor @Override protected IStatus run(IProgressMonitor monitor) { // get the folder name - String folderName = config.getFolderName(ResourceFolderType.LAYOUT); + String folderName = config.getFolderName(ResourceFolderType.LAYOUT, + Sdk.getCurrent().getTarget(mEditedFile.getProject())); try { - + // look to see if it exists. // get the res folder IFolder res = (IFolder)mEditedFile.getParent().getParent(); String path = res.getLocation().toOSString(); - + File newLayoutFolder = new File(path + File.separator + folderName); if (newLayoutFolder.isFile()) { // this should not happen since aapt would have complained @@ -2271,34 +2261,34 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor // happen. String message = String.format("File 'res/%1$s' is in the way!", folderName); - + AdtPlugin.displayError("Layout Creation", message); - + return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message); } else if (newLayoutFolder.exists() == false) { // create it. newLayoutFolder.mkdir(); } - + // now create the file File newLayoutFile = new File(newLayoutFolder.getAbsolutePath() + File.separator + mEditedFile.getName()); newLayoutFile.createNewFile(); - + InputStream input = mEditedFile.getContents(); - + FileOutputStream fos = new FileOutputStream(newLayoutFile); - + byte[] data = new byte[512]; int count; while ((count = input.read(data)) != -1) { fos.write(data, 0, count); } - + input.close(); fos.close(); - + // refreshes the res folder to show up the new // layout folder (if needed) and the file. // We use a progress monitor to catch the end of the refresh @@ -2346,27 +2336,27 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor String message = String.format( "Failed to create File 'res/%1$s/%2$s' : %3$s", folderName, mEditedFile.getName(), e2.getMessage()); - + AdtPlugin.displayError("Layout Creation", message); - + return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, e2); } catch (CoreException e2) { String message = String.format( "Failed to create File 'res/%1$s/%2$s' : %3$s", folderName, mEditedFile.getName(), e2.getMessage()); - + AdtPlugin.displayError("Layout Creation", message); return e2.getStatus(); } - + return Status.OK_STATUS; } }.schedule(); } - + /** * Returns a {@link ProjectResources} for the framework resources. * @return the framework resources or null if not found. @@ -2376,10 +2366,10 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor Sdk currentSdk = Sdk.getCurrent(); if (currentSdk != null) { IAndroidTarget target = currentSdk.getTarget(mEditedFile.getProject()); - + if (target != null) { AndroidTargetData data = currentSdk.getTargetData(target); - + if (data != null) { return data.getFrameworkResources(); } @@ -2389,7 +2379,7 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor return null; } - + /** * Computes a layout by calling the correct computeLayout method of ILayoutBridge based on * the implementation API level. @@ -2402,12 +2392,12 @@ public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor Map> projectResources, Map> frameworkResources, IProjectCallback projectCallback, ILayoutLog logger) { - + if (bridge.apiLevel >= 3) { // newer api with boolean for separation of project/framework theme, // and density support. return bridge.bridge.computeLayout(layoutDescription, - projectKey, screenWidth, screenHeight, density, xdpi, ydpi, + projectKey, screenWidth, screenHeight, density, xdpi, ydpi, themeName, isProjectTheme, projectResources, frameworkResources, projectCallback, logger); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutCreatorDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutCreatorDialog.java index 5cd527c45..a55f1d056 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutCreatorDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutCreatorDialog.java @@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.internal.resources.configurations.ResourceQua import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType; import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector; import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.ConfigurationState; +import com.android.sdklib.IAndroidTarget; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.TrayDialog; @@ -40,22 +41,26 @@ class LayoutCreatorDialog extends TrayDialog { private ConfigurationSelector mSelector; private Composite mStatusComposite; - private Label mStatusLabel; + private Label mStatusLabel; private Label mStatusImage; private final FolderConfiguration mConfig = new FolderConfiguration(); private final String mFileName; + private final IAndroidTarget mTarget; /** * Creates a dialog, and init the UI from a {@link FolderConfiguration}. * @param parentShell the parent {@link Shell}. * @param config The starting configuration. */ - LayoutCreatorDialog(Shell parentShell, String fileName, FolderConfiguration config) { + LayoutCreatorDialog(Shell parentShell, String fileName, IAndroidTarget target, + FolderConfiguration config) { super(parentShell); - mFileName = fileName; - // FIXME: add some data to know what configurations already exist. + mFileName = fileName; + mTarget = target; + + // FIXME: add some data to know what configurations already exist. mConfig.set(config); } @@ -67,22 +72,22 @@ class LayoutCreatorDialog extends TrayDialog { new Label(top, SWT.NONE).setText( String.format("Configuration for the alternate version of %1$s", mFileName)); - + mSelector = new ConfigurationSelector(top); mSelector.setConfiguration(mConfig); - + // parent's layout is a GridLayout as specified in the javadoc. GridData gd = new GridData(); gd.widthHint = ConfigurationSelector.WIDTH_HINT; gd.heightHint = ConfigurationSelector.HEIGHT_HINT; mSelector.setLayoutData(gd); - + // add a listener to check on the validity of the FolderConfiguration as // they are built. mSelector.setOnChangeListener(new Runnable() { public void run() { ConfigurationState state = mSelector.getState(); - + switch (state) { case OK: mSelector.getConfiguration(mConfig); @@ -125,16 +130,16 @@ class LayoutCreatorDialog extends TrayDialog { return top; } - + public void getConfiguration(FolderConfiguration config) { config.set(mConfig); } - + /** * resets the status label to show the file that will be created. */ private void resetStatus() { mStatusLabel.setText(String.format("New File: res/%1$s/%2$s", - mConfig.getFolderName(ResourceFolderType.LAYOUT), mFileName)); + mConfig.getFolderName(ResourceFolderType.LAYOUT, mTarget), mFileName)); } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java index a3fdb7dc2..072b1b814 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java @@ -420,7 +420,7 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage // recreate the res path from the current configuration mConfigSelector.getConfiguration(mTempConfig); StringBuffer sb = new StringBuffer(RES_FOLDER_ABS); - sb.append(mTempConfig.getFolderName(ResourceFolderType.VALUES)); + sb.append(mTempConfig.getFolderName(ResourceFolderType.VALUES, mProject)); sb.append('/'); String newPath = sb.toString(); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java index c624035f2..f570bacd8 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -33,9 +34,9 @@ public final class CountryCodeQualifier extends ResourceQualifier { private final static Pattern sCountryCodePattern = Pattern.compile("^mcc(\\d{3})$");//$NON-NLS-1$ private int mCode = DEFAULT_CODE; - + public static final String NAME = "Mobile Country Code"; - + /** * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, * null is returned. @@ -54,15 +55,15 @@ public final class CountryCodeQualifier extends ResourceQualifier { // looks like the string we extracted wasn't a valid number. return null; } - + CountryCodeQualifier qualifier = new CountryCodeQualifier(); qualifier.mCode = code; return qualifier; } - + return null; } - + /** * Returns the folder name segment for the given value. This is equivalent to calling * {@link #toString()} on a {@link CountryCodeQualifier} object. @@ -72,29 +73,29 @@ public final class CountryCodeQualifier extends ResourceQualifier { if (code != DEFAULT_CODE && code >= 100 && code <=999) { // code is 3 digit.) { return String.format("mcc%1$d", code); //$NON-NLS-1$ } - + return ""; //$NON-NLS-1$ } - + public int getCode() { return mCode; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return "Country Code"; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("mcc"); //$NON-NLS-1$ } - + @Override public boolean isValid() { return mCode != DEFAULT_CODE; @@ -107,29 +108,29 @@ public final class CountryCodeQualifier extends ResourceQualifier { config.setCountryCodeQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof CountryCodeQualifier) { return mCode == ((CountryCodeQualifier)qualifier).mCode; } - + return false; } - + @Override public int hashCode() { return mCode; } - + /** * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { return getFolderSegment(mCode); } @@ -138,7 +139,7 @@ public final class CountryCodeQualifier extends ResourceQualifier { if (mCode != DEFAULT_CODE) { return String.format("MCC %1$d", mCode); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java index aea146b54..ff8c26aa8 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java @@ -17,6 +17,10 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.sdklib.IAndroidTarget; + +import org.eclipse.core.resources.IProject; /** @@ -27,7 +31,7 @@ public final class FolderConfiguration implements Comparableconfig. * @param config @@ -62,7 +66,7 @@ public final class FolderConfiguration implements Comparablenull if they are all valid (or if none * exists). @@ -73,11 +77,11 @@ public final class FolderConfiguration implements Comparablenull if the configuration - * is default. + * Returns the name of a folder with the configuration. + */ + public String getFolderName(ResourceFolderType folder, IProject project) { + IAndroidTarget target = null; + if (project != null) { + Sdk currentSdk = Sdk.getCurrent(); + if (currentSdk != null) { + target = currentSdk.getTarget(project); + } + } + + return getFolderName(folder, target); + } + + /** + * Returns {@link #toDisplayString()}. */ @Override public String toString() { - StringBuilder result = null; - - for (ResourceQualifier irq : mQualifiers) { - if (irq != null) { - if (result == null) { - result = new StringBuilder(); - } else { - result.append(QUALIFIER_SEP); - } - result.append(irq.toString()); - } - } - - if (result != null) { - return result.toString(); - } else { - return null; - } + return toDisplayString(); } - + /** * Returns a string valid for display purpose. */ @@ -322,7 +323,7 @@ public final class FolderConfiguration implements Comparablenull is returned. @@ -42,12 +43,12 @@ public final class LanguageQualifier extends ResourceQualifier { if (sLanguagePattern.matcher(segment).matches()) { LanguageQualifier qualifier = new LanguageQualifier(); qualifier.mValue = segment; - + return qualifier; } return null; } - + /** * Returns the folder name segment for the given value. This is equivalent to calling * {@link #toString()} on a {@link LanguageQualifier} object. @@ -58,7 +59,7 @@ public final class LanguageQualifier extends ResourceQualifier { if (sLanguagePattern.matcher(segment).matches()) { return segment; } - + return null; } @@ -66,25 +67,25 @@ public final class LanguageQualifier extends ResourceQualifier { if (mValue != null) { return mValue; } - + return ""; //$NON-NLS-1$ } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return NAME; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("language"); //$NON-NLS-1$ } - + @Override public boolean isValid() { return mValue != null; @@ -97,10 +98,10 @@ public final class LanguageQualifier extends ResourceQualifier { config.setLanguageQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof LanguageQualifier) { @@ -109,7 +110,7 @@ public final class LanguageQualifier extends ResourceQualifier { } return mValue.equals(((LanguageQualifier)qualifier).mValue); } - + return false; } @@ -118,15 +119,15 @@ public final class LanguageQualifier extends ResourceQualifier { if (mValue != null) { return mValue.hashCode(); } - + return 0; } - + /** * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { if (mValue != null) { return getFolderSegment(mValue); } @@ -139,7 +140,7 @@ public final class LanguageQualifier extends ResourceQualifier { if (mValue != null) { return mValue; } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NavigationMethodQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NavigationMethodQualifier.java index 6315014ee..0a5c9685a 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NavigationMethodQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NavigationMethodQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -26,7 +27,7 @@ import org.eclipse.swt.graphics.Image; * Resource Qualifier for Navigation Method. */ public final class NavigationMethodQualifier extends ResourceQualifier { - + public static final String NAME = "Navigation Method"; private NavigationMethod mValue; @@ -39,15 +40,15 @@ public final class NavigationMethodQualifier extends ResourceQualifier { TRACKBALL("trackball", "Trackball"), //$NON-NLS-1$ WHEEL("wheel", "Wheel"), //$NON-NLS-1$ NONAV("nonav", "No Navigation"); //$NON-NLS-1$ - + private String mValue; private String mDisplay; - + private NavigationMethod(String value, String display) { mValue = value; mDisplay = display; } - + /** * Returns the enum for matching the provided qualifier value. * @param value The qualifier value. @@ -59,14 +60,14 @@ public final class NavigationMethodQualifier extends ResourceQualifier { return orient; } } - + return null; } - + public String getValue() { return mValue; } - + public String getDisplayValue() { return mDisplay; } @@ -77,7 +78,7 @@ public final class NavigationMethodQualifier extends ResourceQualifier { if (nav == value) { return i; } - + i++; } @@ -95,7 +96,7 @@ public final class NavigationMethodQualifier extends ResourceQualifier { return null; } } - + public NavigationMethodQualifier() { // pass } @@ -107,18 +108,18 @@ public final class NavigationMethodQualifier extends ResourceQualifier { public NavigationMethod getValue() { return mValue; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return "Navigation"; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("navpad"); //$NON-NLS-1$ @@ -138,16 +139,16 @@ public final class NavigationMethodQualifier extends ResourceQualifier { config.setNavigationMethodQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof NavigationMethodQualifier) { return mValue == ((NavigationMethodQualifier)qualifier).mValue; } - + return false; } @@ -156,19 +157,19 @@ public final class NavigationMethodQualifier extends ResourceQualifier { if (mValue != null) { return mValue.hashCode(); } - + return 0; } - + /** * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { if (mValue != null) { return mValue.getValue(); } - + return ""; //$NON-NLS-1$ } @@ -177,7 +178,7 @@ public final class NavigationMethodQualifier extends ResourceQualifier { if (mValue != null) { return mValue.getDisplayValue(); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java index c7f7fadd7..32bd66724 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -33,9 +34,9 @@ public final class NetworkCodeQualifier extends ResourceQualifier { private final static Pattern sNetworkCodePattern = Pattern.compile("^mnc(\\d{1,3})$"); //$NON-NLS-1$ private int mCode = DEFAULT_CODE; - + public final static String NAME = "Mobile Network Code"; - + /** * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, * null is returned. @@ -54,7 +55,7 @@ public final class NetworkCodeQualifier extends ResourceQualifier { // looks like the string we extracted wasn't a valid number. return null; } - + NetworkCodeQualifier qualifier = new NetworkCodeQualifier(); qualifier.mCode = code; return qualifier; @@ -72,29 +73,29 @@ public final class NetworkCodeQualifier extends ResourceQualifier { if (code != DEFAULT_CODE && code >= 1 && code <= 999) { // code is 1-3 digit. return String.format("mnc%1$d", code); //$NON-NLS-1$ } - + return ""; //$NON-NLS-1$ } public int getCode() { return mCode; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return "Network Code"; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("mnc"); //$NON-NLS-1$ } - + @Override public boolean isValid() { return mCode != DEFAULT_CODE; @@ -113,22 +114,22 @@ public final class NetworkCodeQualifier extends ResourceQualifier { // looks like the string we extracted wasn't a valid number. return false; } - + NetworkCodeQualifier qualifier = new NetworkCodeQualifier(); qualifier.mCode = code; config.setNetworkCodeQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof NetworkCodeQualifier) { return mCode == ((NetworkCodeQualifier)qualifier).mCode; } - + return false; } @@ -136,12 +137,12 @@ public final class NetworkCodeQualifier extends ResourceQualifier { public int hashCode() { return mCode; } - + /** * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { return getFolderSegment(mCode); } @@ -150,7 +151,7 @@ public final class NetworkCodeQualifier extends ResourceQualifier { if (mCode != DEFAULT_CODE) { return String.format("MNC %1$d", mCode); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java index a2c690b8b..f75e9cbef 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java @@ -17,6 +17,8 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.AndroidVersion; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -27,118 +29,202 @@ import java.util.regex.Pattern; * Resource Qualifier for Screen Pixel Density. */ public final class PixelDensityQualifier extends ResourceQualifier { - /** Default pixel density value. This means the property is not set. */ - private final static int DEFAULT_DENSITY = -1; - - private final static Pattern sPixelDensityPattern = Pattern.compile("^(\\d+)dpi$");//$NON-NLS-1$ + private final static Pattern sDensityLegacyPattern = Pattern.compile("^(\\d+)dpi$");//$NON-NLS-1$ public static final String NAME = "Pixel Density"; - private int mValue = DEFAULT_DENSITY; - - /** - * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, - * null is returned. - * @param folderSegment the folder segment from which to create a qualifier. - * @return a new {@link CountryCodeQualifier} object or null - */ - public static PixelDensityQualifier getQualifier(String folderSegment) { - Matcher m = sPixelDensityPattern.matcher(folderSegment); - if (m.matches()) { - String v = m.group(1); + private Density mValue = Density.MEDIUM; - int density = -1; - try { - density = Integer.parseInt(v); - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid number. - return null; + /** + * Screen Orientation enum. + */ + public static enum Density { + HIGH("hdpi", 240, "High Density"), //$NON-NLS-1$ + MEDIUM("mdpi", 160, "Medium Density"), //$NON-NLS-1$ + LOW("ldpi", 120, "Low Density"), //$NON-NLS-1$ + NODPI("nodpi", -1, "No Density"); //$NON-NLS-1$ + + private final String mValue; + private final String mDisplayValue; + private final int mDpiValue; + + private Density(String value, int dpiValue, String displayValue) { + mValue = value; + mDpiValue = dpiValue; + mDisplayValue = displayValue; + } + + /** + * Returns the enum for matching the provided qualifier value. + * @param value The qualifier value. + * @return the enum for the qualifier value or null if no matching was found. + */ + static Density getEnum(String value) { + for (Density orient : values()) { + if (orient.mValue.equals(value)) { + return orient; + } } - - PixelDensityQualifier qualifier = new PixelDensityQualifier(); - qualifier.mValue = density; - - return qualifier; + + return null; + } + + static Density getLegacyEnum(String value) { + Matcher m = sDensityLegacyPattern.matcher(value); + if (m.matches()) { + String v = m.group(1); + + try { + int density = Integer.parseInt(v); + for (Density orient : values()) { + if (orient.mDpiValue == density) { + return orient; + } + } + } catch (NumberFormatException e) { + // looks like the string we extracted wasn't a valid number + // which really shouldn't happen since the regexp would have failed. + } + } + return null; + } + + public String getValue() { + return mValue; + } + + public int getDpiValue() { + return mDpiValue; + } + + public String getLegacyValue() { + if (this != NODPI) { + return String.format("%1$ddpi", mDpiValue); + } + + return ""; + } + + public String getDisplayValue() { + return mDisplayValue; + } + + public static int getIndex(Density value) { + int i = 0; + for (Density input : values()) { + if (value == input) { + return i; + } + + i++; + } + + return -1; + } + + public static Density getByIndex(int index) { + int i = 0; + for (Density value : values()) { + if (i == index) { + return value; + } + i++; + } + return null; } - return null; } - /** - * Returns the folder name segment for the given value. This is equivalent to calling - * {@link #toString()} on a {@link NetworkCodeQualifier} object. - * @param value the value of the qualifier, as returned by {@link #getValue()}. - */ - public static String getFolderSegment(int value) { - if (value != DEFAULT_DENSITY) { - return String.format("%1$ddpi", value); //$NON-NLS-1$ - } - - return ""; //$NON-NLS-1$ + public PixelDensityQualifier() { + // pass } - public int getValue() { + public PixelDensityQualifier(Density value) { + mValue = value; + } + + public Density getValue() { return mValue; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return NAME; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("dpi"); //$NON-NLS-1$ } - + @Override public boolean isValid() { - return mValue != DEFAULT_DENSITY; + return mValue != null; } @Override public boolean checkAndSet(String value, FolderConfiguration config) { - PixelDensityQualifier qualifier = getQualifier(value); - if (qualifier != null) { + Density density = Density.getEnum(value); + if (density == null) { + density = Density.getLegacyEnum(value); + } + + if (density != null) { + PixelDensityQualifier qualifier = new PixelDensityQualifier(); + qualifier.mValue = density; config.setPixelDensityQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof PixelDensityQualifier) { return mValue == ((PixelDensityQualifier)qualifier).mValue; } - + return false; } @Override public int hashCode() { - return mValue; + if (mValue != null) { + return mValue.hashCode(); + } + + return 0; } - + /** * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { - return getFolderSegment(mValue); + public String getFolderSegment(IAndroidTarget target) { + if (mValue != null) { + if (target != null) { + AndroidVersion version = target.getVersion(); + if (version.getApiLevel() <= 3 && version.getCodename() == null) { + return mValue.getLegacyValue(); + } + } + return mValue.getValue(); + } + + return ""; //$NON-NLS-1$ } @Override public String getStringValue() { - if (mValue != DEFAULT_DENSITY) { - return String.format("%1$d dpi", mValue); + if (mValue != null) { + return mValue.getDisplayValue(); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/RegionQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/RegionQualifier.java index be54f2b7d..3f3abccca 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/RegionQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/RegionQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -30,9 +31,9 @@ public final class RegionQualifier extends ResourceQualifier { private final static Pattern sRegionPattern = Pattern.compile("^r([A-Z]{2})$"); //$NON-NLS-1$ public static final String NAME = "Region"; - + private String mValue; - + /** * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, * null is returned. @@ -49,7 +50,7 @@ public final class RegionQualifier extends ResourceQualifier { } return null; } - + /** * Returns the folder name segment for the given value. This is equivalent to calling * {@link #toString()} on a {@link RegionQualifier} object. @@ -62,7 +63,7 @@ public final class RegionQualifier extends ResourceQualifier { return segment; } } - + return ""; //$NON-NLS-1$ } @@ -70,20 +71,20 @@ public final class RegionQualifier extends ResourceQualifier { if (mValue != null) { return mValue; } - + return ""; //$NON-NLS-1$ } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return NAME; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("region"); //$NON-NLS-1$ @@ -101,10 +102,10 @@ public final class RegionQualifier extends ResourceQualifier { config.setRegionQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof RegionQualifier) { @@ -113,7 +114,7 @@ public final class RegionQualifier extends ResourceQualifier { } return mValue.equals(((RegionQualifier)qualifier).mValue); } - + return false; } @@ -122,15 +123,15 @@ public final class RegionQualifier extends ResourceQualifier { if (mValue != null) { return mValue.hashCode(); } - + return 0; } - + /** * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { return getFolderSegment(mValue); } @@ -139,7 +140,7 @@ public final class RegionQualifier extends ResourceQualifier { if (mValue != null) { return mValue; } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java index b644e8f8b..bfee8d231 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; +import com.android.sdklib.IAndroidTarget; + import org.eclipse.swt.graphics.Image; /** @@ -23,28 +25,28 @@ import org.eclipse.swt.graphics.Image; *

    The resource qualifier classes are designed as immutable. */ public abstract class ResourceQualifier implements Comparable { - + /** * Returns the human readable name of the qualifier. */ public abstract String getName(); - + /** * Returns a shorter human readable name for the qualifier. * @see #getName() */ public abstract String getShortName(); - + /** * Returns the icon for the qualifier. */ public abstract Image getIcon(); - + /** * Returns whether the qualifier has a valid filter value. */ public abstract boolean isValid(); - + /** * Check if the value is valid for this qualifier, and if so sets the value * into a Folder Configuration. @@ -53,13 +55,17 @@ public abstract class ResourceQualifier implements Comparable * @return true if the value was valid and was set. */ public abstract boolean checkAndSet(String value, FolderConfiguration config); - + /** * Returns a string formated to be used in a folder name. *

    This is declared as abstract to force children classes to implement it. */ + public abstract String getFolderSegment(IAndroidTarget target); + @Override - public abstract String toString(); + public String toString() { + return getFolderSegment(null); + } /** * Returns a string formatted for display purpose. @@ -72,7 +78,7 @@ public abstract class ResourceQualifier implements Comparable */ @Override public abstract boolean equals(Object object); - + /** * Returns a hash code value for the object. *

    This is declared as abstract to force children classes to implement it. diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenDimensionQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenDimensionQualifier.java index e75664488..ff8a93064 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenDimensionQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenDimensionQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -46,7 +47,7 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { * 200 but that'll be Y in landscape and X in portrait. * Default value is DEFAULT_SIZE */ private int mValue2 = DEFAULT_SIZE; - + public int getValue1() { return mValue1; } @@ -54,17 +55,17 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { public int getValue2() { return mValue2; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return "Dimension"; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("dimension"); //$NON-NLS-1$ @@ -81,7 +82,7 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { if (m.matches()) { String d1 = m.group(1); String d2 = m.group(2); - + ScreenDimensionQualifier qualifier = getQualifier(d1, d2); if (qualifier != null) { config.setScreenDimensionQualifier(qualifier); @@ -90,14 +91,14 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { } return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof ScreenDimensionQualifier) { ScreenDimensionQualifier q = (ScreenDimensionQualifier)qualifier; return (mValue1 == q.mValue1 && mValue2 == q.mValue2); } - + return false; } @@ -105,12 +106,12 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { public int hashCode() { return toString().hashCode(); } - + public static ScreenDimensionQualifier getQualifier(String size1, String size2) { try { int s1 = Integer.parseInt(size1); int s2 = Integer.parseInt(size2); - + ScreenDimensionQualifier qualifier = new ScreenDimensionQualifier(); if (s1 > s2) { @@ -125,7 +126,7 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { } catch (NumberFormatException e) { // looks like the string we extracted wasn't a valid number. } - + return null; } @@ -133,7 +134,7 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { return String.format("%1$dx%2$d", mValue1, mValue2); //$NON-NLS-1$ } @@ -142,7 +143,7 @@ public final class ScreenDimensionQualifier extends ResourceQualifier { if (mValue1 != -1 && mValue2 != -1) { return String.format("%1$dx%2$d", mValue1, mValue2); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenOrientationQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenOrientationQualifier.java index 6e1b829a8..85d0c03a6 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenOrientationQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenOrientationQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -24,7 +25,7 @@ import org.eclipse.swt.graphics.Image; * Resource Qualifier for Screen Orientation. */ public final class ScreenOrientationQualifier extends ResourceQualifier { - + public static final String NAME = "Screen Orientation"; private ScreenOrientation mValue = null; @@ -36,15 +37,15 @@ public final class ScreenOrientationQualifier extends ResourceQualifier { PORTRAIT("port", "Portrait"), //$NON-NLS-1$ LANDSCAPE("land", "Landscape"), //$NON-NLS-1$ SQUARE("square", "Square"); //$NON-NLS-1$ - + private String mValue; private String mDisplayValue; - + private ScreenOrientation(String value, String displayValue) { mValue = value; mDisplayValue = displayValue; } - + /** * Returns the enum for matching the provided qualifier value. * @param value The qualifier value. @@ -63,18 +64,18 @@ public final class ScreenOrientationQualifier extends ResourceQualifier { public String getValue() { return mValue; } - + public String getDisplayValue() { return mDisplayValue; } - + public static int getIndex(ScreenOrientation orientation) { int i = 0; for (ScreenOrientation orient : values()) { if (orient == orientation) { return i; } - + i++; } @@ -104,22 +105,22 @@ public final class ScreenOrientationQualifier extends ResourceQualifier { public ScreenOrientation getValue() { return mValue; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return "Orientation"; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("orientation"); //$NON-NLS-1$ } - + @Override public boolean isValid() { return mValue != null; @@ -133,10 +134,10 @@ public final class ScreenOrientationQualifier extends ResourceQualifier { config.setScreenOrientationQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof ScreenOrientationQualifier) { @@ -151,19 +152,19 @@ public final class ScreenOrientationQualifier extends ResourceQualifier { if (mValue != null) { return mValue.hashCode(); } - + return 0; } - + /** * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { if (mValue != null) { return mValue.getValue(); } - + return ""; //$NON-NLS-1$ } @@ -172,7 +173,7 @@ public final class ScreenOrientationQualifier extends ResourceQualifier { if (mValue != null) { return mValue.getDisplayValue(); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TextInputMethodQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TextInputMethodQualifier.java index add45cc91..6289147b5 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TextInputMethodQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TextInputMethodQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -31,7 +32,7 @@ public final class TextInputMethodQualifier extends ResourceQualifier { public static final String NAME = "Text Input Method"; private TextInputMethod mValue; - + /** * Screen Orientation enum. */ @@ -39,15 +40,15 @@ public final class TextInputMethodQualifier extends ResourceQualifier { NOKEY("nokeys", "No Keys"), //$NON-NLS-1$ QWERTY("qwerty", "Qwerty"), //$NON-NLS-1$ TWELVEKEYS("12key", "12 Key"); //$NON-NLS-1$ - + private String mValue; private String mDisplayValue; - + private TextInputMethod(String value, String displayValue) { mValue = value; mDisplayValue = displayValue; } - + /** * Returns the enum for matching the provided qualifier value. * @param value The qualifier value. @@ -59,14 +60,14 @@ public final class TextInputMethodQualifier extends ResourceQualifier { return orient; } } - + return null; } public String getValue() { return mValue; } - + public String getDisplayValue() { return mDisplayValue; } @@ -77,7 +78,7 @@ public final class TextInputMethodQualifier extends ResourceQualifier { if (value == input) { return i; } - + i++; } @@ -95,7 +96,7 @@ public final class TextInputMethodQualifier extends ResourceQualifier { return null; } } - + public TextInputMethodQualifier() { // pass } @@ -107,17 +108,17 @@ public final class TextInputMethodQualifier extends ResourceQualifier { public TextInputMethod getValue() { return mValue; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return "Text Input"; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("text_input"); //$NON-NLS-1$ @@ -137,10 +138,10 @@ public final class TextInputMethodQualifier extends ResourceQualifier { config.setTextInputMethodQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof TextInputMethodQualifier) { @@ -155,7 +156,7 @@ public final class TextInputMethodQualifier extends ResourceQualifier { if (mValue != null) { return mValue.hashCode(); } - + return 0; } @@ -163,11 +164,11 @@ public final class TextInputMethodQualifier extends ResourceQualifier { * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { if (mValue != null) { return mValue.getValue(); } - + return ""; //$NON-NLS-1$ } @@ -176,7 +177,7 @@ public final class TextInputMethodQualifier extends ResourceQualifier { if (mValue != null) { return mValue.getDisplayValue(); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TouchScreenQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TouchScreenQualifier.java index 1ed7d951e..758c87fd4 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TouchScreenQualifier.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TouchScreenQualifier.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.resources.configurations; import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.IAndroidTarget; import org.eclipse.swt.graphics.Image; @@ -29,7 +30,7 @@ public final class TouchScreenQualifier extends ResourceQualifier { public static final String NAME = "Touch Screen"; private TouchScreenType mValue; - + /** * Screen Orientation enum. */ @@ -37,15 +38,15 @@ public final class TouchScreenQualifier extends ResourceQualifier { NOTOUCH("notouch", "No Touch"), //$NON-NLS-1$ STYLUS("stylus", "Stylus"), //$NON-NLS-1$ FINGER("finger", "Finger"); //$NON-NLS-1$ - + private String mValue; private String mDisplayValue; - + private TouchScreenType(String value, String displayValue) { mValue = value; mDisplayValue = displayValue; } - + /** * Returns the enum for matching the provided qualifier value. * @param value The qualifier value. @@ -57,14 +58,14 @@ public final class TouchScreenQualifier extends ResourceQualifier { return orient; } } - + return null; } public String getValue() { return mValue; } - + public String getDisplayValue() { return mDisplayValue; } @@ -75,7 +76,7 @@ public final class TouchScreenQualifier extends ResourceQualifier { if (t == touch) { return i; } - + i++; } @@ -94,7 +95,7 @@ public final class TouchScreenQualifier extends ResourceQualifier { return null; } } - + public TouchScreenQualifier() { // pass } @@ -106,17 +107,17 @@ public final class TouchScreenQualifier extends ResourceQualifier { public TouchScreenType getValue() { return mValue; } - + @Override public String getName() { return NAME; } - + @Override public String getShortName() { return NAME; } - + @Override public Image getIcon() { return IconFactory.getInstance().getIcon("touch"); //$NON-NLS-1$ @@ -136,10 +137,10 @@ public final class TouchScreenQualifier extends ResourceQualifier { config.setTouchTypeQualifier(qualifier); return true; } - + return false; } - + @Override public boolean equals(Object qualifier) { if (qualifier instanceof TouchScreenQualifier) { @@ -153,7 +154,7 @@ public final class TouchScreenQualifier extends ResourceQualifier { if (mValue != null) { return mValue.hashCode(); } - + return 0; } @@ -161,11 +162,11 @@ public final class TouchScreenQualifier extends ResourceQualifier { * Returns the string used to represent this qualifier in the folder name. */ @Override - public String toString() { + public String getFolderSegment(IAndroidTarget target) { if (mValue != null) { return mValue.getValue(); } - + return ""; //$NON-NLS-1$ } @@ -174,7 +175,7 @@ public final class TouchScreenQualifier extends ResourceQualifier { if (mValue != null) { return mValue.getDisplayValue(); } - + return ""; //$NON-NLS-1$ } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java index d6cfeae80..f2e883dcb 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java @@ -377,6 +377,20 @@ public class Sdk implements IProjectListener { } } + /** + * Return the {@link AndroidTargetData} for a given {@link IProject}. + */ + public AndroidTargetData getTargetData(IProject project) { + synchronized (AdtPlugin.getDefault().getSdkLockObject()) { + IAndroidTarget target = getTarget(project); + if (target != null) { + return getTargetData(target); + } + } + + return null; + } + /** * Returns the configuration map for a given project. *

    The Map key are name to be used in the apk filename, while the values are comma separated diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java index 7378d4136..34a2391b5 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java @@ -31,6 +31,7 @@ import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMe import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier; import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier.KeyboardState; import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier.NavigationMethod; +import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density; import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation; import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier.TextInputMethod; import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier.TouchScreenType; @@ -80,13 +81,13 @@ import java.util.HashMap; *

      *
    • Use {@link #setConfiguration(String)} or {@link #setConfiguration(FolderConfiguration)}. *
    • Retrieve the configuration using {@link #getConfiguration(FolderConfiguration)}. - *
    + *
*/ public class ConfigurationSelector extends Composite { - + public static final int WIDTH_HINT = 600; public static final int HEIGHT_HINT = 250; - + private Runnable mOnChangeListener; private TableViewer mFullTableViewer; @@ -94,16 +95,16 @@ public class ConfigurationSelector extends Composite { private Button mAddButton; private Button mRemoveButton; private StackLayout mStackLayout; - + private boolean mOnRefresh = false; private final FolderConfiguration mBaseConfiguration = new FolderConfiguration(); private final FolderConfiguration mSelectedConfiguration = new FolderConfiguration(); - + private final HashMap, QualifierEditBase> mUiMap = new HashMap, QualifierEditBase>(); private Composite mQualifierEditParent; - + /** * Basic of {@link VerifyListener} to only accept digits. */ @@ -119,7 +120,7 @@ public class ConfigurationSelector extends Composite { } } } - + /** * Implementation of {@link VerifyListener} for Country Code qualifiers. */ @@ -138,7 +139,7 @@ public class ConfigurationSelector extends Composite { } } } - + /** * Implementation of {@link VerifyListener} for the Language and Region qualifiers. */ @@ -149,7 +150,7 @@ public class ConfigurationSelector extends Composite { e.doit = false; return; } - + // check for lower case only. for (int i = 0 ; i < e.text.length(); i++) { char letter = e.text.charAt(i); @@ -160,17 +161,17 @@ public class ConfigurationSelector extends Composite { } } } - + /** * Implementation of {@link VerifyListener} for the Pixel Density qualifier. */ public static class DensityVerifier extends DigitVerifier { } - + /** * Implementation of {@link VerifyListener} for the Screen Dimension qualifier. */ public static class DimensionVerifier extends DigitVerifier { } - + /** * Enum for the state of the configuration being created. */ @@ -186,18 +187,18 @@ public class ConfigurationSelector extends Composite { GridLayout gl = new GridLayout(4, false); gl.marginWidth = gl.marginHeight = 0; setLayout(gl); - + // first column is the first table final Table fullTable = new Table(this, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER); fullTable.setLayoutData(new GridData(GridData.FILL_BOTH)); fullTable.setHeaderVisible(true); fullTable.setLinesVisible(true); - + // create the column final TableColumn fullTableColumn = new TableColumn(fullTable, SWT.LEFT); // set the header fullTableColumn.setText("Available Qualifiers"); - + fullTable.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { @@ -217,24 +218,24 @@ public class ConfigurationSelector extends Composite { if (selection instanceof IStructuredSelection) { IStructuredSelection structSelection = (IStructuredSelection)selection; Object first = structSelection.getFirstElement(); - + if (first instanceof ResourceQualifier) { mAddButton.setEnabled(true); return; } } - + mAddButton.setEnabled(false); } }); - + // 2nd column is the left/right arrow button Composite buttonComposite = new Composite(this, SWT.NONE); gl = new GridLayout(1, false); gl.marginWidth = gl.marginHeight = 0; buttonComposite.setLayout(gl); buttonComposite.setLayoutData(new GridData(GridData.FILL_VERTICAL)); - + new Composite(buttonComposite, SWT.NONE); mAddButton = new Button(buttonComposite, SWT.BORDER | SWT.PUSH); mAddButton.setText("->"); @@ -242,20 +243,20 @@ public class ConfigurationSelector extends Composite { mAddButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { - IStructuredSelection selection = + IStructuredSelection selection = (IStructuredSelection)mFullTableViewer.getSelection(); - + Object first = selection.getFirstElement(); if (first instanceof ResourceQualifier) { ResourceQualifier qualifier = (ResourceQualifier)first; - + mBaseConfiguration.removeQualifier(qualifier); mSelectedConfiguration.addQualifier(qualifier); - + mFullTableViewer.refresh(); mSelectionTableViewer.refresh(); mSelectionTableViewer.setSelection(new StructuredSelection(qualifier), true); - + onChange(false /* keepSelection */); } } @@ -267,19 +268,19 @@ public class ConfigurationSelector extends Composite { mRemoveButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { - IStructuredSelection selection = + IStructuredSelection selection = (IStructuredSelection)mSelectionTableViewer.getSelection(); - + Object first = selection.getFirstElement(); if (first instanceof ResourceQualifier) { ResourceQualifier qualifier = (ResourceQualifier)first; - + mSelectedConfiguration.removeQualifier(qualifier); mBaseConfiguration.addQualifier(qualifier); mFullTableViewer.refresh(); mSelectionTableViewer.refresh(); - + onChange(false /* keepSelection */); } } @@ -290,12 +291,12 @@ public class ConfigurationSelector extends Composite { selectionTable.setLayoutData(new GridData(GridData.FILL_BOTH)); selectionTable.setHeaderVisible(true); selectionTable.setLinesVisible(true); - + // create the column final TableColumn selectionTableColumn = new TableColumn(selectionTable, SWT.LEFT); // set the header selectionTableColumn.setText("Chosen Qualifiers"); - + selectionTable.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { @@ -318,22 +319,22 @@ public class ConfigurationSelector extends Composite { ISelection selection = event.getSelection(); if (selection instanceof IStructuredSelection) { IStructuredSelection structSelection = (IStructuredSelection)selection; - + if (structSelection.isEmpty() == false) { Object first = structSelection.getFirstElement(); - + if (first instanceof ResourceQualifier) { mRemoveButton.setEnabled(true); - + QualifierEditBase composite = mUiMap.get(first.getClass()); - + if (composite != null) { composite.setQualifier((ResourceQualifier)first); } - + mStackLayout.topControl = composite; mQualifierEditParent.layout(); - + return; } } else { @@ -341,16 +342,16 @@ public class ConfigurationSelector extends Composite { mQualifierEditParent.layout(); } } - + mRemoveButton.setEnabled(false); } }); - - // 4th column is the detail of the selected qualifier + + // 4th column is the detail of the selected qualifier mQualifierEditParent = new Composite(this, SWT.NONE); mQualifierEditParent.setLayout(mStackLayout = new StackLayout()); mQualifierEditParent.setLayoutData(new GridData(GridData.FILL_VERTICAL)); - + // create the UI for all the qualifiers, and associate them to the ResourceQualifer class. mUiMap.put(CountryCodeQualifier.class, new MCCEdit(mQualifierEditParent)); mUiMap.put(NetworkCodeQualifier.class, new MNCEdit(mQualifierEditParent)); @@ -364,7 +365,7 @@ public class ConfigurationSelector extends Composite { mUiMap.put(NavigationMethodQualifier.class, new NavigationEdit(mQualifierEditParent)); mUiMap.put(ScreenDimensionQualifier.class, new ScreenDimensionEdit(mQualifierEditParent)); } - + /** * Sets a listener to be notified when the configuration changes. * @param listener A {@link Runnable} whose run() method is called when the @@ -373,7 +374,7 @@ public class ConfigurationSelector extends Composite { public void setOnChangeListener(Runnable listener) { mOnChangeListener = listener; } - + /** * Initialize the UI with a given {@link FolderConfiguration}. This must * be called from the UI thread. @@ -382,24 +383,24 @@ public class ConfigurationSelector extends Composite { public void setConfiguration(FolderConfiguration config) { mSelectedConfiguration.set(config); mSelectionTableViewer.refresh(); - + // create the base config, which is the default config minus the qualifiers // in SelectedConfiguration mBaseConfiguration.substract(mSelectedConfiguration); mFullTableViewer.refresh(); } - + /** * Initialize the UI with the configuration represented by a resource folder name. * This must be called from the UI thread. - * + * * @param folderSegments the segments of the folder name, * split using {@link FolderConfiguration#QUALIFIER_SEP}. * @return true if success, or false if the folder name is not a valid name. */ public boolean setConfiguration(String[] folderSegments) { FolderConfiguration config = ResourceManager.getInstance().getConfig(folderSegments); - + if (config == null) { return false; } @@ -408,7 +409,7 @@ public class ConfigurationSelector extends Composite { return true; } - + /** * Initialize the UI with the configuration represented by a resource folder name. * This must be called from the UI thread. @@ -421,7 +422,7 @@ public class ConfigurationSelector extends Composite { return setConfiguration(folderSegments); } - + /** * Gets the configuration as setup by the widget. * @param config the {@link FolderConfiguration} object to be filled with the information @@ -430,7 +431,7 @@ public class ConfigurationSelector extends Composite { public void getConfiguration(FolderConfiguration config) { config.set(mSelectedConfiguration); } - + /** * Returns the state of the configuration being edited/created. */ @@ -438,14 +439,14 @@ public class ConfigurationSelector extends Composite { if (mSelectedConfiguration.getInvalidQualifier() != null) { return ConfigurationState.INVALID_CONFIG; } - + if (mSelectedConfiguration.checkRegion() == false) { return ConfigurationState.REGION_WITHOUT_LANGUAGE; } - + return ConfigurationState.OK; } - + /** * Returns the first invalid qualifier of the configuration being edited/created, * or null if they are all valid (or if none exists). @@ -469,7 +470,7 @@ public class ConfigurationSelector extends Composite { } mSelectionTableViewer.refresh(true); - + if (keepSelection) { mSelectionTableViewer.setSelection(selection); mOnRefresh = false; @@ -479,12 +480,12 @@ public class ConfigurationSelector extends Composite { mOnChangeListener.run(); } } - + /** * Content provider around a {@link FolderConfiguration}. */ private static class QualifierContentProvider implements IStructuredContentProvider { - + private FolderConfiguration mInput; public QualifierContentProvider() { @@ -505,12 +506,12 @@ public class ConfigurationSelector extends Composite { } } } - + /** * Label provider for {@link ResourceQualifier} objects. */ private static class QualifierLabelProvider implements ITableLabelProvider { - + private final boolean mShowQualifierValue; public QualifierLabelProvider(boolean showQualifierValue) { @@ -528,7 +529,7 @@ public class ConfigurationSelector extends Composite { } else { return value; } - + } else { return ((ResourceQualifier)element).getShortName(); } @@ -536,7 +537,7 @@ public class ConfigurationSelector extends Composite { return null; } - + public Image getColumnImage(Object element, int columnIndex) { // only one column, so we can ignore columnIndex if (element instanceof ResourceQualifier) { @@ -563,7 +564,7 @@ public class ConfigurationSelector extends Composite { // pass } } - + /** * Base class for Edit widget for {@link ResourceQualifier}. */ @@ -575,10 +576,10 @@ public class ConfigurationSelector extends Composite { new Label(this, SWT.NONE).setText(title); } - + public abstract void setQualifier(ResourceQualifier qualifier); } - + /** * Edit widget for {@link CountryCodeQualifier}. */ @@ -588,13 +589,13 @@ public class ConfigurationSelector extends Composite { public MCCEdit(Composite parent) { super(parent, CountryCodeQualifier.NAME); - + mText = new Text(this, SWT.BORDER); mText.addVerifyListener(new MobileCodeVerifier()); mText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { onTextChange(); - } + } }); mText.addFocusListener(new FocusAdapter() { @@ -603,13 +604,13 @@ public class ConfigurationSelector extends Composite { onTextChange(); } }); - + new Label(this, SWT.NONE).setText("(3 digit code)"); } - + private void onTextChange() { String value = mText.getText(); - + if (value.length() == 0) { // empty string, means a qualifier with no value. // Since the qualifier classes are immutable, and we don't want to @@ -632,7 +633,7 @@ public class ConfigurationSelector extends Composite { mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier()); } } - + // notify of change onChange(true /* keepSelection */); } @@ -640,7 +641,7 @@ public class ConfigurationSelector extends Composite { @Override public void setQualifier(ResourceQualifier qualifier) { CountryCodeQualifier q = (CountryCodeQualifier)qualifier; - + mText.setText(Integer.toString(q.getCode())); } } @@ -653,7 +654,7 @@ public class ConfigurationSelector extends Composite { public MNCEdit(Composite parent) { super(parent, NetworkCodeQualifier.NAME); - + mText = new Text(this, SWT.BORDER); mText.addVerifyListener(new MobileCodeVerifier()); mText.addModifyListener(new ModifyListener() { @@ -670,10 +671,10 @@ public class ConfigurationSelector extends Composite { new Label(this, SWT.NONE).setText("(1-3 digit code)"); } - + private void onTextChange() { String value = mText.getText(); - + if (value.length() == 0) { // empty string, means a qualifier with no value. // Since the qualifier classes are immutable, and we don't want to @@ -696,19 +697,19 @@ public class ConfigurationSelector extends Composite { mSelectedConfiguration.setNetworkCodeQualifier(new NetworkCodeQualifier()); } } - + // notify of change onChange(true /* keepSelection */); - } + } @Override public void setQualifier(ResourceQualifier qualifier) { NetworkCodeQualifier q = (NetworkCodeQualifier)qualifier; - + mText.setText(Integer.toString(q.getCode())); } } - + /** * Edit widget for {@link LanguageQualifier}. */ @@ -741,7 +742,7 @@ public class ConfigurationSelector extends Composite { private void onLanguageChange() { // update the current config String value = mLanguage.getText(); - + if (value.length() == 0) { // empty string, means no qualifier. // Since the qualifier classes are immutable, and we don't want to @@ -809,7 +810,7 @@ public class ConfigurationSelector extends Composite { private void onRegionChange() { // update the current config String value = mRegion.getText(); - + if (value.length() == 0) { // empty string, means no qualifier. // Since the qualifier classes are immutable, and we don't want to @@ -844,7 +845,7 @@ public class ConfigurationSelector extends Composite { } } } - + /** * Edit widget for {@link ScreenOrientationQualifier}. */ @@ -908,63 +909,58 @@ public class ConfigurationSelector extends Composite { * Edit widget for {@link PixelDensityQualifier}. */ private class PixelDensityEdit extends QualifierEditBase { - private Text mText; + private Combo mDensity; public PixelDensityEdit(Composite parent) { super(parent, PixelDensityQualifier.NAME); - - mText = new Text(this, SWT.BORDER); - mText.addVerifyListener(new DensityVerifier()); - mText.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onTextChange(); - } - }); - mText.addFocusListener(new FocusAdapter() { - @Override - public void focusLost(FocusEvent e) { - onTextChange(); + + mDensity = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY); + Density[] soValues = Density.values(); + for (Density value : soValues) { + mDensity.add(value.getDisplayValue()); + } + + mDensity.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mDensity.addSelectionListener(new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + onDensityChange(); + } + public void widgetSelected(SelectionEvent e) { + onDensityChange(); } }); + } - - private void onTextChange() { - String value = mText.getText(); - - if (value.length() == 0) { - // empty string, means a qualifier with no value. + + private void onDensityChange() { + // update the current config + int index = mDensity.getSelectionIndex(); + + if (index != -1) { + mSelectedConfiguration.setPixelDensityQualifier(new PixelDensityQualifier( + Density.getByIndex(index))); + } else { + // empty selection, means no qualifier. // Since the qualifier classes are immutable, and we don't want to // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setPixelDensityQualifier(new PixelDensityQualifier()); - } else { - try { - PixelDensityQualifier qualifier = PixelDensityQualifier.getQualifier( - PixelDensityQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mSelectedConfiguration.setPixelDensityQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong - // (for instance a one letter string). - // We do nothing in this case. - return; - } - } catch (NumberFormatException nfe) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - // We do nothing in this case. - return; - } + mSelectedConfiguration.setPixelDensityQualifier( + new PixelDensityQualifier()); } - + // notify of change onChange(true /* keepSelection */); - } + } @Override public void setQualifier(ResourceQualifier qualifier) { PixelDensityQualifier q = (PixelDensityQualifier)qualifier; - - mText.setText(Integer.toString(q.getValue())); + + Density value = q.getValue(); + if (value == null) { + mDensity.clearSelection(); + } else { + mDensity.select(Density.getIndex(value)); + } } } @@ -1202,7 +1198,7 @@ public class ConfigurationSelector extends Composite { } } } - + /** * Edit widget for {@link ScreenDimensionQualifier}. */ @@ -1217,9 +1213,9 @@ public class ConfigurationSelector extends Composite { ModifyListener modifyListener = new ModifyListener() { public void modifyText(ModifyEvent e) { onSizeChange(); - } + } }; - + FocusAdapter focusListener = new FocusAdapter() { @Override public void focusLost(FocusEvent e) { @@ -1237,12 +1233,12 @@ public class ConfigurationSelector extends Composite { mSize2.addModifyListener(modifyListener); mSize2.addFocusListener(focusListener); } - + private void onSizeChange() { // update the current config String size1 = mSize1.getText(); String size2 = mSize2.getText(); - + if (size1.length() == 0 || size2.length() == 0) { // if one of the strings is empty, reset to no qualifier. // Since the qualifier classes are immutable, and we don't want to @@ -1262,7 +1258,7 @@ public class ConfigurationSelector extends Composite { new ScreenDimensionQualifier()); } } - + // notify of change onChange(true /* keepSelection */); } @@ -1270,7 +1266,7 @@ public class ConfigurationSelector extends Composite { @Override public void setQualifier(ResourceQualifier qualifier) { ScreenDimensionQualifier q = (ScreenDimensionQualifier)qualifier; - + mSize1.setText(Integer.toString(q.getValue1())); mSize2.setText(Integer.toString(q.getValue2())); } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java index 4edfb77c4..bd4e7a3d8 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java @@ -897,6 +897,9 @@ class NewXmlFileCreationPage extends WizardPage { // enable types based on new API level enableTypesBasedOnApi(); + // update the folder name based on API level + resetFolderPath(false /*validate*/); + // update the Type with the new descriptors. initializeRootValues(); @@ -1023,7 +1026,7 @@ class NewXmlFileCreationPage extends WizardPage { // The configuration is valid. Reformat the folder path using the canonical // value from the configuration. - newPath = RES_FOLDER_ABS + mTempConfig.getFolderName(type.getResFolderType()); + newPath = RES_FOLDER_ABS + mTempConfig.getFolderName(type.getResFolderType(), mProject); } else { // The configuration is invalid. We still update the path but this time // do it manually on the string. @@ -1032,7 +1035,8 @@ class NewXmlFileCreationPage extends WizardPage { "^(" + RES_FOLDER_ABS +")[^-]*(.*)", //$NON-NLS-1$ //$NON-NLS-2$ "\\1" + type.getResFolderName() + "\\2"); //$NON-NLS-1$ //$NON-NLS-2$ } else { - newPath = RES_FOLDER_ABS + mTempConfig.getFolderName(type.getResFolderType()); + newPath = RES_FOLDER_ABS + mTempConfig.getFolderName(type.getResFolderType(), + mProject); } } @@ -1085,19 +1089,7 @@ class NewXmlFileCreationPage extends WizardPage { return; } - TypeInfo type = getSelectedType(); - - if (type != null) { - mConfigSelector.getConfiguration(mTempConfig); - StringBuffer sb = new StringBuffer(RES_FOLDER_ABS); - sb.append(mTempConfig.getFolderName(type.getResFolderType())); - - mInternalWsFolderPathUpdate = true; - mWsFolderPathTextField.setText(sb.toString()); - mInternalWsFolderPathUpdate = false; - - validatePage(); - } + resetFolderPath(true /*validate*/); } } @@ -1138,6 +1130,28 @@ class NewXmlFileCreationPage extends WizardPage { } } + /** + * Reset the current Folder path based on the UI selection + * @param validate if true, force a call to {@link #validatePage()}. + */ + private void resetFolderPath(boolean validate) { + TypeInfo type = getSelectedType(); + + if (type != null) { + mConfigSelector.getConfiguration(mTempConfig); + StringBuffer sb = new StringBuffer(RES_FOLDER_ABS); + sb.append(mTempConfig.getFolderName(type.getResFolderType(), mProject)); + + mInternalWsFolderPathUpdate = true; + mWsFolderPathTextField.setText(sb.toString()); + mInternalWsFolderPathUpdate = false; + + if (validate) { + validatePage(); + } + } + } + /** * Validates the fields, displays errors and warnings. * Enables the finish button if there are no errors. diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java b/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java index dd82bed90..c93f2a2f3 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java @@ -34,6 +34,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.files.IFileWrapper import com.android.ide.eclipse.adt.internal.resources.manager.files.IFolderWrapper; import com.android.ide.eclipse.mock.FileMock; import com.android.ide.eclipse.mock.FolderMock; +import com.android.sdklib.SdkConstants; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -44,7 +45,7 @@ public class ConfigMatchTest extends TestCase { private static final String SEARCHED_FILENAME = "main.xml"; //$NON-NLS-1$ private static final String MISC1_FILENAME = "foo.xml"; //$NON-NLS-1$ private static final String MISC2_FILENAME = "bar.xml"; //$NON-NLS-1$ - + private ProjectResources mResources; private ResourceQualifier[] mQualifierList; private FolderConfiguration config4; @@ -55,20 +56,20 @@ public class ConfigMatchTest extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); - + // create a Resource Manager to get a list of qualifier as instantiated by the real code. - // Thanks for QualifierListTest we know this contains all the qualifiers. + // Thanks for QualifierListTest we know this contains all the qualifiers. ResourceManager manager = ResourceManager.getInstance(); Field qualifierListField = ResourceManager.class.getDeclaredField("mQualifiers"); assertNotNull(qualifierListField); qualifierListField.setAccessible(true); - + // get the actual list. mQualifierList = (ResourceQualifier[])qualifierListField.get(manager); - + // create the project resources. mResources = new ProjectResources(false /* isFrameworkRepository */); - + // create 2 arrays of IResource. one with the filename being looked up, and one without. // Since the required API uses IResource, we can use MockFolder for them. FileMock[] validMemberList = new FileMock[] { @@ -80,7 +81,7 @@ public class ConfigMatchTest extends TestCase { new FileMock(MISC1_FILENAME), new FileMock(MISC2_FILENAME), }; - + // add multiple ResourceFolder to the project resource. FolderConfiguration defaultConfig = getConfiguration( null, // country code @@ -94,9 +95,9 @@ public class ConfigMatchTest extends TestCase { null, // text input null, // navigation null); // screen size - + addFolder(mResources, defaultConfig, validMemberList); - + config1 = getConfiguration( null, // country code null, // network code @@ -109,7 +110,7 @@ public class ConfigMatchTest extends TestCase { null, // text input null, // navigation null); // screen size - + addFolder(mResources, config1, validMemberList); config2 = getConfiguration( @@ -124,7 +125,7 @@ public class ConfigMatchTest extends TestCase { null, // text input null, // navigation null); // screen size - + addFolder(mResources, config2, validMemberList); config3 = getConfiguration( @@ -139,7 +140,7 @@ public class ConfigMatchTest extends TestCase { null, // text input null, // navigation null); // screen size - + addFolder(mResources, config3, validMemberList); config4 = getConfiguration( @@ -154,7 +155,7 @@ public class ConfigMatchTest extends TestCase { TextInputMethod.QWERTY.getValue(), // text input NavigationMethod.DPAD.getValue(), // navigation "480x320"); // screen size - + addFolder(mResources, config4, invalidMemberList); } @@ -177,10 +178,10 @@ public class ConfigMatchTest extends TestCase { TextInputMethod.QWERTY.getValue(), // text input NavigationMethod.DPAD.getValue(), // navigation "480x320"); // screen size - + ResourceFile result = mResources.getMatchingFile(SEARCHED_FILENAME, ResourceFolderType.LAYOUT, testConfig); - + boolean bresult = result.getFolder().getConfiguration().equals(config3); assertEquals(bresult, true); } @@ -193,10 +194,10 @@ public class ConfigMatchTest extends TestCase { */ private FolderConfiguration getConfiguration(String... qualifierValues) { FolderConfiguration config = new FolderConfiguration(); - + // those must be of the same length assertEquals(qualifierValues.length, mQualifierList.length); - + int index = 0; for (ResourceQualifier qualifier : mQualifierList) { @@ -208,7 +209,7 @@ public class ConfigMatchTest extends TestCase { return config; } - + /** * Adds a folder to the given {@link ProjectResources} with the given * {@link FolderConfiguration}. The folder is filled with files from the provided list. @@ -218,13 +219,10 @@ public class ConfigMatchTest extends TestCase { */ private void addFolder(ProjectResources resources, FolderConfiguration config, FileMock[] memberList) throws Exception { - + // figure out the folder name based on the configuration - String folderName = "layout"; - if (config.isDefault() == false) { - folderName += "-" + config.toString(); - } - + String folderName = config.getFolderName(ResourceFolderType.LAYOUT); + // create the folder mock FolderMock folder = new FolderMock(folderName, memberList); @@ -237,15 +235,15 @@ public class ConfigMatchTest extends TestCase { } } - /** Calls ProjectResource.add method via reflection to circumvent access - * restrictions that are enforced when running in the plug-in environment + /** Calls ProjectResource.add method via reflection to circumvent access + * restrictions that are enforced when running in the plug-in environment * ie cannot access package or protected members in a different plug-in, even * if they are in the same declared package as the accessor */ private ResourceFolder _addProjectResourceFolder(ProjectResources resources, FolderConfiguration config, FolderMock folder) throws Exception { - Method addMethod = ProjectResources.class.getDeclaredMethod("add", + Method addMethod = ProjectResources.class.getDeclaredMethod("add", ResourceFolderType.class, FolderConfiguration.class, IAbstractFolder.class); addMethod.setAccessible(true); @@ -253,7 +251,4 @@ public class ConfigMatchTest extends TestCase { ResourceFolderType.LAYOUT, config, new IFolderWrapper(folder)); return resFolder; } - - - } From 64bd2d5f3a7a109aed560e1856242d806aa4099f Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 11 Aug 2009 18:41:54 -0700 Subject: [PATCH 43/87] Add internal support for screen size/ratio, and version qualifiers. UI will come later. BUG: 2048256, 2048264 --- .../configurations/FolderConfiguration.java | 60 ++++-- .../configurations/ScreenRatioQualifier.java | 180 +++++++++++++++++ .../configurations/ScreenSizeQualifier.java | 184 ++++++++++++++++++ .../configurations/VersionQualifier.java | 151 ++++++++++++++ .../resources/manager/ConfigMatchTest.java | 4 +- 5 files changed, 565 insertions(+), 14 deletions(-) create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenRatioQualifier.java create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenSizeQualifier.java create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/VersionQualifier.java diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java index ff8c26aa8..23a6440fc 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java @@ -32,18 +32,21 @@ public final class FolderConfiguration implements Comparableconfig. @@ -108,6 +111,10 @@ public final class FolderConfiguration implements Comparable= 4 || + (version.getApiLevel() == 3 && "Donut".equals(version.getCodename()))) { + return mValue.getValue(); + } + } + + return ""; //$NON-NLS-1$ + } + + @Override + public String getStringValue() { + if (mValue != null) { + return mValue.getDisplayValue(); + } + + return ""; //$NON-NLS-1$ + } +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenSizeQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenSizeQualifier.java new file mode 100644 index 000000000..613219362 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenSizeQualifier.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.adt.internal.resources.configurations; + +import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.AndroidVersion; +import com.android.sdklib.IAndroidTarget; + +import org.eclipse.swt.graphics.Image; + +/** + * Resource Qualifier for Screen Size. Size can be "small", "normal", and "large" + */ +public class ScreenSizeQualifier extends ResourceQualifier { + + public static final String NAME = "Screen Size"; + + private ScreenSize mValue = null; + + /** + * Screen Orientation enum. + */ + public static enum ScreenSize { + SMALL("small", "Small"), //$NON-NLS-1$ + NORMAL("normal", "Normal"), //$NON-NLS-1$ + LARGE("large", "Large"); //$NON-NLS-1$ + + private String mValue; + private String mDisplayValue; + + private ScreenSize(String value, String displayValue) { + mValue = value; + mDisplayValue = displayValue; + } + + /** + * Returns the enum for matching the provided qualifier value. + * @param value The qualifier value. + * @return the enum for the qualifier value or null if no matching was found. + */ + static ScreenSize getEnum(String value) { + for (ScreenSize orient : values()) { + if (orient.mValue.equals(value)) { + return orient; + } + } + + return null; + } + + public String getValue() { + return mValue; + } + + public String getDisplayValue() { + return mDisplayValue; + } + + public static int getIndex(ScreenSize orientation) { + int i = 0; + for (ScreenSize orient : values()) { + if (orient == orientation) { + return i; + } + + i++; + } + + return -1; + } + + public static ScreenSize getByIndex(int index) { + int i = 0; + for (ScreenSize orient : values()) { + if (i == index) { + return orient; + } + i++; + } + + return null; + } + } + + public ScreenSizeQualifier() { + } + + public ScreenSizeQualifier(ScreenSize value) { + mValue = value; + } + + public ScreenSize getValue() { + return mValue; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String getShortName() { + return "Size"; + } + + @Override + public Image getIcon() { + return IconFactory.getInstance().getIcon("size"); //$NON-NLS-1$ + } + + @Override + public boolean isValid() { + return mValue != null; + } + + @Override + public boolean checkAndSet(String value, FolderConfiguration config) { + ScreenSize size = ScreenSize.getEnum(value); + if (size != null) { + ScreenSizeQualifier qualifier = new ScreenSizeQualifier(size); + config.setScreenSizeQualifier(qualifier); + return true; + } + + return false; + } + + @Override + public boolean equals(Object qualifier) { + if (qualifier instanceof ScreenSizeQualifier) { + return mValue == ((ScreenSizeQualifier)qualifier).mValue; + } + + return false; + } + + @Override + public int hashCode() { + if (mValue != null) { + return mValue.hashCode(); + } + + return 0; + } + + /** + * Returns the string used to represent this qualifier in the folder name. + */ + @Override + public String getFolderSegment(IAndroidTarget target) { + if (mValue != null) { + AndroidVersion version = target.getVersion(); + if (version.getApiLevel() >= 4 || + (version.getApiLevel() == 3 && "Donut".equals(version.getCodename()))) { + return mValue.getValue(); + } + } + + return ""; //$NON-NLS-1$ + } + + @Override + public String getStringValue() { + if (mValue != null) { + return mValue.getDisplayValue(); + } + + return ""; //$NON-NLS-1$ + } +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/VersionQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/VersionQualifier.java new file mode 100644 index 000000000..c82e7e985 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/VersionQualifier.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.adt.internal.resources.configurations; + +import com.android.ide.eclipse.adt.internal.editors.IconFactory; +import com.android.sdklib.AndroidVersion; +import com.android.sdklib.IAndroidTarget; + +import org.eclipse.swt.graphics.Image; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Resource Qualifier for Platform Version. + */ +public final class VersionQualifier extends ResourceQualifier { + /** Default pixel density value. This means the property is not set. */ + private final static int DEFAULT_VERSION = -1; + + private final static Pattern sCountryCodePattern = Pattern.compile("^v(\\d+)$");//$NON-NLS-1$ + + private int mVersion = DEFAULT_VERSION; + + public static final String NAME = "Platform Version"; + + /** + * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, + * null is returned. + * @param segment the folder segment from which to create a qualifier. + * @return a new {@link VersionQualifier} object or null + */ + public static VersionQualifier getQualifier(String segment) { + Matcher m = sCountryCodePattern.matcher(segment); + if (m.matches()) { + String v = m.group(1); + + int code = -1; + try { + code = Integer.parseInt(v); + } catch (NumberFormatException e) { + // looks like the string we extracted wasn't a valid number. + return null; + } + + VersionQualifier qualifier = new VersionQualifier(); + qualifier.mVersion = code; + return qualifier; + } + + return null; + } + + /** + * Returns the folder name segment for the given value. This is equivalent to calling + * {@link #toString()} on a {@link VersionQualifier} object. + * @param version the value of the qualifier, as returned by {@link #getVersion()}. + */ + public static String getFolderSegment(int version) { + if (version != DEFAULT_VERSION) { + return String.format("v%1$d", version); //$NON-NLS-1$ + } + + return ""; //$NON-NLS-1$ + } + + public int getVersion() { + return mVersion; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String getShortName() { + return "Version"; + } + + @Override + public Image getIcon() { + return IconFactory.getInstance().getIcon("version"); //$NON-NLS-1$ + } + + @Override + public boolean isValid() { + return mVersion != DEFAULT_VERSION; + } + + @Override + public boolean checkAndSet(String value, FolderConfiguration config) { + VersionQualifier qualifier = getQualifier(value); + if (qualifier != null) { + config.setVersionQualifier(qualifier); + return true; + } + + return false; + } + + @Override + public boolean equals(Object qualifier) { + if (qualifier instanceof VersionQualifier) { + return mVersion == ((VersionQualifier)qualifier).mVersion; + } + + return false; + } + + @Override + public int hashCode() { + return mVersion; + } + + /** + * Returns the string used to represent this qualifier in the folder name. + */ + @Override + public String getFolderSegment(IAndroidTarget target) { + AndroidVersion version = target.getVersion(); + if (version.getApiLevel() >= 3) { + return getFolderSegment(mVersion); + } + + return ""; //$NON-NLS-1$ + } + + @Override + public String getStringValue() { + if (mVersion != DEFAULT_VERSION) { + return String.format("v%1$d", mVersion); + } + + return ""; //$NON-NLS-1$ + } +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java b/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java index c93f2a2f3..7601648ad 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java @@ -34,7 +34,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.files.IFileWrapper import com.android.ide.eclipse.adt.internal.resources.manager.files.IFolderWrapper; import com.android.ide.eclipse.mock.FileMock; import com.android.ide.eclipse.mock.FolderMock; -import com.android.sdklib.SdkConstants; +import com.android.sdklib.IAndroidTarget; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -221,7 +221,7 @@ public class ConfigMatchTest extends TestCase { FileMock[] memberList) throws Exception { // figure out the folder name based on the configuration - String folderName = config.getFolderName(ResourceFolderType.LAYOUT); + String folderName = config.getFolderName(ResourceFolderType.LAYOUT, (IAndroidTarget)null); // create the folder mock FolderMock folder = new FolderMock(folderName, memberList); From 4e7bb1b603df36d5c97db4f2d7c5e0aee3540708 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 11 Aug 2009 20:23:10 -0700 Subject: [PATCH 44/87] Properly update the new path of the AVD during an 'android avd move' BUG: 2048358 --- .../sdklib/src/com/android/sdklib/internal/avd/AvdManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java index 23f87e510..954da1715 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java @@ -911,7 +911,7 @@ public final class AvdManager { replaceAvd(avdInfo, info); // update the ini file - createAvdIniFile(avdInfo); + createAvdIniFile(info); } if (newName != null) { From b8d30c1a3cc55c9c7ead3bf49701eaba0621745b Mon Sep 17 00:00:00 2001 From: Gaurav Mathur Date: Tue, 11 Aug 2009 17:52:01 -0700 Subject: [PATCH 45/87] Checking in frame-work for new Open source site modified: index.jd modified: index.jd --- pdk/docs/community/index.jd | 6 + pdk/docs/guide/audio.jd | 1 + pdk/docs/guide/bluetooth.jd | 1 + pdk/docs/guide/bluetooth/bluetooth_process.jd | 3 +- pdk/docs/guide/bring_up.jd | 3 +- pdk/docs/guide/build_cookbook.jd | 3 +- pdk/docs/guide/build_new_device.jd | 1 + pdk/docs/guide/build_system.jd | 3 +- pdk/docs/guide/camera.jd | 1 + pdk/docs/guide/customization.jd | 3 +- pdk/docs/guide/dalvik.jd | 1 + pdk/docs/guide/debugging_gdb.jd | 3 +- pdk/docs/guide/debugging_native.jd | 1 + pdk/docs/guide/display_drivers.jd | 1 + pdk/docs/guide/getting_source_code.jd | 2 + pdk/docs/guide/gps.jd | 1 + pdk/docs/guide/group__memory.jd | 2 + pdk/docs/guide/group__networking.jd | 2 + pdk/docs/guide/index.jd | 1 + pdk/docs/guide/instrumentation_framework.jd | 2 + pdk/docs/guide/instrumentation_testing.jd | 1 + pdk/docs/guide/intro_source_code.jd | 2 + pdk/docs/guide/keymaps_keyboard_input.jd | 3 +- pdk/docs/guide/lights.jd | 1 + pdk/docs/guide/power_management.jd | 1 + pdk/docs/guide/release_keys.jd | 2 + pdk/docs/guide/sensors.jd | 1 + pdk/docs/guide/source_setup_guide.jd | 2 + pdk/docs/guide/stk.jd | 1 + pdk/docs/guide/system_requirements.jd | 3 +- pdk/docs/guide/tcpdump.jd | 3 +- pdk/docs/guide/telephony.jd | 1 + pdk/docs/guide/wifi.jd | 1 + pdk/docs/index.jd | 133 ++++++++++++++++++ pdk/docs/licenses/index.jd | 47 +++++++ pdk/docs/licenses/licenses_toc.cs | 21 +++ pdk/docs/releases/index.jd | 7 + pdk/docs/releases/releases_toc.cs | 22 +++ 38 files changed, 284 insertions(+), 9 deletions(-) create mode 100644 pdk/docs/community/index.jd create mode 100644 pdk/docs/index.jd create mode 100644 pdk/docs/licenses/index.jd create mode 100644 pdk/docs/licenses/licenses_toc.cs create mode 100644 pdk/docs/releases/index.jd create mode 100644 pdk/docs/releases/releases_toc.cs diff --git a/pdk/docs/community/index.jd b/pdk/docs/community/index.jd new file mode 100644 index 000000000..bc04eee7d --- /dev/null +++ b/pdk/docs/community/index.jd @@ -0,0 +1,6 @@ +home=true +@jd:body + +

+ Some community information here +

diff --git a/pdk/docs/guide/audio.jd b/pdk/docs/guide/audio.jd index 14e80bb45..66c05f744 100755 --- a/pdk/docs/guide/audio.jd +++ b/pdk/docs/guide/audio.jd @@ -1,5 +1,6 @@ page.title=Audio pdk.version=1.0 +doc.type=guide @jd:body
diff --git a/pdk/docs/guide/bluetooth.jd b/pdk/docs/guide/bluetooth.jd index e514ef0eb..bcf88dbec 100755 --- a/pdk/docs/guide/bluetooth.jd +++ b/pdk/docs/guide/bluetooth.jd @@ -1,5 +1,6 @@ page.title=Bluetooth pdk.version=1.0 +doc.type=guide @jd:body
diff --git a/pdk/docs/guide/bluetooth/bluetooth_process.jd b/pdk/docs/guide/bluetooth/bluetooth_process.jd index 86e9c935d..ea46f231e 100755 --- a/pdk/docs/guide/bluetooth/bluetooth_process.jd +++ b/pdk/docs/guide/bluetooth/bluetooth_process.jd @@ -1,6 +1,7 @@ page.title=Bluetooth Process Diagram pdk.version=1.0 +doc.type=guide @jd:body

The diagram below offers a process-oriented architectural overview of Android's Bluetooth stack. Click Bluetooth to return to the Bluetooth overview page.

- \ No newline at end of file + diff --git a/pdk/docs/guide/bring_up.jd b/pdk/docs/guide/bring_up.jd index 85d7b266c..a11fe00ff 100755 --- a/pdk/docs/guide/bring_up.jd +++ b/pdk/docs/guide/bring_up.jd @@ -1,5 +1,6 @@ page.title=Bring Up pdk.version=1.0 +doc.type=guide @jd:body

Once your code is built and you have verified that all necessary directories exist, power on and test your device with basic bring up, as described below. Bring up tests are typically designed to stress certain aspects of your system and allow you to characterize the device's behavior.

@@ -355,4 +356,4 @@ service akmd /sbin/akmd disabled user akmd group akmd - \ No newline at end of file + diff --git a/pdk/docs/guide/build_cookbook.jd b/pdk/docs/guide/build_cookbook.jd index fc34132c0..4bed9471b 100755 --- a/pdk/docs/guide/build_cookbook.jd +++ b/pdk/docs/guide/build_cookbook.jd @@ -1,5 +1,6 @@ page.title=Build Cookbook pdk.version=1.0 +doc.type=guide @jd:body
@@ -552,4 +553,4 @@ module. This can be fixed. If you ever need it to be, just ask.

- \ No newline at end of file + diff --git a/pdk/docs/guide/build_new_device.jd b/pdk/docs/guide/build_new_device.jd index dabdfb061..28e7c2eb3 100755 --- a/pdk/docs/guide/build_new_device.jd +++ b/pdk/docs/guide/build_new_device.jd @@ -1,5 +1,6 @@ page.title=Configuring a New Product pdk.version=1.0 +doc.type=guide @jd:body diff --git a/pdk/docs/guide/build_system.jd b/pdk/docs/guide/build_system.jd index d22998383..fd0ff8074 100755 --- a/pdk/docs/guide/build_system.jd +++ b/pdk/docs/guide/build_system.jd @@ -1,5 +1,6 @@ page.title=Android Build System pdk.version=1.0 +doc.type=guide @jd:body @@ -266,4 +267,4 @@ If you build one flavor and then want to build another, you should run make installclean between the two makes to guarantee that you don't pick up files installed by the previous flavor. make clean will also suffice, but it takes a lot longer. -

\ No newline at end of file +

diff --git a/pdk/docs/guide/camera.jd b/pdk/docs/guide/camera.jd index 281f76dd6..98636d8de 100755 --- a/pdk/docs/guide/camera.jd +++ b/pdk/docs/guide/camera.jd @@ -1,5 +1,6 @@ page.title=Camera pdk.version=1.0 +doc.type=guide @jd:body
diff --git a/pdk/docs/guide/customization.jd b/pdk/docs/guide/customization.jd index 9c39cd735..9c56681d1 100755 --- a/pdk/docs/guide/customization.jd +++ b/pdk/docs/guide/customization.jd @@ -1,5 +1,6 @@ page.title=Customization pdk.version=1.0 +doc.type=guide @jd:body
@@ -317,4 +318,4 @@ include $(LOCAL_PATH)/client/Android.mk

Animations

Android supports configurable animations for window and view transitions. System-level animations are defined in XML in global resource files located in //android/framework/base/core/res/res/anim/.

- \ No newline at end of file + diff --git a/pdk/docs/guide/dalvik.jd b/pdk/docs/guide/dalvik.jd index 948496a98..6fa37da9b 100755 --- a/pdk/docs/guide/dalvik.jd +++ b/pdk/docs/guide/dalvik.jd @@ -1,5 +1,6 @@ page.title=Dalvik pdk.version=1.0 +doc.type=guide @jd:body
diff --git a/pdk/docs/guide/debugging_gdb.jd b/pdk/docs/guide/debugging_gdb.jd index 9717cf384..f2a2db5d4 100755 --- a/pdk/docs/guide/debugging_gdb.jd +++ b/pdk/docs/guide/debugging_gdb.jd @@ -1,5 +1,6 @@ page.title=Debugging with GDB pdk.version=1.0 +doc.type=guide @jd:body
@@ -142,4 +143,4 @@ Execute the line shown in the debug output, substituting 5039 for the proper

Otherwise you need to determine the path of the crashing binary and follow the steps as mentioned above (for example, gdbclient hoser :5039 if - the hoser command has failed).

\ No newline at end of file + the hoser command has failed).

diff --git a/pdk/docs/guide/debugging_native.jd b/pdk/docs/guide/debugging_native.jd index 6705766a8..0f8b39731 100755 --- a/pdk/docs/guide/debugging_native.jd +++ b/pdk/docs/guide/debugging_native.jd @@ -1,5 +1,6 @@ page.title=Debugging Native Code pdk.version=1.0 +doc.type=guide @jd:body diff --git a/pdk/docs/guide/display_drivers.jd b/pdk/docs/guide/display_drivers.jd index ac41c55ce..1eddd155b 100755 --- a/pdk/docs/guide/display_drivers.jd +++ b/pdk/docs/guide/display_drivers.jd @@ -1,5 +1,6 @@ page.title=Display Drivers pdk.version=1.0 +doc.type=guide @jd:body diff --git a/pdk/docs/guide/getting_source_code.jd b/pdk/docs/guide/getting_source_code.jd index 19a7069ab..e7352743b 100755 --- a/pdk/docs/guide/getting_source_code.jd +++ b/pdk/docs/guide/getting_source_code.jd @@ -1,4 +1,6 @@ page.title=Getting Source Code +pdk.version=1.0 +doc.type=guide @jd:body diff --git a/pdk/docs/guide/gps.jd b/pdk/docs/guide/gps.jd index f2ce11c16..2acad6d7d 100755 --- a/pdk/docs/guide/gps.jd +++ b/pdk/docs/guide/gps.jd @@ -1,5 +1,6 @@ page.title=GPS pdk.version=1.0 +doc.type=guide @jd:body
diff --git a/pdk/docs/guide/group__memory.jd b/pdk/docs/guide/group__memory.jd index 87f19d5f9..0423515ae 100755 --- a/pdk/docs/guide/group__memory.jd +++ b/pdk/docs/guide/group__memory.jd @@ -1,4 +1,6 @@ page.title=Providing Heap Memory +pdk.version=1.0 +doc.type=guide @jd:body