) mWaitingForDebuggerApplications.clone();
for (DelayedLaunchInfo launchInfo : copyList) {
- if (launchInfo.mDevice == device) {
- AdtPlugin.printErrorToConsole(launchInfo.mProject,
- String.format(message, device.getSerialNumber(), launchInfo.mActivity));
- launchInfo.mLaunch.stopLaunch();
- mWaitingForDebuggerApplications.remove(launchInfo);
+ if (launchInfo.getDevice() == device) {
+ AdtPlugin.printErrorToConsole(launchInfo.getProject(),
+ String.format(message, device.getSerialNumber(),
+ launchInfo.getLaunchAction().getLaunchDescription()));
+ stopLaunch(launchInfo);
}
}
}
@@ -1641,13 +1300,13 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
if (home.equals(applicationName)) {
// looks like home is up, get its device
- Device device = client.getDevice();
+ IDevice device = client.getDevice();
// look for application waiting for home
synchronized (sListLock) {
- for (int i = 0 ; i < mWaitingForReadyEmulatorList.size() ;) {
+ for (int i = 0; i < mWaitingForReadyEmulatorList.size(); ) {
DelayedLaunchInfo launchInfo = mWaitingForReadyEmulatorList.get(i);
- if (launchInfo.mDevice == device) {
+ if (launchInfo.getDevice() == device) {
// it's match, remove from the list
mWaitingForReadyEmulatorList.remove(i);
@@ -1657,13 +1316,13 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
// so we check now
if (checkBuildInfo(launchInfo, device) == false) {
// device is not the proper API!
- AdtPlugin.printErrorToConsole(launchInfo.mProject,
+ AdtPlugin.printErrorToConsole(launchInfo.getProject(),
"Launch canceled!");
- launchInfo.mLaunch.stopLaunch();
+ stopLaunch(launchInfo);
return;
}
- AdtPlugin.printToConsole(launchInfo.mProject,
+ AdtPlugin.printToConsole(launchInfo.getProject(),
String.format("HOME is up on device '%1$s'",
device.getSerialNumber()));
@@ -1673,9 +1332,9 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
launchApp(launchInfo, device);
} else {
// failure! Cancel and return
- AdtPlugin.printErrorToConsole(launchInfo.mProject,
+ AdtPlugin.printErrorToConsole(launchInfo.getProject(),
"Launch canceled!");
- launchInfo.mLaunch.stopLaunch();
+ stopLaunch(launchInfo);
}
break;
@@ -1727,18 +1386,18 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
String applicationName = client.getClientData().getClientDescription();
Log.d("adt", "App Name: " + applicationName);
synchronized (sListLock) {
- for (int i = 0 ; i < mWaitingForDebuggerApplications.size() ;) {
+ for (int i = 0; i < mWaitingForDebuggerApplications.size(); ) {
final DelayedLaunchInfo launchInfo = mWaitingForDebuggerApplications.get(i);
- if (client.getDevice() == launchInfo.mDevice &&
- applicationName.equals(launchInfo.mPackageName)) {
+ if (client.getDevice() == launchInfo.getDevice() &&
+ applicationName.equals(launchInfo.getPackageName())) {
// this is a match. We remove the launch info from the list
mWaitingForDebuggerApplications.remove(i);
// and connect the debugger.
String msg = String.format(
"Attempting to connect debugger to '%1$s' on port %2$d",
- launchInfo.mPackageName, client.getDebuggerListenPort());
- AdtPlugin.printToConsole(launchInfo.mProject, msg);
+ launchInfo.getPackageName(), client.getDebuggerListenPort());
+ AdtPlugin.printToConsole(launchInfo.getProject(), msg);
new Thread("Debugger Connection") { //$NON-NLS-1$
@Override
@@ -1746,18 +1405,19 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
try {
if (connectRemoteDebugger(
client.getDebuggerListenPort(),
- launchInfo.mLaunch, launchInfo.mMonitor) == false) {
+ launchInfo.getLaunch(),
+ launchInfo.getMonitor()) == false) {
return;
}
} catch (CoreException e) {
// well something went wrong.
- AdtPlugin.printErrorToConsole(launchInfo.mProject,
+ AdtPlugin.printErrorToConsole(launchInfo.getProject(),
String.format("Launch error: %s", e.getMessage()));
// stop the launch
- launchInfo.mLaunch.stopLaunch();
+ stopLaunch(launchInfo);
}
- launchInfo.mMonitor.done();
+ launchInfo.getMonitor().done();
}
}.start();
@@ -1833,4 +1493,15 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
}.start();
}
+ /* (non-Javadoc)
+ * @see com.android.ide.eclipse.adt.launch.ILaunchController#stopLaunch(com.android.ide.eclipse.adt.launch.AndroidLaunchController.DelayedLaunchInfo)
+ */
+ public void stopLaunch(DelayedLaunchInfo launchInfo) {
+ launchInfo.getLaunch().stopLaunch();
+ synchronized (sListLock) {
+ mWaitingForReadyEmulatorList.remove(launchInfo);
+ mWaitingForDebuggerApplications.remove(launchInfo);
+ }
+ }
}
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java
new file mode 100644
index 000000000..a59518cd7
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java
@@ -0,0 +1,226 @@
+/*
+ * 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.launch;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import com.android.ddmlib.IDevice;
+
+/**
+ * A delayed launch waiting for a device to be present or ready before the
+ * application is launched.
+ */
+public final class DelayedLaunchInfo {
+
+ /**
+ * Used to indicate behavior when Android app already exists
+ */
+ enum InstallRetryMode {
+ NEVER, ALWAYS, PROMPT;
+ }
+
+ /** The device on which to launch the app */
+ private IDevice mDevice = null;
+
+ /** The eclipse project */
+ private final IProject mProject;
+
+ /** Package name */
+ private final String mPackageName;
+
+ /** IFile to the package (.apk) file */
+ private final IFile mPackageFile;
+
+ /** debuggable attribute of the manifest file. */
+ private final Boolean mDebuggable;
+
+ /** Required ApiVersionNumber by the app. 0 means no requirements */
+ private final int mRequiredApiVersionNumber;
+
+ private InstallRetryMode mRetryMode = InstallRetryMode.NEVER;
+
+ /** Launch action. */
+ private final IAndroidLaunchAction mLaunchAction;
+
+ /** the launch object */
+ private final AndroidLaunch mLaunch;
+
+ /** the monitor object */
+ private final IProgressMonitor mMonitor;
+
+ /** debug mode flag */
+ private boolean mDebugMode;
+
+ /** current number of launch attempts */
+ private int mAttemptCount = 0;
+
+ /** cancellation state of launch */
+ private boolean mCancelled = false;
+
+ /**
+ * Basic constructor with activity and package info.
+ *
+ * @param project the eclipse project that corresponds to Android app
+ * @param packageName package name of Android app
+ * @param launchAction action to perform after app install
+ * @param pack IFile to the package (.apk) file
+ * @param debuggable debuggable attribute of the app's manifest file.
+ * @param requiredApiVersionNumber required SDK version by the app. 0 means no requirements.
+ * @param launch the launch object
+ * @param monitor progress monitor for launch
+ */
+ public DelayedLaunchInfo(IProject project, String packageName,
+ IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable,
+ int requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) {
+ mProject = project;
+ mPackageName = packageName;
+ mPackageFile = pack;
+ mLaunchAction = launchAction;
+ mLaunch = launch;
+ mMonitor = monitor;
+ mDebuggable = debuggable;
+ mRequiredApiVersionNumber = requiredApiVersionNumber;
+ }
+
+ /**
+ * @return the device on which to launch the app
+ */
+ public IDevice getDevice() {
+ return mDevice;
+ }
+
+ /**
+ * Set the device on which to launch the app
+ */
+ public void setDevice(IDevice device) {
+ mDevice = device;
+ }
+
+ /**
+ * @return the eclipse project that corresponds to Android app
+ */
+ public IProject getProject() {
+ return mProject;
+ }
+
+ /**
+ * @return the package name of the Android app
+ */
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * @return the application package file
+ */
+ public IFile getPackageFile() {
+ return mPackageFile;
+ }
+
+ /**
+ * @return true if Android app is marked as debuggable in its manifest
+ */
+ public Boolean getDebuggable() {
+ return mDebuggable;
+ }
+
+ /**
+ * @return the required api version number for the Android app
+ */
+ public int getRequiredApiVersionNumber() {
+ return mRequiredApiVersionNumber;
+ }
+
+ /**
+ * @param retryMode the install retry mode to set
+ */
+ public void setRetryMode(InstallRetryMode retryMode) {
+ this.mRetryMode = retryMode;
+ }
+
+ /**
+ * @return the installation retry mode
+ */
+ public InstallRetryMode getRetryMode() {
+ return mRetryMode;
+ }
+
+ /**
+ * @return the launch action
+ */
+ public IAndroidLaunchAction getLaunchAction() {
+ return mLaunchAction;
+ }
+
+ /**
+ * @return the launch
+ */
+ public AndroidLaunch getLaunch() {
+ return mLaunch;
+ }
+
+ /**
+ * @return the launch progress monitor
+ */
+ public IProgressMonitor getMonitor() {
+ return mMonitor;
+ }
+
+ /**
+ * @param debugMode the debug mode to set
+ */
+ public void setDebugMode(boolean debugMode) {
+ this.mDebugMode = debugMode;
+ }
+
+ /**
+ * @return true if this is a debug launch
+ */
+ public boolean isDebugMode() {
+ return mDebugMode;
+ }
+
+ /**
+ * Increases the number of launch attempts
+ */
+ public void incrementAttemptCount() {
+ mAttemptCount++;
+ }
+
+ /**
+ * @return the number of launch attempts made
+ */
+ public int getAttemptCount() {
+ return mAttemptCount;
+ }
+
+ /**
+ * Set if launch has been cancelled
+ */
+ public void setCancelled(boolean cancelled) {
+ this.mCancelled = cancelled;
+ }
+
+ /**
+ * @return true if launch has been cancelled
+ */
+ public boolean isCancelled() {
+ return mCancelled;
+ }
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
index a960bda0d..13bb83acb 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
@@ -231,9 +231,9 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
public static class DeviceChooserResponse {
private AvdInfo mAvdToLaunch;
- private Device mDeviceToUse;
+ private IDevice mDeviceToUse;
- public void setDeviceToUse(Device d) {
+ public void setDeviceToUse(IDevice d) {
mDeviceToUse = d;
mAvdToLaunch = null;
}
@@ -243,7 +243,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
mDeviceToUse = null;
}
- public Device getDeviceToUse() {
+ public IDevice getDeviceToUse() {
return mDeviceToUse;
}
@@ -737,3 +737,4 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
mDisableAvdSelectionChange = false;
}
}
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmptyLaunchAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmptyLaunchAction.java
new file mode 100644
index 000000000..02ae6757c
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmptyLaunchAction.java
@@ -0,0 +1,38 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+import com.android.ide.eclipse.adt.AdtPlugin;
+
+/**
+ * A launch action that does nothing after the application has been installed
+ */
+public class EmptyLaunchAction implements IAndroidLaunchAction {
+
+ public boolean doLaunchAction(DelayedLaunchInfo info, IDevice device) {
+ // we're not supposed to do anything, just return;
+ String msg = String.format("%1$s installed on device",
+ info.getPackageFile().getFullPath().toOSString());
+ AdtPlugin.printToConsole(info.getProject(), msg, "Done!");
+ // return false so launch controller will not wait for debugger to attach
+ return false;
+ }
+
+ public String getLaunchDescription() {
+ return "sync";
+ }
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/IAndroidLaunchAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/IAndroidLaunchAction.java
new file mode 100644
index 000000000..2f3cb8934
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/IAndroidLaunchAction.java
@@ -0,0 +1,42 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+import com.android.ide.eclipse.adt.launch.DelayedLaunchInfo;
+
+/**
+ * An action to perform after performing a launch of an Android application
+ */
+public interface IAndroidLaunchAction {
+
+ /**
+ * Do the launch
+ *
+ * @param info the {@link DelayedLaunchInfo} that contains launch details
+ * @param device the Android device to perform action on
+ * @returns true if launch was successfully, and controller should wait for debugger to attach
+ * (if applicable)
+ */
+ boolean doLaunchAction(DelayedLaunchInfo info, IDevice device);
+
+ /**
+ * Return a description of launch, to be used for logging and error messages
+ */
+ String getLaunchDescription();
+
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ILaunchController.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ILaunchController.java
new file mode 100644
index 000000000..2372c2d27
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/ILaunchController.java
@@ -0,0 +1,40 @@
+/*
+ * 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.launch;
+
+import com.android.ddmlib.IDevice;
+
+/**
+ * Interface for managing Android launches
+ */
+public interface ILaunchController {
+
+ /**
+ * Launches an application on a device or emulator
+ *
+ * @param launchInfo the {@link DelayedLaunchInfo} that indicates the launch action
+ * @param device the device or emulator to launch the application on
+ */
+ public void launchApp(DelayedLaunchInfo launchInfo, IDevice device);
+
+ /**
+ * Cancels a launch
+ *
+ * @param launchInfo the {@link DelayedLaunchInfo} to cancel
+ */
+ void stopLaunch(DelayedLaunchInfo launchInfo);
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
index a46f56c59..80f62eaa8 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
@@ -18,7 +18,6 @@ package com.android.ide.eclipse.adt.launch;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.launch.AndroidLaunchController.AndroidLaunchConfiguration;
import com.android.ide.eclipse.adt.project.ProjectHelper;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
@@ -233,7 +232,16 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
return;
}
- String activityName = null;
+ doLaunch(configuration, mode, monitor, project, androidLaunch, config, controller,
+ applicationPackage, manifestParser);
+ }
+
+ protected void doLaunch(ILaunchConfiguration configuration, String mode,
+ IProgressMonitor monitor, IProject project, AndroidLaunch androidLaunch,
+ AndroidLaunchConfiguration config, AndroidLaunchController controller,
+ IFile applicationPackage, AndroidManifestParser manifestParser) {
+
+ String activityName = null;
if (config.mLaunchAction == ACTION_ACTIVITY) {
// Get the activity name defined in the config
@@ -292,11 +300,16 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
}
}
+ IAndroidLaunchAction launchAction = new EmptyLaunchAction();
+ if (activityName != null) {
+ launchAction = new ActivityLaunchAction(activityName, controller);
+ }
+
// everything seems fine, we ask the launch controller to handle
// the rest
controller.launch(project, mode, applicationPackage, manifestParser.getPackage(),
manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(),
- activityName, config, androidLaunch, monitor);
+ launchAction, config, androidLaunch, monitor);
}
@Override
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
index fd0c045d8..c650b9846 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
@@ -400,6 +400,9 @@ public final class ProjectHelper {
try {
parser = AndroidManifestParser.parseForData(manifestFile);
} catch (CoreException e) {
+ // ignore, handled below.
+ }
+ if (parser == null) {
// skip this project.
continue;
}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
index d6868304a..5aeb3358c 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
@@ -253,8 +253,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
if (markerMessage != null) {
// log the error and put the marker on the project if we can.
if (outputToConsole) {
- AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, iProject,
- markerMessage);
+ AdtPlugin.printErrorToConsole(iProject, markerMessage);
}
try {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
index 6c4f4ba57..0dd88c077 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
@@ -36,7 +36,6 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
@@ -823,12 +822,7 @@ public class NewProjectCreationPage extends WizardPage {
Path path = new Path(f.getPath());
String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
- AndroidManifestParser manifestData = null;
- try {
- manifestData = AndroidManifestParser.parseForData(osPath);
- } catch (CoreException e1) {
- // ignore any parsing issue
- }
+ AndroidManifestParser manifestData = AndroidManifestParser.parseForData(osPath);
if (manifestData == null) {
return;
}
@@ -1096,10 +1090,8 @@ public class NewProjectCreationPage extends WizardPage {
}
// Parse it and check the important fields.
- AndroidManifestParser manifestData;
- try {
- manifestData = AndroidManifestParser.parseForData(osPath);
- } catch (CoreException e) {
+ AndroidManifestParser manifestData = AndroidManifestParser.parseForData(osPath);
+ if (manifestData == null) {
return setStatus(
String.format("File %1$s could not be parsed.", osPath),
MSG_ERROR);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
index b2817ff0d..0a45196a4 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
@@ -686,7 +686,8 @@ public class AndroidManifestParser {
* Parses the manifest file, and collects data.
* @param manifestFile The manifest file to parse.
* @return an {@link AndroidManifestParser} or null if the parsing failed.
- * @throws CoreException
+ * @throws CoreException for example the file does not exist in the workspace or
+ * the workspace needs to be refreshed.
*/
public static AndroidManifestParser parseForData(IFile manifestFile) throws CoreException {
return parse(null /* javaProject */, manifestFile, null /* errorListener */,
@@ -698,11 +699,15 @@ public class AndroidManifestParser {
*
* @param osManifestFilePath The OS path of the manifest file to parse.
* @return an {@link AndroidManifestParser} or null if the parsing failed.
- * @throws CoreException
*/
- public static AndroidManifestParser parseForData(String osManifestFilePath)
- throws CoreException {
- return parse(new File(osManifestFilePath));
+ public static AndroidManifestParser parseForData(String osManifestFilePath) {
+ try {
+ return parse(new File(osManifestFilePath));
+ } catch (CoreException e) {
+ // Ignore workspace errors (unlikely to happen since this parses an actual file,
+ // not a workspace resource).
+ return null;
+ }
}
/**
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/AbstractGraphicalLayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/AbstractGraphicalLayoutEditor.java
new file mode 100644
index 000000000..049986745
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/AbstractGraphicalLayoutEditor.java
@@ -0,0 +1,106 @@
+/*
+ * 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.editors.layout;
+
+import com.android.ide.eclipse.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
+import com.android.ide.eclipse.editors.layout.parts.ElementCreateCommand;
+import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration;
+import com.android.ide.eclipse.editors.uimodel.UiDocumentNode;
+import com.android.ide.eclipse.editors.uimodel.UiElementNode;
+
+import org.eclipse.gef.DefaultEditDomain;
+import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette;
+import org.eclipse.gef.ui.parts.SelectionSynchronizer;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Abstract GraphicalLayoutEditor.
+ */
+/*package*/ abstract class AbstractGraphicalLayoutEditor extends GraphicalEditorWithPalette
+ implements IWorkbenchPart, ILayoutReloadListener {
+
+ /**
+ * Sets the UI for the edition of a new file.
+ * @param configuration the configuration of the new file.
+ */
+ abstract void editNewFile(FolderConfiguration configuration);
+
+ /**
+ * Reloads this editor, by getting the new model from the {@link LayoutEditor}.
+ */
+ abstract void reloadEditor();
+
+ /**
+ * Callback for XML model changed. Only update/recompute the layout if the editor is visible
+ */
+ abstract void onXmlModelChanged();
+
+ /**
+ * Responds to a page change that made the Graphical editor page the activated page.
+ */
+ abstract void activated();
+
+ /**
+ * Responds to a page change that made the Graphical editor page the deactivated page
+ */
+ abstract void deactivated();
+
+ /**
+ * Used by LayoutEditor.UiEditorActions.selectUiNode to select a new UI Node
+ * created by {@link ElementCreateCommand#execute()}.
+ *
+ * @param uiNodeModel The {@link UiElementNode} to select.
+ */
+ abstract void selectModel(UiElementNode uiNodeModel);
+
+ /**
+ * Returns the selection synchronizer object.
+ * The synchronizer can be used to sync the selection of 2 or more EditPartViewers.
+ *
+ * This is changed from protected to public so that the outline can use it.
+ *
+ * @return the synchronizer
+ */
+ @Override
+ public SelectionSynchronizer getSelectionSynchronizer() {
+ return super.getSelectionSynchronizer();
+ }
+
+ /**
+ * Returns the edit domain.
+ *
+ * This is changed from protected to public so that the outline can use it.
+ *
+ * @return the edit domain
+ */
+ @Override
+ public DefaultEditDomain getEditDomain() {
+ return super.getEditDomain();
+ }
+
+ abstract void reloadPalette();
+
+ abstract void recomputeLayout();
+
+ abstract UiDocumentNode getModel();
+
+ abstract LayoutEditor getLayoutEditor();
+
+ abstract Clipboard getClipboard();
+
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
index eb7dee6db..9c529e5da 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
@@ -86,8 +86,6 @@ import org.eclipse.gef.dnd.TemplateTransferDropTargetListener;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.requests.CreationFactory;
-import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette;
-import org.eclipse.gef.ui.parts.SelectionSynchronizer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
@@ -141,7 +139,7 @@ import java.util.Set;
*
* To understand Drag'n'drop: http://www.eclipse.org/articles/Article-Workbench-DND/drag_drop.html
*/
-public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
+public class GraphicalLayoutEditor extends AbstractGraphicalLayoutEditor
implements ILayoutReloadListener {
private final static String THEME_SEPARATOR = "----------"; //$NON-NLS-1$
@@ -595,6 +593,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
return mPaletteRoot;
}
+ @Override
public Clipboard getClipboard() {
return mClipboard;
}
@@ -716,7 +715,8 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
*
* @param uiNodeModel The {@link UiElementNode} to select.
*/
- public void selectModel(UiElementNode uiNodeModel) {
+ @Override
+ void selectModel(UiElementNode uiNodeModel) {
GraphicalViewer viewer = getGraphicalViewer();
// Give focus to the graphical viewer (in case the outline has it)
@@ -734,6 +734,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
// Local methods
//--------------
+ @Override
public LayoutEditor getLayoutEditor() {
return mLayoutEditor;
}
@@ -863,7 +864,8 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
* Sets the UI for the edition of a new file.
* @param configuration the configuration of the new file.
*/
- public void editNewFile(FolderConfiguration configuration) {
+ @Override
+ void editNewFile(FolderConfiguration configuration) {
// update the configuration UI
setConfiguration(configuration);
@@ -1015,6 +1017,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
/**
* Reloads this editor, by getting the new model from the {@link LayoutEditor}.
*/
+ @Override
void reloadEditor() {
GraphicalViewer viewer = getGraphicalViewer();
viewer.setContents(getModel());
@@ -1036,6 +1039,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
/**
* Callback for XML model changed. Only update/recompute the layout if the editor is visible
*/
+ @Override
void onXmlModelChanged() {
if (mLayoutEditor.isGraphicalEditorActive()) {
doXmlReload(true /* force */);
@@ -1265,10 +1269,12 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
mCurrentLayoutLabel.setText(current != null ? current : "(Default)");
}
+ @Override
UiDocumentNode getModel() {
return mLayoutEditor.getUiRootNode();
}
+ @Override
void reloadPalette() {
PaletteFactory.createPaletteRoot(mPaletteRoot, mLayoutEditor.getTargetData());
}
@@ -1667,6 +1673,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
/**
* Recomputes the layout with the help of layoutlib.
*/
+ @Override
@SuppressWarnings("deprecation")
void recomputeLayout() {
doXmlReload(false /* force */);
@@ -1968,6 +1975,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
/**
* Responds to a page change that made the Graphical editor page the activated page.
*/
+ @Override
void activated() {
if (mNeedsRecompute || mNeedsXmlReload) {
recomputeLayout();
@@ -1977,6 +1985,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
/**
* Responds to a page change that made the Graphical editor page the deactivated page
*/
+ @Override
void deactivated() {
// nothing to be done here for now.
}
@@ -2233,31 +2242,6 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
return mConfiguredFrameworkRes;
}
- /**
- * Returns the selection synchronizer object.
- * The synchronizer can be used to sync the selection of 2 or more EditPartViewers.
- *
- * This is changed from protected to public so that the outline can use it.
- *
- * @return the synchronizer
- */
- @Override
- public SelectionSynchronizer getSelectionSynchronizer() {
- return super.getSelectionSynchronizer();
- }
-
- /**
- * Returns the edit domain.
- *
- * This is changed from protected to public so that the outline can use it.
- *
- * @return the edit domain
- */
- @Override
- public DefaultEditDomain getEditDomain() {
- return super.getEditDomain();
- }
-
/**
* Creates a new layout file from the specificed {@link FolderConfiguration}.
*/
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
index dabe79779..f3a5113a9 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
@@ -55,7 +55,7 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
/** Root node of the UI element hierarchy */
private UiDocumentNode mUiRootNode;
- private GraphicalLayoutEditor mGraphicalEditor;
+ private AbstractGraphicalLayoutEditor mGraphicalEditor;
private int mGraphicalEditorIndex;
/** Implementation of the {@link IContentOutlinePage} for this editor */
private UiContentOutlinePage mOutline;
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java
index 3e0f5d85c..536e9020b 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java
@@ -70,7 +70,7 @@ import java.util.List;
*/
class UiContentOutlinePage extends ContentOutlinePage {
- private GraphicalLayoutEditor mEditor;
+ private AbstractGraphicalLayoutEditor mEditor;
private Action mAddAction;
private Action mDeleteAction;
@@ -79,7 +79,7 @@ class UiContentOutlinePage extends ContentOutlinePage {
private UiOutlineActions mUiActions = new UiOutlineActions();
- public UiContentOutlinePage(GraphicalLayoutEditor editor, final EditPartViewer viewer) {
+ public UiContentOutlinePage(AbstractGraphicalLayoutEditor editor, final EditPartViewer viewer) {
super(viewer);
mEditor = editor;
IconFactory factory = IconFactory.getInstance();
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
index c3f4dd807..5726d7899 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
@@ -18,7 +18,6 @@ package com.android.ide.eclipse.editors.layout.descriptors;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.resources.DeclareStyleableInfo;
-import com.android.ide.eclipse.common.resources.ResourceType;
import com.android.ide.eclipse.common.resources.ViewClassInfo;
import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo;
import com.android.ide.eclipse.common.resources.ViewClassInfo.LayoutParamsInfo;
@@ -27,7 +26,6 @@ import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils;
import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor;
import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider;
-import com.android.ide.eclipse.editors.descriptors.ReferenceAttributeDescriptor;
import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor;
import com.android.sdklib.SdkConstants;
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
index fa0930553..2d14c06a9 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
@@ -217,8 +217,10 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
try {
IFile manifestFile = AndroidManifestParser.getManifest(project);
AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile);
- String javaPackage = data.getPackage();
- return javaPackage + ".R"; //$NON-NLS-1$
+ if (data != null) {
+ String javaPackage = data.getPackage();
+ return javaPackage + ".R"; //$NON-NLS-1$
+ }
} catch (CoreException e) {
// This will typically happen either because the manifest file is not present
// and/or the workspace needs to be refreshed.
@@ -227,8 +229,8 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
"Failed to find the package of the AndroidManifest of project %1$s. Reason: %2$s",
project.getName(),
e.getMessage());
- return null;
}
+ return null;
}
}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java
index 48f8a7f24..32cac9f2b 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java
@@ -158,6 +158,35 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
return null;
}
+ /**
+ * Gets all the values one could use to auto-complete a "resource" value in an XML
+ * content assist.
+ *
+ * Typically the user is editing the value of an attribute in a resource XML, e.g.
+ * "<Button android:test="@string/my_[caret]_string..."
+ *
+ *
+ * "prefix" is the value that the user has typed so far (or more exactly whatever is on the
+ * left side of the insertion point). In the example above it would be "@style/my_".
+ *
+ *
+ * To avoid a huge long list of values, the completion works on two levels:
+ *
+ * - If a resource type as been typed so far (e.g. "@style/"), then limit the values to
+ * the possible completions that match this type.
+ *
- If no resource type as been typed so far, then return the various types that could be
+ * completed. So if the project has only strings and layouts resources, for example,
+ * the returned list will only include "@string/" and "@layout/".
+ *
+ *
+ * Finally if anywhere in the string we find the special token "android:", we use the
+ * current framework system resources rather than the project resources.
+ * This works for both "@android:style/foo" and "@style/android:foo" conventions even though
+ * the reconstructed name will always be of the former form.
+ *
+ * Note that "android:" here is a keyword specific to Android resources and should not be
+ * mixed with an XML namespace for an XML attribute name.
+ */
@Override
public String[] getPossibleValues(String prefix) {
IResourceRepository repository = null;
@@ -174,6 +203,8 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
}
} else {
// If there's a prefix with "android:" in it, use the system resources
+ //
+ // TODO find a way to only list *public* framework resources here.
AndroidTargetData data = editor.getTargetData();
repository = data.getSystemResources();
isSystem = true;
diff --git a/tools/makedict/Android.mk b/tools/makedict/Android.mk
new file mode 100644
index 000000000..b9fc5533d
--- /dev/null
+++ b/tools/makedict/Android.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_JAR_MANIFEST := etc/manifest.txt
+LOCAL_MODULE := makedict
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+include $(LOCAL_PATH)/etc/Android.mk
diff --git a/tools/makedict/etc/Android.mk b/tools/makedict/etc/Android.mk
new file mode 100644
index 000000000..da162868a
--- /dev/null
+++ b/tools/makedict/etc/Android.mk
@@ -0,0 +1,20 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_EXECUTABLES := makedict
+include $(BUILD_HOST_PREBUILT)
+
diff --git a/tools/makedict/etc/makedict b/tools/makedict/etc/makedict
new file mode 100755
index 000000000..8420d6e5e
--- /dev/null
+++ b/tools/makedict/etc/makedict
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Copyright 2009, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+ newProg=`/bin/ls -ld "${prog}"`
+ newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+ if expr "x${newProg}" : 'x/' >/dev/null; then
+ prog="${newProg}"
+ else
+ progdir=`dirname "${prog}"`
+ prog="${progdir}/${newProg}"
+ fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=makedict.jar
+frameworkdir="$progdir"
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+ frameworkdir=`dirname "$progdir"`/tools/lib
+ libdir=`dirname "$progdir"`/tools/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+ frameworkdir=`dirname "$progdir"`/framework
+ libdir=`dirname "$progdir"`/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+ echo `basename "$prog"`": can't find $jarfile"
+ exit 1
+fi
+
+if [ "$OSTYPE" = "cygwin" ] ; then
+ jarpath=`cygpath -w "$frameworkdir/$jarfile"`
+ progdir=`cygpath -w "$progdir"`
+else
+ jarpath="$frameworkdir/$jarfile"
+fi
+
+# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
+# might need more memory, e.g. -Xmx128M
+exec java -Djava.ext.dirs="$frameworkdir" -jar "$jarpath" "$@"
diff --git a/tools/makedict/etc/manifest.txt b/tools/makedict/etc/manifest.txt
new file mode 100644
index 000000000..aa3a3e84c
--- /dev/null
+++ b/tools/makedict/etc/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.tools.dict.MakeBinaryDictionary
diff --git a/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java
new file mode 100755
index 000000000..cbe702872
--- /dev/null
+++ b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java
@@ -0,0 +1,294 @@
+/*
+ * 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.tools.dict;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+/**
+ * Compresses a list of words and frequencies into a tree structured binary dictionary.
+ */
+public class MakeBinaryDictionary {
+
+ public static final int ALPHA_SIZE = 256;
+
+ public static final String TAG_WORD = "w";
+ public static final String ATTR_FREQ = "f";
+
+ public static final CharNode EMPTY_NODE = new CharNode();
+
+ List roots;
+ Map mDictionary;
+ int mWordCount;
+
+ static class CharNode {
+ char data;
+ int freq;
+ boolean terminal;
+ List children;
+ static int sNodes;
+
+ public CharNode() {
+ sNodes++;
+ }
+ }
+
+ public static void usage() {
+ System.err.println("Usage: makedict ");
+ System.exit(-1);
+ }
+
+ public static void main(String[] args) {
+ if (args.length < 2) {
+ usage();
+ } else {
+ new MakeBinaryDictionary(args[0], args[1]);
+ }
+ }
+
+ public MakeBinaryDictionary(String srcFilename, String destFilename) {
+ populateDictionary(srcFilename);
+ writeToDict(destFilename);
+ // Enable the code below to verify that the generated tree is traversable.
+ if (false) {
+ traverseDict(0, new char[32], 0);
+ }
+ }
+
+ private void populateDictionary(String filename) {
+ roots = new ArrayList();
+ try {
+ SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+ parser.parse(new File(filename), new DefaultHandler() {
+ boolean inWord;
+ int freq;
+
+ @Override
+ public void startElement(String uri, String localName,
+ String qName, Attributes attributes) {
+ if (qName.equals("w")) {
+ inWord = true;
+ freq = Integer.parseInt(attributes.getValue(0));
+ }
+ }
+
+ @Override
+ public void characters(char[] data, int offset, int length) {
+ // Ignore other whitespace
+ if (!inWord) return;
+
+ // Ignore one letter words
+ if (length < 2) return;
+ mWordCount++;
+ String word = new String(data, offset, length);
+ addWordTop(word, freq);
+ }
+
+ @Override
+ public void endElement(String uri, String localName,
+ String qName) {
+ if (qName.equals("w")) inWord = false;
+ }
+ });
+ } catch (Exception ioe) {
+ System.err.println("Exception in parsing\n" + ioe);
+ ioe.printStackTrace();
+ }
+ System.out.println("Nodes = " + CharNode.sNodes);
+ }
+
+ private int indexOf(List children, char c) {
+ if (children == null) {
+ return -1;
+ }
+ for (int i = 0; i < children.size(); i++) {
+ if (children.get(i).data == c) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void addWordTop(String word, int occur) {
+ if (occur > 255) occur = 255;
+
+ char firstChar = word.charAt(0);
+ int index = indexOf(roots, firstChar);
+ if (index == -1) {
+ CharNode newNode = new CharNode();
+ newNode.data = firstChar;
+ newNode.freq = occur;
+ index = roots.size();
+ roots.add(newNode);
+ } else {
+ roots.get(index).freq += occur;
+ }
+ if (word.length() > 1) {
+ addWordRec(roots.get(index), word, 1, occur);
+ } else {
+ roots.get(index).terminal = true;
+ }
+ }
+
+ private void addWordRec(CharNode parent, String word, int charAt, int occur) {
+ CharNode child = null;
+ char data = word.charAt(charAt);
+ if (parent.children == null) {
+ parent.children = new ArrayList();
+ } else {
+ for (int i = 0; i < parent.children.size(); i++) {
+ CharNode node = parent.children.get(i);
+ if (node.data == data) {
+ child = node;
+ break;
+ }
+ }
+ }
+ if (child == null) {
+ child = new CharNode();
+ parent.children.add(child);
+ }
+ child.data = data;
+ child.freq += occur;
+ if (word.length() > charAt + 1) {
+ addWordRec(child, word, charAt + 1, occur);
+ } else {
+ child.terminal = true;
+ child.freq = occur;
+ }
+ }
+
+ byte[] dict;
+ int dictSize;
+ static final int CHAR_WIDTH = 8;
+ static final int FLAGS_WIDTH = 1; // Terminal flag (word end)
+ static final int ADDR_WIDTH = 23; // Offset to children
+ static final int FREQ_WIDTH_BYTES = 1;
+ static final int COUNT_WIDTH_BYTES = 1;
+ static final int NODE_SIZE_BYTES =
+ (CHAR_WIDTH + FLAGS_WIDTH + ADDR_WIDTH) / 8 + FREQ_WIDTH_BYTES;
+
+ private void addCount(int count) {
+ dict[dictSize++] = (byte) (0xFF & count);
+ }
+
+ /* TODO: Allow characters to be beyond the 0-255 range. This is required for some latin
+ language not currently supported */
+ private void addNode(CharNode node) {
+ int charData = 0xFFFF & node.data;
+ if (charData > 254) {
+ System.out.println("WARNING: Non-ASCII character encountered : " + node.data +
+ ", value = " + charData);
+ dict[dictSize++] = '@';
+ } else {
+ dict[dictSize++] = (byte) (0xFF & node.data);
+ }
+ dictSize += 3; // Space for children address
+ if ((0xFFFFFF & node.freq) > 255) {
+ node.freq = (byte) 255;
+ }
+ dict[dictSize++] = (byte) (0xFF & node.freq);
+ }
+
+ private void updateNodeAddress(int nodeAddress, CharNode node,
+ int childrenAddress) {
+ childrenAddress = 0x7FFFFF & childrenAddress;
+ if (node.terminal) {
+ childrenAddress |= 0x800000;
+ }
+ dict[nodeAddress + 1] = (byte) (childrenAddress >> 16);
+ dict[nodeAddress + 2] = (byte) ((childrenAddress & 0xFF00) >> 8);
+ dict[nodeAddress + 3] = (byte) ((childrenAddress & 0xFF));
+ }
+
+ void writeWordsRec(List children) {
+ if (children == null || children.size() == 0) {
+ return;
+ }
+ addCount(children.size());
+ int childrenStart = dictSize;
+ for (int j = 0; j < children.size(); j++) {
+ CharNode node = children.get(j);
+ addNode(node);
+ }
+ for (int j = 0; j < children.size(); j++) {
+ CharNode node = children.get(j);
+ // TODO: Fix this when child length becomes variable
+ int nodeAddress = childrenStart + NODE_SIZE_BYTES * j;
+ int cacheDictSize = dictSize;
+ writeWordsRec(node.children);
+ updateNodeAddress(nodeAddress, node, node.children != null
+ ? cacheDictSize : 0);
+ }
+ }
+
+ void writeToDict(String dictFilename) {
+ // 2MB max
+ dict = new byte[2 * 1024 * 1024]; // 2MB upper limit. Actual is probably
+ // < 1MB in most cases, as there is a limit in the
+ // resource size in apks.
+ dictSize = 0;
+ writeWordsRec(roots);
+ System.out.println("Dict Size = " + dictSize);
+ try {
+ FileOutputStream fos = new FileOutputStream(dictFilename);
+ fos.write(dict, 0, dictSize);
+ fos.close();
+ } catch (IOException ioe) {
+ System.err.println("Error writing dict file:" + ioe);
+ }
+ }
+
+ void traverseDict(int pos, char[] word, int depth) {
+ int count = dict[pos++] & 0xFF;
+ for (int i = 0; i < count; i++) {
+ char c = (char) (dict[pos] & 0xFF);
+ word[depth] = c;
+ if ((dict[pos + 1] & 0x80) > 0) {
+ showWord(word, depth + 1, dict[pos + 4] & 0xFF);
+ }
+ int address =
+ ((dict[pos + 1] & 0x7F) << 16)
+ | ((dict[pos + 2] & 0xFF) << 8)
+ | ((dict[pos + 3] & 0xFF));
+ if (address != 0) {
+ traverseDict(address, word, depth + 1);
+ }
+ pos += NODE_SIZE_BYTES;
+ }
+ }
+
+ void showWord(char[] word, int size, int freq) {
+ System.out.print(new String(word, 0, size) + " " + freq + "\n");
+ }
+}
diff --git a/tools/scripts/android_rules.xml b/tools/scripts/android_rules.xml
index 799aa0b8a..aad9dbd6e 100644
--- a/tools/scripts/android_rules.xml
+++ b/tools/scripts/android_rules.xml
@@ -28,6 +28,7 @@
+
@@ -39,6 +40,7 @@
+
@@ -46,9 +48,6 @@
-
-
-
@@ -73,6 +72,8 @@
Creating output directories if needed...
+
+
@@ -84,7 +85,7 @@
-
+
@@ -100,6 +101,7 @@
+
@@ -107,11 +109,12 @@
-
+
+
+