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
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"
}
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}
# 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"
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
/**
* 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;
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);
}
--- /dev/null
+/*
+ * 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;
+ }
+}
*/
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;
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;
/**
private static final String TAG = "MonkeyStub";
private interface MonkeyCommand {
- MonkeyEvent translateCommand(List<String> command);
+ MonkeyEvent translateCommand(List<String> command, CommandQueue queue);
}
/**
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)) {
// 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;
// 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;
// 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;
}
/**
+ * 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);
}
}
+ /**
+ * 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>();
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
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;
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);
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;
}
// 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.");
*.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
AdbWinApi.a
LOCAL_PREBUILT_EXECUTABLES := \
- AdbWinApi.dll
+ AdbWinApi.dll \
+ AdbWinUsbApi.dll
.PHONY : kill-adb
</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 -->
<!-- ************************************* -->
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
<string name="hide_me">Hide Me!</string>
+ <string name="density_title">Density: Unknown Screen</string>
+
<!-- ============================ -->
<!-- media examples strings -->
<!-- ============================ -->
<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>
// 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;
}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
<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 -->
<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">
<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>
<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>
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,
* 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
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;
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;
*/
public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
implements ILayoutReloadListener {
-
+
private final static String THEME_SEPARATOR = "----------"; //$NON-NLS-1$
/** Reference to the layout editor */
private Combo mLanguage;
private Combo mRegion;
private Combo mOrientation;
- private Text mDensity;
+ private Combo mDensity;
private Combo mTouch;
private Combo mKeyboard;
private Combo mTextInput;
public void onTargetsLoaded() {
// because the SDK changed we must reset the configured framework resource.
mConfiguredFrameworkRes = null;
-
+
updateUIFromResources();
mThemeCombo.getParent().layout();
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();
}
});
@Override
public void widgetSelected(SelectionEvent e) {
onNavigationChange();
- }
+ }
});
Composite labelParent = new Composite(topParent, SWT.NONE);
mSize1.addSelectionListener(sl);
mSize2.addSelectionListener(sl);
-
+
ModifyListener sizeModifyListener = new ModifyListener() {
public void modifyText(ModifyEvent e) {
onSizeChange();
@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);
}
}
@Override
protected PaletteRoot getPaletteRoot() {
mPaletteRoot = PaletteFactory.createPaletteRoot(mPaletteRoot,
- mLayoutEditor.getTargetData());
+ mLayoutEditor.getTargetData());
return mPaletteRoot;
}
getCommandStack().markSaveLocation();
firePropertyChange(PROP_DIRTY);
}
-
+
@Override
protected void configurePaletteViewer() {
super.configurePaletteViewer();
// 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);
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);
public Object getObjectType() {
return template;
}
-
+
};
}
}
input.toString());
}
}
-
+
/* (non-javadoc)
* Sets the graphicalViewer for this EditorPart.
* @param viewer the graphical viewer
/**
* 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);
}
MenuManager menuManager = new MenuManager();
menuManager.setRemoveAllWhenShown(true);
menuManager.addMenuListener(new ActionMenuListener(viewer));
-
+
return menuManager;
}
}
}
}
-
+
if (selected.size() > 0) {
doCreateMenuAction(manager, mViewer, selected);
}
}
}
-
+
private void doCreateMenuAction(IMenuManager manager,
final GraphicalViewer viewer,
final ArrayList<UiElementNode> selected) {
// 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
});
manager.add(new Separator());
-
+
manager.add(new Action("Up", factory.getImageDescriptor("up")) { //$NON-NLS-2$
@Override
public void run() {
}
});
}
-
- }
+
+ }
/**
* Sets the UI for the edition of a new file.
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) {
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
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.
// 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.
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;
}
}
mNeedsXmlReload = true;
}
}
-
+
/**
* Actually performs the XML reload
* @see #onXmlModelChanged()
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;
}
}
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);
}
// 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.
*/
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) {
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)");
UiDocumentNode getModel() {
return mLayoutEditor.getUiRootNode();
}
-
+
@Override
void reloadPalette() {
PaletteFactory.createPaletteRoot(mPaletteRoot, mLayoutEditor.getTargetData());
}
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
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) {
// 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);
} else {
// update the configuration icons with the new edited config.
displayConfigError();
-
+
// enable the Create button
mCreateButton.setEnabled(true);
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);
}
int themeIndex = mThemeCombo.getSelectionIndex();
if (themeIndex != -1) {
String theme = mThemeCombo.getItem(themeIndex);
-
+
if (theme.equals(THEME_SEPARATOR)) {
mThemeCombo.select(0);
}
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
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);
// 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();
}
}
// 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());
}
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();
// sort them and add them to the combo
Collections.sort(themes);
-
+
for (String theme : themes) {
mThemeCombo.add(theme);
}
-
+
mPlatformThemeCount = themes.size();
themes.clear();
}
languages.addAll(frameworkLanguages);
}
}
-
+
// now get the themes and languages from the project.
ProjectResources project = null;
if (mEditedFile != null) {
// 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();
// 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.
if (mPlatformThemeCount > 0 && themes.size() > 0) {
mThemeCombo.add(THEME_SEPARATOR);
}
-
+
Collections.sort(themes);
-
+
for (String theme : themes) {
mThemeCombo.add(theme);
}
for (String language : languages) {
mLanguage.add(language);
}
-
+
mDisableUpdates = false;
// and update the Region UI based on the current language
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) {
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());
mDisableUpdates = false;
}
}
-
+
private Map<String, Map<String, IResourceValue>> getConfiguredFrameworkResources() {
if (mConfiguredFrameworkRes == null) {
ProjectResources frameworkRes = getFrameworkResources();
// get the framework resource values based on the current config
mConfiguredFrameworkRes = frameworkRes.getConfiguredResources(mCurrentConfig);
}
-
+
return mConfiguredFrameworkRes;
}
@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
// 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
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.
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();
}
return null;
}
-
+
/**
* Computes a layout by calling the correct computeLayout method of ILayoutBridge based on
* the implementation API level.
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);
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;
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);
}
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);
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));
}
}
// 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();
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;
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.
// 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.
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;
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);
}
if (mCode != DEFAULT_CODE) {
return String.format("MCC %1$d", mCode);
}
-
+
return ""; //$NON-NLS-1$
}
}
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;
/**
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
}
}
}
-
+
/**
* Returns the first invalid qualifier, or <code>null<code> if they are all valid (or if none
* exists).
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.
return true;
}
-
+
/**
* Adds a qualifier to the {@link FolderConfiguration}
* @param qualifier the {@link ResourceQualifier} to add.
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) {
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.
}
}
}
-
+
public void setCountryCodeQualifier(CountryCodeQualifier qualifier) {
mQualifiers[INDEX_COUNTRY_CODE] = qualifier;
}
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;
}
public TextInputMethodQualifier getTextInputMethodQualifier() {
return (TextInputMethodQualifier)mQualifiers[INDEX_TEXT_INPUT_METHOD];
}
-
+
public void setNavigationMethodQualifier(NavigationMethodQualifier qualifier) {
mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier;
}
public NavigationMethodQualifier getNavigationMethodQualifier() {
return (NavigationMethodQualifier)mQualifiers[INDEX_NAVIGATION_METHOD];
}
-
+
public void setScreenDimensionQualifier(ScreenDimensionQualifier qualifier) {
mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier;
}
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.
*/
if (obj == this) {
return true;
}
-
+
if (obj instanceof FolderConfiguration) {
FolderConfiguration fc = (FolderConfiguration)obj;
for (int i = 0 ; i < INDEX_COUNT ; i++) {
return true;
}
-
+
return false;
}
public int hashCode() {
return toString().hashCode();
}
-
+
/**
* Returns whether the Configuration has only default values.
*/
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.
*/
StringBuilder result = null;
int index = 0;
ResourceQualifier qualifier = null;
-
+
// pre- language/region qualifiers
while (index < INDEX_LANGUAGE) {
qualifier = mQualifiers[index++];
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();
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++];
result.append(", "); //$NON-NLS-1$
}
result.append(qualifier.getStringValue());
-
+
}
}
}
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;
return 1;
} else {
int result = qualifier1.compareTo(qualifier2);
-
+
if (result == 0) {
continue;
}
-
+
return result;
}
}
}
-
+
// if we arrive here, all the qualifier matches
return 0;
}
*/
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) {
} else if (testQualifier.equals(referenceQualifier) == false) {
return -1;
}
-
+
// the qualifier match, increment the count
matchCount++;
}
return i;
}
}
-
+
return -1;
}
-
+
/**
* Create default qualifiers.
*/
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();
mQualifiers[INDEX_TEXT_INPUT_METHOD] = new TextInputMethodQualifier();
mQualifiers[INDEX_NAVIGATION_METHOD] = new NavigationMethodQualifier();
mQualifiers[INDEX_SCREEN_DIMENSION] = new ScreenDimensionQualifier();
+ mQualifiers[INDEX_VERSION] = new VersionQualifier();
}
/**
count++;
}
}
-
+
ResourceQualifier[] array = new ResourceQualifier[count];
int index = 0;
for (int i = 0 ; i < INDEX_COUNT ; i++) {
array[index++] = mQualifiers[i];
}
}
-
+
return array;
}
}
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;
* Resource Qualifier for keyboard state.
*/
public final class KeyboardStateQualifier extends ResourceQualifier {
-
+
public static final String NAME = "Keyboard State";
private KeyboardState mValue = null;
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.
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++;
}
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);
config.setKeyboardStateQualifier(qualifier);
return true;
}
-
+
return false;
}
-
+
@Override
public boolean equals(Object qualifier) {
if (qualifier instanceof KeyboardStateQualifier) {
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$
}
if (mValue != null) {
return mValue.getDisplayValue();
}
-
+
return ""; //$NON-NLS-1$
}
}
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;
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.
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.
if (sLanguagePattern.matcher(segment).matches()) {
return segment;
}
-
+
return null;
}
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;
config.setLanguageQualifier(qualifier);
return true;
}
-
+
return false;
}
-
+
@Override
public boolean equals(Object qualifier) {
if (qualifier instanceof LanguageQualifier) {
}
return mValue.equals(((LanguageQualifier)qualifier).mValue);
}
-
+
return false;
}
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);
}
if (mValue != null) {
return mValue;
}
-
+
return ""; //$NON-NLS-1$
}
}
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;
* Resource Qualifier for Navigation Method.
*/
public final class NavigationMethodQualifier extends ResourceQualifier {
-
+
public static final String NAME = "Navigation Method";
private NavigationMethod mValue;
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.
return orient;
}
}
-
+
return null;
}
-
+
public String getValue() {
return mValue;
}
-
+
public String getDisplayValue() {
return mDisplay;
}
if (nav == value) {
return i;
}
-
+
i++;
}
return null;
}
}
-
+
public NavigationMethodQualifier() {
// pass
}
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$
config.setNavigationMethodQualifier(qualifier);
return true;
}
-
+
return false;
}
-
+
@Override
public boolean equals(Object qualifier) {
if (qualifier instanceof NavigationMethodQualifier) {
return mValue == ((NavigationMethodQualifier)qualifier).mValue;
}
-
+
return false;
}
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$
}
if (mValue != null) {
return mValue.getDisplayValue();
}
-
+
return ""; //$NON-NLS-1$
}
}
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;
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.
// looks like the string we extracted wasn't a valid number.
return null;
}
-
+
NetworkCodeQualifier qualifier = new NetworkCodeQualifier();
qualifier.mCode = code;
return qualifier;
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;
// 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;
}
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);
}
if (mCode != DEFAULT_CODE) {
return String.format("MNC %1$d", mCode);
}
-
+
return ""; //$NON-NLS-1$
}
}
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 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$
}
}
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;
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.
}
return null;
}
-
+
/**
* Returns the folder name segment for the given value. This is equivalent to calling
* {@link #toString()} on a {@link RegionQualifier} object.
return segment;
}
}
-
+
return ""; //$NON-NLS-1$
}
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$
config.setRegionQualifier(qualifier);
return true;
}
-
+
return false;
}
-
+
@Override
public boolean equals(Object qualifier) {
if (qualifier instanceof RegionQualifier) {
}
return mValue.equals(((RegionQualifier)qualifier).mValue);
}
-
+
return false;
}
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);
}
if (mValue != null) {
return mValue;
}
-
+
return ""; //$NON-NLS-1$
}
}
package com.android.ide.eclipse.adt.internal.resources.configurations;
+import com.android.sdklib.IAndroidTarget;
+
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.
* @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.
*/
@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.
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;
* 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;
}
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$
if (m.matches()) {
String d1 = m.group(1);
String d2 = m.group(2);
-
+
ScreenDimensionQualifier qualifier = getQualifier(d1, d2);
if (qualifier != null) {
config.setScreenDimensionQualifier(qualifier);
}
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;
}
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) {
} catch (NumberFormatException e) {
// looks like the string we extracted wasn't a valid number.
}
-
+
return null;
}
* 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$
}
if (mValue1 != -1 && mValue2 != -1) {
return String.format("%1$dx%2$d", mValue1, mValue2);
}
-
+
return ""; //$NON-NLS-1$
}
}
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;
* Resource Qualifier for Screen Orientation.
*/
public final class ScreenOrientationQualifier extends ResourceQualifier {
-
+
public static final String NAME = "Screen Orientation";
private ScreenOrientation mValue = null;
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.
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++;
}
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;
config.setScreenOrientationQualifier(qualifier);
return true;
}
-
+
return false;
}
-
+
@Override
public boolean equals(Object qualifier) {
if (qualifier instanceof ScreenOrientationQualifier) {
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$
}
if (mValue != null) {
return mValue.getDisplayValue();
}
-
+
return ""; //$NON-NLS-1$
}
}
--- /dev/null
+/*
+ * 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$
+ }
+}
--- /dev/null
+/*
+ * 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$
+ }
+}
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;
public static final String NAME = "Text Input Method";
private TextInputMethod mValue;
-
+
/**
* Screen Orientation enum.
*/
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.
return orient;
}
}
-
+
return null;
}
public String getValue() {
return mValue;
}
-
+
public String getDisplayValue() {
return mDisplayValue;
}
if (value == input) {
return i;
}
-
+
i++;
}
return null;
}
}
-
+
public TextInputMethodQualifier() {
// pass
}
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$
config.setTextInputMethodQualifier(qualifier);
return true;
}
-
+
return false;
}
-
+
@Override
public boolean equals(Object qualifier) {
if (qualifier instanceof TextInputMethodQualifier) {
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$
}
if (mValue != null) {
return mValue.getDisplayValue();
}
-
+
return ""; //$NON-NLS-1$
}
}
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;
public static final String NAME = "Touch Screen";
private TouchScreenType mValue;
-
+
/**
* Screen Orientation enum.
*/
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.
return orient;
}
}
-
+
return null;
}
public String getValue() {
return mValue;
}
-
+
public String getDisplayValue() {
return mDisplayValue;
}
if (t == touch) {
return i;
}
-
+
i++;
}
return null;
}
}
-
+
public TouchScreenQualifier() {
// pass
}
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$
config.setTouchTypeQualifier(qualifier);
return true;
}
-
+
return false;
}
-
+
@Override
public boolean equals(Object qualifier) {
if (qualifier instanceof TouchScreenQualifier) {
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$
}
if (mValue != null) {
return mValue.getDisplayValue();
}
-
+
return ""; //$NON-NLS-1$
}
}
--- /dev/null
+/*
+ * 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$
+ }
+}
}
/**
+ * 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.
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;
* <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;
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.
*/
}
}
}
-
+
/**
* Implementation of {@link VerifyListener} for Country Code qualifiers.
*/
}
}
}
-
+
/**
* Implementation of {@link VerifyListener} for the Language and Region qualifiers.
*/
e.doit = false;
return;
}
-
+
// check for lower case only.
for (int i = 0 ; i < e.text.length(); i++) {
char letter = e.text.charAt(i);
}
}
}
-
+
/**
* 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.
*/
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) {
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("->");
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 */);
}
}
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 */);
}
}
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) {
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 {
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));
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
public void setOnChangeListener(Runnable listener) {
mOnChangeListener = listener;
}
-
+
/**
* Initialize the UI with a given {@link FolderConfiguration}. This must
* be called from the UI thread.
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;
}
return true;
}
-
+
/**
* Initialize the UI with the configuration represented by a resource folder name.
* This must be called from the UI thread.
return setConfiguration(folderSegments);
}
-
+
/**
* Gets the configuration as setup by the widget.
* @param config the {@link FolderConfiguration} object to be filled with the information
public void getConfiguration(FolderConfiguration config) {
config.set(mSelectedConfiguration);
}
-
+
/**
* Returns the state of the configuration being edited/created.
*/
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).
}
mSelectionTableViewer.refresh(true);
-
+
if (keepSelection) {
mSelectionTableViewer.setSelection(selection);
mOnRefresh = false;
mOnChangeListener.run();
}
}
-
+
/**
* Content provider around a {@link FolderConfiguration}.
*/
private static class QualifierContentProvider implements IStructuredContentProvider {
-
+
private FolderConfiguration mInput;
public QualifierContentProvider() {
}
}
}
-
+
/**
* Label provider for {@link ResourceQualifier} objects.
*/
private static class QualifierLabelProvider implements ITableLabelProvider {
-
+
private final boolean mShowQualifierValue;
public QualifierLabelProvider(boolean showQualifierValue) {
} else {
return value;
}
-
+
} else {
return ((ResourceQualifier)element).getShortName();
}
return null;
}
-
+
public Image getColumnImage(Object element, int columnIndex) {
// only one column, so we can ignore columnIndex
if (element instanceof ResourceQualifier) {
// pass
}
}
-
+
/**
* Base class for Edit widget for {@link ResourceQualifier}.
*/
new Label(this, SWT.NONE).setText(title);
}
-
+
public abstract void setQualifier(ResourceQualifier qualifier);
}
-
+
/**
* Edit widget for {@link CountryCodeQualifier}.
*/
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() {
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
mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier());
}
}
-
+
// notify of change
onChange(true /* keepSelection */);
}
@Override
public void setQualifier(ResourceQualifier qualifier) {
CountryCodeQualifier q = (CountryCodeQualifier)qualifier;
-
+
mText.setText(Integer.toString(q.getCode()));
}
}
public MNCEdit(Composite parent) {
super(parent, NetworkCodeQualifier.NAME);
-
+
mText = new Text(this, SWT.BORDER);
mText.addVerifyListener(new MobileCodeVerifier());
mText.addModifyListener(new ModifyListener() {
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
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}.
*/
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
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
}
}
}
-
+
/**
* Edit widget for {@link ScreenOrientationQualifier}.
*/
* 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));
+ }
}
}
}
}
}
-
+
/**
* Edit widget for {@link ScreenDimensionQualifier}.
*/
ModifyListener modifyListener = new ModifyListener() {
public void modifyText(ModifyEvent e) {
onSizeChange();
- }
+ }
};
-
+
FocusAdapter focusListener = new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
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
new ScreenDimensionQualifier());
}
}
-
+
// notify of change
onChange(true /* keepSelection */);
}
@Override
public void setQualifier(ResourceQualifier qualifier) {
ScreenDimensionQualifier q = (ScreenDimensionQualifier)qualifier;
-
+
mSize1.setText(Integer.toString(q.getValue1()));
mSize2.setText(Integer.toString(q.getValue2()));
}
// 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();
// 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.
"^(" + 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);
}
}
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*/);
}
}
}
/**
+ * 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.
*/
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
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,
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;
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;
@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[] {
new FileMock(MISC1_FILENAME),
new FileMock(MISC2_FILENAME),
};
-
+
// add multiple ResourceFolder to the project resource.
FolderConfiguration defaultConfig = getConfiguration(
null, // country code
null, // text input
null, // navigation
null); // screen size
-
+
addFolder(mResources, defaultConfig, validMemberList);
-
+
config1 = getConfiguration(
null, // country code
null, // network code
null, // text input
null, // navigation
null); // screen size
-
+
addFolder(mResources, config1, validMemberList);
config2 = getConfiguration(
null, // text input
null, // navigation
null); // screen size
-
+
addFolder(mResources, config2, validMemberList);
config3 = getConfiguration(
null, // text input
null, // navigation
null); // screen size
-
+
addFolder(mResources, config3, validMemberList);
config4 = getConfiguration(
TextInputMethod.QWERTY.getValue(), // text input
NavigationMethod.DPAD.getValue(), // navigation
"480x320"); // screen size
-
+
addFolder(mResources, config4, invalidMemberList);
}
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);
}
*/
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) {
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.
*/
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);
}
}
- /** 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);
ResourceFolderType.LAYOUT, config, new IFolderWrapper(folder));
return resFolder;
}
-
-
-
}
<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">
<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">
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() {
*/\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
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
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
*/\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
}\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
* 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
/** 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
<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>
<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
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
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
});\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
\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
}\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
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
* @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
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
}\r
}\r
\r
- return filteredList.toArray();\r
+ return filteredList.toArray(new Package[filteredList.size()]);\r
}\r
}\r
*/\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
private Button mNewButton;
private Button mRefreshButton;
private Button mManagerButton;
- private Button mUpdateButton;
+ private Button mRepairButton;
private Button mStartButton;
private SelectionListener mSelectionListener;
}
});
- 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();
}
});
if (mDeleteButton != null) {
mDeleteButton.setEnabled(false);
}
- if (mUpdateButton != null) {
- mUpdateButton.setEnabled(false);
+ if (mRepairButton != null) {
+ mRepairButton.setEnabled(false);
}
} else {
AvdInfo selection = getTableSelection();
if (mDeleteButton != null) {
mDeleteButton.setEnabled(hasSelection);
}
- if (mUpdateButton != null) {
- mUpdateButton.setEnabled(hasSelection &&
+ if (mRepairButton != null) {
+ mRepairButton.setEnabled(hasSelection &&
selection.getStatus() == AvdStatus.ERROR_IMAGE_DIR);
}
}
}
}
- 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