OSDN Git Service

Merge change 20890 into donut
authorAndroid (Google) Code Review <android-gerrit@google.com>
Wed, 12 Aug 2009 04:34:57 +0000 (21:34 -0700)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Wed, 12 Aug 2009 04:34:57 +0000 (21:34 -0700)
* changes:
  Checking in frame-work for new Open source site

88 files changed:
build/sdk.atree
build/tools/make_windows_sdk.sh
cmds/monkey/README.NETWORK.txt
cmds/monkey/src/com/android/commands/monkey/MonkeyEvent.java
cmds/monkey/src/com/android/commands/monkey/MonkeyNoopEvent.java [new file with mode: 0644]
cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetwork.java
host/windows/.gitignore
host/windows/prebuilt/usb/AdbWinApi.dll
host/windows/prebuilt/usb/AdbWinUsbApi.dll [new file with mode: 0755]
host/windows/prebuilt/usb/Android.mk
samples/ApiDemos/AndroidManifest.xml
samples/ApiDemos/res/drawable-hdpi/logo240dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-hdpi/npatch240dpi.9.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-hdpi/reslogo240dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-hdpi/smlnpatch240dpi.9.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-hdpi/stylogo240dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-ldpi/logo120dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-ldpi/npatch120dpi.9.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-ldpi/reslogo120dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-ldpi/smlnpatch120dpi.9.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-ldpi/stylogo120dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-nodpi/logonodpi120.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-nodpi/logonodpi160.png [new file with mode: 0644]
samples/ApiDemos/res/drawable-nodpi/logonodpi240.png [new file with mode: 0644]
samples/ApiDemos/res/drawable/logo160dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable/npatch160dpi.9.png [new file with mode: 0644]
samples/ApiDemos/res/drawable/reslogo160dpi.png [new file with mode: 0644]
samples/ApiDemos/res/drawable/smlnpatch160dpi.9.png [new file with mode: 0644]
samples/ApiDemos/res/drawable/stylogo160dpi.png [new file with mode: 0644]
samples/ApiDemos/res/layout/density_image_views.xml [new file with mode: 0644]
samples/ApiDemos/res/layout/density_styled_image_views.xml [new file with mode: 0644]
samples/ApiDemos/res/values-large-long/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-large-notlong/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-large/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-long/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-normal-long/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-normal-notlong/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-normal/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-notlong/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-small-long/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-small-notlong/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values-small/strings.xml [new file with mode: 0644]
samples/ApiDemos/res/values/strings.xml
samples/ApiDemos/res/values/styles.xml
samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java
samples/ApiDemos/src/com/example/android/apis/graphics/DensityActivity.java [new file with mode: 0644]
testrunner/test_defs.xml
tools/eclipse/features/com.android.ide.eclipse.adt/feature.xml
tools/eclipse/features/com.android.ide.eclipse.ddms/feature.xml
tools/eclipse/features/com.android.ide.eclipse.tests/feature.xml
tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutCreatorDialog.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/KeyboardStateQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/LanguageQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NavigationMethodQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/RegionQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenDimensionQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenOrientationQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenRatioQualifier.java [new file with mode: 0644]
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenSizeQualifier.java [new file with mode: 0644]
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TextInputMethodQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/TouchScreenQualifier.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/VersionQualifier.java [new file with mode: 0644]
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
tools/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF
tools/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF
tools/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/resources/manager/ConfigMatchTest.java
tools/eclipse/sites/external/site.xml
tools/eclipse/sites/internal/site.xml
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd
tools/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml
tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java
tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java
tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java
tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png [new file with mode: 0755]
tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java

index 9136e5e..40a2876 100644 (file)
@@ -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
index 2a6433a..68e6c80 100755 (executable)
@@ -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}
 
@@ -195,9 +202,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"
index f3f69d4..1a1ad9c 100644 (file)
@@ -73,6 +73,20 @@ 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.
+
+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
index d926be8..2783dde 100644 (file)
@@ -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 (file)
index 0000000..ea92735
--- /dev/null
@@ -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;
+    }
+}
index de784d0..63e226c 100644 (file)
  */
 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;
@@ -31,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;
 
 /**
@@ -42,7 +49,7 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
     private static final String TAG = "MonkeyStub";
 
     private interface MonkeyCommand {
-        MonkeyEvent translateCommand(List<String> command);
+        MonkeyEvent translateCommand(List<String> command, CommandQueue queue);
     }
 
     /**
@@ -51,7 +58,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
     private static class FlipCommand implements MonkeyCommand {
         // flip open
         // flip closed
-        public MonkeyEvent translateCommand(List<String> command) {
+        public MonkeyEvent translateCommand(List<String> command,
+                                            CommandQueue queue) {
             if (command.size() > 1) {
                 String direction = command.get(1);
                 if ("open".equals(direction)) {
@@ -72,7 +80,8 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
         // touch down 120 120
         // touch move 140 140
         // touch up 140 140
-        public MonkeyEvent translateCommand(List<String> command) {
+        public MonkeyEvent translateCommand(List<String> command,
+                                            CommandQueue queue) {
             if (command.size() == 4) {
                 String actionName = command.get(1);
                 int x = 0;
@@ -115,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<String> command) {
+        public MonkeyEvent translateCommand(List<String> command,
+                                            CommandQueue queue) {
             if (command.size() == 3) {
                 int dx = 0;
                 int dy = 0;
@@ -142,29 +152,14 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
         // key [down|up] [keycode]
         // key down 82
         // key up 82
-        public MonkeyEvent translateCommand(List<String> command) {
+        public MonkeyEvent translateCommand(List<String> 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;
@@ -184,11 +179,38 @@ 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<String> command) {
+        public MonkeyEvent translateCommand(List<String> command,
+                                            CommandQueue queue) {
             if (command.size() == 2) {
                 int sleep = -1;
                 String sleepStr = command.get(1);
@@ -203,6 +225,93 @@ public class MonkeySourceNetwork implements MonkeyEventSource {
         }
     }
 
+    /**
+     * Command to wake the device up
+     */
+    private static class WakeCommand implements MonkeyCommand {
+        // wake
+        public MonkeyEvent translateCommand(List<String> 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<String> 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<String> 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.
+     *
+     * @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<String, MonkeyCommand> COMMAND_MAP = new HashMap<String, MonkeyCommand>();
 
@@ -213,6 +322,9 @@ 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());
+        COMMAND_MAP.put("tap", new TapCommand());
+        COMMAND_MAP.put("press", new PressCommand());
     }
 
     // QUIT command
@@ -222,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<MonkeyEvent> queuedEvents = new LinkedList<MonkeyEvent>();
+
+        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;
@@ -246,6 +391,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);
@@ -305,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;
         }
@@ -326,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.");
index dc7a154..434a0fa 100755 (executable)
@@ -1,9 +1,12 @@
 *.sln\r
 *.vcproj*\r
+*.aps\r
 usb/api.*\r
 usb/Debug\r
 usb/Release\r
 usb/api/obj*\r
 usb/api/*.log\r
 usb/adb_winapi_test/obj*\r
-usb/adb_winapi_test/*.log
\ No newline at end of file
+usb/adb_winapi_test/*.log\r
+usb/winusb/obj*\r
+usb/winusb/*.log
\ No newline at end of file
index 1fcfaa9..b5586eb 100755 (executable)
Binary files a/host/windows/prebuilt/usb/AdbWinApi.dll and b/host/windows/prebuilt/usb/AdbWinApi.dll differ
diff --git a/host/windows/prebuilt/usb/AdbWinUsbApi.dll b/host/windows/prebuilt/usb/AdbWinUsbApi.dll
new file mode 100755 (executable)
index 0000000..0c9e00b
Binary files /dev/null and b/host/windows/prebuilt/usb/AdbWinUsbApi.dll differ
index 1806101..9cf4e61 100644 (file)
@@ -6,7 +6,8 @@ LOCAL_PREBUILT_LIBS := \
        AdbWinApi.a
 
 LOCAL_PREBUILT_EXECUTABLES := \
-       AdbWinApi.dll
+       AdbWinApi.dll  \
+       AdbWinUsbApi.dll
        
 .PHONY : kill-adb
        
index fb34afa..032f5c2 100644 (file)
             </intent-filter>
         </activity-alias>
 
+        <activity android:name=".graphics.DensityActivity" android:label="Graphics/Density">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <!-- ************************************* -->
         <!--             MEDIA SAMPLES             -->
         <!-- ************************************* -->
diff --git a/samples/ApiDemos/res/drawable-hdpi/logo240dpi.png b/samples/ApiDemos/res/drawable-hdpi/logo240dpi.png
new file mode 100644 (file)
index 0000000..4d717a8
Binary files /dev/null and b/samples/ApiDemos/res/drawable-hdpi/logo240dpi.png differ
diff --git a/samples/ApiDemos/res/drawable-hdpi/npatch240dpi.9.png b/samples/ApiDemos/res/drawable-hdpi/npatch240dpi.9.png
new file mode 100644 (file)
index 0000000..a362b0f
Binary files /dev/null and b/samples/ApiDemos/res/drawable-hdpi/npatch240dpi.9.png differ
diff --git a/samples/ApiDemos/res/drawable-hdpi/reslogo240dpi.png b/samples/ApiDemos/res/drawable-hdpi/reslogo240dpi.png
new file mode 100644 (file)
index 0000000..4d717a8
Binary files /dev/null and b/samples/ApiDemos/res/drawable-hdpi/reslogo240dpi.png differ
diff --git a/samples/ApiDemos/res/drawable-hdpi/smlnpatch240dpi.9.png b/samples/ApiDemos/res/drawable-hdpi/smlnpatch240dpi.9.png
new file mode 100644 (file)
index 0000000..84bdcb0
Binary files /dev/null and b/samples/ApiDemos/res/drawable-hdpi/smlnpatch240dpi.9.png differ
diff --git a/samples/ApiDemos/res/drawable-hdpi/stylogo240dpi.png b/samples/ApiDemos/res/drawable-hdpi/stylogo240dpi.png
new file mode 100644 (file)
index 0000000..4d717a8
Binary files /dev/null and b/samples/ApiDemos/res/drawable-hdpi/stylogo240dpi.png differ
diff --git a/samples/ApiDemos/res/drawable-ldpi/logo120dpi.png b/samples/ApiDemos/res/drawable-ldpi/logo120dpi.png
new file mode 100644 (file)
index 0000000..46bbd5b
Binary files /dev/null and b/samples/ApiDemos/res/drawable-ldpi/logo120dpi.png differ
diff --git a/samples/ApiDemos/res/drawable-ldpi/npatch120dpi.9.png b/samples/ApiDemos/res/drawable-ldpi/npatch120dpi.9.png
new file mode 100644 (file)
index 0000000..0d8115b
Binary files /dev/null and b/samples/ApiDemos/res/drawable-ldpi/npatch120dpi.9.png differ
diff --git a/samples/ApiDemos/res/drawable-ldpi/reslogo120dpi.png b/samples/ApiDemos/res/drawable-ldpi/reslogo120dpi.png
new file mode 100644 (file)
index 0000000..46bbd5b
Binary files /dev/null and b/samples/ApiDemos/res/drawable-ldpi/reslogo120dpi.png differ
diff --git a/samples/ApiDemos/res/drawable-ldpi/smlnpatch120dpi.9.png b/samples/ApiDemos/res/drawable-ldpi/smlnpatch120dpi.9.png
new file mode 100644 (file)
index 0000000..de8d607
Binary files /dev/null and b/samples/ApiDemos/res/drawable-ldpi/smlnpatch120dpi.9.png differ
diff --git a/samples/ApiDemos/res/drawable-ldpi/stylogo120dpi.png b/samples/ApiDemos/res/drawable-ldpi/stylogo120dpi.png
new file mode 100644 (file)
index 0000000..46bbd5b
Binary files /dev/null and b/samples/ApiDemos/res/drawable-ldpi/stylogo120dpi.png differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/logonodpi120.png b/samples/ApiDemos/res/drawable-nodpi/logonodpi120.png
new file mode 100644 (file)
index 0000000..46bbd5b
Binary files /dev/null and b/samples/ApiDemos/res/drawable-nodpi/logonodpi120.png differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/logonodpi160.png b/samples/ApiDemos/res/drawable-nodpi/logonodpi160.png
new file mode 100644 (file)
index 0000000..c23b2ce
Binary files /dev/null and b/samples/ApiDemos/res/drawable-nodpi/logonodpi160.png differ
diff --git a/samples/ApiDemos/res/drawable-nodpi/logonodpi240.png b/samples/ApiDemos/res/drawable-nodpi/logonodpi240.png
new file mode 100644 (file)
index 0000000..4d717a8
Binary files /dev/null and b/samples/ApiDemos/res/drawable-nodpi/logonodpi240.png differ
diff --git a/samples/ApiDemos/res/drawable/logo160dpi.png b/samples/ApiDemos/res/drawable/logo160dpi.png
new file mode 100644 (file)
index 0000000..c23b2ce
Binary files /dev/null and b/samples/ApiDemos/res/drawable/logo160dpi.png differ
diff --git a/samples/ApiDemos/res/drawable/npatch160dpi.9.png b/samples/ApiDemos/res/drawable/npatch160dpi.9.png
new file mode 100644 (file)
index 0000000..44d89a9
Binary files /dev/null and b/samples/ApiDemos/res/drawable/npatch160dpi.9.png differ
diff --git a/samples/ApiDemos/res/drawable/reslogo160dpi.png b/samples/ApiDemos/res/drawable/reslogo160dpi.png
new file mode 100644 (file)
index 0000000..c23b2ce
Binary files /dev/null and b/samples/ApiDemos/res/drawable/reslogo160dpi.png differ
diff --git a/samples/ApiDemos/res/drawable/smlnpatch160dpi.9.png b/samples/ApiDemos/res/drawable/smlnpatch160dpi.9.png
new file mode 100644 (file)
index 0000000..76c4ae8
Binary files /dev/null and b/samples/ApiDemos/res/drawable/smlnpatch160dpi.9.png differ
diff --git a/samples/ApiDemos/res/drawable/stylogo160dpi.png b/samples/ApiDemos/res/drawable/stylogo160dpi.png
new file mode 100644 (file)
index 0000000..c23b2ce
Binary files /dev/null and b/samples/ApiDemos/res/drawable/stylogo160dpi.png differ
diff --git a/samples/ApiDemos/res/layout/density_image_views.xml b/samples/ApiDemos/res/layout/density_image_views.xml
new file mode 100644 (file)
index 0000000..6a91497
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/reslogo120dpi" />
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/reslogo160dpi" />
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/reslogo240dpi" />
+
+</LinearLayout>
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 (file)
index 0000000..86c63bf
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <ImageView style="@style/ImageView120dpi" />
+    <ImageView style="@style/ImageView160dpi" />
+    <ImageView style="@style/ImageView240dpi" />
+
+</LinearLayout>
diff --git a/samples/ApiDemos/res/values-large-long/strings.xml b/samples/ApiDemos/res/values-large-long/strings.xml
new file mode 100644 (file)
index 0000000..7c392d8
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Large Long</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-large-notlong/strings.xml b/samples/ApiDemos/res/values-large-notlong/strings.xml
new file mode 100644 (file)
index 0000000..40328ea
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Large NotLong</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-large/strings.xml b/samples/ApiDemos/res/values-large/strings.xml
new file mode 100644 (file)
index 0000000..c9fb189
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Large</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-long/strings.xml b/samples/ApiDemos/res/values-long/strings.xml
new file mode 100644 (file)
index 0000000..5d15048
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Long</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-normal-long/strings.xml b/samples/ApiDemos/res/values-normal-long/strings.xml
new file mode 100644 (file)
index 0000000..01a0487
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Normal Long</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-normal-notlong/strings.xml b/samples/ApiDemos/res/values-normal-notlong/strings.xml
new file mode 100644 (file)
index 0000000..bea3f8d
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Normal NotLong</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-normal/strings.xml b/samples/ApiDemos/res/values-normal/strings.xml
new file mode 100644 (file)
index 0000000..16ff46f
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Normal</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-notlong/strings.xml b/samples/ApiDemos/res/values-notlong/strings.xml
new file mode 100644 (file)
index 0000000..a3e78db
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: NotLong</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-small-long/strings.xml b/samples/ApiDemos/res/values-small-long/strings.xml
new file mode 100644 (file)
index 0000000..8526f61
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Small Long</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-small-notlong/strings.xml b/samples/ApiDemos/res/values-small-notlong/strings.xml
new file mode 100644 (file)
index 0000000..bc8a676
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Small NotLong</string>
+</resources>
diff --git a/samples/ApiDemos/res/values-small/strings.xml b/samples/ApiDemos/res/values-small/strings.xml
new file mode 100644 (file)
index 0000000..56db730
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="density_title">Density: Small</string>
+</resources>
index 29bbcec..c2c9829 100644 (file)
 
     <string name="hide_me">Hide Me!</string>
 
+    <string name="density_title">Density: Unknown Screen</string>
+    
     <!-- ============================ -->
     <!--  media examples strings  -->
     <!-- ============================ -->
index 40e934e..3c9c681 100644 (file)
         <item name="android:textStyle">normal</item>
     </style>
 
+    <style name="ImageView120dpi">
+        <item name="android:src">@drawable/stylogo120dpi</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="ImageView160dpi">
+        <item name="android:src">@drawable/stylogo160dpi</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="ImageView240dpi">
+        <item name="android:src">@drawable/stylogo240dpi</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
 </resources>
index ceff150..e3cf976 100644 (file)
@@ -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;
     }
 
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 (file)
index 0000000..10c42a7
--- /dev/null
@@ -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);
+        }
+    }
+}
index 9d03558..44db464 100644 (file)
@@ -72,7 +72,7 @@ See test_defs.xsd for more information.
 <test name="launchperf"
     build_path="development/apps/launchperf"
     package="com.android.launchperf"
-    class="com.android.launchperf.SimpleActivityLaunchPerformance"
+    runner=".SimpleActivityLaunchPerformance"
     coverage_target="framework" />
 
 <!--  targeted framework tests -->
index 74002cb..6dd3ee7 100644 (file)
@@ -2,7 +2,7 @@
 <feature
       id="com.android.ide.eclipse.adt"
       label="Android Development Tools"
-      version="0.9.2.qualifier"
+      version="0.9.3.qualifier"
       provider-name="The Android Open Source Project"
       plugin="com.android.ide.eclipse.adt">
 
index 884669b..e67f960 100644 (file)
@@ -2,7 +2,7 @@
 <feature
       id="com.android.ide.eclipse.ddms"
       label="Android DDMS"
-      version="0.9.2.qualifier"
+      version="0.9.3.qualifier"
       provider-name="The Android Open Source Project">
 
    <description>
index d2778fe..cc34045 100644 (file)
@@ -2,7 +2,7 @@
 <feature
       id="com.android.ide.eclipse.tests"
       label="ADT Tests"
-      version="0.9.2.qualifier"
+      version="0.9.3.qualifier"
       provider-name="The Android Open Source Project">
 
    <copyright>
index f9c1e9c..32c939b 100644 (file)
@@ -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,
index c940b9f..225d5bd 100644 (file)
@@ -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<UiElementNode> 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}.
      * <p/>This uses the <code>wrap_content</code> mode for both <code>layout_width</code> 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<String, Map<String, IResourceValue>> 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<String> languages = new HashSet<String>();
         ArrayList<String> themes = new ArrayList<String>();
-        
+
         // get the themes, and languages from the Framework.
         if (frameworkProject != null) {
             // get the configured resources for the framework
             Map<String, Map<String, IResourceValue>> frameworResources =
                 getConfiguredFrameworkResources();
-            
+
             if (frameworResources != null) {
                 // get the styles.
                 Map<String, IResourceValue> 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<String, IResourceValue> 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<String, IResourceValue> 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/<name>. 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<String, Map<String, IResourceValue>> 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<String, Map<String, IResourceValue>> projectResources,
             Map<String, Map<String, IResourceValue>> 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);
index 5cd527c..a55f1d0 100644 (file)
@@ -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));
     }
 }
index a3fdb7d..072b1b8 100644 (file)
@@ -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();
index c624035..f570bac 100644 (file)
@@ -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,
      * <code>null</code> 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$
     }
 }
index aea146b..23a6440 100644 (file)
 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,20 +31,23 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
     public final static String QUALIFIER_SEP = "-"; //$NON-NLS-1$
 
     private final ResourceQualifier[] mQualifiers = new ResourceQualifier[INDEX_COUNT];
-    
-    private final static int INDEX_COUNTRY_CODE = 0;
-    private final static int INDEX_NETWORK_CODE = 1;
-    private final static int INDEX_LANGUAGE = 2;
-    private final static int INDEX_REGION = 3;
-    private final static int INDEX_SCREEN_ORIENTATION = 4;
-    private final static int INDEX_PIXEL_DENSITY = 5;
-    private final static int INDEX_TOUCH_TYPE = 6;
-    private final static int INDEX_KEYBOARD_STATE = 7;
-    private final static int INDEX_TEXT_INPUT_METHOD = 8;
-    private final static int INDEX_NAVIGATION_METHOD = 9;
-    private final static int INDEX_SCREEN_DIMENSION = 10;
-    private final static int INDEX_COUNT = 11;
-    
+
+    private final static int INDEX_COUNTRY_CODE       = 0;
+    private final static int INDEX_NETWORK_CODE       = 1;
+    private final static int INDEX_LANGUAGE           = 2;
+    private final static int INDEX_REGION             = 3;
+    private final static int INDEX_SCREEN_SIZE        = 4;
+    private final static int INDEX_SCREEN_RATIO       = 5;
+    private final static int INDEX_SCREEN_ORIENTATION = 6;
+    private final static int INDEX_PIXEL_DENSITY      = 7;
+    private final static int INDEX_TOUCH_TYPE         = 8;
+    private final static int INDEX_KEYBOARD_STATE     = 9;
+    private final static int INDEX_TEXT_INPUT_METHOD  = 10;
+    private final static int INDEX_NAVIGATION_METHOD  = 11;
+    private final static int INDEX_SCREEN_DIMENSION   = 12;
+    private final static int INDEX_VERSION            = 13;
+    private final static int INDEX_COUNT              = 14;
+
     /**
      * Sets the config from the qualifiers of a given <var>config</var>.
      * @param config
@@ -62,7 +69,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
             }
         }
     }
-    
+
     /**
      * Returns the first invalid qualifier, or <code>null<code> if they are all valid (or if none
      * exists).
@@ -73,11 +80,11 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                 return mQualifiers[i];
             }
         }
-        
+
         // all allocated qualifiers are valid, we return null.
         return null;
     }
-    
+
     /**
      * Returns whether the Region qualifier is valid. Region qualifier can only be present if a
      * Language qualifier is present as well.
@@ -90,7 +97,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
 
         return true;
     }
-    
+
     /**
      * Adds a qualifier to the {@link FolderConfiguration}
      * @param qualifier the {@link ResourceQualifier} to add.
@@ -104,6 +111,10 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
             mQualifiers[INDEX_LANGUAGE] = qualifier;
         } else if (qualifier instanceof RegionQualifier) {
             mQualifiers[INDEX_REGION] = qualifier;
+        } else if (qualifier instanceof ScreenSizeQualifier) {
+            mQualifiers[INDEX_SCREEN_SIZE] = qualifier;
+        } else if (qualifier instanceof ScreenRatioQualifier) {
+            mQualifiers[INDEX_SCREEN_RATIO] = qualifier;
         } else if (qualifier instanceof ScreenOrientationQualifier) {
             mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier;
         } else if (qualifier instanceof PixelDensityQualifier) {
@@ -118,9 +129,11 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
             mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier;
         } else if (qualifier instanceof ScreenDimensionQualifier) {
             mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier;
+        } else if (qualifier instanceof VersionQualifier) {
+            mQualifiers[INDEX_VERSION] = qualifier;
         }
     }
-    
+
     /**
      * Removes a given qualifier from the {@link FolderConfiguration}.
      * @param qualifier the {@link ResourceQualifier} to remove.
@@ -133,7 +146,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
             }
         }
     }
-    
+
     public void setCountryCodeQualifier(CountryCodeQualifier qualifier) {
         mQualifiers[INDEX_COUNTRY_CODE] = qualifier;
     }
@@ -166,6 +179,22 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
         return (RegionQualifier)mQualifiers[INDEX_REGION];
     }
 
+    public void setScreenSizeQualifier(ScreenSizeQualifier qualifier) {
+        mQualifiers[INDEX_SCREEN_SIZE] = qualifier;
+    }
+
+    public ScreenSizeQualifier getScreenSizeQualifier() {
+        return (ScreenSizeQualifier)mQualifiers[INDEX_SCREEN_SIZE];
+    }
+
+    public void setScreenRatioQualifier(ScreenRatioQualifier qualifier) {
+        mQualifiers[INDEX_SCREEN_RATIO] = qualifier;
+    }
+
+    public ScreenRatioQualifier getScreenRatioQualifier() {
+        return (ScreenRatioQualifier)mQualifiers[INDEX_SCREEN_RATIO];
+    }
+
     public void setScreenOrientationQualifier(ScreenOrientationQualifier qualifier) {
         mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier;
     }
@@ -205,7 +234,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
     public TextInputMethodQualifier getTextInputMethodQualifier() {
         return (TextInputMethodQualifier)mQualifiers[INDEX_TEXT_INPUT_METHOD];
     }
-    
+
     public void setNavigationMethodQualifier(NavigationMethodQualifier qualifier) {
         mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier;
     }
@@ -213,7 +242,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
     public NavigationMethodQualifier getNavigationMethodQualifier() {
         return (NavigationMethodQualifier)mQualifiers[INDEX_NAVIGATION_METHOD];
     }
-    
+
     public void setScreenDimensionQualifier(ScreenDimensionQualifier qualifier) {
         mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier;
     }
@@ -222,6 +251,14 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
         return (ScreenDimensionQualifier)mQualifiers[INDEX_SCREEN_DIMENSION];
     }
 
+    public void setVersionQualifier(VersionQualifier qualifier) {
+        mQualifiers[INDEX_VERSION] = qualifier;
+    }
+
+    public VersionQualifier getVersionQualifier() {
+        return (VersionQualifier)mQualifiers[INDEX_VERSION];
+    }
+
     /**
      * Returns whether an object is equals to the receiver.
      */
@@ -230,7 +267,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
         if (obj == this) {
             return true;
         }
-        
+
         if (obj instanceof FolderConfiguration) {
             FolderConfiguration fc = (FolderConfiguration)obj;
             for (int i = 0 ; i < INDEX_COUNT ; i++) {
@@ -247,7 +284,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
 
             return true;
         }
-        
+
         return false;
     }
 
@@ -255,7 +292,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
     public int hashCode() {
         return toString().hashCode();
     }
-    
+
     /**
      * Returns whether the Configuration has only default values.
      */
@@ -265,52 +302,49 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                 return false;
             }
         }
-        
+
         return true;
     }
-    
+
     /**
      * Returns the name of a folder with the configuration.
      */
-    public String getFolderName(ResourceFolderType folder) {
+    public String getFolderName(ResourceFolderType folder, IAndroidTarget target) {
         StringBuilder result = new StringBuilder(folder.getName());
-        
+
         for (ResourceQualifier qualifier : mQualifiers) {
             if (qualifier != null) {
                 result.append(QUALIFIER_SEP);
-                result.append(qualifier.toString());
+                result.append(qualifier.getFolderSegment(target));
             }
         }
-        
+
         return result.toString();
     }
-    
+
     /**
-     * Returns a string valid for usage in a folder name, or <code>null</code> if the configuration
-     * is default.
+     * Returns the name of a folder with the configuration.
      */
-    @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());
+    public String getFolderName(ResourceFolderType folder, IProject project) {
+        IAndroidTarget target = null;
+        if (project != null) {
+            Sdk currentSdk = Sdk.getCurrent();
+            if (currentSdk != null) {
+                target = currentSdk.getTarget(project);
             }
         }
-        
-        if (result != null) {
-            return result.toString();
-        } else {
-            return null;
-        }
+
+        return getFolderName(folder, target);
     }
-    
+
+    /**
+     * Returns {@link #toDisplayString()}.
+     */
+    @Override
+    public String toString() {
+        return toDisplayString();
+    }
+
     /**
      * Returns a string valid for display purpose.
      */
@@ -322,7 +356,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
         StringBuilder result = null;
         int index = 0;
         ResourceQualifier qualifier = null;
-        
+
         // pre- language/region qualifiers
         while (index < INDEX_LANGUAGE) {
             qualifier = mQualifiers[index++];
@@ -333,10 +367,10 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                     result.append(", "); //$NON-NLS-1$
                 }
                 result.append(qualifier.getStringValue());
-                
+
             }
         }
-        
+
         // process the language/region qualifier in a custom way, if there are both non null.
         if (mQualifiers[INDEX_LANGUAGE] != null && mQualifiers[INDEX_REGION] != null) {
             String language = mQualifiers[INDEX_LANGUAGE].getStringValue();
@@ -348,10 +382,10 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                 result.append(", "); //$NON-NLS-1$
             }
             result.append(String.format("%s_%s", language, region)); //$NON-NLS-1$
-            
+
             index += 2;
         }
-        
+
         // post language/region qualifiers.
         while (index < INDEX_COUNT) {
             qualifier = mQualifiers[index++];
@@ -362,7 +396,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                     result.append(", "); //$NON-NLS-1$
                 }
                 result.append(qualifier.getStringValue());
-                
+
             }
         }
 
@@ -377,12 +411,12 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
             }
             return -1;
         }
-        
+
         // now we compare the qualifiers
         for (int i = 0 ; i < INDEX_COUNT; i++) {
             ResourceQualifier qualifier1 = mQualifiers[i];
             ResourceQualifier qualifier2 = folderConfig.mQualifiers[i];
-            
+
             if (qualifier1 == null) {
                 if (qualifier2 == null) {
                     continue;
@@ -394,16 +428,16 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                     return 1;
                 } else {
                     int result = qualifier1.compareTo(qualifier2);
-                    
+
                     if (result == 0) {
                         continue;
                     }
-                    
+
                     return result;
                 }
             }
         }
-        
+
         // if we arrive here, all the qualifier matches
         return 0;
     }
@@ -421,11 +455,11 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
      */
     public int match(FolderConfiguration referenceConfig) {
         int matchCount = 0;
-        
+
         for (int i = 0 ; i < INDEX_COUNT ; i++) {
             ResourceQualifier testQualifier = mQualifiers[i];
             ResourceQualifier referenceQualifier = referenceConfig.mQualifiers[i];
-            
+
             // we only care if testQualifier is non null. If it's null, it's a match but
             // without increasing the matchCount.
             if (testQualifier != null) {
@@ -434,7 +468,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                 } else if (testQualifier.equals(referenceQualifier) == false) {
                     return -1;
                 }
-                
+
                 // the qualifier match, increment the count
                 matchCount++;
             }
@@ -454,10 +488,10 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                 return i;
             }
         }
-        
+
         return -1;
     }
-    
+
     /**
      * Create default qualifiers.
      */
@@ -466,6 +500,8 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
         mQualifiers[INDEX_NETWORK_CODE] = new NetworkCodeQualifier();
         mQualifiers[INDEX_LANGUAGE] = new LanguageQualifier();
         mQualifiers[INDEX_REGION] = new RegionQualifier();
+        mQualifiers[INDEX_SCREEN_SIZE] = new ScreenSizeQualifier();
+        mQualifiers[INDEX_SCREEN_RATIO] = new ScreenRatioQualifier();
         mQualifiers[INDEX_SCREEN_ORIENTATION] = new ScreenOrientationQualifier();
         mQualifiers[INDEX_PIXEL_DENSITY] = new PixelDensityQualifier();
         mQualifiers[INDEX_TOUCH_TYPE] = new TouchScreenQualifier();
@@ -473,6 +509,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
         mQualifiers[INDEX_TEXT_INPUT_METHOD] = new TextInputMethodQualifier();
         mQualifiers[INDEX_NAVIGATION_METHOD] = new NavigationMethodQualifier();
         mQualifiers[INDEX_SCREEN_DIMENSION] = new ScreenDimensionQualifier();
+        mQualifiers[INDEX_VERSION] = new VersionQualifier();
     }
 
     /**
@@ -485,7 +522,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                 count++;
             }
         }
-        
+
         ResourceQualifier[] array = new ResourceQualifier[count];
         int index = 0;
         for (int i = 0 ; i < INDEX_COUNT ; i++) {
@@ -493,7 +530,7 @@ public final class FolderConfiguration implements Comparable<FolderConfiguration
                 array[index++] = mQualifiers[i];
             }
         }
-        
+
         return array;
     }
 }
index 2acebcc..1aa9286 100644 (file)
@@ -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 keyboard state.
  */
 public final class KeyboardStateQualifier extends ResourceQualifier {
-    
+
     public static final String NAME = "Keyboard State";
 
     private KeyboardState mValue = null;
@@ -37,15 +38,15 @@ public final class KeyboardStateQualifier extends ResourceQualifier {
     public static enum KeyboardState {
         EXPOSED("keysexposed", "Exposed"), //$NON-NLS-1$
         HIDDEN("keyshidden", "Hidden"); //$NON-NLS-1$
-        
+
         private String mValue;
         private String mDisplayValue;
-        
+
         private KeyboardState(String value, String displayValue) {
             mValue = value;
             mDisplayValue = displayValue;
         }
-        
+
         /**
          * Returns the enum for matching the provided qualifier value.
          * @param value The qualifier value.
@@ -57,25 +58,25 @@ public final class KeyboardStateQualifier extends ResourceQualifier {
                     return orient;
                 }
             }
-            
+
             return null;
         }
 
         public String getValue() {
             return mValue;
         }
-        
+
         public String getDisplayValue() {
             return mDisplayValue;
         }
-        
+
         public static int getIndex(KeyboardState value) {
             int i = 0;
             for (KeyboardState input : values()) {
                 if (value == input) {
                     return i;
                 }
-                
+
                 i++;
             }
 
@@ -105,27 +106,27 @@ public final class KeyboardStateQualifier extends ResourceQualifier {
     public KeyboardState getValue() {
         return mValue;
     }
-    
+
     @Override
     public String getName() {
         return NAME;
     }
-    
+
     @Override
     public String getShortName() {
         return "Keyboard";
     }
-    
+
     @Override
     public Image getIcon() {
         return IconFactory.getInstance().getIcon("keyboard"); //$NON-NLS-1$
     }
-    
+
     @Override
     public boolean isValid() {
         return mValue != null;
     }
-    
+
     @Override
     public boolean checkAndSet(String value, FolderConfiguration config) {
         KeyboardState orientation = KeyboardState.getEnum(value);
@@ -135,10 +136,10 @@ public final class KeyboardStateQualifier extends ResourceQualifier {
             config.setKeyboardStateQualifier(qualifier);
             return true;
         }
-        
+
         return false;
     }
-    
+
     @Override
     public boolean equals(Object qualifier) {
         if (qualifier instanceof KeyboardStateQualifier) {
@@ -153,19 +154,19 @@ public final class KeyboardStateQualifier 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$
     }
 
@@ -174,7 +175,7 @@ public final class KeyboardStateQualifier extends ResourceQualifier {
         if (mValue != null) {
             return mValue.getDisplayValue();
         }
-        
+
         return ""; //$NON-NLS-1$
     }
 }
index 799fc06..a098e44 100644 (file)
@@ -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,9 +30,9 @@ public final class LanguageQualifier extends ResourceQualifier {
     private final static Pattern sLanguagePattern = Pattern.compile("^[a-z]{2}$"); //$NON-NLS-1$
 
     public static final String NAME = "Language";
-    
+
     private String mValue;
-    
+
     /**
      * Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
      * <code>null</code> 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$
     }
 }
index 6315014..0a5c968 100644 (file)
@@ -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$
     }
 }
index c7f7fad..32bd667 100644 (file)
@@ -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,
      * <code>null</code> 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$
     }
 }
index a2c690b..f75e9cb 100644 (file)
@@ -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;
-    
+    private Density mValue = Density.MEDIUM;
+
     /**
-     * Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
-     * <code>null</code> is returned.
-     * @param folderSegment the folder segment from which to create a qualifier.
-     * @return a new {@link CountryCodeQualifier} object or <code>null</code>
+     * Screen Orientation enum.
      */
-    public static PixelDensityQualifier getQualifier(String folderSegment) {
-        Matcher m = sPixelDensityPattern.matcher(folderSegment);
-        if (m.matches()) {
-            String v = m.group(1);
-
-            int density = -1;
-            try {
-                density = Integer.parseInt(v);
-            } catch (NumberFormatException e) {
-                // looks like the string we extracted wasn't a valid number.
-                return null;
+    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;
         }
-        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$
+        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;
         }
-        
-        return ""; //$NON-NLS-1$
+
+        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;
+        }
+    }
+
+    public PixelDensityQualifier() {
+        // pass
+    }
+
+    public PixelDensityQualifier(Density value) {
+        mValue = value;
     }
 
-    public int getValue() {
+    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$
     }
 }
index be54f2b..3f3abcc 100644 (file)
@@ -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,
      * <code>null</code> 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$
     }
 }
index b644e8f..bfee8d2 100644 (file)
@@ -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;
  * <p/>The resource qualifier classes are designed as immutable.
  */
 public abstract class ResourceQualifier implements Comparable<ResourceQualifier> {
-    
+
     /**
      * 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<ResourceQualifier>
      * @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.
      * <p/>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<ResourceQualifier>
      */
     @Override
     public abstract boolean equals(Object object);
-    
+
     /**
      * Returns a hash code value for the object.
      * <p/>This is declared as abstract to force children classes to implement it.
index e756644..ff8a930 100644 (file)
@@ -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 <code>DEFAULT_SIZE</code> */
     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$
     }
 }
index 6e1b829..85d0c03 100644 (file)
@@ -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/ScreenRatioQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ScreenRatioQualifier.java
new file mode 100644 (file)
index 0000000..dda49fc
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * 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;
+
+public class ScreenRatioQualifier extends ResourceQualifier {
+
+    public static final String NAME = "Screen Ratio";
+
+    private ScreenRatio mValue = null;
+
+    /**
+     * Screen Orientation enum.
+     */
+    public static enum ScreenRatio {
+        NOTLONG("notlong", "Not Long"), //$NON-NLS-1$
+        LONG("long", "Long"); //$NON-NLS-1$
+
+        private String mValue;
+        private String mDisplayValue;
+
+        private ScreenRatio(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 ScreenRatio getEnum(String value) {
+            for (ScreenRatio 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(ScreenRatio orientation) {
+            int i = 0;
+            for (ScreenRatio orient : values()) {
+                if (orient == orientation) {
+                    return i;
+                }
+
+                i++;
+            }
+
+            return -1;
+        }
+
+        public static ScreenRatio getByIndex(int index) {
+            int i = 0;
+            for (ScreenRatio orient : values()) {
+                if (i == index) {
+                    return orient;
+                }
+                i++;
+            }
+
+            return null;
+        }
+    }
+
+    public ScreenRatioQualifier() {
+    }
+
+    public ScreenRatioQualifier(ScreenRatio value) {
+        mValue = value;
+    }
+
+    public ScreenRatio getValue() {
+        return mValue;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getShortName() {
+        return "Ratio";
+    }
+
+    @Override
+    public Image getIcon() {
+        return IconFactory.getInstance().getIcon("ratio"); //$NON-NLS-1$
+    }
+
+    @Override
+    public boolean isValid() {
+        return mValue != null;
+    }
+
+    @Override
+    public boolean checkAndSet(String value, FolderConfiguration config) {
+        ScreenRatio size = ScreenRatio.getEnum(value);
+        if (size != null) {
+            ScreenRatioQualifier qualifier = new ScreenRatioQualifier(size);
+            config.setScreenRatioQualifier(qualifier);
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object qualifier) {
+        if (qualifier instanceof ScreenRatioQualifier) {
+            return mValue == ((ScreenRatioQualifier)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/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 (file)
index 0000000..6132193
--- /dev/null
@@ -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$
+    }
+}
index add45cc..6289147 100644 (file)
@@ -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$
     }
 }
index 1ed7d95..758c87f 100644 (file)
@@ -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/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 (file)
index 0000000..c82e7e9
--- /dev/null
@@ -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,
+     * <code>null</code> is returned.
+     * @param segment the folder segment from which to create a qualifier.
+     * @return a new {@link VersionQualifier} object or <code>null</code>
+     */
+    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$
+    }
+}
index d6cfeae..f2e883d 100644 (file)
@@ -378,6 +378,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.
      * <p/>The Map key are name to be used in the apk filename, while the values are comma separated
      * config values. The config value can be passed directly to aapt through the -c option.
index 7378d41..34a2391 100644 (file)
@@ -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;
  * <ul>
  * <li>Use {@link #setConfiguration(String)} or {@link #setConfiguration(FolderConfiguration)}.
  * <li>Retrieve the configuration using {@link #getConfiguration(FolderConfiguration)}.
- * </ul> 
+ * </ul>
  */
 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<Class<? extends ResourceQualifier>, QualifierEditBase> mUiMap =
         new HashMap<Class<? extends ResourceQualifier>, 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 <code>run()</code> 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 <code>null<code> 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();
+
+            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();
                 }
-            });
-            mText.addFocusListener(new FocusAdapter() {
-                @Override
-                public void focusLost(FocusEvent e) {
-                    onTextChange();
+                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()));
         }
index 4edfb77..bd4e7a3 100644 (file)
@@ -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*/);
         }
     }
 
@@ -1139,6 +1131,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.
      */
index ebdec6d..9f021ae 100644 (file)
@@ -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
index 61bfbe4..a8ec3da 100644 (file)
@@ -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,
index dd82bed..7601648 100644 (file)
@@ -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.IAndroidTarget;
 
 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, (IAndroidTarget)null);
+
         // 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;
     }
-    
-
-    
 }
index 7dee775..a00d1a4 100644 (file)
@@ -3,10 +3,10 @@
    <description url="https://dl-ssl.google.com/android/eclipse/">
       Update Site for Android Development Toolkit
    </description>
-   <feature url="features/com.android.ide.eclipse.adt_0.9.2.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.2.qualifier">
+   <feature url="features/com.android.ide.eclipse.adt_0.9.3.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.3.qualifier">
       <category name="developer"/>
    </feature>
-   <feature url="features/com.android.ide.eclipse.ddms_0.9.2.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.2.qualifier">
+   <feature url="features/com.android.ide.eclipse.ddms_0.9.3.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.3.qualifier">
       <category name="developer"/>
    </feature>
    <category-def name="developer" label="Developer Tools">
index 4fd5333..e19c119 100644 (file)
@@ -3,13 +3,13 @@
    <description url="https://android.corp.google.com/adt/">
       Update Site for Android Development Toolkit
    </description>
-   <feature url="features/com.android.ide.eclipse.adt_0.9.2.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.2.qualifier">
+   <feature url="features/com.android.ide.eclipse.adt_0.9.3.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.3.qualifier">
       <category name="developer"/>
    </feature>
-   <feature url="features/com.android.ide.eclipse.ddms_0.9.2.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.2.qualifier">
+   <feature url="features/com.android.ide.eclipse.ddms_0.9.3.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.3.qualifier">
       <category name="developer"/>
    </feature>
-   <feature url="features/com.android.ide.eclipse.tests_0.9.2.qualifier.jar" id="com.android.ide.eclipse.tests" version="0.9.2.qualifier">
+   <feature url="features/com.android.ide.eclipse.tests_0.9.3.qualifier.jar" id="com.android.ide.eclipse.tests" version="0.9.3.qualifier">
       <category name="test"/>
    </feature>
    <category-def name="developer" label="Application Developer Tools">
index 293d66a..d72cd94 100644 (file)
@@ -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.
+         * <p/>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() {
index 8d19c0f..5afe73c 100755 (executable)
@@ -42,16 +42,20 @@ import java.util.Properties;
  */\r
 public abstract class Package implements IDescription {\r
 \r
-    private static final String PROP_REVISION    = "Pkg.Revision";     //$NON-NLS-1$\r
-    private static final String PROP_LICENSE     = "Pkg.License";      //$NON-NLS-1$\r
-    private static final String PROP_DESC        = "Pkg.Desc";         //$NON-NLS-1$\r
-    private static final String PROP_DESC_URL    = "Pkg.DescUrl";      //$NON-NLS-1$\r
-    private static final String PROP_SOURCE_URL  = "Pkg.SourceUrl";    //$NON-NLS-1$\r
-    private static final String PROP_USER_SOURCE = "Pkg.UserSrc";      //$NON-NLS-1$\r
+    private static final String PROP_REVISION     = "Pkg.Revision";     //$NON-NLS-1$\r
+    private static final String PROP_LICENSE      = "Pkg.License";      //$NON-NLS-1$\r
+    private static final String PROP_DESC         = "Pkg.Desc";         //$NON-NLS-1$\r
+    private static final String PROP_DESC_URL     = "Pkg.DescUrl";      //$NON-NLS-1$\r
+    private static final String PROP_RELEASE_NOTE = "Pkg.RelNote";      //$NON-NLS-1$\r
+    private static final String PROP_RELEASE_URL  = "Pkg.RelNoteUrl";   //$NON-NLS-1$\r
+    private static final String PROP_SOURCE_URL   = "Pkg.SourceUrl";    //$NON-NLS-1$\r
+    private static final String PROP_USER_SOURCE  = "Pkg.UserSrc";      //$NON-NLS-1$\r
     private final int mRevision;\r
     private final String mLicense;\r
     private final String mDescription;\r
     private final String mDescUrl;\r
+    private final String mReleaseNote;\r
+    private final String mReleaseUrl;\r
     private final Archive[] mArchives;\r
     private final RepoSource mSource;\r
 \r
@@ -80,6 +84,8 @@ public abstract class Package implements IDescription {
         mRevision    = XmlParserUtils.getXmlInt   (packageNode, SdkRepository.NODE_REVISION, 0);\r
         mDescription = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_DESCRIPTION);\r
         mDescUrl     = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_DESC_URL);\r
+        mReleaseNote = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_RELEASE_NOTE);\r
+        mReleaseUrl  = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_RELEASE_URL);\r
 \r
         mLicense  = parseLicense(packageNode, licenses);\r
         mArchives = parseArchives(XmlParserUtils.getFirstChild(\r
@@ -104,10 +110,19 @@ public abstract class Package implements IDescription {
             Arch archiveArch,\r
             String archiveOsPath) {\r
 \r
+        if (description == null) {\r
+            description = "";\r
+        }\r
+        if (descUrl == null) {\r
+            descUrl = "";\r
+        }\r
+\r
         mRevision = Integer.parseInt(getProperty(props, PROP_REVISION, Integer.toString(revision)));\r
-        mLicense     = getProperty(props, PROP_LICENSE,  license);\r
-        mDescription = getProperty(props, PROP_DESC,     description);\r
-        mDescUrl     = getProperty(props, PROP_DESC_URL, descUrl);\r
+        mLicense     = getProperty(props, PROP_LICENSE,      license);\r
+        mDescription = getProperty(props, PROP_DESC,         description);\r
+        mDescUrl     = getProperty(props, PROP_DESC_URL,     descUrl);\r
+        mReleaseNote = getProperty(props, PROP_RELEASE_NOTE, "");\r
+        mReleaseUrl  = getProperty(props, PROP_RELEASE_URL,  "");\r
 \r
         // If source is null and we can find a source URL in the properties, generate\r
         // a dummy source just to store the URL. This allows us to easily remember where\r
@@ -145,16 +160,24 @@ public abstract class Package implements IDescription {
      */\r
     void saveProperties(Properties props) {\r
         props.setProperty(PROP_REVISION, Integer.toString(mRevision));\r
-        if (mLicense != null) {\r
+        if (mLicense != null && mLicense.length() > 0) {\r
             props.setProperty(PROP_LICENSE, mLicense);\r
         }\r
-        if (mDescription != null) {\r
+\r
+        if (mDescription != null && mDescription.length() > 0) {\r
             props.setProperty(PROP_DESC, mDescription);\r
         }\r
-        if (mDescUrl != null) {\r
+        if (mDescUrl != null && mDescUrl.length() > 0) {\r
             props.setProperty(PROP_DESC_URL, mDescUrl);\r
         }\r
 \r
+        if (mReleaseNote != null && mReleaseNote.length() > 0) {\r
+            props.setProperty(PROP_RELEASE_NOTE, mReleaseNote);\r
+        }\r
+        if (mReleaseUrl != null && mReleaseUrl.length() > 0) {\r
+            props.setProperty(PROP_RELEASE_URL, mReleaseUrl);\r
+        }\r
+\r
         if (mSource != null) {\r
             props.setProperty(PROP_SOURCE_URL,  mSource.getUrl());\r
             props.setProperty(PROP_USER_SOURCE, Boolean.toString(mSource.isUserSource()));\r
@@ -259,6 +282,22 @@ public abstract class Package implements IDescription {
     }\r
 \r
     /**\r
+     * Returns the optional release note for all packages (platform, add-on, tool, doc) or\r
+     * for a lib. Can be empty but not null.\r
+     */\r
+    public String getReleaseNote() {\r
+        return mReleaseNote;\r
+    }\r
+\r
+    /**\r
+     * Returns the optional release note URL for all packages (platform, add-on, tool, doc).\r
+     * Can be empty but not null.\r
+     */\r
+    public String getReleaseNoteUrl() {\r
+        return mReleaseUrl;\r
+    }\r
+\r
+    /**\r
      * Returns the archives defined in this package.\r
      * Can be an empty array but not null.\r
      */\r
@@ -291,7 +330,31 @@ public abstract class Package implements IDescription {
      * Can be empty but not null.\r
      */\r
     public String getLongDescription() {\r
-        return String.format("%1$s\nRevision %2$d", getDescription(), getRevision());\r
+        StringBuilder sb = new StringBuilder();\r
+\r
+        String s = getDescription();\r
+        if (s != null) {\r
+            sb.append(s);\r
+        }\r
+\r
+        sb.append(String.format("\nRevision %1$d", getRevision()));\r
+\r
+        s = getDescUrl();\r
+        if (s != null && s.length() > 0) {\r
+            sb.append(String.format("\n\nMore information at %1$s", s));\r
+        }\r
+\r
+        s = getReleaseNote();\r
+        if (s != null && s.length() > 0) {\r
+            sb.append("\n\nRelease note:\n").append(s);\r
+        }\r
+\r
+        s = getReleaseNoteUrl();\r
+        if (s != null && s.length() > 0) {\r
+            sb.append("\nRelease note URL: ").append(s);\r
+        }\r
+\r
+        return sb.toString();\r
     }\r
 \r
     /**\r
index 88d18db..4b12d59 100755 (executable)
@@ -53,11 +53,15 @@ public class SdkRepository {
     /** The optional uses-license for all packages (platform, add-on, tool, doc) or for a lib. */\r
     public static final String NODE_USES_LICENSE = "uses-license";              //$NON-NLS-1$\r
     /** The revision, an int > 0, for all packages (platform, add-on, tool, doc). */\r
-    public static final String NODE_REVISION    = "revision";                   //$NON-NLS-1$\r
+    public static final String NODE_REVISION     = "revision";                  //$NON-NLS-1$\r
     /** The optional description for all packages (platform, add-on, tool, doc) or for a lib. */\r
-    public static final String NODE_DESCRIPTION = "description";                //$NON-NLS-1$\r
+    public static final String NODE_DESCRIPTION  = "description";               //$NON-NLS-1$\r
     /** The optional description URL for all packages (platform, add-on, tool, doc). */\r
-    public static final String NODE_DESC_URL    = "desc-url";                   //$NON-NLS-1$\r
+    public static final String NODE_DESC_URL     = "desc-url";                  //$NON-NLS-1$\r
+    /** The optional release note for all packages (platform, add-on, tool, doc). */\r
+    public static final String NODE_RELEASE_NOTE = "release-note";              //$NON-NLS-1$\r
+    /** The optional release note URL for all packages (platform, add-on, tool, doc). */\r
+    public static final String NODE_RELEASE_URL  = "release-url";               //$NON-NLS-1$\r
 \r
     /** The version, a string, for platform packages. */\r
     public static final String NODE_VERSION   = "version";                      //$NON-NLS-1$\r
index a697c83..7ca0892 100755 (executable)
                             <xsd:element name="description"  type="xsd:string"      minOccurs="0" />
                             <!-- The optional description URL of this package -->
                             <xsd:element name="desc-url"     type="xsd:token"       minOccurs="0" />
+                            <!-- The optional release note for this package. -->
+                            <xsd:element name="release-note" type="xsd:string"      minOccurs="0" />
+                            <!-- The optional release note URL of this package -->
+                            <xsd:element name="release-url"  type="xsd:token"       minOccurs="0" />
                             <!-- A list of file archives for this package. -->
                             <xsd:element name="archives"     type="sdk:archivesType" />
                         </xsd:all>
                             <xsd:element name="description"  type="xsd:string"      minOccurs="0" />
                             <!-- The optional description URL of this package -->
                             <xsd:element name="desc-url"     type="xsd:token"       minOccurs="0" />
+                            <!-- The optional release note for this package. -->
+                            <xsd:element name="release-note" type="xsd:string"      minOccurs="0" />
+                            <!-- The optional release note URL of this package -->
+                            <xsd:element name="release-url"  type="xsd:token"       minOccurs="0" />
                             <!-- A list of file archives for this package. -->
                             <xsd:element name="archives"     type="sdk:archivesType" />
 
                             <xsd:element name="description"  type="xsd:string"      minOccurs="0" />
                             <!-- The optional description URL of this package -->
                             <xsd:element name="desc-url"     type="xsd:token"       minOccurs="0" />
+                            <!-- The optional release note for this package. -->
+                            <xsd:element name="release-note" type="xsd:string"      minOccurs="0" />
+                            <!-- The optional release note URL of this package -->
+                            <xsd:element name="release-url"  type="xsd:token"       minOccurs="0" />
                             <!-- A list of file archives for this package. -->
                             <xsd:element name="archives"     type="sdk:archivesType" />
                         </xsd:all>
                             <xsd:element name="description"  type="xsd:string"      minOccurs="0" />
                             <!-- The optional description URL of this package -->
                             <xsd:element name="desc-url"     type="xsd:token"       minOccurs="0" />
+                            <!-- The optional release note for this package. -->
+                            <xsd:element name="release-note" type="xsd:string"      minOccurs="0" />
+                            <!-- The optional release note URL of this package -->
+                            <xsd:element name="release-url"  type="xsd:token"       minOccurs="0" />
                             <!-- A list of file archives for this package. -->
                             <xsd:element name="archives"     type="sdk:archivesType" />
                         </xsd:all>
                             <xsd:element name="description"  type="xsd:string"      minOccurs="0" />
                             <!-- The optional description URL of this package -->
                             <xsd:element name="desc-url"     type="xsd:token"       minOccurs="0" />
+                            <!-- The optional release note for this package. -->
+                            <xsd:element name="release-note" type="xsd:string"      minOccurs="0" />
+                            <!-- The optional release note URL of this package -->
+                            <xsd:element name="release-url"  type="xsd:token"       minOccurs="0" />
                             <!-- A list of file archives for this package. -->
                             <xsd:element name="archives"     type="sdk:archivesType" />
                         </xsd:all>
index 7340549..20b8571 100755 (executable)
         <sdk:uses-license ref="license1" />\r
         <sdk:description>Some optional description</sdk:description>\r
         <sdk:desc-url>http://www.example.com/platform1.html</sdk:desc-url>\r
+        <sdk:release-note>This is an optional release note\r
+            for this package. It's a free multi-line text.\r
+        </sdk:release-note>\r
+        <sdk:release-url>http://some/url/for/the/release/note.html</sdk:release-url>\r
         <!-- The archives node is mandatory and it cannot be empty. -->\r
         <sdk:archives>\r
             <sdk:archive os="any">\r
index a7c1a83..6ea040c 100755 (executable)
@@ -62,7 +62,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
     private Group mDescriptionContainer;\r
     private Button mAddSiteButton;\r
     private Button mDeleteSiteButton;\r
-    private Label mPlaceholder3;\r
     private Button mRefreshButton;\r
     private Button mInstallSelectedButton;\r
     private Label mDescriptionLabel;\r
@@ -118,16 +117,6 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
         spacer.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));\r
         gd.heightHint = 0;\r
 \r
-        mUpdateOnlyCheckBox = new Button(composite, SWT.CHECK);\r
-        mUpdateOnlyCheckBox.setText("Display updates only");\r
-        mUpdateOnlyCheckBox.setSelection(mUpdaterData.getSettingsController().getShowUpdateOnly());\r
-        mUpdateOnlyCheckBox.addSelectionListener(new SelectionAdapter() {\r
-            @Override\r
-            public void widgetSelected(SelectionEvent arg0) {\r
-                onShowUpdateOnly(); //$hide$\r
-            }\r
-        });\r
-\r
         mDescriptionContainer = new Group(parent, SWT.NONE);\r
         mDescriptionContainer.setLayout(new GridLayout(1, false));\r
         mDescriptionContainer.setText("Description");\r
@@ -155,8 +144,16 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
         });\r
         mDeleteSiteButton.setText("Delete Site...");\r
 \r
-        mPlaceholder3 = new Label(parent, SWT.NONE);\r
-        mPlaceholder3.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));\r
+        mUpdateOnlyCheckBox = new Button(parent, SWT.CHECK);\r
+        mUpdateOnlyCheckBox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));\r
+        mUpdateOnlyCheckBox.setText("Display updates only");\r
+        mUpdateOnlyCheckBox.setSelection(mUpdaterData.getSettingsController().getShowUpdateOnly());\r
+        mUpdateOnlyCheckBox.addSelectionListener(new SelectionAdapter() {\r
+            @Override\r
+            public void widgetSelected(SelectionEvent arg0) {\r
+                onShowUpdateOnly(); //$hide$\r
+            }\r
+        });\r
 \r
         mRefreshButton = new Button(parent, SWT.NONE);\r
         mRefreshButton.addSelectionListener(new SelectionAdapter() {\r
index dbf46f5..de12666 100755 (executable)
@@ -43,6 +43,11 @@ public class RepoSourcesAdapter {
 \r
     private final UpdaterData mUpdaterData;\r
 \r
+    /**\r
+     * A dummy RepoSource entry returned for sources which had load errors.\r
+     * It displays a summary of the error as its short description or\r
+     * it displays the source's long description.\r
+     */\r
     public static class RepoSourceError implements IDescription {\r
 \r
         private final RepoSource mSource;\r
@@ -60,6 +65,33 @@ public class RepoSourcesAdapter {
         }\r
     }\r
 \r
+    /**\r
+     * A dummy RepoSource entry returned for sources with no packages.\r
+     * We need that to force the SWT tree to display an open/close triangle\r
+     * even for empty sources.\r
+     */\r
+    public static class RepoSourceEmpty implements IDescription {\r
+\r
+        private final RepoSource mSource;\r
+        private final boolean mEmptyBecauseOfUpdateOnly;\r
+\r
+        public RepoSourceEmpty(RepoSource source, boolean emptyBecauseOfUpdateOnly) {\r
+            mSource = source;\r
+            mEmptyBecauseOfUpdateOnly = emptyBecauseOfUpdateOnly;\r
+        }\r
+\r
+        public String getLongDescription() {\r
+            return mSource.getLongDescription();\r
+        }\r
+\r
+        public String getShortDescription() {\r
+            if (mEmptyBecauseOfUpdateOnly) {\r
+                return "Some packages were found but are not compatible updates.";\r
+            } else {\r
+                return "No packages found";\r
+            }\r
+        }\r
+    }\r
 \r
     public RepoSourcesAdapter(UpdaterData updaterData) {\r
         mUpdaterData = updaterData;\r
@@ -137,48 +169,76 @@ public class RepoSourcesAdapter {
                 return mUpdaterData.getSources().getSources();\r
 \r
             } else if (parentElement instanceof RepoSource) {\r
-                final RepoSource source = (RepoSource) parentElement;\r
-                Package[] packages = source.getPackages();\r
+                return getRepoSourceChildren((RepoSource) parentElement);\r
+\r
+            } else if (parentElement instanceof Package) {\r
+                return getPackageChildren((Package) parentElement);\r
+            }\r
+\r
+            return new Object[0];\r
+        }\r
 \r
-                if (packages == null && source.getFetchError() == null) {\r
-                    final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp();\r
+        /**\r
+         * Returns the list of packages for this repo source, eventually filtered to display\r
+         * only update packages. If the list is empty, returns a specific empty node. If there's\r
+         * an error, returns a specific error node.\r
+         */\r
+        private Object[] getRepoSourceChildren(final RepoSource source) {\r
+            Package[] packages = source.getPackages();\r
 \r
-                    mUpdaterData.getTaskFactory().start("Loading Source", new ITask() {\r
-                        public void run(ITaskMonitor monitor) {\r
-                            source.load(monitor, forceHttp);\r
-                        }\r
-                    });\r
+            if (packages == null && source.getFetchError() == null) {\r
+                final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp();\r
 \r
-                    packages = source.getPackages();\r
-                }\r
-                if (packages != null) {\r
-                    // filter out only the packages that are new/upgrade.\r
-                    if (mUpdaterData.getSettingsController().getShowUpdateOnly()) {\r
-                        return filteredPackages(packages);\r
+                mUpdaterData.getTaskFactory().start("Loading Source", new ITask() {\r
+                    public void run(ITaskMonitor monitor) {\r
+                        source.load(monitor, forceHttp);\r
                     }\r
-                    return packages;\r
-                } else if (source.getFetchError() != null) {\r
-                    // Return a dummy entry to display the fetch error\r
-                    return new Object[] { new RepoSourceError(source) };\r
-                }\r
+                });\r
 \r
-            } else if (parentElement instanceof Package) {\r
-                Archive[] archives = ((Package) parentElement).getArchives();\r
-                if (mUpdaterData.getSettingsController().getShowUpdateOnly()) {\r
-                    for (Archive archive : archives) {\r
-                        // if we only want the compatible archives, then we just take the first\r
-                        // one. it's unlikely there are 2 compatible archives for the same\r
-                        // package\r
-                        if (archive.isCompatible()) {\r
-                            return new Object[] { archive };\r
-                        }\r
+                packages = source.getPackages();\r
+            }\r
+\r
+            boolean wasEmptyBeforeFilter = (packages == null || packages.length == 0);\r
+\r
+            // filter out only the packages that are new/upgrade.\r
+            if (packages != null && mUpdaterData.getSettingsController().getShowUpdateOnly()) {\r
+                packages = filteredPackages(packages);\r
+            }\r
+            if (packages != null && packages.length == 0) {\r
+                packages = null;\r
+            }\r
+\r
+            if (packages != null && source.getFetchError() != null) {\r
+                // Return a dummy entry to display the fetch error\r
+                return new Object[] { new RepoSourceError(source) };\r
+            }\r
+\r
+            // Either return a non-null package list or create a new empty node\r
+            if (packages != null) {\r
+                return packages;\r
+            } else {\r
+                return new Object[] { new RepoSourceEmpty(source, !wasEmptyBeforeFilter) } ;\r
+            }\r
+        }\r
+\r
+        /**\r
+         * Returns the list of archives for the given package, eventually filtering it\r
+         * to only show the compatible archives.\r
+         */\r
+        private Object[] getPackageChildren(Package pkg) {\r
+            Archive[] archives = pkg.getArchives();\r
+            if (mUpdaterData.getSettingsController().getShowUpdateOnly()) {\r
+                for (Archive archive : archives) {\r
+                    // if we only want the compatible archives, then we just take the first\r
+                    // one. it's unlikely there are 2 compatible archives for the same\r
+                    // package\r
+                    if (archive.isCompatible()) {\r
+                        return new Object[] { archive };\r
                     }\r
                 }\r
-\r
-                return archives;\r
             }\r
 \r
-            return new Object[0];\r
+            return archives;\r
         }\r
 \r
         /**\r
@@ -213,7 +273,7 @@ public class RepoSourcesAdapter {
      * @param remotePackages the list of packages to filter.\r
      * @return a non null (but maybe empty) list of new or update packages.\r
      */\r
-    private Object[] filteredPackages(Package[] remotePackages) {\r
+    private Package[] filteredPackages(Package[] remotePackages) {\r
         // get the installed packages\r
         Package[] installedPackages = mUpdaterData.getInstalledPackage();\r
 \r
@@ -233,10 +293,10 @@ public class RepoSourcesAdapter {
                     if (info == UpdateInfo.UPDATE) {\r
                         filteredList.add(remotePkg);\r
                         newPkg = false;\r
-                        break; // there shouldn't be 2 revision of the same package\r
+                        break; // there shouldn't be 2 revisions of the same package\r
                     } else if (info != UpdateInfo.INCOMPATIBLE) {\r
                         newPkg = false;\r
-                        break; // there shouldn't be 2 revision of the same package\r
+                        break; // there shouldn't be 2 revisions of the same package\r
                     }\r
                 }\r
 \r
@@ -247,6 +307,6 @@ public class RepoSourcesAdapter {
             }\r
         }\r
 \r
-        return filteredList.toArray();\r
+        return filteredList.toArray(new Package[filteredList.size()]);\r
     }\r
 }\r
index bd39c5e..cbd846e 100755 (executable)
@@ -91,31 +91,34 @@ public class ImageFactory {
      */\r
     public Image getImageForObject(Object object) {\r
         if (object instanceof RepoSource) {\r
-            return getImageByName("source_icon16.png");\r
+            return getImageByName("source_icon16.png");                         //$NON-NLS-1$\r
 \r
         } else if (object instanceof RepoSourcesAdapter.RepoSourceError) {\r
-            return getImageByName("error_icon16.png");\r
+            return getImageByName("error_icon16.png");                          //$NON-NLS-1$\r
+\r
+        } else if (object instanceof RepoSourcesAdapter.RepoSourceEmpty) {\r
+            return getImageByName("nopkg_icon16.png");                          //$NON-NLS-1$\r
 \r
         } else if (object instanceof PlatformPackage) {\r
-            return getImageByName("android_icon_16.png");\r
+            return getImageByName("android_icon_16.png");                       //$NON-NLS-1$\r
 \r
         } else if (object instanceof AddonPackage) {\r
-            return getImageByName("addon_icon16.png");\r
+            return getImageByName("addon_icon16.png");                          //$NON-NLS-1$\r
 \r
         } else if (object instanceof ToolPackage) {\r
-            return getImageByName("tool_icon16.png");\r
+            return getImageByName("tool_icon16.png");                           //$NON-NLS-1$\r
 \r
         } else if (object instanceof DocPackage) {\r
-            return getImageByName("doc_icon16.png");\r
+            return getImageByName("doc_icon16.png");                            //$NON-NLS-1$\r
 \r
         } else if (object instanceof ExtraPackage) {\r
-            return getImageByName("extra_icon16.png");\r
+            return getImageByName("extra_icon16.png");                          //$NON-NLS-1$\r
 \r
         } else if (object instanceof Archive) {\r
             if (((Archive) object).isCompatible()) {\r
-                return getImageByName("archive_icon16.png");\r
+                return getImageByName("archive_icon16.png");                    //$NON-NLS-1$\r
             } else {\r
-                return getImageByName("incompat_icon16.png");\r
+                return getImageByName("incompat_icon16.png");                   //$NON-NLS-1$\r
             }\r
         }\r
         return null;\r
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 (executable)
index 0000000..147837f
Binary files /dev/null and b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/nopkg_icon16.png differ
index 96d1b65..ba1bb4c 100644 (file)
@@ -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.
+     * <p/>
+     * For now this only supports fixing the wrong value in image.sysdir.*
+     */
+    private void onRepair() {
         final AvdInfo avdInfo = getTableSelection();
 
         // get the current Display