diff --git a/andmore-core/features/feature/feature.xml b/andmore-core/features/feature/feature.xml
index 1e756cdb..4bf18a53 100644
--- a/andmore-core/features/feature/feature.xml
+++ b/andmore-core/features/feature/feature.xml
@@ -40,9 +40,9 @@
-
-
-
+
+
+
diff --git a/andmore-core/plugins/android/plugin.xml b/andmore-core/plugins/android/plugin.xml
index 6dd53136..5b105ede 100644
--- a/andmore-core/plugins/android/plugin.xml
+++ b/andmore-core/plugins/android/plugin.xml
@@ -92,9 +92,6 @@
-
-
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndmoreDeviceChangeListener.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndmoreDeviceChangeListener.java
deleted file mode 100644
index 09c60038..00000000
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndmoreDeviceChangeListener.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android;
-
-import org.eclipse.ui.IStartup;
-
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IDevice.DeviceState;
-
-/**
- * DESCRIPTION: The device change listener to be used by the whole
- * tool. Other plugins should not register listeners in DDMS.
- * Instead, use DDMSFacade
- *
- * RESPONSIBILITY: Delegate the deviceConnected and deviceDisconnected events to
- * the registered runnables
- *
- * COLABORATORS: None.
- *
- * USAGE: This class shall be used by DDMS and DDMSFacade only
- */
-public class AndmoreDeviceChangeListener implements IDeviceChangeListener, IStartup {
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.ui.IStartup#earlyStartup()
- */
- @Override
- public void earlyStartup() {
- // Adding the listener in the early startup to guarantee that we will
- // receive
- // events for the devices that were already online before starting the
- // workbench
- AndroidDebugBridge.addDeviceChangeListener(this);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceChanged
- * (com.android.ddmlib.Device, int)
- */
- @Override
- public void deviceChanged(IDevice device, int i) {
- if (i == IDevice.CHANGE_STATE) {
- // a handset should only be instantiated when its state change from
- // OFFLINE to ONLINE
- // to avoid the problem of a remote device on the OFFLINE state be
- // presented as an ONLINE handset
- if ((device.getState() == DeviceState.ONLINE) && (!device.isEmulator())) {
- DDMSFacade.deviceConnected(device);
- }
- DDMSFacade.deviceStatusChanged(device);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceConnected
- * (com.android.ddmlib.Device)
- */
- @Override
- public void deviceConnected(IDevice device) {
- // handsets should not be instantiated right after connection because at
- // that time
- // they appear on the OFFLINE state
- if (device.isEmulator()) {
- DDMSFacade.deviceConnected(device);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#
- * deviceDisconnected(com.android.ddmlib.Device)
- */
- @Override
- public void deviceDisconnected(IDevice device) {
- DDMSFacade.deviceDisconnected(device);
- }
-}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndmoreHProfDumpHandler.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndmoreHProfDumpHandler.java
index 447674a1..31d88a7b 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndmoreHProfDumpHandler.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndmoreHProfDumpHandler.java
@@ -54,6 +54,7 @@
* Class to handle post HPROF dumping things. Based on the existing HprofHandler
* from ADT.
*/
+@SuppressWarnings("deprecation") // Now used via recommended HprofData mechanism
public class AndmoreHProfDumpHandler extends BaseFileHandler implements IHprofDumpHandler {
public final static String SAVE_ACTION = "hprof.save"; //$NON-NLS-1$
@@ -106,9 +107,6 @@ public void run() {
.getClientData().getClientDescription(), message != null ? message + "\n\n" : ""); //$NON-NLS-1$ //$NON-NLS-2$
}
});
- synchronized (DDMSFacade.class) {
- DDMSFacade.class.notify();
- }
}
@Override
@@ -119,9 +117,6 @@ public void run() {
extractRemoteHprof(remoteFilePath, client);
}
});
- synchronized (DDMSFacade.class) {
- DDMSFacade.class.notify();
- }
}
private void extractRemoteHprof(final String remoteFilePath, final Client client) {
@@ -190,9 +185,6 @@ public void run() {
extractLocalHprof(data, client, progressMonitor);
}
});
- synchronized (DDMSFacade.class) {
- DDMSFacade.class.notify();
- }
}
private void extractLocalHprof(final byte[] data, final Client client, IProgressMonitor monitor) {
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndroidPlugin.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndroidPlugin.java
index 3b7ec04c..1af05787 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndroidPlugin.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/AndroidPlugin.java
@@ -1,256 +1,256 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android;
-
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Set;
-
-import org.eclipse.andmore.android.common.IAndroidConstants;
-import org.eclipse.andmore.android.common.log.AndmoreLogger;
-import org.eclipse.core.runtime.jobs.IJobChangeEvent;
-import org.eclipse.core.runtime.jobs.IJobManager;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.core.runtime.jobs.JobChangeAdapter;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.ui.IWindowListener;
-import org.eclipse.ui.IWorkbench;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.osgi.framework.BundleContext;
-
-/**
- * The activator class controls the plug-in life cycle
- */
-public class AndroidPlugin extends AbstractUIPlugin {
- // Listening to this job, instead of loading sdk job, which seems to don't
- // exist anymore.
- private static final String ANDROID_SDK_CONTENT_LOADER_JOB = "Android SDK Content Loader";
-
- private final LinkedList listeners = new LinkedList();
-
- protected boolean sdkLoaded = false;
-
- /**
- * The plug-in ID
- */
- public static final String PLUGIN_ID = "org.eclipse.andmore.android";
-
- /**
- * Studio for Android Perspective ID
- */
- public static final String PERSPECTIVE_ID = "org.eclipse.andmore.android.perspective";
-
- /**
- * Nature of Android projects
- */
- public static final String Android_Nature = IAndroidConstants.ANDROID_NATURE;
-
- /**
- * The Motorola Android Branding icon
- */
- public static final String ANDROID_MOTOROLA_BRAND_ICON_PATH = "icons/obj16/plate16.png";
-
- public static final String SHALL_UNEMBED_EMULATORS_PREF_KEY = "shallUnembedEmulators";
-
- // The shared instance
- private static AndroidPlugin plugin;
-
- public static final String NDK_LOCATION_PREFERENCE = PLUGIN_ID + ".ndkpath";
-
- public static final String CYGWIN_LOCATION_PREFERENCE = PLUGIN_ID + ".cigwinpath";
-
- public static final String WARN_ABOUT_HPROF_PREFERENCE = PLUGIN_ID + ".warnAboutHprofSaveAction";
-
- public static final String GCC_VERSION_PROPERTY = "gccversion";
-
- public static final String PLATFORM_PROPERTY = "platform";
-
- public static final String SRC_LOCATION_PROPERTY = "srclocation";
-
- public static final String OBJ_LOCATION_PROPERTY = "objlocation";
-
- public static final String LIB_LOCATION_PROPERTY = "liblocation";
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
- * )
- */
- @Override
- public void start(BundleContext context) throws Exception {
- AndmoreLogger.debug(AndroidPlugin.class, "Starting Andmore Plugin...");
-
- super.start(context);
- plugin = this;
-
- Thread t = new Thread("DDMS Setup") {
- @Override
- public void run() {
- IWorkbench workbench = PlatformUI.getWorkbench();
- IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
-
- /*
- * Linux problem with e4. Check if workbench window is done
- * before calling DDMSFacade#setup(). If the workbench window is
- * not done yet, then add a listener to the workbench window
- * that will be responsible to call DDMSFacade#setup(). It seems
- * that e4 changed its behavior when loading plugins, which was
- * causing deadlocks on linux startup. This workaround works in
- * any OS.
- */
- if (window != null) {
- AndmoreLogger.debug(AndroidPlugin.class, "Starting DDMS facade WITHOUT using listener...");
-
- DDMSFacade.setup();
-
- AndmoreLogger.debug(AndroidPlugin.class, "DDMS facade started WITHOUT using listener.");
- } else {
- workbench.addWindowListener(new IWindowListener() {
-
- @Override
- public void windowActivated(IWorkbenchWindow window) {
- // do nothing
- }
-
- @Override
- public void windowDeactivated(IWorkbenchWindow window) {
- // do nothing
- }
-
- @Override
- public void windowClosed(IWorkbenchWindow window) {
- // do nothing
- }
-
- @Override
- public void windowOpened(IWorkbenchWindow window) {
- AndmoreLogger.debug(AndroidPlugin.class, "Starting DDMS facade using listener...");
-
- DDMSFacade.setup();
-
- AndmoreLogger.debug(AndroidPlugin.class, "DDMS facade started using listener.");
- }
- });
- }
- };
- };
-
- getPreferenceStore().setDefault(AndroidPlugin.SHALL_UNEMBED_EMULATORS_PREF_KEY, true);
-
- // every time the Android SDK Job finishes its execution
- IJobManager manager = Job.getJobManager();
- manager.addJobChangeListener(new JobChangeAdapter() {
- @Override
- public void done(IJobChangeEvent event) {
- Job job = event.getJob();
- if (job != null) {
- String jobName = job.getName();
- if (jobName != null) {
- if (jobName.equals(ANDROID_SDK_CONTENT_LOADER_JOB)) {
-
- sdkLoaded = true;
-
- /*
- * Workaround The Listener should be copied in this
- * set, to avoid exceptions in the loop. The
- * exception occurs when a listener remove itself.
- */
- AndmoreLogger.debug(AndroidPlugin.this, "Notify SDK loader listeners");
- Set setListeners = new HashSet(listeners);
- for (Runnable listener : setListeners) {
- try {
- listener.run();
- } catch (Throwable e) {
- // Log error of this listener and keep
- // handling the next listener...
- AndmoreLogger.error(AndroidPlugin.class,
- "Error while handling SDK loader procedure.", e);
- }
- }
- }
- }
- }
- }
- });
- t.start();
-
- AndmoreLogger.debug(AndroidPlugin.class, "Andmore Plugin started.");
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
- * )
- */
- @Override
- public void stop(BundleContext context) throws Exception {
- plugin = null;
- super.stop(context);
- }
-
- /**
- * Add a Listener that will be executed after any SDK loader action.
- *
- * @param listener
- */
- public void addSDKLoaderListener(Runnable listener) {
- listeners.addLast(listener);
-
- if (sdkLoaded) {
- listener.run();
- }
- }
-
- /**
- * Remove the given Listener.
- *
- * @param listener
- */
- public void removeSDKLoaderListener(Runnable listener) {
- if (listeners.contains(listener)) {
- listeners.remove(listener);
- }
- }
-
- /**
- * Returns the shared instance
- *
- * @return the shared instance
- */
- public static AndroidPlugin getDefault() {
- return plugin;
- }
-
- /**
- * Creates and returns a new image descriptor for an image file in this
- * plug-in.
- *
- * @param path
- * the relative path of the image file, relative to the root of
- * the plug-in; the path must be legal
- * @return an image descriptor, or null if no image could be found
- */
- public static ImageDescriptor getImageDescriptor(String path) {
- return imageDescriptorFromPlugin(PLUGIN_ID, path);
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
+import org.eclipse.andmore.android.common.IAndroidConstants;
+import org.eclipse.andmore.android.common.log.AndmoreLogger;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class AndroidPlugin extends AbstractUIPlugin {
+ // Listening to this job, instead of loading sdk job, which seems to don't
+ // exist anymore.
+ private static final String ANDROID_SDK_CONTENT_LOADER_JOB = "Android SDK Content Loader";
+
+ private final LinkedList listeners = new LinkedList();
+
+ protected boolean sdkLoaded = false;
+
+ /**
+ * The plug-in ID
+ */
+ public static final String PLUGIN_ID = "org.eclipse.andmore.android";
+
+ /**
+ * Studio for Android Perspective ID
+ */
+ public static final String PERSPECTIVE_ID = "org.eclipse.andmore.android.perspective";
+
+ /**
+ * Nature of Android projects
+ */
+ public static final String Android_Nature = IAndroidConstants.ANDROID_NATURE;
+
+ /**
+ * The Motorola Android Branding icon
+ */
+ public static final String ANDROID_MOTOROLA_BRAND_ICON_PATH = "icons/obj16/plate16.png";
+
+ public static final String SHALL_UNEMBED_EMULATORS_PREF_KEY = "shallUnembedEmulators";
+
+ // The shared instance
+ private static AndroidPlugin plugin;
+
+ public static final String NDK_LOCATION_PREFERENCE = PLUGIN_ID + ".ndkpath";
+
+ public static final String CYGWIN_LOCATION_PREFERENCE = PLUGIN_ID + ".cigwinpath";
+
+ public static final String WARN_ABOUT_HPROF_PREFERENCE = PLUGIN_ID + ".warnAboutHprofSaveAction";
+
+ public static final String GCC_VERSION_PROPERTY = "gccversion";
+
+ public static final String PLATFORM_PROPERTY = "platform";
+
+ public static final String SRC_LOCATION_PROPERTY = "srclocation";
+
+ public static final String OBJ_LOCATION_PROPERTY = "objlocation";
+
+ public static final String LIB_LOCATION_PROPERTY = "liblocation";
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
+ * )
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ AndmoreLogger.debug(AndroidPlugin.class, "Starting Andmore Plugin...");
+
+ super.start(context);
+ plugin = this;
+ // The Device Monitor places a job on a queue which starts after the workbench is ready
+ DeviceMonitor.instance().start();
+/*
+ Thread t = new Thread("DDMS Setup") {
+ @Override
+ public void run() {
+
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+*/
+ /*
+ * Linux problem with e4. Check if workbench window is done
+ * before calling DDMSFacade#setup(). If the workbench window is
+ * not done yet, then add a listener to the workbench window
+ * that will be responsible to call DDMSFacade#setup(). It seems
+ * that e4 changed its behavior when loading plugins, which was
+ * causing deadlocks on linux startup. This workaround works in
+ * any OS.
+ *//*
+ if (window != null) {
+ AndmoreLogger.debug(AndroidPlugin.class, "Starting DDMS facade WITHOUT using listener...");
+
+ DDMSFacade.setup();
+
+ AndmoreLogger.debug(AndroidPlugin.class, "DDMS facade started WITHOUT using listener.");
+ } else {
+ workbench.addWindowListener(new IWindowListener() {
+
+ @Override
+ public void windowActivated(IWorkbenchWindow window) {
+ // do nothing
+ }
+
+ @Override
+ public void windowDeactivated(IWorkbenchWindow window) {
+ // do nothing
+ }
+
+ @Override
+ public void windowClosed(IWorkbenchWindow window) {
+ // do nothing
+ }
+
+ @Override
+ public void windowOpened(IWorkbenchWindow window) {
+ AndmoreLogger.debug(AndroidPlugin.class, "Starting DDMS facade using listener...");
+
+ DDMSFacade.setup();
+
+ AndmoreLogger.debug(AndroidPlugin.class, "DDMS facade started using listener.");
+ }
+ });
+ }
+ };
+ };
+*/
+ getPreferenceStore().setDefault(AndroidPlugin.SHALL_UNEMBED_EMULATORS_PREF_KEY, true);
+
+ // every time the Android SDK Job finishes its execution
+ IJobManager manager = Job.getJobManager();
+ manager.addJobChangeListener(new JobChangeAdapter() {
+ @Override
+ public void done(IJobChangeEvent event) {
+ Job job = event.getJob();
+ if (job != null) {
+ String jobName = job.getName();
+ if (jobName != null) {
+ if (jobName.equals(ANDROID_SDK_CONTENT_LOADER_JOB)) {
+
+ sdkLoaded = true;
+
+ /*
+ * Workaround The Listener should be copied in this
+ * set, to avoid exceptions in the loop. The
+ * exception occurs when a listener remove itself.
+ */
+ AndmoreLogger.debug(AndroidPlugin.this, "Notify SDK loader listeners");
+ Set setListeners = new HashSet(listeners);
+ for (Runnable listener : setListeners) {
+ try {
+ listener.run();
+ } catch (Throwable e) {
+ // Log error of this listener and keep
+ // handling the next listener...
+ AndmoreLogger.error(AndroidPlugin.class,
+ "Error while handling SDK loader procedure.", e);
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ //t.start();
+
+ AndmoreLogger.debug(AndroidPlugin.class, "Andmore Plugin started.");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
+ * )
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ DeviceMonitor.dispose();
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Add a Listener that will be executed after any SDK loader action.
+ *
+ * @param listener
+ */
+ public void addSDKLoaderListener(Runnable listener) {
+ listeners.addLast(listener);
+
+ if (sdkLoaded) {
+ listener.run();
+ }
+ }
+
+ /**
+ * Remove the given Listener.
+ *
+ * @param listener
+ */
+ public void removeSDKLoaderListener(Runnable listener) {
+ if (listeners.contains(listener)) {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static AndroidPlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Creates and returns a new image descriptor for an image file in this
+ * plug-in.
+ *
+ * @param path
+ * the relative path of the image file, relative to the root of
+ * the plug-in; the path must be legal
+ * @return an image descriptor, or null if no image could be found
+ */
+ public static ImageDescriptor getImageDescriptor(String path) {
+ return imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/DDMSUtils.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/DDMSUtils.java
index 917b6d6f..cfc4b9f7 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/DDMSUtils.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/DDMSUtils.java
@@ -152,7 +152,7 @@ public static void takeScreenshot(final String serialNumber) {
public void run() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
ScreenShotDialog sshot = new ScreenShotDialog(new Shell(shell));
- sshot.open(DDMSFacade.getDeviceBySerialNumber(serialNumber));
+ sshot.open(DeviceMonitor.instance().getDeviceBySerialNumber(serialNumber));
}
});
}
@@ -218,9 +218,9 @@ public static List getApplicationDatabases(String serialNumber, String a
String appDbPath = "/data/data/" + applicationName + "/databases/";
- Collection commandOutput = DDMSFacade.execRemoteApp(serialNumber, "ls " + appDbPath,
+ Collection commandOutput = DeviceMonitor.instance().execRemoteApp(serialNumber, "ls " + appDbPath,
new NullProgressMonitor());
- List dbPathCandidates = new ArrayList(commandOutput.size() + 10);
+ List dbPathCandidates = new ArrayList<>(commandOutput.size() + 10);
for (String commandOutline : commandOutput) {
String[] strings = commandOutline.split(" ");
@@ -240,7 +240,7 @@ public static List getApplicationDatabases(String serialNumber, String a
*/
private static FileListingService getFileListingService(String serialNumber) {
FileListingService fileListing = null;
- IDevice dev = DDMSFacade.getDeviceBySerialNumber(serialNumber);
+ IDevice dev = DeviceMonitor.instance().getDeviceBySerialNumber(serialNumber);
if (dev != null) {
synchronized (dev) {
fileListing = deviceFileListingServiceMap.get(serialNumber);
@@ -274,8 +274,8 @@ public static String[] getCurrentEmulatorLanguageAndCountry(final String serialN
try {
// Do not write the command output to the console
- languageCommandResult = DDMSFacade.executeCommand(languageCommand, null);
- countryCommandResult = DDMSFacade.executeCommand(countryCommand, null);
+ languageCommandResult = DeviceMonitor.instance().executeCommand(languageCommand, null);
+ countryCommandResult = DeviceMonitor.instance().executeCommand(countryCommand, null);
responses[0] = languageCommandResult.replaceAll("\\n$", "");
responses[1] = countryCommandResult.replaceAll("\\n$", "");
} catch (IOException e) {
@@ -320,7 +320,7 @@ public void run() {
bean.setCanOverwrite(wizard.canOverwrite());
}
} catch (Throwable e) {
- AndmoreLogger.error(DDMSFacade.class, "Error executing deploy wizard", e);
+ AndmoreLogger.error(DeviceMonitor.class, "Error executing deploy wizard", e);
}
}
});
@@ -395,7 +395,7 @@ public static IStatus installPackage(String serialNumber, String path, INSTALL_T
public static IStatus uninstallPackage(File path, String serialNumber, OutputStream processOut) {
IStatus returnStatus = null;
if ((path != null) && path.exists() && path.isFile()) {
- IDevice dev = DDMSFacade.getDeviceBySerialNumber(serialNumber);
+ IDevice dev = DeviceMonitor.instance().getDeviceBySerialNumber(serialNumber);
String apiLevel = dev.getProperty("ro.build.version.sdk");
IAndroidTarget target = SdkUtils.getTargetByAPILevel(Integer.parseInt(apiLevel));
String aaptPath = SdkUtils.getTargetAAPTPath(target);
@@ -434,7 +434,7 @@ public static IStatus uninstallPackage(File path, String serialNumber, OutputStr
}
} else {
- AndmoreLogger.error(DDMSFacade.class,
+ AndmoreLogger.error(DeviceMonitor.class,
"Impossible to check APK package name. No android targets found inside SDK");
}
@@ -458,7 +458,7 @@ public static IStatus uninstallPackage(String serialNumber, String packageName,
String command[] = createUninstallCommand(serialNumber, packageName);
try {
- String commandResult = DDMSFacade.executeCommand(command, processOutput);
+ String commandResult = DeviceMonitor.instance().executeCommand(command, processOutput);
if (!commandResult.toLowerCase().contains(SUCCESS_CONSTANT.toLowerCase())) {
status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
AndroidNLS.ERR_DDMSFacade_UninstallPackageError + ": " + packageName);
@@ -467,7 +467,7 @@ public static IStatus uninstallPackage(String serialNumber, String packageName,
} catch (Exception e) {
status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
AndroidNLS.ERR_DDMSFacade_UninstallPackageException, e);
- AndmoreLogger.error(DDMSFacade.class, "Failed to remove package: " + packageName + ". " + e.getMessage());
+ AndmoreLogger.error(DeviceMonitor.class, "Failed to remove package: " + packageName + ". " + e.getMessage());
}
return status;
}
@@ -487,11 +487,11 @@ public static IStatus runMonkey(String serialNumber, String allPackages, OutputS
String command[] = createMonkeyCommand(serialNumber, allPackages, otherCmd);
try {
- DDMSFacade.executeCommand(command, processOutput);
+ DeviceMonitor.instance().executeCommand(command, processOutput);
} catch (Exception e) {
EclipseUtils.showErrorDialog(AndroidNLS.UI_MonkeyError_Title, AndroidNLS.UI_MonkeyError_Msg);
- AndmoreLogger.error(DDMSFacade.class, "Failed to run monkey command: " + command + " " + e.getMessage());
+ AndmoreLogger.error(DeviceMonitor.class, "Failed to run monkey command: " + command + " " + e.getMessage());
}
return status;
}
@@ -776,11 +776,11 @@ public static Map listInstalledPackages(String serialNumber) thr
Map packages = new LinkedHashMap();
String sdkPath = SdkUtils.getSdkPath();
String command[] = new String[] {
- sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, DDMSFacade.SHELL_CMD, PM_CMD, PM_LIST_DIRECTIVE,
+ sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, DeviceMonitor.SHELL_CMD, PM_CMD, PM_LIST_DIRECTIVE,
PM_PACKAGES_DIRECTIVE, PM_PACKAGES_DIRECTIVE_FORCE };
- String commResult = DDMSFacade.executeCommand(command, null);
+ String commResult = DeviceMonitor.instance().executeCommand(command, null);
String[] packageList = null;
if ((commResult != null) && (commResult.length() > 0) && !commResult.contains("system running?")) {
packageList = commResult.trim().replaceAll("\n\n", "\n").split("\n");
@@ -831,7 +831,7 @@ public static IStatus installPackage(String serialNumber, String path, boolean c
}
// Return if instance is not started
- if (status.isOK() && !DDMSFacade.isDeviceOnline(serialNumber)) {
+ if (status.isOK() && !DeviceMonitor.instance().isDeviceOnline(serialNumber)) {
AndmoreLogger.error("Abort deploy operation. Device is not online.");
status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, "");
}
@@ -840,7 +840,7 @@ public static IStatus installPackage(String serialNumber, String path, boolean c
if (status.isOK()) {
try {
String[] cmd = createInstallCommand(canOverwrite, path, serialNumber);
- command_results = DDMSFacade.executeCommand(cmd, processOut, serialNumber);
+ command_results = DeviceMonitor.instance().executeCommand(cmd, processOut, serialNumber);
// Check if the result has a success message
if (!command_results.contains(SUCCESS_CONSTANT)) {
@@ -890,7 +890,7 @@ public void run() {
consoleOut.write(AndroidNLS.UI_ChangeLang_Country + " " + country + "\n");
}
- DDMSFacade.executeCommand(cmd, consoleOut);
+ DeviceMonitor.instance().executeCommand(cmd, consoleOut);
consoleOut.write("\n " + serialNumber + ":" + AndroidNLS.UI_ChangeLang_Restart_Device_Manually
+ "\n\n");
AndmoreEventManager.fireEvent(EventType.LANGUAGE_CHANGED, serialNumber);
@@ -932,19 +932,19 @@ private static String[] createChangeLanguageCommand(String serialNumber, String
// The tools folder should exist and be here, but double-checking
// once more wont kill
- File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
+ File f = new File(sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists()) {
- AndmoreLogger.error("Language: Could not find tools folder on " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Language: Could not find tools folder on " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
} else {
if (!f.isDirectory()) {
- AndmoreLogger.error("Language: Invalid tools folder " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Language: Invalid tools folder " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
}
}
- String cmdTemp[] = { sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, "shell", CHANGE_LANGUAGE_CMD };
+ String cmdTemp[] = { sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, "shell", CHANGE_LANGUAGE_CMD };
cmd = cmdTemp;
return cmd;
@@ -968,21 +968,21 @@ private static ArrayList createCurrentEmulatorLanguageAndCountryComman
String GET_COUNTRY_CMD = "getprop persist.sys.country";
// The tools folder should exist and be here, but double-cheking
// once more wont kill
- File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
+ File f = new File(sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists()) {
- AndmoreLogger.error("Language: Could not find tools folder on " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Language: Could not find tools folder on " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
} else {
if (!f.isDirectory()) {
- AndmoreLogger.error("Language: Invalid tools folder " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Language: Invalid tools folder " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
}
}
- String langCmdTemp[] = { sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, "shell", GET_LANGUAGE_CMD };
+ String langCmdTemp[] = { sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, "shell", GET_LANGUAGE_CMD };
String countryCmdTemp[] = {
- sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, "shell", GET_COUNTRY_CMD };
+ sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, "shell", GET_COUNTRY_CMD };
languageCommand = langCmdTemp;
countryCommand = countryCmdTemp;
@@ -1011,13 +1011,13 @@ private static String[] createInstallCommand(boolean canOverwrite, String path,
// The tools folder should exist and be here, but double-checking
// once more wont kill
- File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
+ File f = new File(sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists()) {
- AndmoreLogger.error("Deploy: Could not find tools folder on " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Deploy: Could not find tools folder on " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
} else {
if (!f.isDirectory()) {
- AndmoreLogger.error("Deploy: Invalid tools folder " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Deploy: Invalid tools folder " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
}
}
@@ -1025,14 +1025,14 @@ private static String[] createInstallCommand(boolean canOverwrite, String path,
if (canOverwrite) {
// If overwrite option is checked, create command with the -r
// paramater
- String cmdTemp[] = { sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, INSTALL_CMD, ADB_INSTALL_OVERWRITE, path };
+ String cmdTemp[] = { sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, INSTALL_CMD, ADB_INSTALL_OVERWRITE, path };
cmd = cmdTemp;
} else {
// If overwrite option is unchecked, create command without the -r
// paramater
- String cmdTemp[] = { sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, INSTALL_CMD, path };
+ String cmdTemp[] = { sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, INSTALL_CMD, path };
cmd = cmdTemp;
}
@@ -1043,19 +1043,19 @@ private static String[] createUninstallCommand(String serialNumber, String packa
String sdkPath = SdkUtils.getSdkPath();
// The tools folder should exist and be here, but double-checking
// once more wont kill
- File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
+ File f = new File(sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists()) {
- AndmoreLogger.error("Run: Could not find tools folder on " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Run: Could not find tools folder on " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
} else {
if (!f.isDirectory()) {
- AndmoreLogger.error("Run: Invalid tools folder " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Run: Invalid tools folder " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
}
}
- String cmd[] = { sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, DDMSFacade.SHELL_CMD, PM_CMD, PM_UNINSTALL_DIRECTIVE,
+ String cmd[] = { sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, DeviceMonitor.SHELL_CMD, PM_CMD, PM_UNINSTALL_DIRECTIVE,
packageName };
return cmd;
@@ -1075,19 +1075,19 @@ private static String[] createMonkeyCommand(String serialNumber, String packages
String sdkPath = SdkUtils.getSdkPath();
// The tools folder should exist and be here, but double-checking
// once more wont kill
- File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
+ File f = new File(sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists()) {
- AndmoreLogger.error("Run: Could not find tools folder on " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Run: Could not find tools folder on " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
} else {
if (!f.isDirectory()) {
- AndmoreLogger.error("Run: Invalid tools folder " + sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER
+ AndmoreLogger.error("Run: Invalid tools folder " + sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER
+ File.separator);
}
}
- String cmd[] = { sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator + DDMSFacade.ADB_COMMAND,
- DDMSFacade.ADB_INSTANCE_PARAMETER, serialNumber, DDMSFacade.SHELL_CMD, MONKEY_CMD, packagesName,
+ String cmd[] = { sdkPath + DeviceMonitor.PLATFORM_TOOLS_FOLDER + File.separator + DeviceMonitor.ADB_COMMAND,
+ DeviceMonitor.ADB_INSTANCE_PARAMETER, serialNumber, DeviceMonitor.SHELL_CMD, MONKEY_CMD, packagesName,
otherCmd };
return cmd;
@@ -1126,7 +1126,7 @@ public void run() {
if (selectedAppSet[0] != null) {
// Dump HPROF file based on the selected application
- status = DDMSFacade.dumpHprofFile(selectedAppSet[0], serialNumber, monitor);
+ status = DeviceMonitor.instance().dumpHprofFile(selectedAppSet[0], serialNumber, monitor);
} else {
status = Status.CANCEL_STATUS;
}
@@ -1136,7 +1136,7 @@ public void run() {
public static int getDeviceApiVersion(String serialNumber) {
int deviceSdkVersion = -1;
- String deviceProperty = DDMSFacade.getDeviceProperty(serialNumber, "ro.build.version.sdk");
+ String deviceProperty = DeviceMonitor.instance().getDeviceProperty(serialNumber, "ro.build.version.sdk");
if (deviceProperty != null) {
deviceSdkVersion = Integer.parseInt(deviceProperty);
}
@@ -1146,7 +1146,7 @@ public static int getDeviceApiVersion(String serialNumber) {
public static boolean remoteFileExists(String serialNumber, String remotePath) throws IOException {
boolean found = false;
- Collection results = DDMSFacade.execRemoteApp(serialNumber,
+ Collection results = DeviceMonitor.instance().execRemoteApp(serialNumber,
"ls " + FileUtil.getEscapedPath(remotePath, Platform.OS_LINUX), new NullProgressMonitor());
for (String result : results) {
if (result.equals(remotePath)) {
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/DDMSFacade.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/DeviceMonitor.java
similarity index 72%
rename from andmore-core/plugins/android/src/org/eclipse/andmore/android/DDMSFacade.java
rename to andmore-core/plugins/android/src/org/eclipse/andmore/android/DeviceMonitor.java
index 90d5d3f7..4eb30ff4 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/DDMSFacade.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/DeviceMonitor.java
@@ -25,6 +25,7 @@
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -32,6 +33,9 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -41,17 +45,18 @@
import org.eclipse.andmore.android.common.IAndroidConstants;
import org.eclipse.andmore.android.common.exception.AndroidException;
import org.eclipse.andmore.android.common.log.AndmoreLogger;
-import org.eclipse.andmore.android.common.log.UsageDataConstants;
import org.eclipse.andmore.android.i18n.AndroidNLS;
import org.eclipse.andmore.android.utilities.TelnetFrameworkAndroid;
import org.eclipse.andmore.ddms.DdmsPlugin;
import org.eclipse.andmore.internal.preferences.AdtPrefs;
+import org.eclipse.andmore.service.AdtStartupService;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
@@ -60,8 +65,10 @@
import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
+import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
import com.android.ddmlib.Client;
import com.android.ddmlib.ClientData;
+import com.android.ddmlib.ClientData.HprofData;
import com.android.ddmlib.EmulatorConsole;
import com.android.ddmlib.FileListingService;
import com.android.ddmlib.FileListingService.FileEntry;
@@ -81,51 +88,50 @@
*
* USAGE: Use the public methods to use DDMS
*/
-public class DDMSFacade {
+public class DeviceMonitor implements IClientChangeListener, IDeviceChangeListener {
/**
- * Command for switching back to USB connection mode.
+ * Defines a stop condition
*/
- private static final String USB_SWITCH_BACK_COMMAND = "usb"; //$NON-NLS-1$
+ interface IStopCondition {
+ public boolean canStop();
+ }
/**
- * Argument which indicates the device to apply a certain command.
+ * The plug-in ID
*/
- private static final String DEVICE_ID_INDICATOR = "-s"; //$NON-NLS-1$
-
- private static final String DEFAULT_WIRELESS_DEVICE_PROPERTY = "tiwlan0"; //$NON-NLS-1$
+ public static final String PLUGIN_ID = "org.eclipse.andmore.android";
/**
- * Map containing all connected devices. It is being kept for us not to
- * depend on ADT every time we need one, preventing deadlocks.
+ * Command for switching back to USB connection mode.
*/
- private static final Map connectedDevices = new HashMap();
+ private static final String USB_SWITCH_BACK_COMMAND = "usb"; //$NON-NLS-1$
/**
- * Set containing the serial numbers of the devices completely loaded. A
- * device is considered completely loaded if it has already loaded the HOME
- * application.
+ * Argument which indicates the device to apply a certain command.
*/
- private static final Set completelyUpDevices = new HashSet();
+ private static final String DEVICE_ID_INDICATOR = "-s"; //$NON-NLS-1$
+
+ private static final String DEFAULT_WIRELESS_DEVICE_PROPERTY = "tiwlan0"; //$NON-NLS-1$
/**
* Folder located inside the SDK folder containing some sdk tools.
*/
- static final String TOOLS_FOLDER = IAndroidConstants.FD_TOOLS;
+ final static String TOOLS_FOLDER = IAndroidConstants.FD_TOOLS;
/**
* Folder located inside the SDK folder and containing the ADB.
*/
- static final String PLATFORM_TOOLS_FOLDER = IAndroidConstants.FD_PLATFORM_TOOLS;
+ final static String PLATFORM_TOOLS_FOLDER = IAndroidConstants.FD_PLATFORM_TOOLS;
/**
* adb (android debug bridge) command.
*/
- static final String ADB_COMMAND = "adb"; //$NON-NLS-1$
+ final static String ADB_COMMAND = "adb"; //$NON-NLS-1$
/**
* Command to concatenate with "adb" to have the device shell.
*/
- static final String SHELL_CMD = "shell"; //$NON-NLS-1$
+ final static String SHELL_CMD = "shell"; //$NON-NLS-1$
/**
* Options to be used with adb to indicate run operation.
@@ -151,7 +157,7 @@ public class DDMSFacade {
/**
* Parameter for selecting emulator instance.
*/
- static final String ADB_INSTANCE_PARAMETER = DEVICE_ID_INDICATOR;
+ final static String ADB_INSTANCE_PARAMETER = DEVICE_ID_INDICATOR;
/**
* Folder for the SDK.
@@ -174,10 +180,6 @@ public class DDMSFacade {
private static final String IFCONFIG_CMD = "ifconfig"; //$NON-NLS-1$
- static Object consoleLock = new Object();
-
- private static Map avdNameMap = new HashMap();
-
/**
* Property from device which represents the wi-fi value to use ipconfig
* command.
@@ -191,183 +193,55 @@ public class DDMSFacade {
+ ZERO_TO_255_PATTERN + "\\." + ZERO_TO_255_PATTERN + "\\." + ZERO_TO_255_PATTERN //$NON-NLS-1$ //$NON-NLS-2$
+ ")+"; //$NON-NLS-1$
- /**
- * Must be called only once, during AndroidPlugin start-up. This method
- * configures all necessary device listeners.
- */
- public static void setup() {
- AndroidPlugin.getDefault().addSDKLoaderListener(new Runnable() {
-
- @Override
- public void run() {
- AndroidDebugBridge adb = AndroidDebugBridge.getBridge();
- if (adb == null) {
- AndroidDebugBridge.disconnectBridge();
- DdmsPlugin.setToolsLocation(AndmoreAndroidPlugin.getOsAbsoluteAdb(), true, AndmoreAndroidPlugin.getOsAbsoluteHprofConv(),
- AndmoreAndroidPlugin.getOsAbsoluteTraceview());
- }
-
- if (adb != null) {
- IDevice[] x = adb.getDevices();
- IDevice[] newDevices = x;
- List oldDevList = new ArrayList(connectedDevices.values());
-
- for (IDevice newDev : newDevices) {
- String serialNum = newDev.getSerialNumber();
- if (connectedDevices.containsKey(serialNum)) {
- IDevice oldDev = connectedDevices.get(serialNum);
- oldDevList.remove(oldDev);
- if (oldDev.getState().compareTo((newDev).getState()) != 0) {
- if ((newDev).getState() == DeviceState.OFFLINE) {
- deviceDisconnected(newDev);
- } else if ((newDev).getState() == DeviceState.ONLINE) {
- deviceConnected(newDev);
- }
- }
- } else {
- deviceConnected(newDev);
- }
- }
-
- for (IDevice oldDev : oldDevList) {
- deviceDisconnected(oldDev);
- }
- }
-
- }
- });
-
- // Adds listener for the HOME application. It adds the serial number of
- // the
- // device to a collection when it identifies that the HOME application
- // has
- // loaded
- AndroidDebugBridge.addClientChangeListener(new IClientChangeListener() {
+ /** Maximum time to wait for notification */
+ private static final long MAX_WAIT_TIME = 20000;
+ private static final IDevice NULL_DEVICE;
- @Override
- public void clientChanged(Client client, int changeMask) {
- if ((changeMask & Client.CHANGE_NAME) == Client.CHANGE_NAME) {
- final Client finalClient = client;
- Thread t = new Thread() {
-
- @Override
- public void run() {
- String applicationName = finalClient.getClientData().getClientDescription();
- if (applicationName != null) {
- IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
- String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
- if (home.equals(applicationName)) {
- String serialNum = finalClient.getDevice().getSerialNumber();
- synchronized (completelyUpDevices) {
- AndmoreLogger.debug("Completely Up Device: " + serialNum); //$NON-NLS-1$
- completelyUpDevices.add(serialNum);
- }
- }
- }
- }
- };
- t.start();
- }
- }
- });
- }
+ private static final String NULL_SERIAL_NUMBER = "%s called with null serial number";
- static void deviceStatusChanged(IDevice device) {
- AndmoreLogger.debug("Device changed: " + device.getSerialNumber()); //$NON-NLS-1$
- synchronized (connectedDevices) {
- connectedDevices.put(device.getSerialNumber(), device);
- }
- if ((device).getState() == DeviceState.ONLINE) {
- IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
- String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
- if (device.getClient(home) != null) {
- synchronized (completelyUpDevices) {
- AndmoreLogger.debug("Completely Up Device: " + device.getSerialNumber()); //$NON-NLS-1$
- if (!completelyUpDevices.contains(device.getSerialNumber())) {
- completelyUpDevices.add(device.getSerialNumber());
- }
- }
- }
- }
+ private static DeviceMonitor singleton;
+
+ static
+ {
+ NULL_DEVICE = new NullDevice();
}
-
+
+ private String sdkPath;
+
/**
- * Registers a device as connected
- *
- * @param device
+ * Map containing all connected devices. It is being kept for us not to
+ * depend on ADT every time we need one, preventing deadlocks.
*/
- static void deviceConnected(IDevice device) {
- final String serialNumber = device.getSerialNumber();
- AndmoreLogger.debug("Device connected: " + serialNumber); //$NON-NLS-1$
- synchronized (connectedDevices) {
- connectedDevices.put(serialNumber, device);
- }
+ private final Map connectedDevices = new ConcurrentHashMap();
- if (!device.isEmulator() && !device.hasClients()) {
- boolean timeout = false;
- long startTime = System.currentTimeMillis();
- int maxInterval = 10000;
- do {
- try {
- Thread.sleep(250);
- } catch (InterruptedException e) {
- // do nothing
- }
- long currentTime = System.currentTimeMillis();
- timeout = ((startTime + maxInterval) < currentTime);
-
- } while (!device.hasClients() && !timeout);
- if (timeout) {
- synchronized (completelyUpDevices) {
- // put the device up anyway.
- completelyUpDevices.add(serialNumber);
- }
- }
- }
-
- if (device.hasClients()) {
- // When a device is connected, look for the HOME application and add
- // the device serial number to a collection if it is already
- // running.
- IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
- String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
- if (device.getClient(home) != null) {
- AndmoreLogger.debug("Completely Up Device: " + serialNumber); //$NON-NLS-1$
- synchronized (completelyUpDevices) {
- completelyUpDevices.add(serialNumber);
- }
- }
- }
+ /**
+ * Set containing the serial numbers of the devices completely loaded. A
+ * device is considered completely loaded if it has already loaded the HOME
+ * application.
+ */
+ private final Set completelyUpDevices = new HashSet();
- AndmoreEventManager.fireEvent(EventType.DEVICE_CONNECTED, serialNumber);
- }
+ private Map avdNameMap = new HashMap();
+ /** Set of client PIDs used for notification */
+ private final HashMap clientPidSet = new HashMap<>();
+ private Object consoleLock = new Object();
/**
- * Unregisters a device as connected
- *
- * @param device
+ * Private constructor to enforce singletion
*/
- static void deviceDisconnected(IDevice device) {
- final String serialNumber = device.getSerialNumber();
- AndmoreLogger.debug("Device disconnected: " + serialNumber); //$NON-NLS-1$
- synchronized (completelyUpDevices) {
- completelyUpDevices.remove(serialNumber);
- }
- synchronized (connectedDevices) {
- connectedDevices.remove(serialNumber);
- }
- AndmoreEventManager.fireEvent(EventType.DEVICE_DISCONNECTED, serialNumber);
- avdNameMap.remove(device.getSerialNumber());
-
+ private DeviceMonitor() {
+
}
-
+
/**
* Get all connected device serial numbers
*
* @return
*/
- public static Collection getConnectedSerialNumbers() {
- return connectedDevices.keySet();
+ public Collection getConnectedSerialNumbers() {
+ List deviceList = new ArrayList<>();
+ deviceList.addAll(connectedDevices.keySet());
+ return deviceList;
}
/**
@@ -377,7 +251,11 @@ public static Collection getConnectedSerialNumbers() {
* Serial number of the device to retrieve
* @return Device associated with the given serial number
*/
- public static IDevice getDeviceBySerialNumber(String serialNumber) {
+ public IDevice getDeviceBySerialNumber(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "getDeviceBySerialNumber"));
+ return NULL_DEVICE;
+ }
return connectedDevices.get(serialNumber);
}
@@ -395,20 +273,20 @@ public static IDevice getDeviceBySerialNumber(String serialNumber) {
*
* @return An IStatus object with the result of the operation
*/
- public static IStatus runActivity(String serialNumber, String activityName, boolean debugMode,
+ public IStatus runActivity(String serialNumber, String activityName, boolean debugMode,
OutputStream processOut) {
IStatus status = Status.OK_STATUS;
// Return if no instance is selected
if (serialNumber == null) {
AndmoreLogger.error("Abort run operation. Serial number is null."); //$NON-NLS-1$
- return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, AndroidNLS.ERR_DDMSFacade_SerialNumberNullPointer);
+ return new Status(IStatus.ERROR, PLUGIN_ID, AndroidNLS.ERR_DDMSFacade_SerialNumberNullPointer);
}
// Return if instance is not started
if (!isDeviceOnline(serialNumber)) {
AndmoreLogger.error("Abort run operation. Device is not online."); //$NON-NLS-1$
- return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
+ return new Status(IStatus.ERROR, PLUGIN_ID, ""); //$NON-NLS-1$
}
try {
@@ -416,339 +294,97 @@ public static IStatus runActivity(String serialNumber, String activityName, bool
executeCommand(cmd, processOut);
} catch (IOException e) {
AndmoreLogger.error("Deploy: Could not execute adb install command."); //$NON-NLS-1$
- status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage());
+ status = new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage());
}
return status;
}
- static String executeCommand(String[] cmd, OutputStream out) throws IOException {
+ public String executeCommand(String[] cmd, OutputStream out) throws IOException {
return executeCommand(cmd, out, null);
}
/**
- * DOCUMENT ME!!
+ * Check if the device is Online (i.e. if it's possible to communicate with
+ * it) Notice it is a verification of the status of the Device which may be
+ * different than the status of the Tml Instance.
*
- * @param cmd
- * @param out
* @param serialNumber
- * @return
- * @throws IOException
+ * @return true if the Device is online, false otherwise
*/
- static String executeCommand(String[] cmd, OutputStream out, String serialNumber) throws IOException {
- String fullCmd = ""; //$NON-NLS-1$
- if (out != null) {
- for (String cmdArg : cmd) {
- fullCmd += cmdArg + " "; //$NON-NLS-1$
- }
- out.write(fullCmd.getBytes());
- out.write("\n".getBytes()); //$NON-NLS-1$
+ public boolean isDeviceOnline(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "isDeviceOnline"));
+ return false;
}
-
- Runtime r = Runtime.getRuntime();
- Process p = r.exec(cmd);
-
- String command_results = ""; //$NON-NLS-1$
- InputStream processIn = p.getInputStream();
- final BufferedReader br = new BufferedReader(new InputStreamReader(processIn));
- String line;
- try {
- while ((line = br.readLine()) != null) {
- command_results += line;
- command_results += "\n"; //$NON-NLS-1$
- if (out != null) {
- if (serialNumber != null) {
- out.write((serialNumber + ": ").getBytes()); //$NON-NLS-1$
- }
- out.write(line.getBytes());
- out.write("\n".getBytes()); //$NON-NLS-1$
- }
- }
- } finally {
- br.close();
+ IDevice device = getDeviceBySerialNumber(serialNumber);
+ if ((device == null) || !device.isOnline()) {
+ return false;
}
-
- return command_results;
+ return true;
}
/**
- * See http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html to
- * understand how Process.exec works and its problems
- *
- * @param cmd
- * Command to be executed.
- * @param out
- * Output Stream.
- * @param timeout
- * Timeout (secs.)
- * @param monitor
- * {@link IProgressMonitor}
+ * Return true if the Device is being shown on the OFFLINE state.
*
- * @return the {@link IStatus} of this process execution.
+ * @param serialNumber
+ * Device�s serial number.
*
- * @throws IOException
- * Exception thrown in case there is any problem executing the
- * command.
+ * @return true in case the Device if offline,
+ * false otherwise.
*/
- private static IStatus executeRemoteDevicesCommand(String[] cmd, OutputStream out, int timeout, String timeoutMsg,
- IStopCondition stopCondition, IProgressMonitor monitor) throws IOException {
-
- IStatus status = Status.OK_STATUS;
-
- long timeoutLimit = -1;
- if (timeout != 0) {
- timeoutLimit = System.currentTimeMillis() + (timeout * 1000);
+ public boolean isDeviceOffline(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "isDeviceOffline"));
+ return true;
}
+ IDevice device = getDeviceBySerialNumber(serialNumber);
+ return ((device == null) || ((device != null) && device.isOffline()));
+ }
- String fullCmd = ""; //$NON-NLS-1$
- for (String cmdArg : cmd) {
- fullCmd += cmdArg + " "; //$NON-NLS-1$
+ /**
+ * Check if the device is completely loaded A device is completely loaded
+ * when it loads the HOME application
+ *
+ * @param serialNumber
+ * @return true if the Device has completely loaded; false otherwise
+ */
+ public boolean isDeviceCompletelyLoaded(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "isDeviceComplietelyLoaded"));
+ return false;
}
- if (out != null) {
- out.write(fullCmd.getBytes());
- out.write("\n".getBytes()); //$NON-NLS-1$
+ boolean isCompletelyLoaded = false;
+ synchronized (completelyUpDevices) {
+ isCompletelyLoaded = completelyUpDevices.contains(serialNumber);
}
+ return isCompletelyLoaded;
+ }
- Runtime r = Runtime.getRuntime();
- Process p = r.exec(cmd);
-
- int errorCode = 0;
+ /**
+ * Tests if the device represented by the serial number (if it exists) is an
+ * emulator
+ *
+ * @param serialNumber
+ * @return true if it is an emulator, false if not or non existent
+ */
+ public boolean isEmulator(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "isEmulator"));
+ return false;
+ }
+ IDevice device = getDeviceBySerialNumber(serialNumber);
+ if ((device != null) && device.isEmulator()) {
+ return true;
+ }
+ return false;
+ }
- // inputStream / errorStream;
- String[] commandResults = new String[] { "", "" //$NON-NLS-1$ //$NON-NLS-2$
- };
-
- commandResults = readCmdOutputFromStreams(commandResults[0], commandResults[1], p.getInputStream(),
- p.getErrorStream(), out);
-
- while (!stopCondition.canStop()) {
- if ((monitor != null) && (monitor.isCanceled())) {
- p.destroy();
- return Status.CANCEL_STATUS;
- }
-
- try {
- errorCode = p.exitValue();
- if (errorCode != 0) {
- break;
- }
-
- } catch (IllegalThreadStateException e) {
- // Process is still running... Proceed with loop
- }
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- AndmoreLogger.error("Execute command: thread has been interrupted"); //$NON-NLS-1$
- }
-
- if (timeout > 0) {
- try {
- testTimeout(timeoutLimit, ((timeoutMsg != null) ? timeoutMsg : AndroidNLS.ERR_GenericTimeout));
- } catch (TimeoutException e) {
- p.destroy();
- AndmoreLogger.debug("The timeout " + timeout //$NON-NLS-1$
- + " has been reached when executing the command " + fullCmd); //$NON-NLS-1$
- return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage(), e);
- }
- }
-
- }
-
- commandResults = readCmdOutputFromStreams(commandResults[0], commandResults[1], p.getInputStream(),
- p.getErrorStream(), out);
-
- if (errorCode != 0) {
- AndmoreLogger.debug("Command " + cmd + " returned an error code: " + errorCode); //$NON-NLS-1$ //$NON-NLS-2$
- status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
- NLS.bind(AndroidNLS.ERR_CommandError, errorCode) + "\n" //$NON-NLS-1$
- + ((!commandResults[1].equals("")) ? commandResults[1] //$NON-NLS-1$
- : commandResults[0]));
- } else {
- status = new Status(IStatus.OK, AndroidPlugin.PLUGIN_ID, commandResults[0]);
- }
-
- return status;
- }
-
- /**
- * Defines a stop condition
- */
- interface IStopCondition {
- public boolean canStop();
- }
-
- /**
- * @param commandResults
- * @param errorResults
- * @param inputStream
- * @param errorStream
- * @param out
- */
- private static String[] readCmdOutputFromStreams(String commandResults, String errorResults,
- InputStream inputStream, InputStream errorStream, OutputStream out) {
- String[] results = new String[2];
- String line = ""; //$NON-NLS-1$
-
- BufferedReader brInput = new BufferedReader(new InputStreamReader(inputStream));
- BufferedReader brError = new BufferedReader(new InputStreamReader(errorStream));
-
- try {
-
- // input stream
- if (brInput.ready()) {
- while ((line = brInput.readLine()) != null) {
- commandResults += line;
- commandResults += "\n"; //$NON-NLS-1$
- if (out != null) {
- out.write(line.getBytes());
- out.write("\n".getBytes()); //$NON-NLS-1$
- }
- }
- }
-
- // error stream
- if (brError.ready()) {
- while ((line = brError.readLine()) != null) {
- errorResults += "\n"; //$NON-NLS-1$
- if (out != null) {
- out.write(line.getBytes());
- out.write("\n".getBytes()); //$NON-NLS-1$
- }
- }
- }
- } catch (IOException e) {
- AndmoreLogger.error("Cannot read command outputs"); //$NON-NLS-1$
- } finally {
- try {
- brInput.close();
- brError.close();
- } catch (IOException e) {
- AndmoreLogger.error("Could not close console stream: " + e.getMessage());
- }
- }
-
- results[0] = commandResults;
- results[1] = errorResults;
-
- return results;
-
- }
-
- /**
- * Checks if the timeout limit has reached.
- *
- * @param timeoutLimit
- * The system time limit that cannot be overtaken, in
- * milliseconds.
- * @throws StartTimeoutException
- * When the system time limit is overtaken.
- */
- private static void testTimeout(long timeoutLimit, String timeoutErrorMessage) throws TimeoutException {
- if (System.currentTimeMillis() > timeoutLimit) {
- throw new TimeoutException(timeoutErrorMessage);
- }
- }
-
- /**
- * Creates a string with the command that should be called in order to run
- * the application.
- */
- private static String[] createRunCommand(String serialNumber, String activityName, boolean debugMode) {
- String cmd[];
- String sdkPath = SdkUtils.getSdkPath();
-
- // The tools folder should exist and be here, but double-cheking
- // once more wont kill
- File f = new File(sdkPath + PLATFORM_TOOLS_FOLDER + File.separator);
- if (!f.exists()) {
- AndmoreLogger.error("Run: Could not find tools folder on " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
- + File.separator);
- } else {
- if (!f.isDirectory()) {
- AndmoreLogger.error("Run: Invalid tools folder " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
- + File.separator);
- }
- }
-
- String completeAppPath = activityName.substring(0, activityName.lastIndexOf(".")) + "/" + activityName; //$NON-NLS-1$ //$NON-NLS-2$
- if (debugMode) {
- // If debugMode option is checked, create command with the -D
- // paramater
- String cmdTemp[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
- ADB_INSTANCE_PARAMETER, serialNumber, SHELL_CMD, AM_CMD, START_CMD, ADB_AM_DEBUG, ADB_AM_NAME,
- completeAppPath };
- cmd = cmdTemp;
- } else {
- // If debugMode option is unchecked, create command without the -D
- // paramater
- String cmdTemp[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
- ADB_INSTANCE_PARAMETER, serialNumber, SHELL_CMD, AM_CMD, START_CMD, ADB_AM_NAME, completeAppPath };
- cmd = cmdTemp;
- }
-
- return cmd;
- }
-
- /**
- * Check if the device is Online (i.e. if it's possible to communicate with
- * it) Notice it is a verification of the status of the Device which may be
- * different than the status of the Tml Instance.
- *
- * @param serialNumber
- * @return true if the Device is online, false otherwise
- */
- public static boolean isDeviceOnline(String serialNumber) {
- IDevice device = getDeviceBySerialNumber(serialNumber);
- if ((device == null) || !device.isOnline()) {
+ public boolean isRemote(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "isRemote"));
return false;
}
- return true;
- }
-
- /**
- * Return true if the Device is being shown on the OFFLINE state.
- *
- * @param serialNumber
- * Device�s serial number.
- *
- * @return true in case the Device if offline,
- * false otherwise.
- */
- public static boolean isDeviceOffline(String serialNumber) {
-
- IDevice device = getDeviceBySerialNumber(serialNumber);
- return ((device == null) || ((device != null) && device.isOffline()));
- }
-
- /**
- * Check if the device is completely loaded A device is completely loaded
- * when it loads the HOME application
- *
- * @param serialNumber
- * @return true if the Device has completely loaded; false otherwise
- */
- public static boolean isDeviceCompletelyLoaded(String serialNumber) {
- return completelyUpDevices.contains(serialNumber);
- }
-
- /**
- * Tests if the device represented by the serial number (if it exists) is an
- * emulator
- *
- * @param serialNumber
- * @return true if it is an emulator, false if not or non existent
- */
- public static boolean isEmulator(String serialNumber) {
- IDevice device = getDeviceBySerialNumber(serialNumber);
- if ((device != null) && device.isEmulator()) {
- return true;
- }
- return false;
- }
-
- public static boolean isRemote(String serialNumber) {
// firstly, test if the serial number has the format "anything:digits"
Pattern p = Pattern.compile("(.)+:(\\d)+"); //$NON-NLS-1$
Matcher m = p.matcher(serialNumber);
@@ -776,7 +412,7 @@ public static boolean isRemote(String serialNumber) {
*
* @throws IOException
*/
- public static Collection execRemoteApp(String serialNumber, String remoteCommand,
+ public Collection execRemoteApp(String serialNumber, String remoteCommand,
final IProgressMonitor monitor) throws IOException {
return executeShellCmd(serialNumber, remoteCommand, monitor);
}
@@ -793,8 +429,12 @@ public static Collection execRemoteApp(String serialNumber, String remot
*
* @throws IOException
*/
- public static Map> execRemoteApp(String serialNumber, Collection remoteCommands,
+ public Map> execRemoteApp(String serialNumber, Collection remoteCommands,
final IProgressMonitor monitor) throws IOException {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "execRemoteApp"));
+ return Collections.emptyMap();
+ }
Map> cmdAnswers = new LinkedHashMap>();
for (String remoteCommand : remoteCommands) {
AndmoreLogger.debug(remoteCommand);
@@ -805,47 +445,68 @@ public static Map> execRemoteApp(String serialNumber,
return cmdAnswers;
}
- private static Collection executeShellCmd(String serialNumber, final String cmd,
- final IProgressMonitor monitor) {
- final Collection results = new ArrayList();
- IDevice d = getDeviceBySerialNumber(serialNumber);
- if (d != null) {
- try {
- d.executeShellCommand(cmd, new MultiLineReceiver() {
- @Override
- public boolean isCancelled() {
- return monitor.isCanceled();
- }
-
- @Override
- public void processNewLines(String[] lines) {
- for (String line : lines) {
- if ((!line.equals("")) && (!line.equals(cmd))) //$NON-NLS-1$
- {
- results.add(line);
- }
- }
- }
- }, 0);
- } catch (Exception e) {
- AndmoreLogger.error(DDMSFacade.class, "Error executing shell command " + cmd //$NON-NLS-1$
- + " at device " + serialNumber, e); //$NON-NLS-1$
- }
- }
- return results;
- }
-
/**
- * Retrieves all properties from the device with provided serial number.
+ * DOCUMENT ME!!
*
+ * @param cmd
+ * @param out
* @param serialNumber
* @return
+ * @throws IOException
*/
- public static Properties getDeviceProperties(String serialNumber) {
- Properties instanceProperties = new Properties();
- if (serialNumber != null) {
- String key = ""; //$NON-NLS-1$
- String value = ""; //$NON-NLS-1$
+ public String executeCommand(String[] cmd, OutputStream out, String serialNumber) throws IOException {
+ String fullCmd = ""; //$NON-NLS-1$
+ if (out != null) {
+ for (String cmdArg : cmd) {
+ fullCmd += cmdArg + " "; //$NON-NLS-1$
+ }
+ out.write(fullCmd.getBytes());
+ out.write("\n".getBytes()); //$NON-NLS-1$
+ }
+
+ Runtime r = Runtime.getRuntime();
+ Process p = r.exec(cmd);
+
+ String command_results = ""; //$NON-NLS-1$
+ InputStream processIn = p.getInputStream();
+ final BufferedReader br = new BufferedReader(new InputStreamReader(processIn));
+ String line;
+ try {
+ while ((line = br.readLine()) != null) {
+ command_results += line;
+ command_results += "\n"; //$NON-NLS-1$
+ if (out != null) {
+ if (serialNumber != null) {
+ out.write((serialNumber + ": ").getBytes()); //$NON-NLS-1$
+ }
+ out.write(line.getBytes());
+ out.write("\n".getBytes()); //$NON-NLS-1$
+ }
+ }
+ } finally {
+ br.close();
+ }
+
+ return command_results;
+ }
+
+ public void deleteFile(String serialNumber, String path) throws IOException {
+ execRemoteApp(serialNumber, "rm " + path, //$NON-NLS-1$
+ new NullProgressMonitor());
+ }
+
+
+ /**
+ * Retrieves all properties from the device with provided serial number.
+ *
+ * @param serialNumber
+ * @return
+ */
+ public Properties getDeviceProperties(String serialNumber) {
+ Properties instanceProperties = new Properties();
+ if (serialNumber != null) {
+ String key = ""; //$NON-NLS-1$
+ String value = ""; //$NON-NLS-1$
Collection lines;
try {
lines = execRemoteApp(serialNumber, "getprop", new NullProgressMonitor()); //$NON-NLS-1$
@@ -880,105 +541,457 @@ public static Properties getDeviceProperties(String serialNumber) {
*
* @return
*/
- public static String getDeviceProperty(String serialNumber, String propertyName) {
+ public String getDeviceProperty(String serialNumber, String propertyName) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "getDeviceProperty"));
+ return "";
+ }
String result = null;
- IDevice device = DDMSFacade.getDeviceBySerialNumber(serialNumber);
+ IDevice device = getDeviceBySerialNumber(serialNumber);
if (device != null) {
result = device.getProperty(propertyName);
}
return result;
}
+ public void start() throws InterruptedException {
+ Job adbJob = new Job("Start Device Monitor") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ AndroidDebugBridge adb = AndroidDebugBridge.getBridge();
+ if (adb == null) {
+ AndroidDebugBridge.disconnectBridge();
+ DdmsPlugin.setToolsLocation(AndmoreAndroidPlugin.getOsAbsoluteAdb(), true, AndmoreAndroidPlugin.getOsAbsoluteHprofConv(),
+ AndmoreAndroidPlugin.getOsAbsoluteTraceview());
+ }
+
+ if ((adb != null) && adb.hasInitialDeviceList()) {
+ IDevice[] x = adb.getDevices();
+ IDevice[] newDevices = x;
+ List oldDevList = new ArrayList(connectedDevices.values());
+
+ for (IDevice newDev : newDevices) {
+ String serialNum = newDev.getSerialNumber();
+ if (connectedDevices.containsKey(serialNum)) {
+ IDevice oldDev = connectedDevices.get(serialNum);
+ oldDevList.remove(oldDev);
+ if (oldDev.getState().compareTo((newDev).getState()) != 0) {
+ if ((newDev).getState() == DeviceState.OFFLINE) {
+ deviceDisconnected(newDev);
+ } else if ((newDev).getState() == DeviceState.ONLINE) {
+ deviceConnected(newDev);
+ }
+ }
+ } else {
+ deviceConnected(newDev);
+ }
+ }
+ for (IDevice oldDev : oldDevList) {
+ deviceDisconnected(oldDev);
+ }
+ }
+ sdkPath = AndmoreAndroidPlugin.getOsSdkFolder();
+ return Status.OK_STATUS;
+ }
+ };
+ adbJob.setPriority(Job.BUILD);
+ AdtStartupService.instance().put(adbJob);
+ }
+
/**
- * Get the name of the VM associated to the emulator running in the given
- * deviceSerial identification.
+ * Create port forward for a given VM
*
- * @param deviceSerial
- * identification of the emulator whose vm name must be
- * retrieved.
- * @return the name of the VM used by the emulator running with the given
- * id, or null if the vmname could be retrieved.
+ * @param serialNumber
+ * Android serial number
+ * @param from
+ * port number from
+ * @param to
+ * port number to
+ * @return true is the port forward was successful, false otherwise
*/
- public static String getVmName(final IDevice d) {
- String vmName = null;
- String serialNumber = d.getSerialNumber();
- int MAX_TRIES = 120;
- int tries = 0;
+ public boolean createForward(String serialNumber, int from, int to) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "createForward"));
+ return false;
+ }
+ boolean ok = true;
+ IDevice device = getDeviceBySerialNumber(serialNumber);
+ try {
+ device.createForward(from, to);
+ } catch (Exception e) {
+ AndmoreLogger.error(DeviceMonitor.class, "Error creating forward of device: " //$NON-NLS-1$
+ + serialNumber + " from " + from + " to " + to, e); //$NON-NLS-1$ //$NON-NLS-2$
+ ok = false;
+ }
+ return ok;
+ }
- while ((vmName == null) && (tries < MAX_TRIES)) {
- synchronized (avdNameMap) {
- vmName = avdNameMap.get(serialNumber);
+ /**
+ * Kill the communication channel
+ *
+ * @param serialNumber
+ * The serial number of the device to kill
+ */
+ public void kill(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "kill"));
+ }
+ if (isDeviceOnline(serialNumber)) {
+ IDevice deviceToKill = getDeviceBySerialNumber(serialNumber);
+ if (deviceToKill != null) {
+ synchronized (consoleLock) {
+ EmulatorConsole console = EmulatorConsole.getConsole(deviceToKill);
+ if (console != null) {
+ console.kill();
+ }
+ }
}
+ }
+ }
- if (vmName == null) {
- vmName = d.getAvdName();
- }
+ /**
+ * Push files to device
+ *
+ * @param serialNumber
+ * Android device serial number
+ * @param localDir
+ * local folder path
+ * @param fileNames
+ * files to transfer
+ * @param remoteDir
+ * destination folder path
+ * @param timeout
+ * timeout for the operation
+ * @param monitor
+ * monitor associated with the operation
+ */
+ public IStatus pushFiles(String serialNumber, String localDir, Collection fileNames,
+ String remoteDir, int timeout, final IProgressMonitor monitor, OutputStream outputStream) {
+ return transferFiles(true, serialNumber, localDir, fileNames, remoteDir, timeout, monitor, outputStream);
+ }
- if (vmName == null) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // do nothing
- } finally {
- tries++;
- }
- }
+ /**
+ * Push files to device
+ *
+ * @param serialNumber
+ * Android device serial number
+ * @param localFiles
+ * destination local files
+ * @param remoteFiles
+ * remote files to transfer as localFiles to desktop
+ * @param timeout
+ * timeout for the operation
+ * @param monitor
+ * monitor associated with the operation
+ */
+ public IStatus pushFiles(String serialNumber, List localFiles, List remoteFiles, int timeout,
+ final IProgressMonitor monitor, OutputStream outputStream) {
+ return transferFiles(true, serialNumber, localFiles, remoteFiles, timeout, monitor, outputStream);
+ }
- // try to get vmname by telnet as last option
- if (vmName == null) {
- vmName = getVmNameByTelnet(serialNumber);
- }
+ /**
+ * Pull files from device
+ *
+ * @param serialNumber
+ * Android device serial number
+ * @param localDir
+ * local folder path
+ * @param fileNames
+ * files to transfer
+ * @param remoteDir
+ * destination folder path
+ * @param timeout
+ * timeout for the operation
+ * @param monitor
+ * monitor associated with the operation
+ */
+ public IStatus pullFiles(String serialNumber, String localDir, Collection fileNames,
+ String remoteDir, int timeout, final IProgressMonitor monitor, OutputStream outputStream) {
+ return transferFiles(false, serialNumber, localDir, fileNames, remoteDir, timeout, monitor, outputStream);
+ }
+
+ /**
+ * Pull files from device
+ *
+ * @param serialNumber
+ * Android device serial number
+ * @param localFiles
+ * local files to transfer as remoteFiles to device
+ * @param remoteFiles
+ * destination remote files
+ * @param timeout
+ * timeout for the operation
+ * @param monitor
+ * monitor associated with the operation
+ */
+ public IStatus pullFiles(String serialNumber, List localFiles, List remoteFiles, int timeout,
+ final IProgressMonitor monitor, OutputStream outputStream) {
+ return transferFiles(false, serialNumber, localFiles, remoteFiles, timeout, monitor, outputStream);
+ }
+ /**
+ * Check if the application is running in the device with specified serial
+ * number
+ *
+ * @param serialNumber
+ * @param applicationName
+ * @return true if it is running, false otherwise
+ */
+ public boolean isApplicationRunning(String serialNumber, String applicationName) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "isApplicationRunning"));
+ return false;
}
+ IDevice dev = null;
+ boolean running = false;
+ dev = connectedDevices.get(serialNumber);
+ if (dev != null) {
+ running = dev.getClient(applicationName) != null;
+ }
+ return running;
+ }
- if (vmName != null) {
- synchronized (avdNameMap) {
- if (avdNameMap.get(serialNumber) == null) {
- avdNameMap.put(serialNumber, vmName);
- }
- }
+ /**
+ * Connect to a Remote Device given its IP/Port
+ *
+ * @param device
+ * the Remote Device Instance
+ * @param host
+ * device host (IP)
+ * @param port
+ * device port
+ * @param timeout
+ * the maximum time allowed to successfully connect to the device
+ * @param monitor
+ * the monitor of the operation
+ * @return the status of the operation
+ * @throws IOException
+ */
+ public IStatus connectTcpIp(final ISerialNumbered device, String host, String port, int timeout,
+ IProgressMonitor monitor) throws IOException {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
+
+ subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgConnectingToDeviceViaTCPIP, 10);
+
+ IStatus status = Status.OK_STATUS;
+
+ String serialNumber = device.getSerialNumber();
+ if (!isDeviceOnline(serialNumber)) // check if it's already connected
+ {
+ String[] cmd = createConnectTcpIpCommand(host, port);
+
+ status = executeRemoteDevicesCommand(cmd, null, timeout,
+ NLS.bind(AndroidNLS.ERR_RemoteDevice_TimeoutWhileConnecting, device.getDeviceName()),
+ new IStopCondition() {
+
+ @Override
+ public boolean canStop() {
+ String serialNumber = device.getSerialNumber();
+ if (serialNumber != null) {
+ return isDeviceOnline(serialNumber);
+ } else {
+ return false;
+ }
+ }
+ }, subMonitor.newChild(1000));
}
- return vmName;
+ subMonitor.worked(1000);
+
+ return status;
}
- private static String getVmNameByTelnet(String serialNumber) {
- Pattern pattern = Pattern.compile("emulator-([0-9]+)"); //$NON-NLS-1$
- TelnetFrameworkAndroid telnet = new TelnetFrameworkAndroid();
- Matcher matcher = pattern.matcher(serialNumber);
- matcher.matches();
- String avdName = null;
+ /**
+ * Method which switches the device connection mode from TCP/IP to USB.
+ *
+ * @param device
+ * {@link ISerialNumbered} device to have its connection mode
+ * changed.
+ * @param host
+ * The IP of the device.
+ * @param port
+ * The port in which the TCP/IP connection is established.
+ * @param timeout
+ * The maximum time which the switching operation is attempted.
+ * @param monitor
+ * The {@link IProgressMonitor} which this operation is being
+ * computed.
+ *
+ * @return Returns the {@link IStatus} of this operation.
+ *
+ * @throws IOException
+ * Exception thrown in case something goes wrong while trying to
+ * switch the device connection mode from TCP/IP to USB.
+ */
+ public IStatus switchFromTCPConnectionModeToUSBConnectionMode(final ISerialNumbered device, String host,
+ String port, int timeout, IProgressMonitor monitor) throws IOException {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
- try {
- Integer telnetPort = Integer.valueOf(matcher.group(1));
- telnet.connect("localhost", telnetPort); //$NON-NLS-1$
- String avdNameRaw = telnet.write("avd name\r\n", new String[] //$NON-NLS-1$
- { "KO" //$NON-NLS-1$
- });
+ subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgSwitchingDeviceFromTCPIPToUSB, 10);
- String split = avdNameRaw.contains("\r\n") ? "\r\n" : "\n";
+ IStatus status = Status.OK_STATUS;
- String[] outputArray = avdNameRaw.split(split);
- if (outputArray.length > 2) {
- avdName = outputArray[2];
- }
+ String serialNumber = device.getSerialNumber();
+ if (isDeviceOnline(serialNumber)) // check if it's already connected
+ {
+ String[] cmd = createSwitchToUSBConnectionModeCommand(host, port);
- if (avdName != null) {
- avdNameMap.put(serialNumber, avdName);
+ status = executeRemoteDevicesCommand(cmd, null, timeout,
+ NLS.bind(AndroidNLS.DDMSFacade_MsgTimeoutReachedSwitchingFromTCPToUSB, device.getDeviceName()),
+ new IStopCondition() {
+
+ @Override
+ public boolean canStop() {
+ String serialNumber = device.getSerialNumber();
+ if (serialNumber != null) {
+ return isDeviceOnline(serialNumber);
+ } else {
+ return false;
+ }
+ }
+ }, subMonitor.newChild(1000));
+ }
+ subMonitor.worked(1000);
+ return status;
+ }
+
+ /**
+ * Get the wireless ip from the connected handset
+ *
+ * @param serialNumber
+ * @param monitor
+ * @return the ip or null if not possible to retrieve it
+ */
+ public String getWirelessIPfromHandset(String serialNumber, IProgressMonitor monitor) {
+ String handset_wireless_ip = null;
+ IDevice device = null;
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "getWirelessIOfromHandset"));
+ return "";
+ }
+ device = connectedDevices.get(serialNumber);
+ if (device != null) {
+ // get the wi-fi name for executing the ipconfig command
+ String wifiProperty = device.getProperty(WIFI_INTERFACE_DEVICE_PROPERTY);
+ if (wifiProperty == null) {
+ wifiProperty = DEFAULT_WIRELESS_DEVICE_PROPERTY;
}
- } catch (NumberFormatException e) {
- avdName = serialNumber;
- } catch (IOException e) {
- avdName = serialNumber;
- } finally {
- try {
- telnet.disconnect();
- } catch (IOException e) {
- // Do nothing.
+ // execute ipconfig command
+ Collection answers = executeShellCmd(serialNumber, IFCONFIG_CMD + " " + wifiProperty, monitor); //$NON-NLS-1$
+
+ // Success message - for example
+ // [tiwlan0: ip 192.168.0.174 mask 255.255.255.0 flags [up broadcast
+ // running multicast]]
+
+ if (answers != null) {
+ String result = answers.toString();
+ if (result != null) {
+ // splits the result of the shell command and gets the third
+ // position
+ // that should be the IP number
+ String[] result_splited = result.split(" "); //$NON-NLS-1$
+ if (result_splited.length >= 3) {
+ // check whether there is an IP
+ Pattern pattern = Pattern.compile(IP_PATTERN);
+ Matcher matcher = pattern.matcher(result);
+ if (matcher.find()) {
+ handset_wireless_ip = result_splited[2];
+ }
+ }
+ }
}
}
- return avdName;
+ return handset_wireless_ip;
+ }
+
+ /**
+ * Switch adb connection mode of an specific device to TCPIP
+ *
+ * @param deviceName
+ * name of the handset instance
+ * @param host
+ * wireless ip of the handset instance
+ * @param port
+ * number of the port to be using during the connection
+ * @param timeout
+ * the maximum time allowed to successfully connect to the device
+ * @param monitor
+ * the monitor of the operation
+ * @return the status of the operation
+ *
+ * @throws IOException
+ * Exception thrown in case there are problems switching the
+ * device.
+ */
+ public IStatus switchUSBtoTcpIp(String deviceName, final String serialNumber, String port, int timeout,
+ IProgressMonitor monitor) throws IOException {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
+
+ subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgSwitchingFromUSBConnection, 10);
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "switchUSBtoTcpIp"));
+ return Status.CANCEL_STATUS;
+ }
+ IStatus status = Status.OK_STATUS;
+
+ if (isDeviceOnline(serialNumber)) {
+ String[] cmd = createSwitchToTcpIpCommand(serialNumber, port);
+
+ status = executeRemoteDevicesCommand(cmd, null, timeout,
+ NLS.bind(AndroidNLS.ERR_WirelessRemoteDevice_TimeoutWhileConnecting, deviceName),
+ new IStopCondition() {
+
+ @Override
+ public boolean canStop() {
+ return isDeviceOffline(serialNumber);
+ }
+ }, subMonitor.newChild(1000));
+ }
+ monitor.worked(1000);
+ return status;
+ }
+
+ /**
+ * Disconnect from a Remote Device given its IP/Port
+ *
+ * @param device
+ * the Remote Device Instance
+ * @param host
+ * device host (IP)
+ * @param port
+ * device port
+ * @param timeout
+ * the maximum time allowed to successfully disconnect from the
+ * device
+ * @param monitor
+ * the monitor of the operation
+ * @return the status of the operation
+ * @throws IOException
+ */
+ public IStatus disconnectTcpIp(final ISerialNumbered device, String host, String port, int timeout,
+ IProgressMonitor monitor) throws IOException {
+ IStatus status = Status.OK_STATUS;
+
+ String serialNumber = device.getSerialNumber();
+ if (isDeviceOnline(serialNumber)) // check if it's already disconnected
+ {
+ String[] cmd = createDisconnectTcpIpCommand(host, port);
+
+ status = executeRemoteDevicesCommand(cmd, null, timeout,
+ NLS.bind(AndroidNLS.ERR_RemoteDevice_TimeoutWhileDisconnecting, device.getDeviceName()),
+ new IStopCondition() {
+
+ @Override
+ public boolean canStop() {
+ String serialNumber = device.getSerialNumber();
+ return !isDeviceOnline(serialNumber);
+ }
+ }, monitor);
+
+ }
+
+ return status;
}
/**
@@ -988,21 +1001,25 @@ private static String getVmNameByTelnet(String serialNumber) {
* Android VM name
* @return Device associated with the given Android VM
*/
- public static IDevice getDeviceWithVmName(String vmName) {
+ public IDevice getDeviceWithVmName(String vmName) {
IDevice toReturn = null;
if (vmName != null) {
Collection devices = connectedDevices.values();
for (IDevice d : devices) {
if (d.isEmulator()) {
- String deviceVmName = DDMSFacade.getVmName(d);
+ String deviceVmName = getVmName(d);
if (vmName.equals(deviceVmName)) {
toReturn = d;
break;
}
}
}
+ if (toReturn == null)
+ AndmoreLogger.error("Device with VM name \"" + vmName + "\" not found");
+ } else {
+ AndmoreLogger.error("getDeviceWithVmName called with null VM name");
}
- return toReturn;
+ return toReturn == null ? NULL_DEVICE : toReturn;
}
/**
@@ -1013,7 +1030,11 @@ public static IDevice getDeviceWithVmName(String vmName) {
* @return the name of the AVD used by the emulator running with the given
* device, or null if the vmname could be retrieved.
*/
- public static String getNameBySerialNumber(String serialNumber) {
+ public String getNameBySerialNumber(String serialNumber) {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "getNameBySerialNumber"));
+ return "";
+ }
String avdName = null;
IDevice d = getDeviceBySerialNumber(serialNumber);
avdName = getNameByDevice(d);
@@ -1029,28 +1050,21 @@ public static String getNameBySerialNumber(String serialNumber) {
* @return the serial number of the given instance, or null if
* no instance with the given name is online
*/
- public static String getSerialNumberByName(String instanceName) {
+ public String getSerialNumberByName(String instanceName) {
String serialNumber = null;
if (instanceName != null) {
- List devices = null;
- synchronized (connectedDevices) {
- devices = new ArrayList(connectedDevices.size());
- devices.addAll(connectedDevices.values());
- }
- if (devices != null) {
- for (IDevice dev : devices) {
- if (instanceName.equals(getNameByDevice(dev))) {
- serialNumber = dev.getSerialNumber();
- break;
- }
+ // Using ConcurrentHashMap iterator is safe if used only on a single thread
+ for (IDevice dev : connectedDevices.values()) {
+ if (instanceName.equals(getNameByDevice(dev))) {
+ serialNumber = dev.getSerialNumber();
+ break;
}
}
}
-
return serialNumber;
}
- public static Collection getRunningApplications(String serialNumber) {
+ public Collection getRunningApplications(String serialNumber) {
Collection apps = new ArrayList();
if (serialNumber != null) {
IDevice dev = getDeviceBySerialNumber(serialNumber);
@@ -1063,10 +1077,56 @@ public static Collection getRunningApplications(String serialNumber) {
}
}
}
-
return apps;
}
+ /**
+ * Check if a device identified by the serial number has a mounted SDCard
+ *
+ * @param serialNumber
+ * the serial number
+ * @return true if the device has a SDCard
+ * @throws IOException
+ */
+ public boolean hasSDCard(String serialNumber) throws IOException {
+ if (serialNumber == null) {
+ AndmoreLogger.error(String.format(NULL_SERIAL_NUMBER, "hasSDCard"));
+ return false;
+ }
+ boolean hasSdCard = false;
+ File tempSdCardFile = File.createTempFile("SDcheck", ".tmp"); //$NON-NLS-1$ //$NON-NLS-2$
+ boolean tempCopiedOnSdCardFile = pushFileToDevice(serialNumber, SDCARD_FOLDER, tempSdCardFile);
+
+ if (tempCopiedOnSdCardFile) {
+ // trying to write on /sdcard folder (it works for phones previous
+ // from Platform 2.2)
+ if (!deleteFileFromDevice(serialNumber, tempSdCardFile.getName(), SDCARD_FOLDER)) {
+ AndmoreLogger
+ .error("DDMSFacade: Could not delete tempfile from /sdcard when checking if card is enabled"); //$NON-NLS-1$
+ }
+ hasSdCard = true;
+ tempSdCardFile.delete();
+ } else {
+
+ File tempMntFile = File.createTempFile("SDcheck", ".tmp"); //$NON-NLS-1$ //$NON-NLS-2$
+ boolean tempCopiedOnMntFile = pushFileToDevice(serialNumber, MNT_SDCARD_FOLDER, tempSdCardFile);
+
+ if (tempCopiedOnMntFile) {
+ // trying to write on /mnt/sdcard folder (it works for phones
+ // since Platform 2.2)
+ if (!deleteFileFromDevice(serialNumber, tempMntFile.getName(), MNT_SDCARD_FOLDER)) {
+ AndmoreLogger
+ .error("DDMSFacade: Could not delete tempfile from /mnt/sdcard when checking if card is enabled"); //$NON-NLS-1$
+ }
+ hasSdCard = true;
+ tempMntFile.delete();
+ }
+
+ }
+
+ return hasSdCard;
+ }
+
/**
* Dumps a HPROF file based on a client description and a device serial
* number
@@ -1074,7 +1134,7 @@ public static Collection getRunningApplications(String serialNumber) {
* @param clientDescription
* A client description of a running application
*/
- public static IStatus dumpHprofFile(String clientDescription, String serialNumber, IProgressMonitor monitor) {
+ public IStatus dumpHprofFile(String clientDescription, String serialNumber, IProgressMonitor monitor) {
IStatus status = Status.OK_STATUS;
monitor.beginTask(AndroidNLS.DumpHprofFile_GeneratingMemoryAnalysisOutput, 100);
@@ -1103,16 +1163,31 @@ public void run() {
try {
// Find a client with matching description and dum the HPROF file
- for (Client c : clients) {
- if (c.getClientData().getClientDescription().equals(clientDescription)) {
+ for (Client client : clients) {
+ if (client.getClientData().getClientDescription().equals(clientDescription)) {
// Set our handler as the HprofDumpHandler
- ClientData.setHprofDumpHandler(hprofHandler);
monitor.setTaskName(AndroidNLS.DumpHprofFile_DumpingHprofFile);
- c.dumpHprof();
- synchronized (DDMSFacade.class) {
- DDMSFacade.class.wait();
+ Integer clientPid = client.getClientData().getPid();
+ synchronized(clientPidSet) {
+ if (!clientPidSet.keySet().contains(clientPid))
+ clientPidSet.put(clientPid, clientPid);
+ }
+ client.dumpHprof();
+ synchronized (clientPid) {
+ while (client.getClientData().getHprofData() == null)
+ clientPid.wait(MAX_WAIT_TIME);
+ }
+ HprofData hprofData = client.getClientData().getHprofData();
+ if (hprofData == null) {
+ hprofHandler.onEndFailure(client, null);
+ status = Status.CANCEL_STATUS;
+ }
+ else {
+ if (hprofData.type == HprofData.Type.DATA)
+ hprofHandler.onSuccess(hprofData.data, client);
+ else
+ hprofHandler.onSuccess(hprofData.filename, client);
}
-
monitor.worked(50);
}
}
@@ -1127,66 +1202,156 @@ public void run() {
}
- /**
- * Gets the AVD name of the device
- *
- * @param d
- * The device to be searched for the AVD name
- *
- * @return The AVD name
- */
- private static String getNameByDevice(final IDevice d) {
- String name = null;
- if (d != null) {
- if (d.isEmulator()) {
-
- name = getVmName(d);
- } else {
- name = d.getSerialNumber();
+ @Override
+ public void clientChanged(Client client, int changeMask) {
+ if ((changeMask & Client.CHANGE_NAME) == Client.CHANGE_NAME) {
+ final Client finalClient = client;
+ Job job = new Job("Change client name"){
+
+ @Override
+ protected IStatus run(IProgressMonitor arg0) {
+ String applicationName = finalClient.getClientData().getClientDescription();
+ if (applicationName != null) {
+ IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
+ String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
+ if (home.equals(applicationName)) {
+ String serialNum = finalClient.getDevice().getSerialNumber();
+ AndmoreLogger.debug("Completely Up Device: " + serialNum); //$NON-NLS-1$
+ synchronized (completelyUpDevices) {
+ completelyUpDevices.add(serialNum);
+ }
+ }
+ }
+ return Status.OK_STATUS;
+ }};
+ job.setPriority(Job.BUILD);
+ job.schedule();
+ } else if ((changeMask & Client.CHANGE_HPROF) == Client.CHANGE_HPROF) {
+ Integer clientPid = client.getClientData().getPid();
+ synchronized(clientPidSet) {
+ if (clientPidSet.keySet().contains(clientPid))
+ clientPid = clientPidSet.get(clientPid);
+ else // This is not expected
+ clientPid = null;
}
+ if (clientPid != null)
+ synchronized(clientPid) {
+ clientPid.notifyAll();
+ }
}
+ }
- return name;
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceChanged
+ * (com.android.ddmlib.Device, int)
+ */
+ @Override
+ public void deviceChanged(IDevice device, int i) {
+ if (i == IDevice.CHANGE_STATE) {
+ // a handset should only be instantiated when its state change from
+ // OFFLINE to ONLINE
+ // to avoid the problem of a remote device on the OFFLINE state be
+ // presented as an ONLINE handset
+ if ((device.getState() == DeviceState.ONLINE) && (!device.isEmulator())) {
+ deviceConnected(device);
+ }
+ deviceStatusChanged(device);
+ }
}
- /**
- * Create port forward for a given VM
+ /*
+ * (non-Javadoc)
*
- * @param serialNumber
- * Android serial number
- * @param from
- * port number from
- * @param to
- * port number to
- * @return true is the port forward was successful, false otherwise
- */
- public static boolean createForward(String serialNumber, int from, int to) {
- boolean ok = true;
- IDevice device = getDeviceBySerialNumber(serialNumber);
- try {
- device.createForward(from, to);
- } catch (Exception e) {
- AndmoreLogger.error(DDMSFacade.class, "Error creating forward of device: " //$NON-NLS-1$
- + serialNumber + " from " + from + " to " + to, e); //$NON-NLS-1$ //$NON-NLS-2$
- ok = false;
+ * @see
+ * com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceConnected
+ * (com.android.ddmlib.Device)
+ */
+ @Override
+ public void deviceConnected(IDevice device) {
+ // handsets should not be instantiated right after connection because at
+ // that time
+ // they appear on the OFFLINE state
+ final String serialNumber = device.getSerialNumber();
+ if (device.isEmulator()) {
+ AndmoreLogger.debug("Device connected: " + serialNumber); //$NON-NLS-1$
+ connectedDevices.put(serialNumber, device);
}
- return ok;
+ if (!device.isEmulator() && !device.hasClients()) {
+ Job job = new Job("Device client wait"){
+
+ @Override
+ protected IStatus run(IProgressMonitor arg0) {
+ boolean timeout = false;
+ long startTime = System.currentTimeMillis();
+ int maxInterval = 10000;
+ do {
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ return Status.CANCEL_STATUS;
+ }
+ long currentTime = System.currentTimeMillis();
+ timeout = ((startTime + maxInterval) < currentTime);
+
+ } while (!device.hasClients() && !timeout && (device.getState() == DeviceState.ONLINE));
+ if (timeout) {
+ synchronized (completelyUpDevices) {
+ // put the device up anyway.
+ completelyUpDevices.add(serialNumber);
+ }
+ }
+ completeDeviceConnection(device, serialNumber);
+ return Status.OK_STATUS;
+ }};
+ job.setPriority(Job.BUILD);
+ job.schedule();
+ } else
+ completeDeviceConnection(device, serialNumber);
}
- /**
- * Kill the communication channel
+ /*
+ * (non-Javadoc)
*
- * @param serialNumber
- * The serial number of the device to kill
+ * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#
+ * deviceDisconnected(com.android.ddmlib.Device)
*/
- public static void kill(String serialNumber) {
- if (isDeviceOnline(serialNumber)) {
- IDevice deviceToKill = getDeviceBySerialNumber(serialNumber);
- if (deviceToKill != null) {
- synchronized (consoleLock) {
- EmulatorConsole console = EmulatorConsole.getConsole(deviceToKill);
- if (console != null) {
- console.kill();
+ @Override
+ public void deviceDisconnected(IDevice device) {
+ final String serialNumber = device.getSerialNumber();
+ AndmoreLogger.debug("Device disconnected: " + serialNumber); //$NON-NLS-1$
+ synchronized (completelyUpDevices) {
+ completelyUpDevices.remove(serialNumber);
+ }
+ connectedDevices.remove(serialNumber);
+ Job job = new Job("Notify device " + serialNumber + " connected"){
+
+ @Override
+ protected IStatus run(IProgressMonitor arg0) {
+ // Fire events in worker thread to prevent blocking caller thread
+ AndmoreEventManager.fireEvent(EventType.DEVICE_DISCONNECTED, serialNumber);
+ synchronized (avdNameMap) {
+ avdNameMap.remove(device.getSerialNumber());
+ }
+ return Status.OK_STATUS;
+ }};
+ job.setPriority(Job.BUILD);
+ job.schedule();
+ }
+
+ private void deviceStatusChanged(IDevice device) {
+ AndmoreLogger.debug("Device changed: " + device.getSerialNumber()); //$NON-NLS-1$
+ connectedDevices.put(device.getSerialNumber(), device);
+ if ((device).getState() == DeviceState.ONLINE) {
+ IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
+ String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
+ if (device.getClient(home) != null) {
+ synchronized (completelyUpDevices) {
+ AndmoreLogger.debug("Completely Up Device: " + device.getSerialNumber()); //$NON-NLS-1$
+ if (!completelyUpDevices.contains(device.getSerialNumber())) {
+ completelyUpDevices.add(device.getSerialNumber());
}
}
}
@@ -1194,83 +1359,53 @@ public static void kill(String serialNumber) {
}
/**
- * Push files to device
+ * Get the name of the VM associated to the emulator running in the given
+ * deviceSerial identification.
*
- * @param serialNumber
- * Android device serial number
- * @param localDir
- * local folder path
- * @param fileNames
- * files to transfer
- * @param remoteDir
- * destination folder path
- * @param timeout
- * timeout for the operation
- * @param monitor
- * monitor associated with the operation
+ * @param device emulator whose vm name must be retrieved.
+ * @return the name of the VM used by the emulator running with the given
+ * id, or null if the vmname could be retrieved.
*/
- public static IStatus pushFiles(String serialNumber, String localDir, Collection fileNames,
- String remoteDir, int timeout, final IProgressMonitor monitor, OutputStream outputStream) {
- return transferFiles(true, serialNumber, localDir, fileNames, remoteDir, timeout, monitor, outputStream);
- }
+ private String getVmName(final IDevice device) {
+ String vmName = null;
+ String serialNumber = device.getSerialNumber();
+ int MAX_TRIES = 120;
+ int tries = 0;
- /**
- * Push files to device
- *
- * @param serialNumber
- * Android device serial number
- * @param localFiles
- * destination local files
- * @param remoteFiles
- * remote files to transfer as localFiles to desktop
- * @param timeout
- * timeout for the operation
- * @param monitor
- * monitor associated with the operation
- */
- public static IStatus pushFiles(String serialNumber, List localFiles, List remoteFiles, int timeout,
- final IProgressMonitor monitor, OutputStream outputStream) {
- return transferFiles(true, serialNumber, localFiles, remoteFiles, timeout, monitor, outputStream);
- }
+ while ((vmName == null) && (tries < MAX_TRIES)) {
+ synchronized (avdNameMap) {
+ vmName = avdNameMap.get(serialNumber);
+ }
- /**
- * Pull files from device
- *
- * @param serialNumber
- * Android device serial number
- * @param localDir
- * local folder path
- * @param fileNames
- * files to transfer
- * @param remoteDir
- * destination folder path
- * @param timeout
- * timeout for the operation
- * @param monitor
- * monitor associated with the operation
- */
- public static IStatus pullFiles(String serialNumber, String localDir, Collection fileNames,
- String remoteDir, int timeout, final IProgressMonitor monitor, OutputStream outputStream) {
- return transferFiles(false, serialNumber, localDir, fileNames, remoteDir, timeout, monitor, outputStream);
- }
+ if (vmName == null) {
+ vmName = device.getAvdName();
+ }
- /**
- * Pull files from device
- *
- * @param serialNumber
- * Android device serial number
- * @param localFiles
- * local files to transfer as remoteFiles to device
- * @param remoteFiles
- * destination remote files
- * @param timeout
- * timeout for the operation
- * @param monitor
- * monitor associated with the operation
- */
- public static IStatus pullFiles(String serialNumber, List localFiles, List remoteFiles, int timeout,
- final IProgressMonitor monitor, OutputStream outputStream) {
- return transferFiles(false, serialNumber, localFiles, remoteFiles, timeout, monitor, outputStream);
+ if (vmName == null) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // do nothing
+ } finally {
+ tries++;
+ }
+ }
+ // TODO - Fix or remove
+ // try to get vmname by telnet as last option
+ //if (vmName == null) {
+ // vmName = getVmNameByTelnet(serialNumber);
+ //}
+
+ }
+
+ if (vmName != null) {
+ synchronized (avdNameMap) {
+ if (avdNameMap.get(serialNumber) == null) {
+ avdNameMap.put(serialNumber, vmName);
+ }
+ }
+ }
+ return vmName;
}
/**
@@ -1286,7 +1421,7 @@ public static IStatus pullFiles(String serialNumber, List localFiles, List
*
* @throws AndroidException
*/
- private static SyncService getSyncService(IDevice device, int timeout, final IProgressMonitor monitor)
+ private SyncService getSyncService(IDevice device, int timeout, final IProgressMonitor monitor)
throws AndroidException {
SyncService service = null;
@@ -1324,7 +1459,7 @@ private static SyncService getSyncService(IDevice device, int timeout, final IPr
return service;
}
- private static IStatus transferFiles(boolean isPush, String serialNumber, String localDir,
+ private IStatus transferFiles(boolean isPush, String serialNumber, String localDir,
Collection fileNames, String remoteDir, int timeout, final IProgressMonitor monitor,
OutputStream outputStream) {
List localList = new ArrayList();
@@ -1336,14 +1471,14 @@ private static IStatus transferFiles(boolean isPush, String serialNumber, String
return transferFiles(isPush, serialNumber, localList, remoteList, timeout, monitor, outputStream);
}
- private static IStatus transferFiles(boolean isPush, String serialNumber, List localFiles,
+ private IStatus transferFiles(boolean isPush, String serialNumber, List localFiles,
List remoteFiles, int timeout, final IProgressMonitor monitor, OutputStream outputStream) {
if (localFiles.size() != remoteFiles.size()) {
- return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, AndroidNLS.ERR_DDMSFacade_IncompatibleFileLists);
+ return new Status(IStatus.ERROR, PLUGIN_ID, AndroidNLS.ERR_DDMSFacade_IncompatibleFileLists);
}
IStatus status = Status.OK_STATUS;
- IDevice device = DDMSFacade.getDeviceBySerialNumber(serialNumber);
+ IDevice device = getDeviceBySerialNumber(serialNumber);
SyncService service = null;
try {
@@ -1470,7 +1605,7 @@ public void startSubTask(String s) {
}
if (resultMessage != null) {
- status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, resultMessage);
+ status = new Status(IStatus.ERROR, PLUGIN_ID, resultMessage);
}
if (syncMonitor.isCanceled()) {
status = Status.CANCEL_STATUS;
@@ -1479,287 +1614,314 @@ public void startSubTask(String s) {
}
}
} catch (AndroidException e) {
- status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage());
+ status = new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage());
} catch (NullPointerException e1) {
- status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, AndroidNLS.ERR_DDMSFacade_FileNotFound);
+ status = new Status(IStatus.ERROR, PLUGIN_ID, AndroidNLS.ERR_DDMSFacade_FileNotFound);
} finally {
if (service != null) {
service.close();
}
}
-
return status;
}
/**
- * Check if the application is running in the device with specified serial
- * number
- *
- * @param serialNumber
- * @param applicationName
- * @return true if it is running, false otherwise
- */
- public static boolean isApplicationRunning(String serialNumber, String applicationName) {
- IDevice dev = null;
- boolean running = false;
- dev = connectedDevices.get(serialNumber);
- if (dev != null) {
- running = dev.getClient(applicationName) != null;
- }
- return running;
- }
-
- /**
- * Connect to a Remote Device given its IP/Port
+ * See http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html to
+ * understand how Process.exec works and its problems
*
- * @param device
- * the Remote Device Instance
- * @param host
- * device host (IP)
- * @param port
- * device port
+ * @param cmd
+ * Command to be executed.
+ * @param out
+ * Output Stream.
* @param timeout
- * the maximum time allowed to successfully connect to the device
+ * Timeout (secs.)
* @param monitor
- * the monitor of the operation
- * @return the status of the operation
+ * {@link IProgressMonitor}
+ *
+ * @return the {@link IStatus} of this process execution.
+ *
* @throws IOException
+ * Exception thrown in case there is any problem executing the
+ * command.
*/
- public static IStatus connectTcpIp(final ISerialNumbered device, String host, String port, int timeout,
- IProgressMonitor monitor) throws IOException {
- SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
-
- subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgConnectingToDeviceViaTCPIP, 10);
+ private IStatus executeRemoteDevicesCommand(String[] cmd, OutputStream out, int timeout, String timeoutMsg,
+ IStopCondition stopCondition, IProgressMonitor monitor) throws IOException {
IStatus status = Status.OK_STATUS;
+ long timeoutLimit = -1;
+ if (timeout != 0) {
+ timeoutLimit = System.currentTimeMillis() + (timeout * 1000);
+ }
- String serialNumber = device.getSerialNumber();
- if (!isDeviceOnline(serialNumber)) // check if it's already connected
- {
- String[] cmd = createConnectTcpIpCommand(host, port);
+ String fullCmd = ""; //$NON-NLS-1$
+ for (String cmdArg : cmd) {
+ fullCmd += cmdArg + " "; //$NON-NLS-1$
+ }
+ if (out != null) {
+ out.write(fullCmd.getBytes());
+ out.write("\n".getBytes()); //$NON-NLS-1$
+ }
+ Runtime r = Runtime.getRuntime();
+ Process p = r.exec(cmd);
- status = executeRemoteDevicesCommand(cmd, null, timeout,
- NLS.bind(AndroidNLS.ERR_RemoteDevice_TimeoutWhileConnecting, device.getDeviceName()),
- new IStopCondition() {
+ int errorCode = 0;
- @Override
- public boolean canStop() {
- String serialNumber = device.getSerialNumber();
- if (serialNumber != null) {
- return isDeviceOnline(serialNumber);
- } else {
- return false;
- }
- }
- }, subMonitor.newChild(1000));
+ // inputStream / errorStream;
+ String[] commandResults = new String[] { "", "" //$NON-NLS-1$ //$NON-NLS-2$
+ };
- }
+ commandResults = readCmdOutputFromStreams(commandResults[0], commandResults[1], p.getInputStream(),
+ p.getErrorStream(), out);
- subMonitor.worked(1000);
+ while (!stopCondition.canStop()) {
+ if ((monitor != null) && (monitor.isCanceled())) {
+ p.destroy();
+ return Status.CANCEL_STATUS;
+ }
+
+ try {
+ errorCode = p.exitValue();
+ if (errorCode != 0) {
+ break;
+ }
+
+ } catch (IllegalThreadStateException e) {
+ // Process is still running... Proceed with loop
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ AndmoreLogger.error("Execute command: thread has been interrupted"); //$NON-NLS-1$
+ }
+
+ if (timeout > 0) {
+ try {
+ testTimeout(timeoutLimit, ((timeoutMsg != null) ? timeoutMsg : AndroidNLS.ERR_GenericTimeout));
+ } catch (TimeoutException e) {
+ p.destroy();
+ AndmoreLogger.debug("The timeout " + timeout //$NON-NLS-1$
+ + " has been reached when executing the command " + fullCmd); //$NON-NLS-1$
+ return new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage(), e);
+ }
+ }
+
+ }
+ commandResults = readCmdOutputFromStreams(commandResults[0], commandResults[1], p.getInputStream(),
+ p.getErrorStream(), out);
+ if (errorCode != 0) {
+ AndmoreLogger.debug("Command " + cmd + " returned an error code: " + errorCode); //$NON-NLS-1$ //$NON-NLS-2$
+ status = new Status(IStatus.ERROR, PLUGIN_ID,
+ NLS.bind(AndroidNLS.ERR_CommandError, errorCode) + "\n" //$NON-NLS-1$
+ + ((!commandResults[1].equals("")) ? commandResults[1] //$NON-NLS-1$
+ : commandResults[0]));
+ } else {
+ status = new Status(IStatus.OK, PLUGIN_ID, commandResults[0]);
+ }
return status;
}
/**
- * Method which switches the device connection mode from TCP/IP to USB.
- *
- * @param device
- * {@link ISerialNumbered} device to have its connection mode
- * changed.
- * @param host
- * The IP of the device.
- * @param port
- * The port in which the TCP/IP connection is established.
- * @param timeout
- * The maximum time which the switching operation is attempted.
- * @param monitor
- * The {@link IProgressMonitor} which this operation is being
- * computed.
- *
- * @return Returns the {@link IStatus} of this operation.
- *
- * @throws IOException
- * Exception thrown in case something goes wrong while trying to
- * switch the device connection mode from TCP/IP to USB.
+ * @param commandResults
+ * @param errorResults
+ * @param inputStream
+ * @param errorStream
+ * @param out
*/
- public static IStatus switchFromTCPConnectionModeToUSBConnectionMode(final ISerialNumbered device, String host,
- String port, int timeout, IProgressMonitor monitor) throws IOException {
- SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
+ private String[] readCmdOutputFromStreams(String commandResults, String errorResults,
+ InputStream inputStream, InputStream errorStream, OutputStream out) {
+ String[] results = new String[2];
+ String line = ""; //$NON-NLS-1$
- subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgSwitchingDeviceFromTCPIPToUSB, 10);
+ BufferedReader brInput = new BufferedReader(new InputStreamReader(inputStream));
+ BufferedReader brError = new BufferedReader(new InputStreamReader(errorStream));
- IStatus status = Status.OK_STATUS;
+ try {
- String serialNumber = device.getSerialNumber();
- if (isDeviceOnline(serialNumber)) // check if it's already connected
- {
- String[] cmd = createSwitchToUSBConnectionModeCommand(host, port);
+ // input stream
+ if (brInput.ready()) {
+ while ((line = brInput.readLine()) != null) {
+ commandResults += line;
+ commandResults += "\n"; //$NON-NLS-1$
+ if (out != null) {
+ out.write(line.getBytes());
+ out.write("\n".getBytes()); //$NON-NLS-1$
+ }
+ }
+ }
- status = executeRemoteDevicesCommand(cmd, null, timeout,
- NLS.bind(AndroidNLS.DDMSFacade_MsgTimeoutReachedSwitchingFromTCPToUSB, device.getDeviceName()),
- new IStopCondition() {
+ // error stream
+ if (brError.ready()) {
+ while ((line = brError.readLine()) != null) {
+ errorResults += "\n"; //$NON-NLS-1$
+ if (out != null) {
+ out.write(line.getBytes());
+ out.write("\n".getBytes()); //$NON-NLS-1$
+ }
+ }
+ }
+ } catch (IOException e) {
+ AndmoreLogger.error("Cannot read command outputs"); //$NON-NLS-1$
+ } finally {
+ try {
+ brInput.close();
+ brError.close();
+ } catch (IOException e) {
+ AndmoreLogger.error("Could not close console stream: " + e.getMessage());
+ }
+ }
- @Override
- public boolean canStop() {
- String serialNumber = device.getSerialNumber();
- if (serialNumber != null) {
- return isDeviceOnline(serialNumber);
- } else {
- return false;
- }
- }
- }, subMonitor.newChild(1000));
+ results[0] = commandResults;
+ results[1] = errorResults;
+
+ return results;
+ }
+
+ /**
+ * Checks if the timeout limit has reached.
+ *
+ * @param timeoutLimit
+ * The system time limit that cannot be overtaken, in
+ * milliseconds.
+ * @throws StartTimeoutException
+ * When the system time limit is overtaken.
+ */
+ private void testTimeout(long timeoutLimit, String timeoutErrorMessage) throws TimeoutException {
+ if (System.currentTimeMillis() > timeoutLimit) {
+ throw new TimeoutException(timeoutErrorMessage);
}
+ }
- subMonitor.worked(1000);
+ /**
+ * Creates a string with the command that should be called in order to run
+ * the application.
+ */
+ private String[] createRunCommand(String serialNumber, String activityName, boolean debugMode) {
+ String cmd[];
+
+ // The tools folder should exist and be here, but double-cheking
+ // once more wont kill
+ File f = new File(sdkPath + PLATFORM_TOOLS_FOLDER + File.separator);
+ if (!f.exists()) {
+ AndmoreLogger.error("Run: Could not find tools folder on " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
+ + File.separator);
+ } else {
+ if (!f.isDirectory()) {
+ AndmoreLogger.error("Run: Invalid tools folder " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
+ + File.separator);
+ }
+ }
- if (status.isOK()) {
- AndmoreLogger.collectUsageData(UsageDataConstants.WHAT_REMOTE_USB, UsageDataConstants.KIND_REMOTE_DEVICE,
- UsageDataConstants.DESCRIPTION_DEFAULT, AndroidPlugin.PLUGIN_ID, AndroidPlugin.getDefault()
- .getBundle().getVersion().toString());
+ String completeAppPath = activityName.substring(0, activityName.lastIndexOf(".")) + "/" + activityName; //$NON-NLS-1$ //$NON-NLS-2$
+ if (debugMode) {
+ // If debugMode option is checked, create command with the -D
+ // paramater
+ String cmdTemp[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
+ ADB_INSTANCE_PARAMETER, serialNumber, SHELL_CMD, AM_CMD, START_CMD, ADB_AM_DEBUG, ADB_AM_NAME,
+ completeAppPath };
+ cmd = cmdTemp;
+ } else {
+ // If debugMode option is unchecked, create command without the -D
+ // paramater
+ String cmdTemp[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
+ ADB_INSTANCE_PARAMETER, serialNumber, SHELL_CMD, AM_CMD, START_CMD, ADB_AM_NAME, completeAppPath };
+ cmd = cmdTemp;
}
- return status;
+ return cmd;
}
- /**
- * Get the wireless ip from the connected handset
- *
- * @param serialNumber
- * @param monitor
- * @return the ip or null if not possible to retrieve it
- */
- public static String getWirelessIPfromHandset(String serialNumber, IProgressMonitor monitor) {
- String handset_wireless_ip = null;
- IDevice device = null;
-
- device = connectedDevices.get(serialNumber);
+ private Collection executeShellCmd(String serialNumber, final String cmd,
+ final IProgressMonitor monitor) {
+ final Collection results = new ArrayList();
+ IDevice device = getDeviceBySerialNumber(serialNumber);
if (device != null) {
- // get the wi-fi name for executing the ipconfig command
- String wifiProperty = device.getProperty(WIFI_INTERFACE_DEVICE_PROPERTY);
- if (wifiProperty == null) {
- wifiProperty = DEFAULT_WIRELESS_DEVICE_PROPERTY;
- }
- // execute ipconfig command
- Collection answers = executeShellCmd(serialNumber, IFCONFIG_CMD + " " + wifiProperty, monitor); //$NON-NLS-1$
-
- // Success message - for example
- // [tiwlan0: ip 192.168.0.174 mask 255.255.255.0 flags [up broadcast
- // running multicast]]
+ try {
+ device.executeShellCommand(cmd, new MultiLineReceiver() {
+ @Override
+ public boolean isCancelled() {
+ return monitor.isCanceled();
+ }
- if (answers != null) {
- String result = answers.toString();
- if (result != null) {
- // splits the result of the shell command and gets the third
- // position
- // that should be the IP number
- String[] result_splited = result.split(" "); //$NON-NLS-1$
- if (result_splited.length >= 3) {
- // check whether there is an IP
- Pattern pattern = Pattern.compile(IP_PATTERN);
- Matcher matcher = pattern.matcher(result);
- if (matcher.find()) {
- handset_wireless_ip = result_splited[2];
+ @Override
+ public void processNewLines(String[] lines) {
+ for (String line : lines) {
+ if ((!line.equals("")) && (!line.equals(cmd))) //$NON-NLS-1$
+ {
+ results.add(line);
+ }
}
}
- }
+ }, 0, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ AndmoreLogger.error(DeviceMonitor.class, "Error executing shell command " + cmd //$NON-NLS-1$
+ + " at device " + serialNumber, e); //$NON-NLS-1$
}
}
- return handset_wireless_ip;
+ return results;
}
- /**
- * Switch adb connection mode of an specific device to TCPIP
- *
- * @param deviceName
- * name of the handset instance
- * @param host
- * wireless ip of the handset instance
- * @param port
- * number of the port to be using during the connection
- * @param timeout
- * the maximum time allowed to successfully connect to the device
- * @param monitor
- * the monitor of the operation
- * @return the status of the operation
- *
- * @throws IOException
- * Exception thrown in case there are problems switching the
- * device.
- */
- public static IStatus switchUSBtoTcpIp(String deviceName, final String serialNumber, String port, int timeout,
- IProgressMonitor monitor) throws IOException {
- SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
-
- subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgSwitchingFromUSBConnection, 10);
-
- IStatus status = Status.OK_STATUS;
+ private String getVmNameByTelnet(String serialNumber) {
+ Pattern pattern = Pattern.compile("emulator-([0-9]+)"); //$NON-NLS-1$
+ TelnetFrameworkAndroid telnet = new TelnetFrameworkAndroid();
+ Matcher matcher = pattern.matcher(serialNumber);
+ matcher.matches();
+ String avdName = null;
- if (isDeviceOnline(serialNumber)) {
- String[] cmd = createSwitchToTcpIpCommand(serialNumber, port);
+ try {
+ Integer telnetPort = Integer.valueOf(matcher.group(1));
+ telnet.connect("localhost", telnetPort); //$NON-NLS-1$
+ String avdNameRaw = telnet.write("avd name\r\n", new String[] //$NON-NLS-1$
+ { "KO" //$NON-NLS-1$
+ });
- status = executeRemoteDevicesCommand(cmd, null, timeout,
- NLS.bind(AndroidNLS.ERR_WirelessRemoteDevice_TimeoutWhileConnecting, deviceName),
- new IStopCondition() {
+ String split = avdNameRaw.contains("\r\n") ? "\r\n" : "\n";
- @Override
- public boolean canStop() {
- if (serialNumber != null) {
- return isDeviceOffline(serialNumber);
- } else {
- return false;
- }
- }
- }, subMonitor.newChild(1000));
+ String[] outputArray = avdNameRaw.split(split);
+ if (outputArray.length > 2) {
+ avdName = outputArray[2];
+ }
+ if (avdName != null) {
+ synchronized(avdNameMap) {
+ avdNameMap.put(serialNumber, avdName);
+ }
+ }
+ } catch (NumberFormatException e) {
+ avdName = serialNumber;
+ } catch (IOException e) {
+ avdName = serialNumber;
+ } finally {
+ try {
+ telnet.disconnect();
+ } catch (IOException e) {
+ // Do nothing.
+ }
}
-
- monitor.worked(1000);
-
- return status;
+ return avdName;
}
/**
- * Disconnect from a Remote Device given its IP/Port
+ * Gets the AVD name of the device
*
- * @param device
- * the Remote Device Instance
- * @param host
- * device host (IP)
- * @param port
- * device port
- * @param timeout
- * the maximum time allowed to successfully disconnect from the
- * device
- * @param monitor
- * the monitor of the operation
- * @return the status of the operation
- * @throws IOException
+ * @param d
+ * The device to be searched for the AVD name
+ *
+ * @return The AVD name
*/
- public static IStatus disconnectTcpIp(final ISerialNumbered device, String host, String port, int timeout,
- IProgressMonitor monitor) throws IOException {
- IStatus status = Status.OK_STATUS;
-
- String serialNumber = device.getSerialNumber();
- if (isDeviceOnline(serialNumber)) // check if it's already disconnected
- {
- String[] cmd = createDisconnectTcpIpCommand(host, port);
-
- status = executeRemoteDevicesCommand(cmd, null, timeout,
- NLS.bind(AndroidNLS.ERR_RemoteDevice_TimeoutWhileDisconnecting, device.getDeviceName()),
- new IStopCondition() {
-
- @Override
- public boolean canStop() {
- String serialNumber = device.getSerialNumber();
- return !isDeviceOnline(serialNumber);
- }
- }, monitor);
+ private String getNameByDevice(final IDevice d) {
+ String name = null;
+ if (d != null) {
+ if (d.isEmulator()) {
+ name = getVmName(d);
+ } else {
+ name = d.getSerialNumber();
+ }
}
-
- return status;
+ return name;
}
/**
@@ -1772,14 +1934,10 @@ public boolean canStop() {
* device port
* @return the command to be used to connect to an IP/Port
*/
- private static String[] createConnectTcpIpCommand(String host, String port) {
+ private String[] createConnectTcpIpCommand(String host, String port) {
String hostPort = host + ":" + port; //$NON-NLS-1$
-
- String sdkPath = SdkUtils.getSdkPath();
-
String cmd[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND, CONNECT_TCPIP_CMD, hostPort };
-
return cmd;
}
@@ -1794,15 +1952,12 @@ private static String[] createConnectTcpIpCommand(String host, String port) {
*
* @return The command to be used to switch back to USB connection mode.
*/
- private static String[] createSwitchToUSBConnectionModeCommand(String host, String port) {
+ private String[] createSwitchToUSBConnectionModeCommand(String host, String port) {
String hostPort = host + ":" + port; //$NON-NLS-1$
- String sdkPath = SdkUtils.getSdkPath();
-
String cmd[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND, DEVICE_ID_INDICATOR, hostPort,
USB_SWITCH_BACK_COMMAND };
-
return cmd;
}
@@ -1816,12 +1971,9 @@ private static String[] createSwitchToUSBConnectionModeCommand(String host, Stri
* device port
* @return the command to be used to switch adb connection to TCPIP mode
*/
- private static String[] createSwitchToTcpIpCommand(String serialNumber, String port) {
- String sdkPath = SdkUtils.getSdkPath();
-
+ private String[] createSwitchToTcpIpCommand(String serialNumber, String port) {
String cmd[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND, ADB_INSTANCE_PARAMETER,
serialNumber, TCPIP_CMD, port };
-
return cmd;
}
@@ -1834,9 +1986,7 @@ private static String[] createSwitchToTcpIpCommand(String serialNumber, String p
* @param folder
* @return
*/
- private static String[] createDeleteFileFromDeviceCommand(String serialNumber, String file, String folder) {
- String sdkPath = SdkUtils.getSdkPath();
-
+ private String[] createDeleteFileFromDeviceCommand(String serialNumber, String file, String folder) {
// The tools folder should exist and be here, but double-cheking
// once more wont kill
File f = new File(sdkPath + PLATFORM_TOOLS_FOLDER + File.separator);
@@ -1849,11 +1999,9 @@ private static String[] createDeleteFileFromDeviceCommand(String serialNumber, S
+ File.separator);
}
}
-
String cmd[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND, ADB_INSTANCE_PARAMETER,
serialNumber, SHELL_CMD, "rm /" + folder + "/" + file //$NON-NLS-1$ //$NON-NLS-2$
};
-
return cmd;
}
@@ -1866,64 +2014,19 @@ private static String[] createDeleteFileFromDeviceCommand(String serialNumber, S
* @return
* @throws IOException
*/
- private static boolean deleteFileFromDevice(String serialNumber, String fileName, String folder) throws IOException {
+ private boolean deleteFileFromDevice(String serialNumber, String fileName, String folder) throws IOException {
String command[] = createDeleteFileFromDeviceCommand(serialNumber, fileName, folder);
IStatus status = executeRemoteDevicesCommand(command, null, 1000, "", new IStopCondition() //$NON-NLS-1$
{
-
@Override
public boolean canStop() {
return true;
}
}, null);
-
return status.isOK();
}
- /**
- * Check if a device identified by the serial number has a mounted SDCard
- *
- * @param serialNumber
- * the serial number
- * @return true if the device has a SDCard
- * @throws IOException
- */
- public static boolean hasSDCard(String serialNumber) throws IOException {
- boolean hasSdCard = false;
- File tempSdCardFile = File.createTempFile("SDcheck", ".tmp"); //$NON-NLS-1$ //$NON-NLS-2$
- boolean tempCopiedOnSdCardFile = pushFileToDevice(serialNumber, SDCARD_FOLDER, tempSdCardFile);
-
- if (tempCopiedOnSdCardFile) {
- // trying to write on /sdcard folder (it works for phones previous
- // from Platform 2.2)
- if (!deleteFileFromDevice(serialNumber, tempSdCardFile.getName(), SDCARD_FOLDER)) {
- AndmoreLogger
- .error("DDMSFacade: Could not delete tempfile from /sdcard when checking if card is enabled"); //$NON-NLS-1$
- }
- hasSdCard = true;
- tempSdCardFile.delete();
- } else {
-
- File tempMntFile = File.createTempFile("SDcheck", ".tmp"); //$NON-NLS-1$ //$NON-NLS-2$
- boolean tempCopiedOnMntFile = pushFileToDevice(serialNumber, MNT_SDCARD_FOLDER, tempSdCardFile);
-
- if (tempCopiedOnMntFile) {
- // trying to write on /mnt/sdcard folder (it works for phones
- // since Platform 2.2)
- if (!deleteFileFromDevice(serialNumber, tempMntFile.getName(), MNT_SDCARD_FOLDER)) {
- AndmoreLogger
- .error("DDMSFacade: Could not delete tempfile from /mnt/sdcard when checking if card is enabled"); //$NON-NLS-1$
- }
- hasSdCard = true;
- tempMntFile.delete();
- }
-
- }
-
- return hasSdCard;
- }
-
/**
*
* @param serialNumber
@@ -1931,7 +2034,7 @@ public static boolean hasSDCard(String serialNumber) throws IOException {
* @param tempFile
* @return true if manages to push file into the folder specified on device
*/
- private static boolean pushFileToDevice(String serialNumber, String folder, File file) {
+ private boolean pushFileToDevice(String serialNumber, String folder, File file) {
Collection files = new ArrayList();
files.add(file.getName());
Path path = new Path(file.getAbsolutePath());
@@ -1952,18 +2055,72 @@ private static boolean pushFileToDevice(String serialNumber, String folder, File
* device port
* @return the command to be used to disconnect from an IP/Port
*/
- private static String[] createDisconnectTcpIpCommand(String host, String port) {
+ private String[] createDisconnectTcpIpCommand(String host, String port) {
String hostPort = host + ":" + port; //$NON-NLS-1$
- String sdkPath = SdkUtils.getSdkPath();
String cmd[] = { sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND, DISCONNECT_TCPIP_CMD, hostPort };
return cmd;
}
- public static void deleteFile(String serialNumber, String path) throws IOException {
- DDMSFacade.execRemoteApp(serialNumber, "rm " + path, //$NON-NLS-1$
- new NullProgressMonitor());
+ private void completeDeviceConnection(IDevice device, final String serialNumber) {
+ if (device.hasClients()) {
+ // When a device is connected, look for the HOME application and add
+ // the device serial number to a collection if it is already
+ // running.
+ IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
+ String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
+ if (device.getClient(home) != null) {
+ AndmoreLogger.debug("Completely Up Device: " + serialNumber); //$NON-NLS-1$
+ synchronized (completelyUpDevices) {
+ completelyUpDevices.add(serialNumber);
+ }
+ }
+ }
+ Job job = new Job("Notify device " + serialNumber + " connected"){
+
+ @Override
+ protected IStatus run(IProgressMonitor arg0) {
+ if (device.isEmulator()) {
+ // Getting VM name first time may block for up to 10 seconds
+ String vmName = null;
+ synchronized (avdNameMap) {
+ vmName = avdNameMap.get(serialNumber);
+ }
+ if (vmName == null)
+ vmName = getVmName(device);
+ if (vmName == null) {
+ AndmoreLogger.error("AVD name not available for device " + serialNumber);
+ return Status.CANCEL_STATUS;
+ }
+ }
+ // Fire events in worker thread to prevent blocking caller thread
+ AndmoreEventManager.fireEvent(EventType.DEVICE_CONNECTED, serialNumber);
+ return Status.OK_STATUS;
+ }};
+ job.setPriority(Job.BUILD);
+ job.schedule();
}
+
+
+ public static DeviceMonitor instance() {
+ if (singleton == null) {
+ synchronized(DeviceMonitor.class) {
+ singleton = new DeviceMonitor();
+ AndroidDebugBridge.addDeviceChangeListener(singleton);
+ // Adds listener for the HOME application. It adds the serial number of the
+ // device to a collection when it identifies that the HOME application has loaded
+ AndroidDebugBridge.addClientChangeListener(singleton);
+ }
+ }
+ return singleton;
+ }
+
+ public static void dispose() {
+ if (singleton != null) {
+ AndroidDebugBridge.removeDeviceChangeListener(singleton);
+ AndroidDebugBridge.removeClientChangeListener(singleton);
+ }
+ }
}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/NullDevice.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/NullDevice.java
new file mode 100644
index 00000000..83f4a30c
--- /dev/null
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/NullDevice.java
@@ -0,0 +1,371 @@
+package org.eclipse.andmore.android;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.Client;
+import com.android.ddmlib.FileListingService;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.InstallException;
+import com.android.ddmlib.RawImage;
+import com.android.ddmlib.ScreenRecorderOptions;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.SyncException;
+import com.android.ddmlib.SyncService;
+import com.android.ddmlib.TimeoutException;
+import com.android.ddmlib.log.LogReceiver;
+import com.android.sdklib.AndroidVersion;
+
+public class NullDevice implements IDevice {
+ class NullFuture implements Future {
+ T value;
+ NullFuture(T value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return true;
+ }
+
+ @Override
+ public T get() throws InterruptedException, ExecutionException {
+ return value;
+ }
+
+ @Override
+ public T get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, java.util.concurrent.TimeoutException {
+
+ return value;
+ }
+ }
+
+ private static final String BLANK = "";
+ private static final String DEVICE_NAME = "null device";
+
+ @Override
+ public String getName() {
+
+ return DEVICE_NAME;
+ }
+
+ @Override
+ public void executeShellCommand(String command, IShellOutputReceiver receiver, long maxTimeToOutputResponse,
+ TimeUnit maxTimeUnits)
+ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public Future getSystemProperty(String name) {
+ return new NullFuture(BLANK);
+ }
+
+ @Override
+ public String getSerialNumber() {
+ return BLANK;
+ }
+
+ @Override
+ public String getAvdName() {
+ return DEVICE_NAME;
+ }
+
+ @Override
+ public DeviceState getState() {
+ return DeviceState.OFFLINE;
+ }
+
+ @Override
+ public Map getProperties() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public int getPropertyCount() {
+ return 0;
+ }
+
+ @Override
+ public String getProperty(String name) {
+ return BLANK;
+ }
+
+ @Override
+ public boolean arePropertiesSet() {
+ return false;
+ }
+
+ @Override
+ public String getPropertySync(String name)
+ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ return BLANK;
+ }
+
+ @Override
+ public String getPropertyCacheOrSync(String name)
+ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ return BLANK;
+ }
+
+ @Override
+ public boolean supportsFeature(Feature feature) {
+ return false;
+ }
+
+ @Override
+ public boolean supportsFeature(HardwareFeature feature) {
+ return false;
+ }
+
+ @Override
+ public String getMountPoint(String name) {
+
+ return BLANK;
+ }
+
+ @Override
+ public boolean isOnline() {
+ return false;
+ }
+
+ @Override
+ public boolean isEmulator() {
+ return false;
+ }
+
+ @Override
+ public boolean isOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean isBootLoader() {
+ return false;
+ }
+
+ @Override
+ public boolean hasClients() {
+ return false;
+ }
+
+ @Override
+ public Client[] getClients() {
+
+ return new Client[0];
+ }
+
+ @Override
+ public Client getClient(String applicationName) {
+ return null;
+ }
+
+ @Override
+ public SyncService getSyncService() throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public FileListingService getFileListingService() {
+ return null;
+ }
+
+ @Override
+ public RawImage getScreenshot() throws TimeoutException, AdbCommandRejectedException, IOException {
+ return new RawImage();
+ }
+
+ @Override
+ public RawImage getScreenshot(long timeout, TimeUnit unit)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ return new RawImage();
+ }
+
+ @Override
+ public void startScreenRecorder(String remoteFilePath, ScreenRecorderOptions options, IShellOutputReceiver receiver)
+ throws TimeoutException, AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void executeShellCommand(String command, IShellOutputReceiver receiver, int maxTimeToOutputResponse)
+ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void executeShellCommand(String command, IShellOutputReceiver receiver)
+ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void runEventLogService(LogReceiver receiver)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void runLogService(String logname, LogReceiver receiver)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void createForward(int localPort, int remotePort)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void createForward(int localPort, String remoteSocketName, DeviceUnixSocketNamespace namespace)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void removeForward(int localPort, int remotePort)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void removeForward(int localPort, String remoteSocketName, DeviceUnixSocketNamespace namespace)
+ throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public String getClientName(int pid) {
+ return DEVICE_NAME;
+ }
+
+ @Override
+ public void pushFile(String local, String remote)
+ throws IOException, AdbCommandRejectedException, TimeoutException, SyncException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void pullFile(String remote, String local)
+ throws IOException, AdbCommandRejectedException, TimeoutException, SyncException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void installPackage(String packageFilePath, boolean reinstall, String... extraArgs) throws InstallException {
+ throw new InstallException(DEVICE_NAME);
+ }
+
+ @Override
+ public void installPackages(List apks, boolean reinstall, List installOptions, long timeout,
+ TimeUnit timeoutUnit) throws InstallException {
+ throw new InstallException(DEVICE_NAME);
+ }
+
+ @Override
+ public String syncPackageToDevice(String localFilePath)
+ throws TimeoutException, AdbCommandRejectedException, IOException, SyncException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public void installRemotePackage(String remoteFilePath, boolean reinstall, String... extraArgs)
+ throws InstallException {
+ throw new InstallException(DEVICE_NAME);
+ }
+
+ @Override
+ public void removeRemotePackage(String remoteFilePath) throws InstallException {
+ throw new InstallException(DEVICE_NAME);
+ }
+
+ @Override
+ public String uninstallPackage(String packageName) throws InstallException {
+ throw new InstallException(DEVICE_NAME);
+ }
+
+ @Override
+ public void reboot(String into) throws TimeoutException, AdbCommandRejectedException, IOException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public boolean root()
+ throws TimeoutException, AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public boolean isRoot()
+ throws TimeoutException, AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public Integer getBatteryLevel()
+ throws TimeoutException, AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public Integer getBatteryLevel(long freshnessMs)
+ throws TimeoutException, AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException {
+ throw new IOException(DEVICE_NAME);
+ }
+
+ @Override
+ public Future getBattery() {
+ return new NullFuture(0);
+ }
+
+ @Override
+ public Future getBattery(long freshnessTime, TimeUnit timeUnit) {
+ return new NullFuture(0);
+ }
+
+ @Override
+ public List getAbis() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public int getDensity() {
+ return 0;
+ }
+
+ @Override
+ public String getLanguage() {
+ return BLANK;
+ }
+
+ @Override
+ public String getRegion() {
+ return BLANK;
+ }
+
+ @Override
+ public AndroidVersion getVersion() {
+ return AndroidVersion.DEFAULT;
+ }
+
+}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/AbstractDeviceDropSupportHandler.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/AbstractDeviceDropSupportHandler.java
index d5db4032..ab81dc3e 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/AbstractDeviceDropSupportHandler.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/AbstractDeviceDropSupportHandler.java
@@ -19,7 +19,7 @@
import java.util.ArrayList;
import java.util.List;
-import org.eclipse.andmore.android.DDMSFacade;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.DDMSUtils;
import org.eclipse.andmore.android.InstallPackageBean;
import org.eclipse.andmore.android.i18n.AndroidNLS;
@@ -114,7 +114,7 @@ private synchronized IStatus installAPK(File apk, final IInstance instance) {
installBean.setCanOverwrite(INSTALL_TYPE.UNINSTALL);
installBean.setPackagePath(apk.getAbsolutePath());
- return DDMSUtils.installPackage(DDMSFacade.getSerialNumberByName(instance.getName()), installBean);
+ return DDMSUtils.installPackage(DeviceMonitor.instance().getSerialNumberByName(instance.getName()), installBean);
}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/DevicesManager.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/DevicesManager.java
index 27b113ba..3c996071 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/DevicesManager.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/devices/DevicesManager.java
@@ -1,259 +1,259 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.devices;
-
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.TreeSet;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.ISerialNumbered;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.sequoyah.device.common.utilities.exception.SequoyahException;
-import org.eclipse.sequoyah.device.framework.DeviceUtils;
-import org.eclipse.sequoyah.device.framework.factory.DeviceTypeRegistry;
-import org.eclipse.sequoyah.device.framework.factory.InstanceRegistry;
-import org.eclipse.sequoyah.device.framework.manager.InstanceManager;
-import org.eclipse.sequoyah.device.framework.model.IDeviceType;
-import org.eclipse.sequoyah.device.framework.model.IInstance;
-import org.eclipse.sequoyah.device.framework.model.IInstanceBuilder;
-import org.eclipse.sequoyah.device.framework.model.IService;
-import org.eclipse.sequoyah.device.framework.model.handler.IServiceHandler;
-
-/**
- * This manager provides information about device instances It shall work with
- * TmL to be able to provide these information
- */
-public class DevicesManager {
-
- // instance
- private static DevicesManager instance;
-
- /**
- * Singleton
- *
- * @return a unique DevicesManager instance
- */
- public static DevicesManager getInstance() {
- if (instance == null) {
- instance = new DevicesManager();
- }
- return instance;
- }
-
- /**
- * Get all devices registered in TmL
- *
- * @return all devices registered in TmL
- */
- public Collection getAllDevices() {
- Collection devicesCollection = new LinkedHashSet();
-
- List tmlDevices = InstanceRegistry.getInstance().getInstances();
-
- for (IInstance tmlInstance : tmlDevices) {
- if (tmlInstance instanceof ISerialNumbered) {
- devicesCollection.add((ISerialNumbered) tmlInstance);
- }
- }
- return devicesCollection;
- }
-
- /**
- * Get all devices registered in TmL, sorted using the comparator passed as
- * a parameter
- *
- * @param comparator
- * the comparator that will be used to sort the devices list
- * @return all devices registered in TmL, sorted using the comparator passed
- * as a parameter
- */
- public Collection getAllDevices(Comparator comparator) {
- Collection sortedDevices = new TreeSet(comparator);
- sortedDevices.addAll(getAllDevices());
- return sortedDevices;
- }
-
- /**
- * Get all devices registered in TmL, sorted using the default comparator
- *
- * @return all devices registered in TmL, sorted using the default
- * comparator
- */
- public Collection getAllDevicesSorted() {
- return getAllDevices(getDefaultComparator());
- }
-
- /**
- * Get the device, given its name
- *
- * @param name
- * the device name
- * @return a device instance
- */
- public ISerialNumbered getDeviceByName(String name) {
- ISerialNumbered instanceToReturn = null;
-
- for (ISerialNumbered device : getAllDevices()) {
- if (device.getDeviceName().equals(name)) {
- instanceToReturn = device;
- break;
- }
- }
- return instanceToReturn;
-
- }
-
- /**
- * Get the device, given its serial number
- *
- * @param serial
- * the device serial name
- * @return a device instance
- */
- public ISerialNumbered getDeviceBySerialNumber(String serial) {
- ISerialNumbered instanceToReturn = null;
-
- String serialNumber = "";
- for (ISerialNumbered device : getAllDevices()) {
- if ((serialNumber = device.getSerialNumber()) != null) {
- if (serialNumber.equals(serial)) {
- instanceToReturn = device;
- break;
- }
- }
- }
- return instanceToReturn;
-
- }
-
- /**
- * Get all devices of certain type
- *
- * @param type
- * the device type
- * @return all devices of the device passed as a parameter
- */
- @SuppressWarnings("unchecked")
- public Collection getInstancesByType(Class type) {
- Collection instancesToReturn = new LinkedHashSet();
-
- for (ISerialNumbered device : getAllDevices()) {
- if (device.getClass().equals(type)) {
- instancesToReturn.add(device);
- }
- }
- return instancesToReturn;
-
- }
-
- /**
- * Get all online devices of certain type
- *
- * @param type
- * the device type
- * @return all online devices of the device passed as a parameter
- */
- @SuppressWarnings("unchecked")
- public Collection getOnlineDevicesByType(Class type) {
- Collection instancesToReturn = new HashSet();
-
- String serialNumber = null;
- for (ISerialNumbered device : getInstancesByType(type)) {
- if (((serialNumber = device.getSerialNumber()) != null) && (DDMSFacade.isDeviceOnline(serialNumber))) {
- instancesToReturn.add(device);
- }
- }
- return instancesToReturn;
-
- }
-
- /**
- * The default comparator to be used to sort ISerialNumbered instances It
- * considers if the devices are online and after that it compares their
- * names Online devices shall be placed in the beginning of the list
- *
- * @return a Comparator instance
- */
- public static Comparator getDefaultComparator() {
- return new Comparator() {
- @Override
- public int compare(ISerialNumbered serial1, ISerialNumbered serial2) {
- int compareResult;
-
- String name1 = serial1.getDeviceName();
- String name2 = serial2.getDeviceName();
- boolean dev1online = serial1.getSerialNumber() != null;
- boolean dev2online = serial2.getSerialNumber() != null;
-
- if ((dev1online && dev2online) || (!dev1online && !dev2online)) {
- compareResult = name1.compareToIgnoreCase(name2);
- } else if (dev1online) {
- compareResult = -1;
- } else
- // dev2online
- {
- compareResult = 1;
- }
-
- return compareResult;
- }
- };
- }
-
- /**
- * Creates a TmL instance
- *
- * @param serialNumber
- * The serial number of the device to create a TmL instance for
- * @throws TmLException
- */
- public void createInstanceForDevice(String serialNumber, String deviceTypeID, IInstanceBuilder instanceBuilder,
- String initServiceID) throws SequoyahException {
-
- ISerialNumbered instance = getDeviceBySerialNumber(serialNumber);
- if (instance == null) {
- IDeviceType tmlDeviceType = DeviceTypeRegistry.getInstance().getDeviceTypeById(deviceTypeID);
-
- InstanceManager.createProject(tmlDeviceType, instanceBuilder, new NullProgressMonitor());
-
- IInstance newInstance = (IInstance) getDeviceBySerialNumber(serialNumber);
- IService service = DeviceUtils.getServiceById(tmlDeviceType, initServiceID);
- IServiceHandler handler = service.getHandler();
- handler.run(newInstance);
- }
-
- }
-
- /**
- * Destroys the TmL instance
- *
- * @param device
- * The device to delete the correspondent TmL instance
- */
- public void deleteInstanceOfDevice(String serialNumber) {
-
- IInstance instanceToDelete = (IInstance) getDeviceBySerialNumber(serialNumber);
- if (instanceToDelete != null) {
- InstanceManager.deleteInstance(instanceToDelete);
- }
-
- }
-
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.devices;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.ISerialNumbered;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.sequoyah.device.common.utilities.exception.SequoyahException;
+import org.eclipse.sequoyah.device.framework.DeviceUtils;
+import org.eclipse.sequoyah.device.framework.factory.DeviceTypeRegistry;
+import org.eclipse.sequoyah.device.framework.factory.InstanceRegistry;
+import org.eclipse.sequoyah.device.framework.manager.InstanceManager;
+import org.eclipse.sequoyah.device.framework.model.IDeviceType;
+import org.eclipse.sequoyah.device.framework.model.IInstance;
+import org.eclipse.sequoyah.device.framework.model.IInstanceBuilder;
+import org.eclipse.sequoyah.device.framework.model.IService;
+import org.eclipse.sequoyah.device.framework.model.handler.IServiceHandler;
+
+/**
+ * This manager provides information about device instances It shall work with
+ * TmL to be able to provide these information
+ */
+public class DevicesManager {
+
+ // instance
+ private static DevicesManager instance;
+
+ /**
+ * Singleton
+ *
+ * @return a unique DevicesManager instance
+ */
+ public static DevicesManager getInstance() {
+ if (instance == null) {
+ instance = new DevicesManager();
+ }
+ return instance;
+ }
+
+ /**
+ * Get all devices registered in TmL
+ *
+ * @return all devices registered in TmL
+ */
+ public Collection getAllDevices() {
+ Collection devicesCollection = new LinkedHashSet();
+
+ List tmlDevices = InstanceRegistry.getInstance().getInstances();
+
+ for (IInstance tmlInstance : tmlDevices) {
+ if (tmlInstance instanceof ISerialNumbered) {
+ devicesCollection.add((ISerialNumbered) tmlInstance);
+ }
+ }
+ return devicesCollection;
+ }
+
+ /**
+ * Get all devices registered in TmL, sorted using the comparator passed as
+ * a parameter
+ *
+ * @param comparator
+ * the comparator that will be used to sort the devices list
+ * @return all devices registered in TmL, sorted using the comparator passed
+ * as a parameter
+ */
+ public Collection getAllDevices(Comparator comparator) {
+ Collection sortedDevices = new TreeSet(comparator);
+ sortedDevices.addAll(getAllDevices());
+ return sortedDevices;
+ }
+
+ /**
+ * Get all devices registered in TmL, sorted using the default comparator
+ *
+ * @return all devices registered in TmL, sorted using the default
+ * comparator
+ */
+ public Collection getAllDevicesSorted() {
+ return getAllDevices(getDefaultComparator());
+ }
+
+ /**
+ * Get the device, given its name
+ *
+ * @param name
+ * the device name
+ * @return a device instance
+ */
+ public ISerialNumbered getDeviceByName(String name) {
+ ISerialNumbered instanceToReturn = null;
+
+ for (ISerialNumbered device : getAllDevices()) {
+ if (device.getDeviceName().equals(name)) {
+ instanceToReturn = device;
+ break;
+ }
+ }
+ return instanceToReturn;
+
+ }
+
+ /**
+ * Get the device, given its serial number
+ *
+ * @param serial
+ * the device serial name
+ * @return a device instance
+ */
+ public ISerialNumbered getDeviceBySerialNumber(String serial) {
+ ISerialNumbered instanceToReturn = null;
+
+ String serialNumber = "";
+ for (ISerialNumbered device : getAllDevices()) {
+ if ((serialNumber = device.getSerialNumber()) != null) {
+ if (serialNumber.equals(serial)) {
+ instanceToReturn = device;
+ break;
+ }
+ }
+ }
+ return instanceToReturn;
+
+ }
+
+ /**
+ * Get all devices of certain type
+ *
+ * @param type
+ * the device type
+ * @return all devices of the device passed as a parameter
+ */
+ @SuppressWarnings("unchecked")
+ public Collection getInstancesByType(Class type) {
+ Collection instancesToReturn = new LinkedHashSet();
+
+ for (ISerialNumbered device : getAllDevices()) {
+ if (device.getClass().equals(type)) {
+ instancesToReturn.add(device);
+ }
+ }
+ return instancesToReturn;
+
+ }
+
+ /**
+ * Get all online devices of certain type
+ *
+ * @param type
+ * the device type
+ * @return all online devices of the device passed as a parameter
+ */
+ @SuppressWarnings("unchecked")
+ public Collection getOnlineDevicesByType(Class type) {
+ Collection instancesToReturn = new HashSet();
+
+ String serialNumber = null;
+ for (ISerialNumbered device : getInstancesByType(type)) {
+ if (((serialNumber = device.getSerialNumber()) != null) && (DeviceMonitor.instance().isDeviceOnline(serialNumber))) {
+ instancesToReturn.add(device);
+ }
+ }
+ return instancesToReturn;
+
+ }
+
+ /**
+ * The default comparator to be used to sort ISerialNumbered instances It
+ * considers if the devices are online and after that it compares their
+ * names Online devices shall be placed in the beginning of the list
+ *
+ * @return a Comparator instance
+ */
+ public static Comparator getDefaultComparator() {
+ return new Comparator() {
+ @Override
+ public int compare(ISerialNumbered serial1, ISerialNumbered serial2) {
+ int compareResult;
+
+ String name1 = serial1.getDeviceName();
+ String name2 = serial2.getDeviceName();
+ boolean dev1online = serial1.getSerialNumber() != null;
+ boolean dev2online = serial2.getSerialNumber() != null;
+
+ if ((dev1online && dev2online) || (!dev1online && !dev2online)) {
+ compareResult = name1.compareToIgnoreCase(name2);
+ } else if (dev1online) {
+ compareResult = -1;
+ } else
+ // dev2online
+ {
+ compareResult = 1;
+ }
+
+ return compareResult;
+ }
+ };
+ }
+
+ /**
+ * Creates a TmL instance
+ *
+ * @param serialNumber
+ * The serial number of the device to create a TmL instance for
+ * @throws TmLException
+ */
+ public void createInstanceForDevice(String serialNumber, String deviceTypeID, IInstanceBuilder instanceBuilder,
+ String initServiceID) throws SequoyahException {
+
+ ISerialNumbered instance = getDeviceBySerialNumber(serialNumber);
+ if (instance == null) {
+ IDeviceType tmlDeviceType = DeviceTypeRegistry.getInstance().getDeviceTypeById(deviceTypeID);
+
+ InstanceManager.createProject(tmlDeviceType, instanceBuilder, new NullProgressMonitor());
+
+ IInstance newInstance = (IInstance) getDeviceBySerialNumber(serialNumber);
+ IService service = DeviceUtils.getServiceById(tmlDeviceType, initServiceID);
+ IServiceHandler handler = service.getHandler();
+ handler.run(newInstance);
+ }
+
+ }
+
+ /**
+ * Destroys the TmL instance
+ *
+ * @param device
+ * The device to delete the correspondent TmL instance
+ */
+ public void deleteInstanceOfDevice(String serialNumber) {
+
+ IInstance instanceToDelete = (IInstance) getDeviceBySerialNumber(serialNumber);
+ if (instanceToDelete != null) {
+ InstanceManager.deleteInstance(instanceToDelete);
+ }
+
+ }
+
+}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/logger/DevicePropertyLogger.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/logger/DevicePropertyLogger.java
index ce020934..7f20aeb0 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/logger/DevicePropertyLogger.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/logger/DevicePropertyLogger.java
@@ -1,135 +1,136 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.logger;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.eclipse.andmore.android.AndroidPlugin;
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.common.log.AndmoreLogger;
-import org.eclipse.andmore.android.logger.collector.core.ILogFile;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.NullProgressMonitor;
-
-/**
- * This class is the Implementation of ILogFile that is responsible to collect
- * device properties and write them to files. These files will be used by the
- * Collect Logs functionality
- */
-public class DevicePropertyLogger implements ILogFile {
-
- private final Collection serialNumbers;
-
- private final Map> properties;
-
- public DevicePropertyLogger() {
- serialNumbers = DDMSFacade.getConnectedSerialNumbers();
- properties = new HashMap>(serialNumbers.size());
- for (String serialNumber : serialNumbers) {
- Map propertiesMap = new HashMap(140);
- String deviceName = DDMSFacade.getNameBySerialNumber(serialNumber);
- try {
- Collection lines = DDMSFacade.execRemoteApp(serialNumber, "getprop", new NullProgressMonitor());
- for (String line : lines) {
- String[] split = line.split(":");
- StringBuffer buffer = new StringBuffer();
- for (int i = 1; i < split.length; i++) {
- buffer.append(split[i]);
- }
-
- if (!"".equals(split[0])) {
- propertiesMap.put(split[0], buffer.toString());
- }
- }
- } catch (IOException e) {
- AndmoreLogger.error(getClass(), "Unable to execute getprop command on device " + deviceName, e);
- }
- properties.put((deviceName), propertiesMap);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.andmore.android.logger.collector.core.ILogFile#getLogFilePath
- * ()
- */
- @Override
- public List getLogFilePath() {
- ArrayList logs = new ArrayList(properties.keySet().size());
- IPath LOG_PATH = AndroidPlugin.getDefault().getStateLocation();
- for (String devicename : properties.keySet()) {
- IPath log = LOG_PATH.append(devicename + "_devProperties.log");
- writeLogFile(log, properties.get(devicename));
- logs.add(log);
- }
-
- return logs;
- }
-
- private void writeLogFile(IPath log, Map devProperties) {
- File logFile = log.toFile();
- BufferedWriter bw = null;
- try {
- bw = new BufferedWriter(new FileWriter(logFile));
-
- for (String propKey : devProperties.keySet()) {
- bw.append(propKey + "=" + devProperties.get(propKey) + System.getProperty("line.separator"));
- }
- } catch (IOException e) {
- AndmoreLogger.error(getClass(), "An error occurred while trying to write device Properties log file, "
- + logFile.getAbsolutePath(), e);
- } finally {
- try {
- bw.flush();
- bw.close();
- } catch (IOException e) {
- AndmoreLogger.error("Could not close stream while writing device property log. " + e.getMessage());
- }
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.andmore.android.logger.collector.core.ILogFile#getLogName()
- */
- @Override
- public String getLogName() {
- return "Device properties";
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.andmore.android.logger.collector.core.ILogFile#
- * getOutputSubfolderName()
- */
- @Override
- public String getOutputSubfolderName() {
- return "Devices";
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.logger;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.andmore.android.AndroidPlugin;
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.common.log.AndmoreLogger;
+import org.eclipse.andmore.android.logger.collector.core.ILogFile;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+/**
+ * This class is the Implementation of ILogFile that is responsible to collect
+ * device properties and write them to files. These files will be used by the
+ * Collect Logs functionality
+ */
+public class DevicePropertyLogger implements ILogFile {
+
+ private final Collection serialNumbers;
+
+ private final Map> properties;
+
+ public DevicePropertyLogger() {
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ serialNumbers = deviceMonitor.getConnectedSerialNumbers();
+ properties = new HashMap>(serialNumbers.size());
+ for (String serialNumber : serialNumbers) {
+ Map propertiesMap = new HashMap(140);
+ String deviceName = deviceMonitor.getNameBySerialNumber(serialNumber);
+ try {
+ Collection lines = DeviceMonitor.instance().execRemoteApp(serialNumber, "getprop", new NullProgressMonitor());
+ for (String line : lines) {
+ String[] split = line.split(":");
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 1; i < split.length; i++) {
+ buffer.append(split[i]);
+ }
+
+ if (!"".equals(split[0])) {
+ propertiesMap.put(split[0], buffer.toString());
+ }
+ }
+ } catch (IOException e) {
+ AndmoreLogger.error(getClass(), "Unable to execute getprop command on device " + deviceName, e);
+ }
+ properties.put((deviceName), propertiesMap);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.andmore.android.logger.collector.core.ILogFile#getLogFilePath
+ * ()
+ */
+ @Override
+ public List getLogFilePath() {
+ ArrayList logs = new ArrayList(properties.keySet().size());
+ IPath LOG_PATH = AndroidPlugin.getDefault().getStateLocation();
+ for (String devicename : properties.keySet()) {
+ IPath log = LOG_PATH.append(devicename + "_devProperties.log");
+ writeLogFile(log, properties.get(devicename));
+ logs.add(log);
+ }
+
+ return logs;
+ }
+
+ private void writeLogFile(IPath log, Map devProperties) {
+ File logFile = log.toFile();
+ BufferedWriter bw = null;
+ try {
+ bw = new BufferedWriter(new FileWriter(logFile));
+
+ for (String propKey : devProperties.keySet()) {
+ bw.append(propKey + "=" + devProperties.get(propKey) + System.getProperty("line.separator"));
+ }
+ } catch (IOException e) {
+ AndmoreLogger.error(getClass(), "An error occurred while trying to write device Properties log file, "
+ + logFile.getAbsolutePath(), e);
+ } finally {
+ try {
+ bw.flush();
+ bw.close();
+ } catch (IOException e) {
+ AndmoreLogger.error("Could not close stream while writing device property log. " + e.getMessage());
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.andmore.android.logger.collector.core.ILogFile#getLogName()
+ */
+ @Override
+ public String getLogName() {
+ return "Device properties";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.andmore.android.logger.collector.core.ILogFile#
+ * getOutputSubfolderName()
+ */
+ @Override
+ public String getOutputSubfolderName() {
+ return "Devices";
+ }
+}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/mat/DumpHPROFTable.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/mat/DumpHPROFTable.java
index e61ca977..f52e980d 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/mat/DumpHPROFTable.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/mat/DumpHPROFTable.java
@@ -17,7 +17,7 @@
import java.util.Collection;
-import org.eclipse.andmore.android.DDMSFacade;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.wizards.elements.TableWithLoadingInfo;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
@@ -72,6 +72,6 @@ protected void executeOperationsAfterTableIsPopulated() {
@Override
protected Collection callServiceForRetrievingDataToPopulateTable(String serialNumber) {
// get the running applications
- return DDMSFacade.getRunningApplications(serialNumber);
+ return DeviceMonitor.instance().getRunningApplications(serialNumber);
}
}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/DeviceSelectionDialog.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/DeviceSelectionDialog.java
index aabef44d..f6223a16 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/DeviceSelectionDialog.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/DeviceSelectionDialog.java
@@ -19,7 +19,7 @@
import java.util.LinkedList;
import org.eclipse.andmore.android.AndroidPlugin;
-import org.eclipse.andmore.android.DDMSFacade;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.ISerialNumbered;
import org.eclipse.andmore.android.devices.DevicesManager;
import org.eclipse.andmore.android.i18n.AndroidNLS;
@@ -71,9 +71,9 @@ public String getText(Object element) {
if ((instances != null) && (instances.size() > 0)) {
Collection filteredInstances = new LinkedList();
-
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
for (ISerialNumbered instance : instances) {
- if (DDMSFacade.isDeviceOnline(instance.getSerialNumber())) {
+ if (deviceMonitor.isDeviceOnline(instance.getSerialNumber())) {
filteredInstances.add(instance);
}
}
diff --git a/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/MonkeyConfigurationTab.java b/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/MonkeyConfigurationTab.java
index b49db884..e1dd9a40 100644
--- a/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/MonkeyConfigurationTab.java
+++ b/andmore-core/plugins/android/src/org/eclipse/andmore/android/wizards/monkey/MonkeyConfigurationTab.java
@@ -20,7 +20,7 @@
import java.util.Map;
import org.eclipse.andmore.android.AndroidPlugin;
-import org.eclipse.andmore.android.DDMSFacade;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.ISerialNumbered;
import org.eclipse.andmore.android.common.log.AndmoreLogger;
import org.eclipse.andmore.android.devices.DevicesManager;
@@ -402,7 +402,7 @@ public void modifyText(ModifyEvent e) {
private boolean validDevice(String deviceName) {
boolean valid = false;
ISerialNumbered sequoyahInstance = DevicesManager.getInstance().getDeviceByName(deviceName);
- if ((sequoyahInstance != null) && DDMSFacade.isDeviceOnline(sequoyahInstance.getSerialNumber())) {
+ if ((sequoyahInstance != null) && DeviceMonitor.instance().isDeviceOnline(sequoyahInstance.getSerialNumber())) {
valid = true;
}
return valid;
diff --git a/andmore-core/plugins/db.devices/META-INF/MANIFEST.MF b/andmore-core/plugins/db.devices/META-INF/MANIFEST.MF
index 675bb1ad..49c57387 100644
--- a/andmore-core/plugins/db.devices/META-INF/MANIFEST.MF
+++ b/andmore-core/plugins/db.devices/META-INF/MANIFEST.MF
@@ -16,7 +16,8 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.datatools.sqltools.result,
org.eclipse.sequoyah.device.framework,
org.eclipse.core.resources,
- org.eclipse.andmore;bundle-version="0.5.0"
+ org.eclipse.andmore;bundle-version="0.5.2",
+ org.eclipse.andmore.swt;bundle-version="0.5.2"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
diff --git a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceDbNode.java b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceDbNode.java
index 098f0cff..b161341c 100644
--- a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceDbNode.java
+++ b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceDbNode.java
@@ -21,8 +21,8 @@
import java.util.List;
import java.util.Set;
-import org.eclipse.andmore.android.DDMSFacade;
import org.eclipse.andmore.android.DDMSUtils;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.common.log.AndmoreLogger;
import org.eclipse.andmore.android.common.utilities.EclipseUtils;
import org.eclipse.andmore.android.common.utilities.FileUtil;
@@ -376,12 +376,12 @@ public IStatus deleteDb() {
IStatus status = null;
try {
closeAssociatedEditors(true, forceCloseEditors);
- DDMSFacade.deleteFile(serialNumber, remoteDbPath.toString());
+ DeviceMonitor.instance().deleteFile(serialNumber, remoteDbPath.toString());
disconnect();
} catch (IOException e) {
status = new Status(IStatus.ERROR, DbDevicesPlugin.PLUGIN_ID, NLS.bind(
DbDevicesNLS.DeviceDbNode_Delete_Remote_File_Failed, remoteDbPath.toString(),
- DDMSFacade.getNameBySerialNumber(serialNumber)));
+ DeviceMonitor.instance().getNameBySerialNumber(serialNumber)));
}
return status != null ? status : Status.OK_STATUS;
}
@@ -455,7 +455,7 @@ private IStatus pullRemoteTempFile(File tempFile) {
List remoteList = Arrays.asList(new String[] { remoteDbPath.toString() });
stream = EclipseUtils.getStudioConsoleOutputStream(false);
- status = DDMSFacade.pullFiles(serialNumber, localList, remoteList, REMOTE_OPERATIONS_TIMEOUT,
+ status = DeviceMonitor.instance().pullFiles(serialNumber, localList, remoteList, REMOTE_OPERATIONS_TIMEOUT,
new NullProgressMonitor(), stream);
} catch (Exception e) {
status = new Status(IStatus.ERROR, DbDevicesPlugin.PLUGIN_ID,
@@ -503,7 +503,7 @@ private IStatus pushLocalDbFile(boolean warnUser) {
List localList = Arrays.asList(new File[] { localDbFile });
List remoteList = Arrays.asList(new String[] { remoteDbPath.toString() });
stream = EclipseUtils.getStudioConsoleOutputStream(false);
- status = DDMSFacade.pushFiles(serialNumber, localList, remoteList, REMOTE_OPERATIONS_TIMEOUT,
+ status = DeviceMonitor.instance().pushFiles(serialNumber, localList, remoteList, REMOTE_OPERATIONS_TIMEOUT,
new NullProgressMonitor(), stream);
if (status.isOK()) {
isDirty = false;
@@ -515,7 +515,7 @@ private IStatus pushLocalDbFile(boolean warnUser) {
String appName = getParent().getName();
if (warnUser) {
- boolean applicationRunning = DDMSFacade.isApplicationRunning(serialNumber, appName);
+ boolean applicationRunning = DeviceMonitor.instance().isApplicationRunning(serialNumber, appName);
if (applicationRunning) {
EclipseUtils.showInformationDialog(DbDevicesNLS.DeviceDbNode_Application_Running_Msg_Title,
@@ -606,7 +606,7 @@ public IPath getRemoteDbPath() {
*/
@Override
public void cleanUp() {
- if (DDMSFacade.isDeviceOnline(serialNumber)) {
+ if (DeviceMonitor.instance().isDeviceOnline(serialNumber)) {
super.cleanUp();
} else {
closeAssociatedEditors(true, forceCloseEditors);
diff --git a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceNode.java b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceNode.java
index 3e68f1e8..d3e04705 100644
--- a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceNode.java
+++ b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DeviceNode.java
@@ -24,7 +24,7 @@
import java.util.Map;
import java.util.Set;
-import org.eclipse.andmore.android.DDMSFacade;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.DdmsRunnable;
import org.eclipse.andmore.android.AndmoreEventManager;
import org.eclipse.andmore.android.AndmoreEventManager.EventType;
@@ -80,7 +80,7 @@ private DeviceNode() {
* this node parent.
*/
public DeviceNode(String serialNumber, ITreeNode parent) {
- super(serialNumber, DDMSFacade.getNameBySerialNumber(serialNumber), parent);
+ super(serialNumber, DeviceMonitor.instance().getNameBySerialNumber(serialNumber), parent);
this.serialNumber = serialNumber;
this.deviceName = getName();
ImageDescriptor icon = AbstractUIPlugin.imageDescriptorFromPlugin(DbDevicesPlugin.PLUGIN_ID, ICON_PATH);
@@ -148,7 +148,7 @@ public void refresh() {
List childNodes = new ArrayList(loadedApps != null ? loadedApps.size() + 1 : 1);
try {
- if (DDMSFacade.hasSDCard(serialNumber)) {
+ if (DeviceMonitor.instance().hasSDCard(serialNumber)) {
ExtStorageNode extStorageNode = new ExtStorageNode(this);
childNodes.add(extStorageNode);
}
diff --git a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DevicesRootNode.java b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DevicesRootNode.java
index 8a156c37..d86e5cc2 100644
--- a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DevicesRootNode.java
+++ b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/DevicesRootNode.java
@@ -19,8 +19,8 @@
import java.util.Collection;
import java.util.List;
-import org.eclipse.andmore.android.DDMSFacade;
import org.eclipse.andmore.android.DdmsRunnable;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.AndmoreEventManager;
import org.eclipse.andmore.android.db.core.CanRefreshStatus;
import org.eclipse.andmore.android.db.core.ui.AbstractTreeNode;
@@ -85,7 +85,7 @@ public IStatus canRefresh() {
@Override
public void refresh() {
clear();
- Collection connectedSerialNumbers = DDMSFacade.getConnectedSerialNumbers();
+ Collection connectedSerialNumbers = DeviceMonitor.instance().getConnectedSerialNumbers();
List deviceNodes = new ArrayList();
for (String serialNumber : connectedSerialNumbers) {
DeviceNode deviceNode = new DeviceNode(serialNumber, this);
diff --git a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/ExtStorageNode.java b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/ExtStorageNode.java
index a711738a..ee0a9a67 100644
--- a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/ExtStorageNode.java
+++ b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/model/ExtStorageNode.java
@@ -21,7 +21,7 @@
import java.util.Map;
import java.util.Set;
-import org.eclipse.andmore.android.DDMSFacade;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.common.log.AndmoreLogger;
import org.eclipse.andmore.android.db.core.CanRefreshStatus;
import org.eclipse.andmore.android.db.core.DbCoreActivator;
@@ -241,7 +241,7 @@ private Set getDbNodes(String serialNumber_) {
@Override
public void saveState(IEclipsePreferences preferences) {
Preferences node = preferences.node(MEMENTO_EXTERNAL_STORAGE);
- Preferences serialNode = node.node(DDMSFacade.getNameBySerialNumber(serialNumber));
+ Preferences serialNode = node.node(DeviceMonitor.instance().getNameBySerialNumber(serialNumber));
int i = 1;
List children = getChildren();
@@ -278,7 +278,7 @@ public void restoreState(IEclipsePreferences preferences) {
try {
if (preferences.nodeExists(MEMENTO_EXTERNAL_STORAGE)) {
Preferences node = preferences.node(MEMENTO_EXTERNAL_STORAGE);
- String deviceName = DDMSFacade.getNameBySerialNumber(serialNumber);
+ String deviceName = DeviceMonitor.instance().getNameBySerialNumber(serialNumber);
if (node.nodeExists(deviceName)) {
Preferences deviceNode = node.node(deviceName);
String[] attributeKeys = deviceNode.keys();
diff --git a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/utils/DeviceDbUtils.java b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/utils/DeviceDbUtils.java
index ff66cda1..b7d53b51 100644
--- a/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/utils/DeviceDbUtils.java
+++ b/andmore-core/plugins/db.devices/src/org/eclipse/andmore/android/db/devices/utils/DeviceDbUtils.java
@@ -20,8 +20,8 @@
import java.util.LinkedHashMap;
import java.util.Map;
-import org.eclipse.andmore.android.DDMSFacade;
import org.eclipse.andmore.android.DDMSUtils;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
@@ -81,13 +81,12 @@ public static Object[] listInstalledPackages(String serialNumber, boolean filter
if (filterDBbApplications) {
Map filteredPackages = new LinkedHashMap();
-
- Collection appDataDirs = DDMSFacade.execRemoteApp(serialNumber,
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ Collection appDataDirs = deviceMonitor.execRemoteApp(serialNumber,
"ls /data/data/", new NullProgressMonitor()); //$NON-NLS-1$
-
for (String appPackage : appDataDirs) {
IPath remoteDbFolder = getRemoteDbFolder(appPackage);
- Collection databases = DDMSFacade.execRemoteApp(serialNumber,
+ Collection databases = deviceMonitor.execRemoteApp(serialNumber,
"ls " + remoteDbFolder.toString(), new NullProgressMonitor()); //$NON-NLS-1$
for (String commandOutline : databases) {
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/EmulatorPlugin.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/EmulatorPlugin.java
index a9020666..b9fb2046 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/EmulatorPlugin.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/EmulatorPlugin.java
@@ -1,397 +1,399 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
-
-import java.util.List;
-import java.util.Properties;
-
-import org.eclipse.andmore.android.AndroidPlugin;
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.DdmsRunnable;
-import org.eclipse.andmore.android.AndmoreEventManager;
-import org.eclipse.andmore.android.common.log.AndmoreLogger;
-import org.eclipse.andmore.android.common.preferences.DialogWithToggleUtils;
-import org.eclipse.andmore.android.emulator.core.devfrm.DeviceFrameworkManager;
-import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
-import org.eclipse.andmore.android.emulator.device.AndroidDeviceUtils;
-import org.eclipse.andmore.android.emulator.device.IDevicePropertiesConstants;
-import org.eclipse.andmore.android.emulator.device.SequoyahLogRedirector;
-import org.eclipse.andmore.android.emulator.device.instance.AndroidDevInstListener;
-import org.eclipse.andmore.android.emulator.device.instance.AndroidDeviceInstance;
-import org.eclipse.andmore.android.emulator.device.refresh.InstancesListRefresh;
-import org.eclipse.andmore.android.emulator.device.sync.DeviceViewsSync;
-import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
-import org.eclipse.andmore.android.emulator.ui.view.AbstractAndroidView;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.osgi.util.NLS;
-import org.eclipse.sequoyah.device.common.utilities.BasePlugin;
-import org.eclipse.sequoyah.device.framework.events.IInstanceListener;
-import org.eclipse.sequoyah.device.framework.events.InstanceAdapter;
-import org.eclipse.sequoyah.device.framework.events.InstanceEvent;
-import org.eclipse.sequoyah.device.framework.events.InstanceEvent.InstanceEventType;
-import org.eclipse.sequoyah.device.framework.events.InstanceEventManager;
-import org.eclipse.sequoyah.device.framework.factory.DeviceTypeRegistry;
-import org.eclipse.sequoyah.device.framework.model.IDeviceType;
-import org.eclipse.sequoyah.device.framework.model.IService;
-import org.eclipse.sequoyah.device.framework.model.handler.IServiceHandler;
-import org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler;
-import org.eclipse.sequoyah.device.framework.ui.DeviceUIPlugin;
-import org.eclipse.sequoyah.device.framework.ui.view.InstanceMgtView;
-import org.eclipse.sequoyah.device.framework.ui.wizard.DefaultDeviceTypeMenuWizardPage;
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.osgi.framework.BundleContext;
-
-/**
- * The activator class controls the plug-in life cycle
- */
-public class EmulatorPlugin extends AbstractUIPlugin {
- // The plug-in ID
- public static final String PLUGIN_ID = "org.eclipse.andmore.android.emulator";
-
- // The shared instance
- private static EmulatorPlugin plugin;
-
- // The ID of the device declared by this plug-in
- public static final String DEVICE_ID = PLUGIN_ID + ".androidDevice";
-
- // The ID of all the status declared by this plug-in
- public static final String STATUS_ONLINE_ID = PLUGIN_ID + ".status.online";
-
- public static final String STATUS_OFFLINE_NO_DATA = PLUGIN_ID + ".status.offlineNoData";
-
- public static final String STATUS_OFFLINE = PLUGIN_ID + ".status.offline";
-
- public static final String STATUS_NOT_AVAILABLE = PLUGIN_ID + ".status.notavailable";
-
- public static final String SERVICE_INIT_ID = PLUGIN_ID + ".initEmulatorService";
-
- public static final String STOP_SERVICE_ID = PLUGIN_ID + ".stopService";
-
- public static final String START_SERVICE_ID = PLUGIN_ID + ".startService";
-
- private static final String DEV_MANAGER_HELP = DeviceUIPlugin.PLUGIN_ID + ".devmgr";
-
- private static final String NEW_DEVICE_HELP = DeviceUIPlugin.PLUGIN_ID + ".newdev";
-
- /**
- * Reference the id of the extension point with the default Android Emulator
- * definitions...
- */
- public static String DEFAULT_EMULATOR_DEFINITION = "org.eclipse.andmore.android.emulator10.defaultEmulatorDefinitions";
-
- public static final String FORCE_ATTR = "force";
-
- public static final String EMULATOR_UNEXPECTEDLY_STOPPED = "emulator.unexpectedly.stopped";
-
- private static AndroidDevInstListener instanceListener;
-
- private static DdmsRunnable connectedListener = new DdmsRunnable() {
- @Override
- public void run(String serialNumber) {
- if (DDMSFacade.isEmulator(serialNumber)) {
- InstancesListRefresh.refresh();
-
- info("New Device connected at " + serialNumber);
-
- String vmName = DDMSFacade.getNameBySerialNumber(serialNumber);
-
- if (vmName != null) {
- DeviceFrameworkManager devFrameworkManager = DeviceFrameworkManager.getInstance();
-
- IAndroidEmulatorInstance instance = devFrameworkManager.getInstanceByName(vmName);
-
- if (instance instanceof AndroidDeviceInstance) {
- final AndroidDeviceInstance emulatorInstance = (AndroidDeviceInstance) instance;
-
- AndroidDeviceUtils.fireDummyStartTransition(emulatorInstance, serialNumber);
-
- }
- }
- }
- }
- };
-
- private static DdmsRunnable disconnectedListener = new DdmsRunnable() {
- @Override
- public void run(String serialNum) {
- if (DDMSFacade.isEmulator(serialNum)) {
- info("Device just disconnected from serial=" + serialNum);
-
- String vmName = DDMSFacade.getNameBySerialNumber(serialNum);
-
- if (vmName != null) {
- IAndroidEmulatorInstance instance = DeviceFrameworkManager.getInstance().getInstanceByName(vmName);
-
- if ((instance != null) && (instance.isStarted())) {
- try {
- instance.stop(true);
- DialogWithToggleUtils.showError(EMULATOR_UNEXPECTEDLY_STOPPED, EmulatorNLS.GEN_Error,
- NLS.bind(EmulatorNLS.ERR_AndroidLogicPlugin_EmulatorStopped, instance.getName()));
-
- } catch (Exception e) {
- error("Error trying to force the stop process on instance associated to disconnected device: "
- + instance);
- }
- }
-
- if (instance instanceof AndroidDeviceInstance) {
- ((AndroidDeviceInstance) instance).setNameSuffix(null);
- InstanceEventManager.getInstance()
- .notifyListeners(
- new InstanceEvent(InstanceEventType.INSTANCE_UPDATED,
- (AndroidDeviceInstance) instance));
- }
- } else {
- // This block is executed if we get a vmName == null
- // condition. This can happen if
- // ADT updates the device in a way that it makes the name
- // not accessible.
- //
- // What is needed to be done in such a case is to iterate on
- // all TmL instances, looking for
- // objects that contain serialNumber as the instance suffix.
- // This guarantees that we will not
- // leave a not consistent serial number being displayed at
- // the Instance Management view.
-
- for (IAndroidEmulatorInstance instance : DeviceFrameworkManager.getInstance().getAllInstances()) {
- if (instance instanceof AndroidDeviceInstance) {
- AndroidDeviceInstance androidInstance = (AndroidDeviceInstance) instance;
- String instanceSuffix = androidInstance.getNameSuffix();
-
- if ((instanceSuffix != null) && instanceSuffix.equals(serialNum)) {
- androidInstance.setNameSuffix(null);
-
- InstanceEventManager.getInstance().notifyListeners(
- new InstanceEvent(InstanceEventType.INSTANCE_UPDATED, androidInstance));
- }
- }
- }
- }
- }
- }
- };
-
- private static final Runnable sdkLoaderListener = new Runnable() {
- @Override
- public void run() {
- InstancesListRefresh.refresh();
- if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
- IPreferenceStore store = getDefault().getPreferenceStore();
- boolean deviceStartupOptionsUpdated = store.getBoolean("DeviceStartupOptionsUpdated");
- if (!deviceStartupOptionsUpdated) {
- for (IAndroidEmulatorInstance instance : DeviceFrameworkManager.getInstance().getAllInstances()) {
- if (instance instanceof AndroidDeviceInstance) {
- AndroidDeviceInstance androidInstance = (AndroidDeviceInstance) instance;
-
- Properties emuProperties = androidInstance.getProperties();
-
- String commandline = emuProperties.getProperty(IDevicePropertiesConstants.commandline, "");
- if (commandline.contains("-no-window")) {
- commandline = commandline.replace("-no-window", "");
- }
- emuProperties.setProperty(IDevicePropertiesConstants.commandline, commandline);
- androidInstance.setProperties(emuProperties);
-
- InstanceEventManager.getInstance().notifyListeners(
- new InstanceEvent(InstanceEventType.INSTANCE_UPDATED, androidInstance));
- }
- }
- store.setValue("DeviceStartupOptionsUpdated", true);
- }
- }
- }
- };
-
- private static IInstanceListener sequoyahInstanceListener = new InstanceAdapter() {
- @Override
- public void instanceUpdated(InstanceEvent e) {
- AbstractAndroidView.updateInstanceName(e.getInstance());
- }
- };
-
- private static ServiceHandler stopServiceHandler = null;
-
- private static ServiceHandler startServiceHandler = null;
-
- private static String stopServiceId = null;
-
- private static String startServiceId = null;
-
- /**
- * The constructor
- */
- public EmulatorPlugin() {
- plugin = this;
- }
-
- /**
- * Activates the plug-in and initializes the logger
- *
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
- */
- @Override
- public void start(BundleContext context) throws Exception {
- AndmoreLogger.debug(EmulatorPlugin.class, "Starting Andmore Emulator Plugin...");
-
- super.start(context);
-
- start();
-
- AndmoreLogger.debug(EmulatorPlugin.class, "Andmore Emulator Plugin started.");
- }
-
- private void start() {
- // Setting the TmL logger to redirect logs to the logger controlled
- // by this class
- SequoyahLogRedirector tmlLogger = new SequoyahLogRedirector();
- org.eclipse.sequoyah.vnc.utilities.logger.Logger.setLogger(tmlLogger);
- BasePlugin.getBaseDefault().setLogger(tmlLogger);
-
- instanceListener = new AndroidDevInstListener();
- InstanceEventManager.getInstance().addInstanceListener(instanceListener);
- AndmoreEventManager.asyncAddDeviceChangeListeners(connectedListener, disconnectedListener);
-
- AndroidPlugin.getDefault().addSDKLoaderListener(sdkLoaderListener);
- // Emulator Views synchronization
- DeviceViewsSync.getInstance().initialize();
- // Setting context sensitive help IDs for the TmL screens we use
- DefaultDeviceTypeMenuWizardPage.setHelpContextId(NEW_DEVICE_HELP);
- InstanceMgtView.setHelp(DEV_MANAGER_HELP);
- InstanceEventManager.getInstance().addInstanceListener(sequoyahInstanceListener);
- registerStopServiceId(STOP_SERVICE_ID);
- registerStartServiceId(START_SERVICE_ID);
- }
-
- /**
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
- */
- @Override
- public void stop(BundleContext context) throws Exception {
- AndroidPlugin.getDefault().removeSDKLoaderListener(sdkLoaderListener);
- InstanceEventManager.getInstance().removeInstanceListener(instanceListener);
- AndmoreEventManager.asyncRemoveDeviceChangeListeners(connectedListener, disconnectedListener);
- InstanceEventManager.getInstance().removeInstanceListener(sequoyahInstanceListener);
- unregisterStopServiceHandler();
- unregisterStartServiceHandler();
- plugin = null;
- super.stop(context);
- }
-
- /**
- * Registers a stop service id, through which the stop service handler will
- * be found and used to delegate stop action of the instances if possible
- *
- * @param stopServiceId
- * The stop service id to be registered
- */
- public static void registerStopServiceId(String stopServiceId) {
- EmulatorPlugin.stopServiceId = stopServiceId;
- }
-
- /**
- * Unregisters the current stop service handler and stop service id.
- *
- * After this method is called, it will not be possible for the instance
- * class to delegate the stop action to a handler.
- */
- public static void unregisterStopServiceHandler() {
- stopServiceHandler = null;
- stopServiceId = null;
- }
-
- /**
- * Retrieves the stop service handler.
- *
- * @return The currently registered stop service handler, or if no
- * handler is registered.
- */
- public static ServiceHandler getStopServiceHandler() {
- if ((stopServiceHandler == null) && (stopServiceId != null)) {
- // find the appropriate stop service handler
- IDeviceType device = DeviceTypeRegistry.getInstance().getDeviceTypeById(EmulatorPlugin.DEVICE_ID);
- List services = device.getServices();
- for (IService service : services) {
- IServiceHandler handler = service.getHandler();
- if (handler.getService().getId().equals(stopServiceId)) {
- stopServiceHandler = (ServiceHandler) handler;
- break;
- }
- }
- }
-
- return stopServiceHandler;
- }
-
- /**
- * Registers a start service id, through which the stop service handler will
- * be found and used to delegate start action of the instances if possible
- *
- * @param stopServiceId
- * The stop service id to be registered
- */
- public static void registerStartServiceId(String startServiceId) {
- EmulatorPlugin.startServiceId = startServiceId;
- }
-
- /**
- * Unregisters the current start service handler and stop service id.
- *
- * After this method is called, it will not be possible for the instance
- * class to delegate the start action to a handler.
- */
- public static void unregisterStartServiceHandler() {
- startServiceHandler = null;
- startServiceId = null;
- }
-
- /**
- * Retrieves the start service handler.
- *
- * @return The currently registered start service handler, or if no
- * handler is registered.
- */
- public static ServiceHandler getStartServiceHandler() {
- if ((startServiceHandler == null) && (startServiceId != null)) {
- // find the appropriate stop service handler
- IDeviceType device = DeviceTypeRegistry.getInstance().getDeviceTypeById(EmulatorPlugin.DEVICE_ID);
- List services = device.getServices();
- for (IService service : services) {
- IServiceHandler handler = service.getHandler();
- if (handler.getService().getId().equals(startServiceId)) {
- startServiceHandler = (ServiceHandler) handler;
- break;
- }
- }
- }
-
- return startServiceHandler;
- }
-
- /**
- * Returns the shared instance
- *
- * @return the shared instance
- */
- public static EmulatorPlugin getDefault() {
- return plugin;
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.andmore.android.AndroidPlugin;
+import org.eclipse.andmore.android.DdmsRunnable;
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.AndmoreEventManager;
+import org.eclipse.andmore.android.common.log.AndmoreLogger;
+import org.eclipse.andmore.android.common.preferences.DialogWithToggleUtils;
+import org.eclipse.andmore.android.emulator.core.devfrm.DeviceFrameworkManager;
+import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
+import org.eclipse.andmore.android.emulator.device.AndroidDeviceUtils;
+import org.eclipse.andmore.android.emulator.device.IDevicePropertiesConstants;
+import org.eclipse.andmore.android.emulator.device.SequoyahLogRedirector;
+import org.eclipse.andmore.android.emulator.device.instance.AndroidDevInstListener;
+import org.eclipse.andmore.android.emulator.device.instance.AndroidDeviceInstance;
+import org.eclipse.andmore.android.emulator.device.refresh.InstancesListRefresh;
+import org.eclipse.andmore.android.emulator.device.sync.DeviceViewsSync;
+import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
+import org.eclipse.andmore.android.emulator.ui.view.AbstractAndroidView;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.sequoyah.device.common.utilities.BasePlugin;
+import org.eclipse.sequoyah.device.framework.events.IInstanceListener;
+import org.eclipse.sequoyah.device.framework.events.InstanceAdapter;
+import org.eclipse.sequoyah.device.framework.events.InstanceEvent;
+import org.eclipse.sequoyah.device.framework.events.InstanceEvent.InstanceEventType;
+import org.eclipse.sequoyah.device.framework.events.InstanceEventManager;
+import org.eclipse.sequoyah.device.framework.factory.DeviceTypeRegistry;
+import org.eclipse.sequoyah.device.framework.model.IDeviceType;
+import org.eclipse.sequoyah.device.framework.model.IService;
+import org.eclipse.sequoyah.device.framework.model.handler.IServiceHandler;
+import org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler;
+import org.eclipse.sequoyah.device.framework.ui.DeviceUIPlugin;
+import org.eclipse.sequoyah.device.framework.ui.view.InstanceMgtView;
+import org.eclipse.sequoyah.device.framework.ui.wizard.DefaultDeviceTypeMenuWizardPage;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class EmulatorPlugin extends AbstractUIPlugin {
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.andmore.android.emulator";
+
+ // The shared instance
+ private static EmulatorPlugin plugin;
+
+ // The ID of the device declared by this plug-in
+ public static final String DEVICE_ID = PLUGIN_ID + ".androidDevice";
+
+ // The ID of all the status declared by this plug-in
+ public static final String STATUS_ONLINE_ID = PLUGIN_ID + ".status.online";
+
+ public static final String STATUS_OFFLINE_NO_DATA = PLUGIN_ID + ".status.offlineNoData";
+
+ public static final String STATUS_OFFLINE = PLUGIN_ID + ".status.offline";
+
+ public static final String STATUS_NOT_AVAILABLE = PLUGIN_ID + ".status.notavailable";
+
+ public static final String SERVICE_INIT_ID = PLUGIN_ID + ".initEmulatorService";
+
+ public static final String STOP_SERVICE_ID = PLUGIN_ID + ".stopService";
+
+ public static final String START_SERVICE_ID = PLUGIN_ID + ".startService";
+
+ private static final String DEV_MANAGER_HELP = DeviceUIPlugin.PLUGIN_ID + ".devmgr";
+
+ private static final String NEW_DEVICE_HELP = DeviceUIPlugin.PLUGIN_ID + ".newdev";
+
+ /**
+ * Reference the id of the extension point with the default Android Emulator
+ * definitions...
+ */
+ public static String DEFAULT_EMULATOR_DEFINITION = "org.eclipse.andmore.android.emulator10.defaultEmulatorDefinitions";
+
+ public static final String FORCE_ATTR = "force";
+
+ public static final String EMULATOR_UNEXPECTEDLY_STOPPED = "emulator.unexpectedly.stopped";
+
+ private static AndroidDevInstListener instanceListener;
+
+ private static DdmsRunnable connectedListener = new DdmsRunnable() {
+ @Override
+ public void run(String serialNumber) {
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ if (deviceMonitor.isEmulator(serialNumber)) {
+ InstancesListRefresh.refresh();
+
+ info("New Device connected at " + serialNumber);
+
+ String vmName = deviceMonitor.getNameBySerialNumber(serialNumber);
+
+ if (vmName != null) {
+ DeviceFrameworkManager devFrameworkManager = DeviceFrameworkManager.getInstance();
+
+ IAndroidEmulatorInstance instance = devFrameworkManager.getInstanceByName(vmName);
+
+ if (instance instanceof AndroidDeviceInstance) {
+ final AndroidDeviceInstance emulatorInstance = (AndroidDeviceInstance) instance;
+
+ AndroidDeviceUtils.fireDummyStartTransition(emulatorInstance, serialNumber);
+
+ }
+ }
+ }
+ }
+ };
+
+ private static DdmsRunnable disconnectedListener = new DdmsRunnable() {
+ @Override
+ public void run(String serialNum) {
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ if (deviceMonitor.isEmulator(serialNum)) {
+ info("Device just disconnected from serial=" + serialNum);
+
+ String vmName = deviceMonitor.getNameBySerialNumber(serialNum);
+
+ if (vmName != null) {
+ IAndroidEmulatorInstance instance = DeviceFrameworkManager.getInstance().getInstanceByName(vmName);
+
+ if ((instance != null) && (instance.isStarted())) {
+ try {
+ instance.stop(true);
+ DialogWithToggleUtils.showError(EMULATOR_UNEXPECTEDLY_STOPPED, EmulatorNLS.GEN_Error,
+ NLS.bind(EmulatorNLS.ERR_AndroidLogicPlugin_EmulatorStopped, instance.getName()));
+
+ } catch (Exception e) {
+ error("Error trying to force the stop process on instance associated to disconnected device: "
+ + instance);
+ }
+ }
+
+ if (instance instanceof AndroidDeviceInstance) {
+ ((AndroidDeviceInstance) instance).setNameSuffix(null);
+ InstanceEventManager.getInstance()
+ .notifyListeners(
+ new InstanceEvent(InstanceEventType.INSTANCE_UPDATED,
+ (AndroidDeviceInstance) instance));
+ }
+ } else {
+ // This block is executed if we get a vmName == null
+ // condition. This can happen if
+ // ADT updates the device in a way that it makes the name
+ // not accessible.
+ //
+ // What is needed to be done in such a case is to iterate on
+ // all TmL instances, looking for
+ // objects that contain serialNumber as the instance suffix.
+ // This guarantees that we will not
+ // leave a not consistent serial number being displayed at
+ // the Instance Management view.
+
+ for (IAndroidEmulatorInstance instance : DeviceFrameworkManager.getInstance().getAllInstances()) {
+ if (instance instanceof AndroidDeviceInstance) {
+ AndroidDeviceInstance androidInstance = (AndroidDeviceInstance) instance;
+ String instanceSuffix = androidInstance.getNameSuffix();
+
+ if ((instanceSuffix != null) && instanceSuffix.equals(serialNum)) {
+ androidInstance.setNameSuffix(null);
+
+ InstanceEventManager.getInstance().notifyListeners(
+ new InstanceEvent(InstanceEventType.INSTANCE_UPDATED, androidInstance));
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ private static final Runnable sdkLoaderListener = new Runnable() {
+ @Override
+ public void run() {
+ InstancesListRefresh.refresh();
+ if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
+ IPreferenceStore store = getDefault().getPreferenceStore();
+ boolean deviceStartupOptionsUpdated = store.getBoolean("DeviceStartupOptionsUpdated");
+ if (!deviceStartupOptionsUpdated) {
+ for (IAndroidEmulatorInstance instance : DeviceFrameworkManager.getInstance().getAllInstances()) {
+ if (instance instanceof AndroidDeviceInstance) {
+ AndroidDeviceInstance androidInstance = (AndroidDeviceInstance) instance;
+
+ Properties emuProperties = androidInstance.getProperties();
+
+ String commandline = emuProperties.getProperty(IDevicePropertiesConstants.commandline, "");
+ if (commandline.contains("-no-window")) {
+ commandline = commandline.replace("-no-window", "");
+ }
+ emuProperties.setProperty(IDevicePropertiesConstants.commandline, commandline);
+ androidInstance.setProperties(emuProperties);
+
+ InstanceEventManager.getInstance().notifyListeners(
+ new InstanceEvent(InstanceEventType.INSTANCE_UPDATED, androidInstance));
+ }
+ }
+ store.setValue("DeviceStartupOptionsUpdated", true);
+ }
+ }
+ }
+ };
+
+ private static IInstanceListener sequoyahInstanceListener = new InstanceAdapter() {
+ @Override
+ public void instanceUpdated(InstanceEvent e) {
+ AbstractAndroidView.updateInstanceName(e.getInstance());
+ }
+ };
+
+ private static ServiceHandler stopServiceHandler = null;
+
+ private static ServiceHandler startServiceHandler = null;
+
+ private static String stopServiceId = null;
+
+ private static String startServiceId = null;
+
+ /**
+ * The constructor
+ */
+ public EmulatorPlugin() {
+ plugin = this;
+ }
+
+ /**
+ * Activates the plug-in and initializes the logger
+ *
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ AndmoreLogger.debug(EmulatorPlugin.class, "Starting Andmore Emulator Plugin...");
+
+ super.start(context);
+
+ start();
+
+ AndmoreLogger.debug(EmulatorPlugin.class, "Andmore Emulator Plugin started.");
+ }
+
+ private void start() {
+ // Setting the TmL logger to redirect logs to the logger controlled
+ // by this class
+ SequoyahLogRedirector tmlLogger = new SequoyahLogRedirector();
+ org.eclipse.sequoyah.vnc.utilities.logger.Logger.setLogger(tmlLogger);
+ BasePlugin.getBaseDefault().setLogger(tmlLogger);
+
+ instanceListener = new AndroidDevInstListener();
+ InstanceEventManager.getInstance().addInstanceListener(instanceListener);
+ AndmoreEventManager.asyncAddDeviceChangeListeners(connectedListener, disconnectedListener);
+
+ AndroidPlugin.getDefault().addSDKLoaderListener(sdkLoaderListener);
+ // Emulator Views synchronization
+ DeviceViewsSync.getInstance().initialize();
+ // Setting context sensitive help IDs for the TmL screens we use
+ DefaultDeviceTypeMenuWizardPage.setHelpContextId(NEW_DEVICE_HELP);
+ InstanceMgtView.setHelp(DEV_MANAGER_HELP);
+ InstanceEventManager.getInstance().addInstanceListener(sequoyahInstanceListener);
+ registerStopServiceId(STOP_SERVICE_ID);
+ registerStartServiceId(START_SERVICE_ID);
+ }
+
+ /**
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ AndroidPlugin.getDefault().removeSDKLoaderListener(sdkLoaderListener);
+ InstanceEventManager.getInstance().removeInstanceListener(instanceListener);
+ AndmoreEventManager.asyncRemoveDeviceChangeListeners(connectedListener, disconnectedListener);
+ InstanceEventManager.getInstance().removeInstanceListener(sequoyahInstanceListener);
+ unregisterStopServiceHandler();
+ unregisterStartServiceHandler();
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Registers a stop service id, through which the stop service handler will
+ * be found and used to delegate stop action of the instances if possible
+ *
+ * @param stopServiceId
+ * The stop service id to be registered
+ */
+ public static void registerStopServiceId(String stopServiceId) {
+ EmulatorPlugin.stopServiceId = stopServiceId;
+ }
+
+ /**
+ * Unregisters the current stop service handler and stop service id.
+ *
+ * After this method is called, it will not be possible for the instance
+ * class to delegate the stop action to a handler.
+ */
+ public static void unregisterStopServiceHandler() {
+ stopServiceHandler = null;
+ stopServiceId = null;
+ }
+
+ /**
+ * Retrieves the stop service handler.
+ *
+ * @return The currently registered stop service handler, or if no
+ * handler is registered.
+ */
+ public static ServiceHandler getStopServiceHandler() {
+ if ((stopServiceHandler == null) && (stopServiceId != null)) {
+ // find the appropriate stop service handler
+ IDeviceType device = DeviceTypeRegistry.getInstance().getDeviceTypeById(EmulatorPlugin.DEVICE_ID);
+ List services = device.getServices();
+ for (IService service : services) {
+ IServiceHandler handler = service.getHandler();
+ if (handler.getService().getId().equals(stopServiceId)) {
+ stopServiceHandler = (ServiceHandler) handler;
+ break;
+ }
+ }
+ }
+
+ return stopServiceHandler;
+ }
+
+ /**
+ * Registers a start service id, through which the stop service handler will
+ * be found and used to delegate start action of the instances if possible
+ *
+ * @param stopServiceId
+ * The stop service id to be registered
+ */
+ public static void registerStartServiceId(String startServiceId) {
+ EmulatorPlugin.startServiceId = startServiceId;
+ }
+
+ /**
+ * Unregisters the current start service handler and stop service id.
+ *
+ * After this method is called, it will not be possible for the instance
+ * class to delegate the start action to a handler.
+ */
+ public static void unregisterStartServiceHandler() {
+ startServiceHandler = null;
+ startServiceId = null;
+ }
+
+ /**
+ * Retrieves the start service handler.
+ *
+ * @return The currently registered start service handler, or if no
+ * handler is registered.
+ */
+ public static ServiceHandler getStartServiceHandler() {
+ if ((startServiceHandler == null) && (startServiceId != null)) {
+ // find the appropriate stop service handler
+ IDeviceType device = DeviceTypeRegistry.getInstance().getDeviceTypeById(EmulatorPlugin.DEVICE_ID);
+ List services = device.getServices();
+ for (IService service : services) {
+ IServiceHandler handler = service.getHandler();
+ if (handler.getService().getId().equals(startServiceId)) {
+ startServiceHandler = (ServiceHandler) handler;
+ break;
+ }
+ }
+ }
+
+ return startServiceHandler;
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static EmulatorPlugin getDefault() {
+ return plugin;
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDevInstListener.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDevInstListener.java
index e04a5390..6e9b892d 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDevInstListener.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDevInstListener.java
@@ -1,99 +1,89 @@
-/* Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.device.instance;
-
-import org.eclipse.andmore.android.SdkUtils;
-import org.eclipse.andmore.android.common.log.AndmoreLogger;
-import org.eclipse.andmore.android.emulator.EmulatorPlugin;
-import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
-import org.eclipse.andmore.android.emulator.core.utils.EmulatorCoreUtils;
-import org.eclipse.andmore.android.emulator.ui.view.AbstractAndroidView;
-import org.eclipse.sequoyah.device.framework.DevicePlugin;
-import org.eclipse.sequoyah.device.framework.events.IInstanceListener;
-import org.eclipse.sequoyah.device.framework.events.InstanceAdapter;
-import org.eclipse.sequoyah.device.framework.events.InstanceEvent;
-import org.eclipse.sequoyah.device.framework.model.IInstance;
-
-/**
- * DESCRIPTION: Implementation of IInstanceListener for device related actions
- * that depend on the TmL instance registry state.
- * RESPONSIBILITY: Guarantee that the emulator views are updated Run the
- * initialization service when an instance is loaded
- * COLABORATORS: None.
- * USAGE: This class shall be used by Eclipse only.
- */
-public class AndroidDevInstListener extends InstanceAdapter {
-
- /**
- * @see IInstanceListener#instanceLoaded(InstanceEvent)
- */
- @Override
- public void instanceLoaded(InstanceEvent e) {
- IInstance instance = e.getInstance();
-
- if (instance instanceof IAndroidEmulatorInstance) {
- // The service definition defined (by convention) that
- // stopped-dirty is the success state, and not available
- // is the failure state. The exception is being thrown for
- // the framework to set the state correctly.
- if (instance.getStatus().equals(DevicePlugin.SEQUOYAH_STATUS_OFF)) {
- instance.setStatus(EmulatorPlugin.STATUS_NOT_AVAILABLE);
- }
- }
- }
-
- /**
- * @see IInstanceListener#instanceDeleted(InstanceEvent)
- */
- @Override
- public void instanceDeleted(InstanceEvent ev) {
- IInstance instance = ev.getInstance();
- if (instance instanceof AndroidDeviceInstance) {
- SdkUtils.deleteVm(instance.getName());
- }
- }
-
- /**
- * @see IInstanceListener#instanceTransitioned(InstanceEvent)
- */
- @Override
- public void instanceTransitioned(InstanceEvent e) {
- IInstance instance = e.getInstance();
-
- if (instance instanceof AndroidDeviceInstance) {
- final AndroidDeviceInstance androidDevice = (AndroidDeviceInstance) instance;
- AndmoreLogger.info("The android device instance status was updated: " + instance + " Status: "
- + instance.getStatus());
-
- if (androidDevice.isStarted()) {
- String transitionId = e.getTransitionId();
- if ((transitionId != null) && transitionId.equals("org.eclipse.andmore.android.emulator.startService")) {
- // If it is coming from other state than the started,
- // connect to VNC server
-
- EmulatorCoreUtils.refreshEmulatorViews();
- AndmoreLogger.info("The emulator " + instance
- + " transitioned to started state. Try to estabilish a VNC connection...");
- }
- } else if (instance.getStatus().equals(EmulatorPlugin.STATUS_OFFLINE)) {
- androidDevice.resetRuntimeVariables();
- EmulatorCoreUtils.refreshEmulatorViews();
- }
-
- }
-
- }
-
-}
+/* Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.device.instance;
+
+import org.eclipse.andmore.android.SdkUtils;
+import org.eclipse.andmore.android.common.log.AndmoreLogger;
+import org.eclipse.andmore.android.emulator.EmulatorPlugin;
+import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
+import org.eclipse.andmore.android.emulator.core.utils.EmulatorCoreUtils;
+import org.eclipse.andmore.android.emulator.ui.view.AbstractAndroidView;
+import org.eclipse.sequoyah.device.framework.DevicePlugin;
+import org.eclipse.sequoyah.device.framework.events.IInstanceListener;
+import org.eclipse.sequoyah.device.framework.events.InstanceAdapter;
+import org.eclipse.sequoyah.device.framework.events.InstanceEvent;
+import org.eclipse.sequoyah.device.framework.model.IInstance;
+
+/**
+ * DESCRIPTION: Implementation of IInstanceListener for device related actions
+ * that depend on the TmL instance registry state.
+ * RESPONSIBILITY: Guarantee that the emulator views are updated Run the
+ * initialization service when an instance is loaded
+ * COLABORATORS: None.
+ * USAGE: This class shall be used by Eclipse only.
+ */
+public class AndroidDevInstListener extends InstanceAdapter {
+
+ /**
+ * @see IInstanceListener#instanceLoaded(InstanceEvent)
+ */
+ @Override
+ public void instanceLoaded(InstanceEvent e) {
+ IInstance instance = e.getInstance();
+
+ if (instance instanceof IAndroidEmulatorInstance) {
+ // The service definition defined (by convention) that
+ // stopped-dirty is the success state, and not available
+ // is the failure state. The exception is being thrown for
+ // the framework to set the state correctly.
+ if (instance.getStatus().equals(DevicePlugin.SEQUOYAH_STATUS_OFF)) {
+ instance.setStatus(EmulatorPlugin.STATUS_NOT_AVAILABLE);
+ }
+ }
+ }
+
+ /**
+ * @see IInstanceListener#instanceDeleted(InstanceEvent)
+ */
+ @Override
+ public void instanceDeleted(InstanceEvent ev) {
+ IInstance instance = ev.getInstance();
+ if (instance instanceof AndroidDeviceInstance) {
+ SdkUtils.deleteVm(instance.getName());
+ }
+ }
+
+ /**
+ * @see IInstanceListener#instanceTransitioned(InstanceEvent)
+ */
+ @Override
+ public void instanceTransitioned(InstanceEvent e) {
+ IInstance instance = e.getInstance();
+
+ if (instance instanceof AndroidDeviceInstance) {
+ final AndroidDeviceInstance androidDevice = (AndroidDeviceInstance) instance;
+ AndmoreLogger.info("The android device instance status was updated: " + instance + " Status: "
+ + instance.getStatus());
+
+ if (!androidDevice.isStarted() && instance.getStatus().equals(EmulatorPlugin.STATUS_OFFLINE)) {
+ androidDevice.resetRuntimeVariables();
+ EmulatorCoreUtils.refreshEmulatorViews();
+ }
+
+ }
+
+ }
+
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDeviceInstance.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDeviceInstance.java
index 3b360074..55eb97bd 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDeviceInstance.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/instance/AndroidDeviceInstance.java
@@ -26,7 +26,7 @@
import java.util.Map;
import java.util.Properties;
-import org.eclipse.andmore.android.DDMSFacade;
+import org.eclipse.andmore.android.DeviceMonitor;
import org.eclipse.andmore.android.ISerialNumbered;
import org.eclipse.andmore.android.SdkUtils;
import org.eclipse.andmore.android.emulator.EmulatorPlugin;
@@ -58,7 +58,6 @@
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.avd.AvdInfo;
-import com.android.sdklib.repository.targets.AndroidTargetManager;
/**
* DESCRIPTION: This class represents a Android Emulator instance
@@ -507,7 +506,8 @@ public IInputLogic getInputLogic() {
@Override
public boolean hasDevice() {
- return (DDMSFacade.getDeviceBySerialNumber(getSerialNumber()) != null);
+ String serialNumber = getSerialNumber();
+ return serialNumber!= null ? (DeviceMonitor.instance().getDeviceBySerialNumber(serialNumber) != null) : false;
}
@Override
@@ -518,7 +518,7 @@ public void changeOrientation(final String parameters) {
@Override
public void run() {
try {
- DDMSFacade.execRemoteApp(getSerialNumber(),
+ DeviceMonitor.instance().execRemoteApp(getSerialNumber(),
AndroidLogicUtils.ORIENTATION_BASE_COMMAND + parameters, new NullProgressMonitor());
} catch (IOException e) {
error("Failed to send the command to change the emulator display orientation to portrait.");
@@ -723,7 +723,7 @@ public Object getParent(Object o) {
*/
@Override
public String getSerialNumber() {
- return DDMSFacade.getSerialNumberByName(getName());
+ return DeviceMonitor.instance().getSerialNumberByName(getName());
}
/*
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/sync/DeviceViewsSync.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/sync/DeviceViewsSync.java
index de958fa3..2bf8582c 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/sync/DeviceViewsSync.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/sync/DeviceViewsSync.java
@@ -1,270 +1,270 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.device.sync;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.common.log.AndmoreLogger;
-import org.eclipse.andmore.android.emulator.EmulatorPlugin;
-import org.eclipse.andmore.android.emulator.core.devfrm.DeviceFrameworkManager;
-import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
-import org.eclipse.andmore.android.emulator.ui.view.AbstractAndroidView;
-import org.eclipse.andmore.ddms.DdmsPlugin;
-import org.eclipse.sequoyah.device.framework.factory.InstanceRegistry;
-import org.eclipse.sequoyah.device.framework.model.IInstance;
-import org.eclipse.sequoyah.device.framework.ui.view.InstanceMgtView;
-import org.eclipse.sequoyah.device.framework.ui.view.model.InstanceSelectionChangeEvent;
-import org.eclipse.sequoyah.device.framework.ui.view.model.InstanceSelectionChangeListener;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-
-public class DeviceViewsSync {
-
- /**
- * DeviceViewsSync unique instance
- */
- private static DeviceViewsSync instance = null;
-
- /**
- * Views
- */
- public static final int EMULATOR_VIEW = 0; // Emulator View
-
- public static final int DEVICE_VIEW = 1; // Device Management View
-
- public static final int DDMS_VIEW = 2; // DDMS Device View
-
- /**
- * Methods used to update the Views
- */
- private Method[] syncMethods = null;
-
- /**
- * During the synchronization, it stores the instance that shall be set to
- * avoid loops
- */
- private static String syncInstance = null;
-
- /**
- * Singleton
- *
- * @return DeviceViewsSync
- */
- public static DeviceViewsSync getInstance() {
- if (instance == null) {
- instance = new DeviceViewsSync();
- }
- return instance;
- }
-
- /*
- * Constructor
- *
- * Define the synchronization methods Define the methods that retrieve the
- * current selection in a View
- */
- @SuppressWarnings("rawtypes")
- private DeviceViewsSync() {
-
- try {
-
- /*
- * Register methods that update each view
- */
- Class parameterTypes[] = new Class[1];
- parameterTypes[0] = String.class;
-
- syncMethods = new Method[3];
-
- syncMethods[EMULATOR_VIEW] = this.getClass().getDeclaredMethod("syncEmulatorView", parameterTypes);
- syncMethods[DEVICE_VIEW] = this.getClass().getDeclaredMethod("syncDeviceView", parameterTypes);
- syncMethods[DDMS_VIEW] = this.getClass().getDeclaredMethod("syncDDMSView", parameterTypes);
- } catch (Exception e) {
- AndmoreLogger.error("Could not add syncronization method: " + e.getMessage());
- }
-
- }
-
- /**
- * Add listeners to events that must initiate the synchronization procedures
- *
- * #1) Emulator View
- *
- * #2) Device Management View
- *
- * #3) DDMS Device View
- */
- public void initialize() {
-
- /*
- * Synchronization #1 Add listener to Emulator View tab switch event
- */
- AbstractAndroidView.addTabSwitchListener(new Listener() {
- @Override
- public void handleEvent(Event event) {
-
- IAndroidEmulatorInstance activeInstance = AbstractAndroidView.getActiveInstance();
- if (activeInstance != null) {
- String selectedInstanceName = activeInstance.getName();
- if ((selectedInstanceName != null) && (!selectedInstanceName.equals(syncInstance))) {
- sync(EMULATOR_VIEW, selectedInstanceName);
- }
- }
-
- }
- });
-
- /*
- * Synchronization #2
- */
- InstanceMgtView.addInstanceSelectionChangeListener(new InstanceSelectionChangeListener() {
- @Override
- public void instanceSelectionChanged(InstanceSelectionChangeEvent event) {
-
- IInstance instance = event.getInstance();
- if ((instance != null) && (EmulatorPlugin.STATUS_ONLINE_ID.equals(instance.getStatus()))) {
- String selectedInstanceName = instance.getName();
- if ((selectedInstanceName != null) && (!selectedInstanceName.equals(syncInstance))) {
- sync(DEVICE_VIEW, selectedInstanceName);
- }
- }
-
- }
- });
-
- /*
- * Synchronization #3
- */
- DdmsPlugin.getDefault().addSelectionListener(new DdmsPlugin.ISelectionListener() {
- @Override
- public void selectionChanged(Client client) {
- // none
- }
-
- @Override
- public void selectionChanged(IDevice device) {
-
- if (device != null) {
- String selectedInstanceName = device.getAvdName();
- if ((selectedInstanceName != null) && (!selectedInstanceName.equals(syncInstance))) {
- sync(DDMS_VIEW, selectedInstanceName);
- }
- }
-
- }
- });
- }
-
- /*
- * Run the synchronization procedures
- *
- * @param fireSyncView the View that has been changed and requires others to
- * synchronize
- *
- * @param instanceName the Device Instance name
- */
- private void sync(Integer fireSyncView, String instanceName) {
- syncInstance = instanceName;
-
- Object arglist[] = new Object[1];
- arglist[0] = instanceName;
-
- for (int i = 0; i < syncMethods.length; i++) {
- if (i != fireSyncView) {
- try {
- syncMethods[i].invoke(this, arglist);
- } catch (Exception e) {
- AndmoreLogger.error("Could not call syncronization method for " + i + " : " + e.getMessage());
- }
- }
- }
-
- syncInstance = null;
-
- }
-
- /*
- * Synchronize the Emulator View by setting the selected instance
- *
- * @param instanceName the Device Instance name
- */
- @SuppressWarnings("unused")
- private void syncEmulatorView(String instanceName) {
- try {
- IAndroidEmulatorInstance emulatorInstance = DeviceFrameworkManager.getInstance().getInstanceByName(
- instanceName);
- if (emulatorInstance != null) {
- AbstractAndroidView.setInstance(emulatorInstance);
- } else {
- AndmoreLogger.warn("Could not synchronize with Emulator View: " + instanceName
- + " not in DeviceFrameworkManager model");
- }
-
- } catch (Exception e) {
- AndmoreLogger.error("Could not synchronize with Emulator View: " + e.getMessage());
- }
- }
-
- /*
- * Synchronize the Device Management View by setting the selected instance
- *
- * @param instanceName the Device Instance name
- */
- @SuppressWarnings("unused")
- private void syncDeviceView(String instanceName) {
-
- try {
- InstanceRegistry registry = InstanceRegistry.getInstance();
- List tmlInstances = registry.getInstancesByName(instanceName);
- if (tmlInstances.size() > 0) {
- IInstance tmlInstance = tmlInstances.get(0);
- InstanceMgtView.setSeletectedInstance(tmlInstance);
- } else {
- AndmoreLogger.warn("Could not synchronize with Device Management View: " + instanceName
- + " not in TmL InstanceManager model");
- }
- } catch (Exception e) {
- AndmoreLogger.error("Could not synchronize with Device Management View: " + e.getMessage());
- }
-
- }
-
- /*
- * Synchronize the DDMS Device View by setting the selected instance
- *
- * @param instanceName the Device Instance name
- */
- @SuppressWarnings("unused")
- private void syncDDMSView(String instanceName) {
- try {
- IDevice device = DDMSFacade.getDeviceWithVmName(instanceName);
- if (device != null) {
- DdmsPlugin.getDefault().selectionChanged(device, null);
- } else {
- AndmoreLogger
- .warn("Could not synchronize with DDMS Devices View: Could not retrieve Device object from ADT model");
- }
- } catch (Exception e) {
- AndmoreLogger.error("Could not synchronize with DDMS Devices View: " + e.getMessage());
- }
-
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.device.sync;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.common.log.AndmoreLogger;
+import org.eclipse.andmore.android.emulator.EmulatorPlugin;
+import org.eclipse.andmore.android.emulator.core.devfrm.DeviceFrameworkManager;
+import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
+import org.eclipse.andmore.android.emulator.ui.view.AbstractAndroidView;
+import org.eclipse.andmore.ddms.DdmsPlugin;
+import org.eclipse.sequoyah.device.framework.factory.InstanceRegistry;
+import org.eclipse.sequoyah.device.framework.model.IInstance;
+import org.eclipse.sequoyah.device.framework.ui.view.InstanceMgtView;
+import org.eclipse.sequoyah.device.framework.ui.view.model.InstanceSelectionChangeEvent;
+import org.eclipse.sequoyah.device.framework.ui.view.model.InstanceSelectionChangeListener;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+
+public class DeviceViewsSync {
+
+ /**
+ * DeviceViewsSync unique instance
+ */
+ private static DeviceViewsSync instance = null;
+
+ /**
+ * Views
+ */
+ public static final int EMULATOR_VIEW = 0; // Emulator View
+
+ public static final int DEVICE_VIEW = 1; // Device Management View
+
+ public static final int DDMS_VIEW = 2; // DDMS Device View
+
+ /**
+ * Methods used to update the Views
+ */
+ private Method[] syncMethods = null;
+
+ /**
+ * During the synchronization, it stores the instance that shall be set to
+ * avoid loops
+ */
+ private static String syncInstance = null;
+
+ /**
+ * Singleton
+ *
+ * @return DeviceViewsSync
+ */
+ public static DeviceViewsSync getInstance() {
+ if (instance == null) {
+ instance = new DeviceViewsSync();
+ }
+ return instance;
+ }
+
+ /*
+ * Constructor
+ *
+ * Define the synchronization methods Define the methods that retrieve the
+ * current selection in a View
+ */
+ @SuppressWarnings("rawtypes")
+ private DeviceViewsSync() {
+
+ try {
+
+ /*
+ * Register methods that update each view
+ */
+ Class parameterTypes[] = new Class[1];
+ parameterTypes[0] = String.class;
+
+ syncMethods = new Method[3];
+
+ syncMethods[EMULATOR_VIEW] = this.getClass().getDeclaredMethod("syncEmulatorView", parameterTypes);
+ syncMethods[DEVICE_VIEW] = this.getClass().getDeclaredMethod("syncDeviceView", parameterTypes);
+ syncMethods[DDMS_VIEW] = this.getClass().getDeclaredMethod("syncDDMSView", parameterTypes);
+ } catch (Exception e) {
+ AndmoreLogger.error("Could not add syncronization method: " + e.getMessage());
+ }
+
+ }
+
+ /**
+ * Add listeners to events that must initiate the synchronization procedures
+ *
+ * #1) Emulator View
+ *
+ * #2) Device Management View
+ *
+ * #3) DDMS Device View
+ */
+ public void initialize() {
+
+ /*
+ * Synchronization #1 Add listener to Emulator View tab switch event
+ */
+ AbstractAndroidView.addTabSwitchListener(new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+
+ IAndroidEmulatorInstance activeInstance = AbstractAndroidView.getActiveInstance();
+ if (activeInstance != null) {
+ String selectedInstanceName = activeInstance.getName();
+ if ((selectedInstanceName != null) && (!selectedInstanceName.equals(syncInstance))) {
+ sync(EMULATOR_VIEW, selectedInstanceName);
+ }
+ }
+
+ }
+ });
+
+ /*
+ * Synchronization #2
+ */
+ InstanceMgtView.addInstanceSelectionChangeListener(new InstanceSelectionChangeListener() {
+ @Override
+ public void instanceSelectionChanged(InstanceSelectionChangeEvent event) {
+
+ IInstance instance = event.getInstance();
+ if ((instance != null) && (EmulatorPlugin.STATUS_ONLINE_ID.equals(instance.getStatus()))) {
+ String selectedInstanceName = instance.getName();
+ if ((selectedInstanceName != null) && (!selectedInstanceName.equals(syncInstance))) {
+ sync(DEVICE_VIEW, selectedInstanceName);
+ }
+ }
+
+ }
+ });
+
+ /*
+ * Synchronization #3
+ */
+ DdmsPlugin.getDefault().addSelectionListener(new DdmsPlugin.ISelectionListener() {
+ @Override
+ public void selectionChanged(Client client) {
+ // none
+ }
+
+ @Override
+ public void selectionChanged(IDevice device) {
+
+ if (device != null) {
+ String selectedInstanceName = device.getAvdName();
+ if ((selectedInstanceName != null) && (!selectedInstanceName.equals(syncInstance))) {
+ sync(DDMS_VIEW, selectedInstanceName);
+ }
+ }
+
+ }
+ });
+ }
+
+ /*
+ * Run the synchronization procedures
+ *
+ * @param fireSyncView the View that has been changed and requires others to
+ * synchronize
+ *
+ * @param instanceName the Device Instance name
+ */
+ private void sync(Integer fireSyncView, String instanceName) {
+ syncInstance = instanceName;
+
+ Object arglist[] = new Object[1];
+ arglist[0] = instanceName;
+
+ for (int i = 0; i < syncMethods.length; i++) {
+ if (i != fireSyncView) {
+ try {
+ syncMethods[i].invoke(this, arglist);
+ } catch (Exception e) {
+ AndmoreLogger.error("Could not call syncronization method for " + i + " : " + e.getMessage());
+ }
+ }
+ }
+
+ syncInstance = null;
+
+ }
+
+ /*
+ * Synchronize the Emulator View by setting the selected instance
+ *
+ * @param instanceName the Device Instance name
+ */
+ @SuppressWarnings("unused")
+ private void syncEmulatorView(String instanceName) {
+ try {
+ IAndroidEmulatorInstance emulatorInstance = DeviceFrameworkManager.getInstance().getInstanceByName(
+ instanceName);
+ if (emulatorInstance != null) {
+ AbstractAndroidView.setInstance(emulatorInstance);
+ } else {
+ AndmoreLogger.warn("Could not synchronize with Emulator View: " + instanceName
+ + " not in DeviceFrameworkManager model");
+ }
+
+ } catch (Exception e) {
+ AndmoreLogger.error("Could not synchronize with Emulator View: " + e.getMessage());
+ }
+ }
+
+ /*
+ * Synchronize the Device Management View by setting the selected instance
+ *
+ * @param instanceName the Device Instance name
+ */
+ @SuppressWarnings("unused")
+ private void syncDeviceView(String instanceName) {
+
+ try {
+ InstanceRegistry registry = InstanceRegistry.getInstance();
+ List tmlInstances = registry.getInstancesByName(instanceName);
+ if (tmlInstances.size() > 0) {
+ IInstance tmlInstance = tmlInstances.get(0);
+ InstanceMgtView.setSeletectedInstance(tmlInstance);
+ } else {
+ AndmoreLogger.warn("Could not synchronize with Device Management View: " + instanceName
+ + " not in TmL InstanceManager model");
+ }
+ } catch (Exception e) {
+ AndmoreLogger.error("Could not synchronize with Device Management View: " + e.getMessage());
+ }
+
+ }
+
+ /*
+ * Synchronize the DDMS Device View by setting the selected instance
+ *
+ * @param instanceName the Device Instance name
+ */
+ @SuppressWarnings("unused")
+ private void syncDDMSView(String instanceName) {
+ try {
+ IDevice device = DeviceMonitor.instance().getDeviceWithVmName(instanceName);
+ if (device != null) {
+ DdmsPlugin.getDefault().selectionChanged(device, null);
+ } else {
+ AndmoreLogger
+ .warn("Could not synchronize with DDMS Devices View: Could not retrieve Device object from ADT model");
+ }
+ } catch (Exception e) {
+ AndmoreLogger.error("Could not synchronize with DDMS Devices View: " + e.getMessage());
+ }
+
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/ui/DevicePropertiesPage.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/ui/DevicePropertiesPage.java
index 32de9ef4..ae89744c 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/ui/DevicePropertiesPage.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/device/ui/DevicePropertiesPage.java
@@ -1,42 +1,42 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.device.ui;
-
-import java.util.Properties;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.ISerialNumbered;
-import org.eclipse.andmore.android.devices.AbstractDevicePropertyPage;
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.ui.IWorkbenchPropertyPage;
-
-public class DevicePropertiesPage extends AbstractDevicePropertyPage implements IWorkbenchPropertyPage {
-
- private ISerialNumbered androidIntance;
-
- @Override
- public void setElement(IAdaptable element) {
-
- this.androidIntance = (ISerialNumbered) element;
-
- super.setElement(element);
- }
-
- @Override
- protected Properties getDeviceProperties() {
- return DDMSFacade.getDeviceProperties(androidIntance.getSerialNumber());
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.device.ui;
+
+import java.util.Properties;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.ISerialNumbered;
+import org.eclipse.andmore.android.devices.AbstractDevicePropertyPage;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.ui.IWorkbenchPropertyPage;
+
+public class DevicePropertiesPage extends AbstractDevicePropertyPage implements IWorkbenchPropertyPage {
+
+ private ISerialNumbered androidIntance;
+
+ @Override
+ public void setElement(IAdaptable element) {
+
+ this.androidIntance = (ISerialNumbered) element;
+
+ super.setElement(element);
+ }
+
+ @Override
+ protected Properties getDeviceProperties() {
+ return DeviceMonitor.instance().getDeviceProperties(androidIntance.getSerialNumber());
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/AndroidLogicUtils.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/AndroidLogicUtils.java
index f21231e9..ee19caa2 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/AndroidLogicUtils.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/AndroidLogicUtils.java
@@ -1,323 +1,323 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.ISerialNumbered;
-import org.eclipse.andmore.android.common.exception.AndroidException;
-import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
-import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
-import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
-import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.osgi.util.NLS;
-
-/**
- * This class is used as an utilities class for operations related to Android
- * Devices
- *
- */
-public class AndroidLogicUtils {
- private static final int INITIAL_VNC_PORT_VALUE = 5900;
-
- public static final String ORIENTATION_BASE_COMMAND = "sendevent /dev/input/event0 ";
-
- /**
- * Execute the VM process
- *
- * @param cmd
- * the command to be executed
- * @return the VM process
- *
- * @throws AndroidException
- * if the command failed to execute
- */
- public static Process executeProcess(final String cmd) throws AndroidException {
- try {
- info("Executing command " + cmd);
- Process vmProcess = Runtime.getRuntime().exec(cmd);
- return vmProcess;
- } catch (IOException e) {
- error("Falied to execute the command: " + cmd);
- throw new AndroidException(NLS.bind(EmulatorNLS.EXC_AndroidLogicUtils_CannotStartProcess, cmd));
- }
- }
-
- /**
- * Execute the VM process
- *
- * @param cmd
- * the command to be executed, described as an array
- * @return the VM process
- *
- * @throws AndroidException
- * if the command failed to execute
- */
- public static Process executeProcess(final String[] cmd) throws AndroidException {
- String cmdString = "";
- for (int i = 0; i < cmd.length; i++) {
- cmdString += cmd[i] + " ";
-
- }
-
- return executeProcess(cmd, cmdString);
- }
-
- /**
- * Execute the VM process
- *
- * @param cmd
- * The command to be executed, described as an array
- * @param cmdToLog
- * The command to be logged.
- *
- * @return the VM process
- *
- * @throws AndroidException
- * if the command failed to execute
- */
- public static Process executeProcess(final String[] cmd, final String cmdToLog) throws AndroidException {
- try {
- info("Executing command " + cmdToLog);
- Process vmProcess = Runtime.getRuntime().exec(cmd);
- return vmProcess;
- } catch (IOException e) {
- error("Falied to execute the command: " + cmd);
- throw new AndroidException(NLS.bind(EmulatorNLS.EXC_AndroidLogicUtils_CannotStartProcess, cmd));
- }
- }
-
- /**
- * }
- *
- * /** Checks if the user has canceled the VM startup
- *
- * @param monitor
- * A progress monitor that will give the user feedback about this
- * long running operation
- * @param instanceHost
- * The IP address of the started emulator instance
- *
- * @return True if the operation can proceed, false otherwise
- *
- * @throws StartCancelledException
- * If the user has canceled the start process
- */
- public static void testCanceled(IProgressMonitor monitor) throws StartCancelledException {
- if (monitor.isCanceled()) {
- info("Operation canceled by the user");
- monitor.subTask(EmulatorNLS.MON_AndroidEmulatorStarter_Canceling);
-
- throw new StartCancelledException(EmulatorNLS.EXC_AndroidEmulatorStarter_EmulatorStartCanceled);
- }
- }
-
- /**
- * Checks if the timeout limit has reached
- *
- * @param timeoutLimit
- * The system time limit that cannot be overtaken, in
- * milliseconds
- *
- * @throws StartTimeoutException
- * When the system time limit is overtaken
- */
- public static void testTimeout(long timeoutLimit, String timeoutErrorMessage) throws StartTimeoutException {
- if (System.currentTimeMillis() > timeoutLimit) {
- error("The emulator was not up within the set timeout");
- throw new StartTimeoutException(timeoutErrorMessage);
- }
- }
-
- /**
- * Get the relative timeout limit, which is the the current time plus the
- * timeout value
- *
- * @param timeout
- * timeout value (in milliseconds)
- * @return Relative timeout limit
- */
- public static long getTimeoutLimit(int timeout) {
- return System.currentTimeMillis() + timeout;
- }
-
- /**
- * Check if the given process is still up and running
- *
- * @param p
- * process
- * @throws InstanceStartException
- */
- public static void testProcessStatus(Process p) throws InstanceStartException {
-
- boolean isRunning;
- int exitCode;
-
- try {
- exitCode = p.exitValue();
- isRunning = false;
- } catch (Exception e) {
- // emulator process is still running... so everything looks fine...
- isRunning = true;
- exitCode = 0;
- }
-
- if (!isRunning) {
- error("Emulator process is not running! Exit code:" + exitCode);
- StringBuffer outBuf = null;
- InputStream inStream = null;
-
- int ch;
-
- // Getting error output stream
- String processAnswer = "";
- inStream = p.getErrorStream();
- outBuf = new StringBuffer();
- try {
- while ((ch = inStream.read()) != -1) {
- outBuf.append((char) ch + "");
- }
- } catch (IOException e) {
- error("Cannot read error output stream from Emulator proccess");
- }
-
- processAnswer = outBuf.toString();
-
- if (processAnswer.length() == 0) {
- // if no error came from process, get standard output stream
- inStream = p.getInputStream();
- outBuf = new StringBuffer();
- try {
- while ((ch = inStream.read()) != -1) {
- outBuf.append((char) ch + "");
- }
- } catch (IOException e) {
- error("Cannot read standard output stream from Emulator proccess");
- }
-
- processAnswer = outBuf.toString();
-
- }
- String msg = EmulatorNLS.EXC_AndroidEmulatorStarter_ProcessTerminated;
- msg += processAnswer;
- throw new InstanceStartException(msg);
- }
-
- }
-
- /**
- * Kill the communication channel
- *
- * @param instance
- * Android instance
- */
- public static void kill(IAndroidLogicInstance instance) {
- if (instance instanceof ISerialNumbered) {
- String serialNumber = ((ISerialNumbered) instance).getSerialNumber();
- DDMSFacade.kill(serialNumber);
- Process process = instance.getProcess();
- if (process != null) {
- int tries = 0;
- Integer exitValue = null;
- while ((process != null) && (tries < 10) && (exitValue == null)) {
- try {
- exitValue = process.exitValue();
- } catch (Throwable t) {
- tries++;
- try {
- Thread.sleep(250);
- } catch (InterruptedException e) {
- // do nothing
- }
- }
- }
- process.destroy();
- instance.setProcess(null);
- }
- }
- }
-
- /**
- * Get the VNC port forward
- *
- * @param serial
- * port number
- * @return VNC port
- */
- public static int getVncServerPortFoward(String serial) {
- if (serial == null) {
- return 0;
- }
-
- int stringSize = serial.length();
- String lastTwoNumbers = serial.substring(stringSize - 2, stringSize);
-
- int port = INITIAL_VNC_PORT_VALUE;
-
- try {
- port += Integer.valueOf(lastTwoNumbers);
- } catch (NumberFormatException e) {
- // do nothing (this should not happen)
- }
-
- return port;
-
- }
-
- public static int getEmulatorPort(String serial) {
- if (serial == null) {
- return 0;
- }
-
- int stringSize = serial.length();
- String lastFourNumbers = serial.substring(stringSize - 4, stringSize);
-
- int port = 0;
-
- try {
- port = Integer.valueOf(lastFourNumbers);
- } catch (NumberFormatException e) {
- // do nothing (this should not happen)
- }
- return port;
- }
-
- /**
- * Checks if the Device is still online... If the device is not online it is
- * not possible to communicate with it. Notice it is a verification of the
- * status of the Device wich may be different than the status of the Tml
- * Instance...
- *
- * @param serialNumber
- * serial number of the device
- *
- * @throws AndroidException
- * If the device is not started
- */
- public static void testDeviceStatus(String serialNumber) throws AndroidException {
- if (!DDMSFacade.isDeviceOnline(serialNumber)) {
- info("Device is offline: " + serialNumber);
-
- throw new AndroidException(EmulatorNLS.EXC_AndroidLogicUtils_DeviceIsOffline);
- }
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.ISerialNumbered;
+import org.eclipse.andmore.android.common.exception.AndroidException;
+import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
+import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
+import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
+import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * This class is used as an utilities class for operations related to Android
+ * Devices
+ *
+ */
+public class AndroidLogicUtils {
+ private static final int INITIAL_VNC_PORT_VALUE = 5900;
+
+ public static final String ORIENTATION_BASE_COMMAND = "sendevent /dev/input/event0 ";
+
+ /**
+ * Execute the VM process
+ *
+ * @param cmd
+ * the command to be executed
+ * @return the VM process
+ *
+ * @throws AndroidException
+ * if the command failed to execute
+ */
+ public static Process executeProcess(final String cmd) throws AndroidException {
+ try {
+ info("Executing command " + cmd);
+ Process vmProcess = Runtime.getRuntime().exec(cmd);
+ return vmProcess;
+ } catch (IOException e) {
+ error("Falied to execute the command: " + cmd);
+ throw new AndroidException(NLS.bind(EmulatorNLS.EXC_AndroidLogicUtils_CannotStartProcess, cmd));
+ }
+ }
+
+ /**
+ * Execute the VM process
+ *
+ * @param cmd
+ * the command to be executed, described as an array
+ * @return the VM process
+ *
+ * @throws AndroidException
+ * if the command failed to execute
+ */
+ public static Process executeProcess(final String[] cmd) throws AndroidException {
+ String cmdString = "";
+ for (int i = 0; i < cmd.length; i++) {
+ cmdString += cmd[i] + " ";
+
+ }
+
+ return executeProcess(cmd, cmdString);
+ }
+
+ /**
+ * Execute the VM process
+ *
+ * @param cmd
+ * The command to be executed, described as an array
+ * @param cmdToLog
+ * The command to be logged.
+ *
+ * @return the VM process
+ *
+ * @throws AndroidException
+ * if the command failed to execute
+ */
+ public static Process executeProcess(final String[] cmd, final String cmdToLog) throws AndroidException {
+ try {
+ info("Executing command " + cmdToLog);
+ Process vmProcess = Runtime.getRuntime().exec(cmd);
+ return vmProcess;
+ } catch (IOException e) {
+ error("Falied to execute the command: " + cmd);
+ throw new AndroidException(NLS.bind(EmulatorNLS.EXC_AndroidLogicUtils_CannotStartProcess, cmd));
+ }
+ }
+
+ /**
+ * }
+ *
+ * /** Checks if the user has canceled the VM startup
+ *
+ * @param monitor
+ * A progress monitor that will give the user feedback about this
+ * long running operation
+ * @param instanceHost
+ * The IP address of the started emulator instance
+ *
+ * @return True if the operation can proceed, false otherwise
+ *
+ * @throws StartCancelledException
+ * If the user has canceled the start process
+ */
+ public static void testCanceled(IProgressMonitor monitor) throws StartCancelledException {
+ if (monitor.isCanceled()) {
+ info("Operation canceled by the user");
+ monitor.subTask(EmulatorNLS.MON_AndroidEmulatorStarter_Canceling);
+
+ throw new StartCancelledException(EmulatorNLS.EXC_AndroidEmulatorStarter_EmulatorStartCanceled);
+ }
+ }
+
+ /**
+ * Checks if the timeout limit has reached
+ *
+ * @param timeoutLimit
+ * The system time limit that cannot be overtaken, in
+ * milliseconds
+ *
+ * @throws StartTimeoutException
+ * When the system time limit is overtaken
+ */
+ public static void testTimeout(long timeoutLimit, String timeoutErrorMessage) throws StartTimeoutException {
+ if (System.currentTimeMillis() > timeoutLimit) {
+ error("The emulator was not up within the set timeout");
+ throw new StartTimeoutException(timeoutErrorMessage);
+ }
+ }
+
+ /**
+ * Get the relative timeout limit, which is the the current time plus the
+ * timeout value
+ *
+ * @param timeout
+ * timeout value (in milliseconds)
+ * @return Relative timeout limit
+ */
+ public static long getTimeoutLimit(int timeout) {
+ return System.currentTimeMillis() + timeout;
+ }
+
+ /**
+ * Check if the given process is still up and running
+ *
+ * @param p
+ * process
+ * @throws InstanceStartException
+ */
+ public static void testProcessStatus(Process p) throws InstanceStartException {
+
+ boolean isRunning;
+ int exitCode;
+
+ try {
+ exitCode = p.exitValue();
+ isRunning = false;
+ } catch (Exception e) {
+ // emulator process is still running... so everything looks fine...
+ isRunning = true;
+ exitCode = 0;
+ }
+
+ if (!isRunning) {
+ error("Emulator process is not running! Exit code:" + exitCode);
+ StringBuffer outBuf = null;
+ InputStream inStream = null;
+
+ int ch;
+
+ // Getting error output stream
+ String processAnswer = "";
+ inStream = p.getErrorStream();
+ outBuf = new StringBuffer();
+ try {
+ while ((ch = inStream.read()) != -1) {
+ outBuf.append((char) ch + "");
+ }
+ } catch (IOException e) {
+ error("Cannot read error output stream from Emulator proccess");
+ }
+
+ processAnswer = outBuf.toString();
+
+ if (processAnswer.length() == 0) {
+ // if no error came from process, get standard output stream
+ inStream = p.getInputStream();
+ outBuf = new StringBuffer();
+ try {
+ while ((ch = inStream.read()) != -1) {
+ outBuf.append((char) ch + "");
+ }
+ } catch (IOException e) {
+ error("Cannot read standard output stream from Emulator proccess");
+ }
+
+ processAnswer = outBuf.toString();
+
+ }
+ String msg = EmulatorNLS.EXC_AndroidEmulatorStarter_ProcessTerminated;
+ msg += processAnswer;
+ throw new InstanceStartException(msg);
+ }
+
+ }
+
+ /**
+ * Kill the communication channel
+ *
+ * @param instance
+ * Android instance
+ */
+ public static void kill(IAndroidLogicInstance instance) {
+ if (instance instanceof ISerialNumbered) {
+ String serialNumber = ((ISerialNumbered) instance).getSerialNumber();
+ DeviceMonitor.instance().kill(serialNumber);
+ Process process = instance.getProcess();
+ if (process != null) {
+ int tries = 0;
+ Integer exitValue = null;
+ while ((process != null) && (tries < 10) && (exitValue == null)) {
+ try {
+ exitValue = process.exitValue();
+ } catch (Throwable t) {
+ tries++;
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ }
+ process.destroy();
+ instance.setProcess(null);
+ }
+ }
+ }
+
+ /**
+ * Get the VNC port forward
+ *
+ * @param serial
+ * port number
+ * @return VNC port
+ */
+ public static int getVncServerPortFoward(String serial) {
+ if (serial == null) {
+ return 0;
+ }
+
+ int stringSize = serial.length();
+ String lastTwoNumbers = serial.substring(stringSize - 2, stringSize);
+
+ int port = INITIAL_VNC_PORT_VALUE;
+
+ try {
+ port += Integer.valueOf(lastTwoNumbers);
+ } catch (NumberFormatException e) {
+ // do nothing (this should not happen)
+ }
+
+ return port;
+
+ }
+
+ public static int getEmulatorPort(String serial) {
+ if (serial == null) {
+ return 0;
+ }
+
+ int stringSize = serial.length();
+ String lastFourNumbers = serial.substring(stringSize - 4, stringSize);
+
+ int port = 0;
+
+ try {
+ port = Integer.valueOf(lastFourNumbers);
+ } catch (NumberFormatException e) {
+ // do nothing (this should not happen)
+ }
+ return port;
+ }
+
+ /**
+ * Checks if the Device is still online... If the device is not online it is
+ * not possible to communicate with it. Notice it is a verification of the
+ * status of the Device wich may be different than the status of the Tml
+ * Instance...
+ *
+ * @param serialNumber
+ * serial number of the device
+ *
+ * @throws AndroidException
+ * If the device is not started
+ */
+ public static void testDeviceStatus(String serialNumber) throws AndroidException {
+ if (!DeviceMonitor.instance().isDeviceOnline(serialNumber)) {
+ info("Device is offline: " + serialNumber);
+
+ throw new AndroidException(EmulatorNLS.EXC_AndroidLogicUtils_DeviceIsOffline);
+ }
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/ForwardVncPortLogic.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/ForwardVncPortLogic.java
index 000ba975..f5048eed 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/ForwardVncPortLogic.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/ForwardVncPortLogic.java
@@ -1,47 +1,47 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
-
-import java.io.IOException;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.ISerialNumbered;
-import org.eclipse.andmore.android.common.exception.AndroidException;
-import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
-import org.eclipse.core.runtime.IProgressMonitor;
-
-public class ForwardVncPortLogic implements IAndroidLogic {
-
- @Override
- public void execute(IAndroidLogicInstance instance, int timeout, IProgressMonitor monitor) throws IOException,
- InstanceStartException {
- int port = AndroidLogicUtils.getVncServerPortFoward(instance.getInstanceIdentifier());
-
- if (instance instanceof ISerialNumbered) {
- String serialNumber = ((ISerialNumbered) instance).getSerialNumber();
- try {
- AndroidLogicUtils.testDeviceStatus(serialNumber);
- } catch (AndroidException e) {
- throw new InstanceStartException(e.getMessage());
- }
-
- boolean forwardOk = DDMSFacade.createForward(serialNumber, port, 5901);
- if (!forwardOk) {
- throw new IOException("Could not forward VNC port 5901 to " + port + " on " + instance.getName());
- }
- }
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
+
+import java.io.IOException;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.ISerialNumbered;
+import org.eclipse.andmore.android.common.exception.AndroidException;
+import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+public class ForwardVncPortLogic implements IAndroidLogic {
+
+ @Override
+ public void execute(IAndroidLogicInstance instance, int timeout, IProgressMonitor monitor) throws IOException,
+ InstanceStartException {
+ int port = AndroidLogicUtils.getVncServerPortFoward(instance.getInstanceIdentifier());
+
+ if (instance instanceof ISerialNumbered) {
+ String serialNumber = ((ISerialNumbered) instance).getSerialNumber();
+ try {
+ AndroidLogicUtils.testDeviceStatus(serialNumber);
+ } catch (AndroidException e) {
+ throw new InstanceStartException(e.getMessage());
+ }
+
+ boolean forwardOk = DeviceMonitor.instance().createForward(serialNumber, port, 5901);
+ if (!forwardOk) {
+ throw new IOException("Could not forward VNC port 5901 to " + port + " on " + instance.getName());
+ }
+ }
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartEmulatorProcessLogic.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartEmulatorProcessLogic.java
index d17f82c6..a0cdaa13 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartEmulatorProcessLogic.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartEmulatorProcessLogic.java
@@ -1,420 +1,423 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.debug;
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Properties;
-import java.util.StringTokenizer;
-
-import org.eclipse.andmore.AndmoreAndroidPlugin;
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.SdkUtils;
-import org.eclipse.andmore.android.common.exception.AndroidException;
-import org.eclipse.andmore.android.common.log.AndmoreLogger;
-import org.eclipse.andmore.android.common.preferences.DialogWithToggleUtils;
-import org.eclipse.andmore.android.common.utilities.EclipseUtils;
-import org.eclipse.andmore.android.emulator.EmulatorPlugin;
-import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
-import org.eclipse.andmore.android.emulator.core.exception.InstanceStopException;
-import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
-import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
-import org.eclipse.andmore.android.emulator.device.IDevicePropertiesConstants;
-import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
-import org.eclipse.andmore.android.nativeos.IDevicePropertiesOSConstants;
-import org.eclipse.andmore.android.nativeos.NativeUIUtils;
-import org.eclipse.andmore.internal.preferences.AdtPrefs;
-import org.eclipse.core.net.proxy.IProxyData;
-import org.eclipse.core.net.proxy.IProxyService;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.osgi.util.NLS;
-import org.eclipse.ui.IViewPart;
-import org.osgi.framework.ServiceReference;
-
-@SuppressWarnings("restriction")
-public class StartEmulatorProcessLogic implements IAndroidLogic {
- /**
- *
- */
- private static final String EMULATOR_NO_SNAPSHOT_LOAD = "-no-snapshot-load";
-
- /**
- *
- */
- private static final String EMULATOR_NO_SNAPSHOT_SAVE = "-no-snapshot-save";
-
- /**
- *
- */
- private static final String EMULATOR_HTTP_PROXY_PARAMETER = "-http-proxy";
-
- // Proxy constants
- private static final String PROXY_AT = "@";
-
- private static final String PROXY_COLON = ":";
-
- private static final String PROXY_HTTP = "http://";
-
- private static final String EMULATOR_VIEW = "org.eclipse.andmore.android.emulator.androidView";
-
- // Strings used to build the command line for launching the emulator process
- private static final String ARM_EMULATOR_RELATIVE_PATH = "/tools/emulator-arm";
-
- private static final String x86_EMULATOR_RELATIVE_PATH = "/tools/emulator-x86";
-
- private static final String EMULATOR_RELATIVE_PATH = "/tools/emulator";
-
- private static final String EMULATOR_VM_PARAMETER = "-avd";
-
- private static String selectedEmulatorPath = "";
-
- @Override
- public void execute(final IAndroidLogicInstance instance, int timeout, IProgressMonitor monitor)
- throws InstanceStartException, StartTimeoutException, StartCancelledException {
-
- long timeoutLimit = AndroidLogicUtils.getTimeoutLimit(timeout);
-
- info("Starting the Android Emulator process: " + instance);
- instance.setWindowHandle(0);
-
- File userData = instance.getUserdata();
-
- if (userData != null) {
- File userdataDir = userData.getParentFile();
- if ((userdataDir != null) && (!userdataDir.exists())) {
- userdataDir.mkdirs();
- }
- }
-
- selectedEmulatorPath = retrieveEmulatorExecutableName(instance);
-
- File emulatorExe = new File(SdkUtils.getSdkPath(), selectedEmulatorPath);
-
- List cmdList = new LinkedList();
-
- cmdList.add(emulatorExe.getAbsolutePath());
- cmdList.add(EMULATOR_VM_PARAMETER);
- cmdList.add(instance.getName());
-
- Properties propArgs = instance.getCommandLineArgumentsAsProperties();
- IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
- String adtEmuOptions = store.getString(AdtPrefs.PREFS_EMU_OPTIONS);
-
- StringTokenizer adtOptionsTokenizer = new StringTokenizer(adtEmuOptions, " ");
- while (adtOptionsTokenizer.hasMoreTokens()) {
- String nextToken = adtOptionsTokenizer.nextToken();
- cmdList.add(nextToken);
- }
-
- for (Object key : propArgs.keySet()) {
- String value = propArgs.getProperty(key.toString());
-
- if (key.equals("other")) {
- StringTokenizer stringTokenizer = new StringTokenizer(value, " ");
- while (stringTokenizer.hasMoreTokens()) {
- cmdList.add(stringTokenizer.nextToken());
- }
- } else {
- if ((value.trim().length() > 0) && !value.equals(Boolean.TRUE.toString())) {
- cmdList.add(key.toString());
- if (Platform.getOS().equals(Platform.OS_MACOSX)) {
- if (value.contains(" ")) {
- value = "\"" + value + "\"";
- }
- } else {
- if (value.contains("\\")) {
- value = value.replace("\\", "\\\\");
- }
-
- if (value.contains(" ")) {
- value = value.replace(" ", "\\ ");
- }
- }
-
- cmdList.add(value);
- } else if ((value.trim().length() > 0) && value.equals(Boolean.TRUE.toString())) {
- cmdList.add(key.toString());
- }
- }
- }
-
- // add proxy in case it is needed
- Properties properties = instance.getProperties();
- if (properties != null) {
- String useProxy = properties.getProperty(IDevicePropertiesConstants.useProxy,
- IDevicePropertiesConstants.defaultUseProxyValue);
- if (Boolean.TRUE.toString().equals(useProxy)) {
- addEmulatorProxyParameter(cmdList);
- }
- }
-
- StringBuffer cmdLog = new StringBuffer("");
-
- boolean httpProxyParamFound = false;
- boolean logHttpProxyUsage = false;
- for (String param : cmdList) {
- // Do not log -http-proxy information
- if (!httpProxyParamFound) {
- if (!param.equals(EMULATOR_HTTP_PROXY_PARAMETER)) {
- if (param.startsWith(emulatorExe.getAbsolutePath())) {
- // do not log emulator full path
- cmdLog.append(selectedEmulatorPath + " ");
- } else {
- cmdLog.append(param + " ");
- }
- } else {
- httpProxyParamFound = true;
- logHttpProxyUsage = true;
- }
- } else {
- httpProxyParamFound = false;
- }
- }
-
- // Append http proxy usage to log
- if (logHttpProxyUsage) {
- cmdLog.append("\nProxy settings are being used by the started emulator (-http-proxy parameter).");
- }
- // add command to not start from snapshot
- if (properties != null) {
- String startFromSnapshot = properties.getProperty(IDevicePropertiesConstants.startFromSnapshot,
- IDevicePropertiesConstants.defaultstartFromSnapshotValue);
- if (Boolean.FALSE.toString().equals(startFromSnapshot)) {
- cmdList.add(EMULATOR_NO_SNAPSHOT_LOAD);
- }
- }
-
- // Add the command to not save snapshot
- if (properties != null) {
- String saveSnapshot = properties.getProperty(IDevicePropertiesConstants.saveSnapshot,
- IDevicePropertiesConstants.defaulSaveSnapshot);
- if (Boolean.FALSE.toString().equals(saveSnapshot)) {
- cmdList.add(EMULATOR_NO_SNAPSHOT_SAVE);
- }
- }
-
- Process p;
- try {
- p = AndroidLogicUtils.executeProcess(cmdList.toArray(new String[0]), cmdLog.toString());
- } catch (AndroidException e) {
- throw new InstanceStartException(e);
- }
- info("Wait until and emulator with the VM " + instance.getName() + " is up ");
-
- AndroidLogicUtils.testProcessStatus(p);
- instance.setProcess(p);
- instance.setComposite(null);
-
- final String avdName = instance.getName();
-
- if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
- Collection openedAndroidViews = EclipseUtils.getAllOpenedViewsWithId(EMULATOR_VIEW);
-
- if (!openedAndroidViews.isEmpty()) {
- Runnable runnable = new Runnable() {
-
- @Override
- public void run() {
- long windowHandle = -1;
- long timeOutToFindWindow = System.currentTimeMillis() + 30000;
-
- do {
- try {
- Thread.sleep(250);
- } catch (InterruptedException e) {
- // do nothing
- }
-
- try {
- AndroidLogicUtils.testTimeout(timeOutToFindWindow, "");
- } catch (StartTimeoutException e) {
- debug("Emulator window could not be found, instance :" + avdName);
- break;
- }
-
- try {
- int port = AndroidLogicUtils.getEmulatorPort(DDMSFacade.getSerialNumberByName(instance
- .getName()));
- if (port > 0) {
- windowHandle = NativeUIUtils.getWindowHandle(instance.getName(), port);
- }
-
- } catch (Exception t) {
- t.getCause().getMessage();
- System.out.println(t.getCause().getMessage());
- }
- } while (windowHandle <= 0);
-
- if (windowHandle > 0) {
- instance.setWindowHandle(windowHandle);
- NativeUIUtils.hideWindow(windowHandle);
- }
- }
- };
- Thread getHandleThread = new Thread(runnable, "Window Handle Thread");
- getHandleThread.start();
- }
- }
-
- if (instance.getProperties().getProperty(IDevicePropertiesOSConstants.useVnc, NativeUIUtils.getDefaultUseVnc())
- .equals(Boolean.TRUE.toString())) {
- do {
- try {
- Thread.sleep(450);
- } catch (InterruptedException e) {
- // do nothing
- }
-
- AndroidLogicUtils.testCanceled(monitor);
- try {
- AndroidLogicUtils
- .testTimeout(timeoutLimit, NLS.bind(EmulatorNLS.EXC_TimeoutWhileStarting, avdName));
- } catch (StartTimeoutException e) {
- debug("Emulator start timeout has been reached, instance :" + avdName + " has device: "
- + instance.hasDevice() + "isOnline? "
- + DDMSFacade.isDeviceOnline(DDMSFacade.getSerialNumberByName(avdName)));
- throw e;
- }
- } while (!isEmulatorReady(avdName));
-
- }
-
- Thread t = new Thread("Process Error") {
- @Override
- public void run() {
- boolean shouldTryAgain = true;
- for (int i = 0; (i < 90) && shouldTryAgain; i++) {
- try {
- sleep(500);
- Process p = instance.getProcess();
- if (p != null) {
- AndroidLogicUtils.testProcessStatus(p);
- }
- } catch (Exception e) {
- AndmoreLogger.info(StartEmulatorProcessLogic.class,
- "Trying to stop the emulator process: execution stopped too early");
- DialogWithToggleUtils.showError(EmulatorPlugin.EMULATOR_UNEXPECTEDLY_STOPPED,
- EmulatorNLS.GEN_Error,
- NLS.bind(EmulatorNLS.ERR_AndroidLogicPlugin_EmulatorStopped, instance.getName()));
- shouldTryAgain = false;
- try {
- instance.stop(true);
- } catch (InstanceStopException ise) {
- AndmoreLogger.error(StartEmulatorProcessLogic.class,
- "Error trying to stop instance on process error", ise);
- }
- }
- }
- }
- };
- t.start();
-
- debug("Emulator instance is now up and running... " + instance);
- }
-
- /**
- * retrives the emulator executable name according to abi type property
- *
- * @param instance
- * @return
- */
- private static String retrieveEmulatorExecutableName(IAndroidLogicInstance instance) {
- String emulatorPath = null;
-
- Properties prop = instance.getProperties();
- String abiType = prop.getProperty("Abi_Type");
-
- if ((abiType == null) || (abiType.equals(""))) {
- emulatorPath = EMULATOR_RELATIVE_PATH;
- } else if (abiType.toLowerCase().contains("arm")) {
- emulatorPath = ARM_EMULATOR_RELATIVE_PATH;
- } else {
- emulatorPath = x86_EMULATOR_RELATIVE_PATH;
- }
-
- File emulatorExe = new File(SdkUtils.getSdkPath(), emulatorPath + ".exe");
-
- if (!emulatorExe.exists()) {
- emulatorPath = EMULATOR_RELATIVE_PATH;
- }
-
- return emulatorPath;
- }
-
- /**
- * Retrieve the Proxy service.
- *
- * @return IProxyService instance.
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private IProxyService retrieveProxyService() {
- IProxyService proxyService = null;
-
- ServiceReference service = EmulatorPlugin.getDefault().getBundle().getBundleContext()
- .getServiceReference(IProxyService.class.getCanonicalName());
- if (service != null) {
- proxyService = (IProxyService) EmulatorPlugin.getDefault().getBundle().getBundleContext()
- .getService(service);
- }
-
- return proxyService;
- }
-
- /**
- * Add the http-proxy parameter to the emulator command line.
- *
- * @param cmdList
- * List holding the commands to be called.
- */
- private void addEmulatorProxyParameter(List cmdList) {
- IProxyService proxyService = retrieveProxyService();
- if (proxyService != null) {
- String host = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getHost();
- int port = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getPort();
- boolean isAuthenticationRequired = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE)
- .isRequiresAuthentication();
- String userId = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getUserId();
- String password = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getPassword();
-
- // there must be a host in order to access via proxy
- if (host != null) {
- cmdList.add(EMULATOR_HTTP_PROXY_PARAMETER);
-
- // add proxy info to the command list - authentication needed
- if (isAuthenticationRequired) {
- cmdList.add(PROXY_HTTP + userId + PROXY_COLON + password + PROXY_AT + host + PROXY_COLON
- + Integer.valueOf(port).toString());
- }
- // add proxy info to the command list - no authentication needed
- else {
- cmdList.add(PROXY_HTTP + host + PROXY_COLON + Integer.valueOf(port).toString());
- }
- }
- }
- }
-
- private boolean isEmulatorReady(String avdName) {
- String serialNum = DDMSFacade.getSerialNumberByName(avdName);
- return DDMSFacade.isDeviceOnline(serialNum);
- }
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.debug;
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.eclipse.andmore.AndmoreAndroidPlugin;
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.SdkUtils;
+import org.eclipse.andmore.android.common.exception.AndroidException;
+import org.eclipse.andmore.android.common.log.AndmoreLogger;
+import org.eclipse.andmore.android.common.preferences.DialogWithToggleUtils;
+import org.eclipse.andmore.android.common.utilities.EclipseUtils;
+import org.eclipse.andmore.android.emulator.EmulatorPlugin;
+import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
+import org.eclipse.andmore.android.emulator.core.exception.InstanceStopException;
+import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
+import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
+import org.eclipse.andmore.android.emulator.device.IDevicePropertiesConstants;
+import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
+import org.eclipse.andmore.android.nativeos.IDevicePropertiesOSConstants;
+import org.eclipse.andmore.android.nativeos.NativeUIUtils;
+import org.eclipse.andmore.internal.preferences.AdtPrefs;
+import org.eclipse.core.net.proxy.IProxyData;
+import org.eclipse.core.net.proxy.IProxyService;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IViewPart;
+import org.osgi.framework.ServiceReference;
+
+@SuppressWarnings("restriction")
+public class StartEmulatorProcessLogic implements IAndroidLogic {
+ /**
+ *
+ */
+ private static final String EMULATOR_NO_SNAPSHOT_LOAD = "-no-snapshot-load";
+
+ /**
+ *
+ */
+ private static final String EMULATOR_NO_SNAPSHOT_SAVE = "-no-snapshot-save";
+
+ /**
+ *
+ */
+ private static final String EMULATOR_HTTP_PROXY_PARAMETER = "-http-proxy";
+
+ // Proxy constants
+ private static final String PROXY_AT = "@";
+
+ private static final String PROXY_COLON = ":";
+
+ private static final String PROXY_HTTP = "http://";
+
+ private static final String EMULATOR_VIEW = "org.eclipse.andmore.android.emulator.androidView";
+
+ // Strings used to build the command line for launching the emulator process
+ private static final String ARM_EMULATOR_RELATIVE_PATH = "/tools/emulator-arm";
+
+ private static final String x86_EMULATOR_RELATIVE_PATH = "/tools/emulator-x86";
+
+ private static final String EMULATOR_RELATIVE_PATH = "/tools/emulator";
+
+ private static final String EMULATOR_VM_PARAMETER = "-avd";
+
+ private static String selectedEmulatorPath = "";
+
+ @Override
+ public void execute(final IAndroidLogicInstance instance, int timeout, IProgressMonitor monitor)
+ throws InstanceStartException, StartTimeoutException, StartCancelledException {
+
+ long timeoutLimit = AndroidLogicUtils.getTimeoutLimit(timeout);
+
+ info("Starting the Android Emulator process: " + instance);
+ instance.setWindowHandle(0);
+
+ File userData = instance.getUserdata();
+
+ if (userData != null) {
+ File userdataDir = userData.getParentFile();
+ if ((userdataDir != null) && (!userdataDir.exists())) {
+ userdataDir.mkdirs();
+ }
+ }
+
+ selectedEmulatorPath = retrieveEmulatorExecutableName(instance);
+
+ File emulatorExe = new File(SdkUtils.getSdkPath(), selectedEmulatorPath);
+
+ List cmdList = new LinkedList();
+
+ cmdList.add(emulatorExe.getAbsolutePath());
+ cmdList.add(EMULATOR_VM_PARAMETER);
+ cmdList.add(instance.getName());
+
+ Properties propArgs = instance.getCommandLineArgumentsAsProperties();
+ IPreferenceStore store = AndmoreAndroidPlugin.getDefault().getPreferenceStore();
+ String adtEmuOptions = store.getString(AdtPrefs.PREFS_EMU_OPTIONS);
+
+ StringTokenizer adtOptionsTokenizer = new StringTokenizer(adtEmuOptions, " ");
+ while (adtOptionsTokenizer.hasMoreTokens()) {
+ String nextToken = adtOptionsTokenizer.nextToken();
+ cmdList.add(nextToken);
+ }
+
+ for (Object key : propArgs.keySet()) {
+ String value = propArgs.getProperty(key.toString());
+
+ if (key.equals("other")) {
+ StringTokenizer stringTokenizer = new StringTokenizer(value, " ");
+ while (stringTokenizer.hasMoreTokens()) {
+ cmdList.add(stringTokenizer.nextToken());
+ }
+ } else {
+ if ((value.trim().length() > 0) && !value.equals(Boolean.TRUE.toString())) {
+ cmdList.add(key.toString());
+ if (Platform.getOS().equals(Platform.OS_MACOSX)) {
+ if (value.contains(" ")) {
+ value = "\"" + value + "\"";
+ }
+ } else {
+ if (value.contains("\\")) {
+ value = value.replace("\\", "\\\\");
+ }
+
+ if (value.contains(" ")) {
+ value = value.replace(" ", "\\ ");
+ }
+ }
+
+ cmdList.add(value);
+ } else if ((value.trim().length() > 0) && value.equals(Boolean.TRUE.toString())) {
+ cmdList.add(key.toString());
+ }
+ }
+ }
+
+ // add proxy in case it is needed
+ Properties properties = instance.getProperties();
+ if (properties != null) {
+ String useProxy = properties.getProperty(IDevicePropertiesConstants.useProxy,
+ IDevicePropertiesConstants.defaultUseProxyValue);
+ if (Boolean.TRUE.toString().equals(useProxy)) {
+ addEmulatorProxyParameter(cmdList);
+ }
+ }
+
+ StringBuffer cmdLog = new StringBuffer("");
+
+ boolean httpProxyParamFound = false;
+ boolean logHttpProxyUsage = false;
+ for (String param : cmdList) {
+ // Do not log -http-proxy information
+ if (!httpProxyParamFound) {
+ if (!param.equals(EMULATOR_HTTP_PROXY_PARAMETER)) {
+ if (param.startsWith(emulatorExe.getAbsolutePath())) {
+ // do not log emulator full path
+ cmdLog.append(selectedEmulatorPath + " ");
+ } else {
+ cmdLog.append(param + " ");
+ }
+ } else {
+ httpProxyParamFound = true;
+ logHttpProxyUsage = true;
+ }
+ } else {
+ httpProxyParamFound = false;
+ }
+ }
+
+ // Append http proxy usage to log
+ if (logHttpProxyUsage) {
+ cmdLog.append("\nProxy settings are being used by the started emulator (-http-proxy parameter).");
+ }
+ // add command to not start from snapshot
+ if (properties != null) {
+ String startFromSnapshot = properties.getProperty(IDevicePropertiesConstants.startFromSnapshot,
+ IDevicePropertiesConstants.defaultstartFromSnapshotValue);
+ if (Boolean.FALSE.toString().equals(startFromSnapshot)) {
+ cmdList.add(EMULATOR_NO_SNAPSHOT_LOAD);
+ }
+ }
+
+ // Add the command to not save snapshot
+ if (properties != null) {
+ String saveSnapshot = properties.getProperty(IDevicePropertiesConstants.saveSnapshot,
+ IDevicePropertiesConstants.defaulSaveSnapshot);
+ if (Boolean.FALSE.toString().equals(saveSnapshot)) {
+ cmdList.add(EMULATOR_NO_SNAPSHOT_SAVE);
+ }
+ }
+
+ Process p;
+ try {
+ p = AndroidLogicUtils.executeProcess(cmdList.toArray(new String[0]), cmdLog.toString());
+ } catch (AndroidException e) {
+ throw new InstanceStartException(e);
+ }
+ info("Wait until and emulator with the VM " + instance.getName() + " is up ");
+
+ AndroidLogicUtils.testProcessStatus(p);
+ instance.setProcess(p);
+ instance.setComposite(null);
+
+ final String avdName = instance.getName();
+
+ if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
+ Collection openedAndroidViews = EclipseUtils.getAllOpenedViewsWithId(EMULATOR_VIEW);
+
+ if (!openedAndroidViews.isEmpty()) {
+ Runnable runnable = new Runnable() {
+
+ @Override
+ public void run() {
+ long windowHandle = -1;
+ long timeOutToFindWindow = System.currentTimeMillis() + 30000;
+
+ do {
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+
+ try {
+ AndroidLogicUtils.testTimeout(timeOutToFindWindow, "");
+ } catch (StartTimeoutException e) {
+ debug("Emulator window could not be found, instance :" + avdName);
+ break;
+ }
+
+ try {
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ int port = AndroidLogicUtils.getEmulatorPort(deviceMonitor.getSerialNumberByName(instance
+ .getName()));
+ if (port > 0) {
+ windowHandle = NativeUIUtils.getWindowHandle(instance.getName(), port);
+ }
+
+ } catch (Exception t) {
+ t.getCause().getMessage();
+ System.out.println(t.getCause().getMessage());
+ }
+ } while (windowHandle <= 0);
+
+ if (windowHandle > 0) {
+ instance.setWindowHandle(windowHandle);
+ NativeUIUtils.hideWindow(windowHandle);
+ }
+ }
+ };
+ Thread getHandleThread = new Thread(runnable, "Window Handle Thread");
+ getHandleThread.start();
+ }
+ }
+
+ if (instance.getProperties().getProperty(IDevicePropertiesOSConstants.useVnc, NativeUIUtils.getDefaultUseVnc())
+ .equals(Boolean.TRUE.toString())) {
+ do {
+ try {
+ Thread.sleep(450);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+
+ AndroidLogicUtils.testCanceled(monitor);
+ try {
+ AndroidLogicUtils
+ .testTimeout(timeoutLimit, NLS.bind(EmulatorNLS.EXC_TimeoutWhileStarting, avdName));
+ } catch (StartTimeoutException e) {
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ debug("Emulator start timeout has been reached, instance :" + avdName + " has device: "
+ + instance.hasDevice() + "isOnline? "
+ + deviceMonitor.isDeviceOnline(deviceMonitor.getSerialNumberByName(avdName)));
+ throw e;
+ }
+ } while (!isEmulatorReady(avdName));
+
+ }
+
+ Thread t = new Thread("Process Error") {
+ @Override
+ public void run() {
+ boolean shouldTryAgain = true;
+ for (int i = 0; (i < 90) && shouldTryAgain; i++) {
+ try {
+ sleep(500);
+ Process p = instance.getProcess();
+ if (p != null) {
+ AndroidLogicUtils.testProcessStatus(p);
+ }
+ } catch (Exception e) {
+ AndmoreLogger.info(StartEmulatorProcessLogic.class,
+ "Trying to stop the emulator process: execution stopped too early");
+ DialogWithToggleUtils.showError(EmulatorPlugin.EMULATOR_UNEXPECTEDLY_STOPPED,
+ EmulatorNLS.GEN_Error,
+ NLS.bind(EmulatorNLS.ERR_AndroidLogicPlugin_EmulatorStopped, instance.getName()));
+ shouldTryAgain = false;
+ try {
+ instance.stop(true);
+ } catch (InstanceStopException ise) {
+ AndmoreLogger.error(StartEmulatorProcessLogic.class,
+ "Error trying to stop instance on process error", ise);
+ }
+ }
+ }
+ }
+ };
+ t.start();
+
+ debug("Emulator instance is now up and running... " + instance);
+ }
+
+ /**
+ * retrives the emulator executable name according to abi type property
+ *
+ * @param instance
+ * @return
+ */
+ private static String retrieveEmulatorExecutableName(IAndroidLogicInstance instance) {
+ String emulatorPath = null;
+
+ Properties prop = instance.getProperties();
+ String abiType = prop.getProperty("Abi_Type");
+
+ if ((abiType == null) || (abiType.equals(""))) {
+ emulatorPath = EMULATOR_RELATIVE_PATH;
+ } else if (abiType.toLowerCase().contains("arm")) {
+ emulatorPath = ARM_EMULATOR_RELATIVE_PATH;
+ } else {
+ emulatorPath = x86_EMULATOR_RELATIVE_PATH;
+ }
+
+ File emulatorExe = new File(SdkUtils.getSdkPath(), emulatorPath + ".exe");
+
+ if (!emulatorExe.exists()) {
+ emulatorPath = EMULATOR_RELATIVE_PATH;
+ }
+
+ return emulatorPath;
+ }
+
+ /**
+ * Retrieve the Proxy service.
+ *
+ * @return IProxyService instance.
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private IProxyService retrieveProxyService() {
+ IProxyService proxyService = null;
+
+ ServiceReference service = EmulatorPlugin.getDefault().getBundle().getBundleContext()
+ .getServiceReference(IProxyService.class.getCanonicalName());
+ if (service != null) {
+ proxyService = (IProxyService) EmulatorPlugin.getDefault().getBundle().getBundleContext()
+ .getService(service);
+ }
+
+ return proxyService;
+ }
+
+ /**
+ * Add the http-proxy parameter to the emulator command line.
+ *
+ * @param cmdList
+ * List holding the commands to be called.
+ */
+ private void addEmulatorProxyParameter(List cmdList) {
+ IProxyService proxyService = retrieveProxyService();
+ if (proxyService != null) {
+ String host = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getHost();
+ int port = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getPort();
+ boolean isAuthenticationRequired = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE)
+ .isRequiresAuthentication();
+ String userId = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getUserId();
+ String password = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE).getPassword();
+
+ // there must be a host in order to access via proxy
+ if (host != null) {
+ cmdList.add(EMULATOR_HTTP_PROXY_PARAMETER);
+
+ // add proxy info to the command list - authentication needed
+ if (isAuthenticationRequired) {
+ cmdList.add(PROXY_HTTP + userId + PROXY_COLON + password + PROXY_AT + host + PROXY_COLON
+ + Integer.valueOf(port).toString());
+ }
+ // add proxy info to the command list - no authentication needed
+ else {
+ cmdList.add(PROXY_HTTP + host + PROXY_COLON + Integer.valueOf(port).toString());
+ }
+ }
+ }
+ }
+
+ private boolean isEmulatorReady(String avdName) {
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ String serialNum = deviceMonitor.getSerialNumberByName(avdName);
+ return deviceMonitor.isDeviceOnline(serialNum);
+ }
}
\ No newline at end of file
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartVncServerLogic.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartVncServerLogic.java
index fd2a088a..35f00a55 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartVncServerLogic.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/StartVncServerLogic.java
@@ -1,226 +1,226 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.ISerialNumbered;
-import org.eclipse.andmore.android.common.exception.AndroidException;
-import org.eclipse.andmore.android.emulator.EmulatorPlugin;
-import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
-import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
-import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
-import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.IJobChangeListener;
-import org.eclipse.core.runtime.jobs.IJobManager;
-import org.eclipse.core.runtime.jobs.ISchedulingRule;
-import org.eclipse.core.runtime.jobs.Job;
-
-/**
- * This class contains the logic to start the VNC server on the given Emulator.
- */
-public final class StartVncServerLogic implements IAndroidLogic {
- public static final String VNC_SERVER_JOB_PREFIX = "VNC Server - ";
-
- public static final Object VNC_SERVER_JOB_FAMILY = new Object();
-
- /**
- * Sequence of commands that must be executed on the emulator to start the
- * VNC server
- */
- private final Collection remoteCommands = new LinkedList();
-
- /**
- * Collection of listeners for the job executing the VNC server.
- */
- private final Collection listeners = new LinkedList();
-
- /**
- * Executes the logic to start the vnc server.
- */
- @Override
- public void execute(final IAndroidLogicInstance instance, int timeout, final IProgressMonitor monitor)
- throws InstanceStartException, StartTimeoutException, StartCancelledException, IOException {
- cancelCurrentVncServerJobs(instance);
-
- // Creates and starts a job that will keep running as long as the VNC
- // server is up on that Emulator instance.
- // add listeners that will receive notifications about the Job
- // life-cycle.
- VncServerJob vncServerJob = new VncServerJob(instance, getRemoteCommands());
- for (IJobChangeListener vncServerListener : listeners) {
- vncServerJob.addJobChangeListener(vncServerListener);
- }
- vncServerJob.schedule();
-
- }
-
- /**
- * Cancel any VncServerJob that is currently running the VNC server on the
- * given emulator instance.
- *
- * @param instance
- * , the emulator instances where VNC server execution must be
- * canceled.
- **/
- public static void cancelCurrentVncServerJobs(IAndroidEmulatorInstance instance) {
- // stop the previous VNC Server job for this instance if any...
- IJobManager manager = Job.getJobManager();
- Job[] allVncJobs = manager.find(StartVncServerLogic.VNC_SERVER_JOB_FAMILY);
- if (allVncJobs.length > 0) {
- for (Job job : allVncJobs) {
- if (job.getName().equals(StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName())) {
- info("Cancel execution of the VNC Server on " + instance);
- job.cancel();
- }
- }
- }
- }
-
- /**
- * Add job listener to receive state-change notifications from the job that
- * runs the VNC Server.
- *
- * @param vncServerListener
- * job listener that willl receive state change notifications
- * from the VNC Serever job.
- */
- public void addVncServerJobListener(IJobChangeListener vncServerListener) {
- listeners.add(vncServerListener);
- }
-
- /**
- * Add a command to be executed in the process of starting the VNC Server on
- * the Emulator.
- *
- * @param remoteCommand
- */
- public void addRemoteCommand(String remoteCommand) {
- remoteCommands.add(remoteCommand);
- }
-
- /**
- * Get the list of commands to be executed on the Emulator in order to start
- * the VNC Server.
- *
- * @return the sequence of commands that must be executed on the Emulator to
- * start the VNC Server.
- */
- public Collection getRemoteCommands() {
- return remoteCommands;
- }
-
-}
-
-/**
- * Job that executes the VNC Server. It will keep running as long as the VNC
- * Server process is running on the Emulator.
- */
-class VncServerJob extends Job implements ISchedulingRule {
- private String serialNumber;
-
- /**
- * Sequence of commands that must be executed on the emulator to start the
- * VNC server
- */
- private final Collection remoteCommands;
-
- /**
- * Creates a new job to execute the VNC server on the given emulator
- * instance.
- *
- * @param instance
- * , emulator instance where the VNC server will be started.
- * @param remoteCommands
- * , sequence of commands that must be executed on the given
- * emulator instance to start the VNC Server.
- * @throws InstanceStartException
- */
- public VncServerJob(IAndroidLogicInstance instance, Collection remoteCommands)
- throws InstanceStartException {
- super(StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName());
-
- this.serialNumber = ((ISerialNumbered) instance).getSerialNumber();
-
- try {
- AndroidLogicUtils.testDeviceStatus(serialNumber);
- } catch (AndroidException e) {
- throw new InstanceStartException(e.getMessage());
- }
-
- this.remoteCommands = remoteCommands;
- setSystem(true);
- setRule(this);
- }
-
- /**
- * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor)
- */
- @Override
- public IStatus run(IProgressMonitor monitor) {
- IStatus status = Status.OK_STATUS;
- try {
- info("Executing VNC Server on " + serialNumber);
- AndroidLogicUtils.testDeviceStatus(serialNumber);
- DDMSFacade.execRemoteApp(serialNumber, remoteCommands, monitor);
-
- if (monitor.isCanceled()) {
- status = Status.CANCEL_STATUS;
- }
- } catch (Exception e) {
- String errorMessage = "Error while trying to run the VNC server on " + serialNumber;
- error(errorMessage + " " + e.getMessage());
- status = new Status(IStatus.CANCEL, EmulatorPlugin.PLUGIN_ID, errorMessage, e);
- }
-
- info("Finished the execution of the VNC Server on " + serialNumber + " with status " + status);
-
- return status;
- }
-
- /**
- * @see org.eclipse.core.runtime.jobs.Job#belongsTo(Object)
- */
- @Override
- public boolean belongsTo(Object family) {
- return StartVncServerLogic.VNC_SERVER_JOB_FAMILY.equals(family);
- }
-
- @Override
- public boolean contains(ISchedulingRule rule) {
- boolean contains = false;
- if (rule instanceof VncServerJob) {
- VncServerJob otherVncServerJob = (VncServerJob) rule;
- contains = otherVncServerJob.serialNumber.equals(serialNumber);
- }
-
- return contains;
- }
-
- @Override
- public boolean isConflicting(ISchedulingRule rule) {
- return contains(rule);
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.ISerialNumbered;
+import org.eclipse.andmore.android.common.exception.AndroidException;
+import org.eclipse.andmore.android.emulator.EmulatorPlugin;
+import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
+import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
+import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
+import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * This class contains the logic to start the VNC server on the given Emulator.
+ */
+public final class StartVncServerLogic implements IAndroidLogic {
+ public static final String VNC_SERVER_JOB_PREFIX = "VNC Server - ";
+
+ public static final Object VNC_SERVER_JOB_FAMILY = new Object();
+
+ /**
+ * Sequence of commands that must be executed on the emulator to start the
+ * VNC server
+ */
+ private final Collection remoteCommands = new LinkedList();
+
+ /**
+ * Collection of listeners for the job executing the VNC server.
+ */
+ private final Collection listeners = new LinkedList();
+
+ /**
+ * Executes the logic to start the vnc server.
+ */
+ @Override
+ public void execute(final IAndroidLogicInstance instance, int timeout, final IProgressMonitor monitor)
+ throws InstanceStartException, StartTimeoutException, StartCancelledException, IOException {
+ cancelCurrentVncServerJobs(instance);
+
+ // Creates and starts a job that will keep running as long as the VNC
+ // server is up on that Emulator instance.
+ // add listeners that will receive notifications about the Job
+ // life-cycle.
+ VncServerJob vncServerJob = new VncServerJob(instance, getRemoteCommands());
+ for (IJobChangeListener vncServerListener : listeners) {
+ vncServerJob.addJobChangeListener(vncServerListener);
+ }
+ vncServerJob.schedule();
+
+ }
+
+ /**
+ * Cancel any VncServerJob that is currently running the VNC server on the
+ * given emulator instance.
+ *
+ * @param instance
+ * , the emulator instances where VNC server execution must be
+ * canceled.
+ **/
+ public static void cancelCurrentVncServerJobs(IAndroidEmulatorInstance instance) {
+ // stop the previous VNC Server job for this instance if any...
+ IJobManager manager = Job.getJobManager();
+ Job[] allVncJobs = manager.find(StartVncServerLogic.VNC_SERVER_JOB_FAMILY);
+ if (allVncJobs.length > 0) {
+ for (Job job : allVncJobs) {
+ if (job.getName().equals(StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName())) {
+ info("Cancel execution of the VNC Server on " + instance);
+ job.cancel();
+ }
+ }
+ }
+ }
+
+ /**
+ * Add job listener to receive state-change notifications from the job that
+ * runs the VNC Server.
+ *
+ * @param vncServerListener
+ * job listener that willl receive state change notifications
+ * from the VNC Serever job.
+ */
+ public void addVncServerJobListener(IJobChangeListener vncServerListener) {
+ listeners.add(vncServerListener);
+ }
+
+ /**
+ * Add a command to be executed in the process of starting the VNC Server on
+ * the Emulator.
+ *
+ * @param remoteCommand
+ */
+ public void addRemoteCommand(String remoteCommand) {
+ remoteCommands.add(remoteCommand);
+ }
+
+ /**
+ * Get the list of commands to be executed on the Emulator in order to start
+ * the VNC Server.
+ *
+ * @return the sequence of commands that must be executed on the Emulator to
+ * start the VNC Server.
+ */
+ public Collection getRemoteCommands() {
+ return remoteCommands;
+ }
+
+}
+
+/**
+ * Job that executes the VNC Server. It will keep running as long as the VNC
+ * Server process is running on the Emulator.
+ */
+class VncServerJob extends Job implements ISchedulingRule {
+ private String serialNumber;
+
+ /**
+ * Sequence of commands that must be executed on the emulator to start the
+ * VNC server
+ */
+ private final Collection remoteCommands;
+
+ /**
+ * Creates a new job to execute the VNC server on the given emulator
+ * instance.
+ *
+ * @param instance
+ * , emulator instance where the VNC server will be started.
+ * @param remoteCommands
+ * , sequence of commands that must be executed on the given
+ * emulator instance to start the VNC Server.
+ * @throws InstanceStartException
+ */
+ public VncServerJob(IAndroidLogicInstance instance, Collection remoteCommands)
+ throws InstanceStartException {
+ super(StartVncServerLogic.VNC_SERVER_JOB_PREFIX + instance.getName());
+
+ this.serialNumber = ((ISerialNumbered) instance).getSerialNumber();
+
+ try {
+ AndroidLogicUtils.testDeviceStatus(serialNumber);
+ } catch (AndroidException e) {
+ throw new InstanceStartException(e.getMessage());
+ }
+
+ this.remoteCommands = remoteCommands;
+ setSystem(true);
+ setRule(this);
+ }
+
+ /**
+ * @see org.eclipse.core.runtime.jobs.Job#run(IProgressMonitor)
+ */
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ IStatus status = Status.OK_STATUS;
+ try {
+ info("Executing VNC Server on " + serialNumber);
+ AndroidLogicUtils.testDeviceStatus(serialNumber);
+ DeviceMonitor.instance().execRemoteApp(serialNumber, remoteCommands, monitor);
+
+ if (monitor.isCanceled()) {
+ status = Status.CANCEL_STATUS;
+ }
+ } catch (Exception e) {
+ String errorMessage = "Error while trying to run the VNC server on " + serialNumber;
+ error(errorMessage + " " + e.getMessage());
+ status = new Status(IStatus.CANCEL, EmulatorPlugin.PLUGIN_ID, errorMessage, e);
+ }
+
+ info("Finished the execution of the VNC Server on " + serialNumber + " with status " + status);
+
+ return status;
+ }
+
+ /**
+ * @see org.eclipse.core.runtime.jobs.Job#belongsTo(Object)
+ */
+ @Override
+ public boolean belongsTo(Object family) {
+ return StartVncServerLogic.VNC_SERVER_JOB_FAMILY.equals(family);
+ }
+
+ @Override
+ public boolean contains(ISchedulingRule rule) {
+ boolean contains = false;
+ if (rule instanceof VncServerJob) {
+ VncServerJob otherVncServerJob = (VncServerJob) rule;
+ contains = otherVncServerJob.serialNumber.equals(serialNumber);
+ }
+
+ return contains;
+ }
+
+ @Override
+ public boolean isConflicting(ISchedulingRule rule) {
+ return contains(rule);
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/TransferFilesLogic.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/TransferFilesLogic.java
index 20e23c8e..3ca08f3d 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/TransferFilesLogic.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/logic/TransferFilesLogic.java
@@ -1,82 +1,82 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
-import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
-import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
-import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-
-public class TransferFilesLogic implements IAndroidLogic {
- private String localDir = "";
-
- private String remoteDir = "";
-
- private final Collection filenames = new LinkedList();
-
- @Override
- public void execute(IAndroidLogicInstance instance, int timeout, IProgressMonitor monitor)
- throws InstanceStartException, StartCancelledException, StartTimeoutException, IOException {
- if ((instance != null) && (timeout > 0) && (localDir != null) && (!"".equals(localDir)) && (remoteDir != null)
- && ("".equals(remoteDir))) {
- error("Cannot transfer files because the parameters provided are not as expected.");
- throw new InstanceStartException(EmulatorNLS.ERR_TransferFilesLogic_NotEnoughInformation);
- }
-
- String serialNumber = DDMSFacade.getSerialNumberByName(instance.getName());
- IStatus status = DDMSFacade.pushFiles(serialNumber, getLocalDir(), getFilenames(), getRemoteDir(), timeout,
- monitor, null);
- if (status.getSeverity() == IStatus.CANCEL) {
- throw new StartCancelledException();
- } else if (status.getSeverity() == IStatus.ERROR) {
- throw new InstanceStartException(status.getMessage());
- }
- }
-
- public void setLocalDir(String localDir) {
- this.localDir = localDir;
- }
-
- public String getLocalDir() {
- return localDir;
- }
-
- public void addFilename(String filename) {
- filenames.add(filename);
- }
-
- public Collection getFilenames() {
- return filenames;
- }
-
- public void setRemoteDir(String remoteDir) {
- this.remoteDir = remoteDir;
- }
-
- public String getRemoteDir() {
- return remoteDir;
- }
-
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.logic;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.emulator.core.exception.InstanceStartException;
+import org.eclipse.andmore.android.emulator.core.exception.StartCancelledException;
+import org.eclipse.andmore.android.emulator.core.exception.StartTimeoutException;
+import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+public class TransferFilesLogic implements IAndroidLogic {
+ private String localDir = "";
+
+ private String remoteDir = "";
+
+ private final Collection filenames = new LinkedList();
+
+ @Override
+ public void execute(IAndroidLogicInstance instance, int timeout, IProgressMonitor monitor)
+ throws InstanceStartException, StartCancelledException, StartTimeoutException, IOException {
+ if ((instance != null) && (timeout > 0) && (localDir != null) && (!"".equals(localDir)) && (remoteDir != null)
+ && ("".equals(remoteDir))) {
+ error("Cannot transfer files because the parameters provided are not as expected.");
+ throw new InstanceStartException(EmulatorNLS.ERR_TransferFilesLogic_NotEnoughInformation);
+ }
+ DeviceMonitor deviceMonitor = DeviceMonitor.instance();
+ String serialNumber = deviceMonitor.getSerialNumberByName(instance.getName());
+ IStatus status = deviceMonitor.pushFiles(serialNumber, getLocalDir(), getFilenames(), getRemoteDir(), timeout,
+ monitor, null);
+ if (status.getSeverity() == IStatus.CANCEL) {
+ throw new StartCancelledException();
+ } else if (status.getSeverity() == IStatus.ERROR) {
+ throw new InstanceStartException(status.getMessage());
+ }
+ }
+
+ public void setLocalDir(String localDir) {
+ this.localDir = localDir;
+ }
+
+ public String getLocalDir() {
+ return localDir;
+ }
+
+ public void addFilename(String filename) {
+ filenames.add(filename);
+ }
+
+ public Collection getFilenames() {
+ return filenames;
+ }
+
+ public void setRemoteDir(String remoteDir) {
+ this.remoteDir = remoteDir;
+ }
+
+ public String getRemoteDir() {
+ return remoteDir;
+ }
+
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/maindisplay/MainDisplayComposite.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/maindisplay/MainDisplayComposite.java
index 80efeab8..d078866e 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/maindisplay/MainDisplayComposite.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/maindisplay/MainDisplayComposite.java
@@ -1,430 +1,430 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.ui.controls.maindisplay;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
-
-import java.util.Properties;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
-import org.eclipse.andmore.android.emulator.core.model.IInputLogic;
-import org.eclipse.andmore.android.emulator.logic.AndroidLogicUtils;
-import org.eclipse.andmore.android.emulator.skin.android.AndroidSkinTranslator;
-import org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite;
-import org.eclipse.andmore.android.emulator.ui.controls.UIHelper;
-import org.eclipse.andmore.android.emulator.ui.handlers.IHandlerConstants;
-import org.eclipse.andmore.android.nativeos.NativeUIUtils;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.sequoyah.vnc.vncviewer.graphics.IRemoteDisplay;
-import org.eclipse.sequoyah.vnc.vncviewer.graphics.swt.SWTRemoteDisplay;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.MouseMoveListener;
-import org.eclipse.swt.events.MouseWheelListener;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Composite;
-
-/**
- * This class is the composite that holds the main display and it is shown by
- * the Emulator Main Display View.
- */
-public class MainDisplayComposite extends Composite implements IAndroidComposite {
-
- /**
- * The zoom factor whose default value is 1.0 (100%)
- */
- private double zoomFactor = 1.0;
-
- private double fitZoomfactor;
-
- // Minimum value to be used as zoom factor. This is necessary to avoid
- // divisions to zero
- private static final double MINIMUM_ZOOM_FACTOR = 0.0001;
-
- private static final double ZOOM_FIT = 0.0;
-
- /**
- * The flag indicating that Ctrl key is pressed
- */
- private boolean ctrlPressed = false;
-
- /**
- * SWT key pressed/released events listener.
- */
- private KeyListener keyListener;
-
- private MouseListener mouseListener;
-
- private MouseMoveListener mouseMoveListener;
-
- private IInputLogic androidInput;
-
- private boolean isMouseLeftButtonPressed;
-
- private boolean isFitToWindow;
-
- private IAndroidEmulatorInstance androidInstance;
-
- private Properties keyMap;
-
- /**
- * Constructor
- *
- * @param parent
- * composite
- * @param style
- * style
- * @param baseWidth
- * the default main display width
- * @param baseHeight
- * the default main display height
- */
- public MainDisplayComposite(Composite parent, int style, int baseWidth, int baseHeight,
- IAndroidEmulatorInstance instance) {
- super(parent, style);
-
- androidInput = instance.getInputLogic();
-
- androidInstance = instance;
-
- isMouseLeftButtonPressed = false;
-
- keyMap = AndroidSkinTranslator.getQwertyKeyMap();
-
- addListener();
-
- if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
- hideEmulatorWindow();
- }
-
- }
-
- private void hideEmulatorWindow() {
- int port = AndroidLogicUtils.getEmulatorPort(DDMSFacade.getSerialNumberByName(androidInstance.getName()));
- long windowHandle = NativeUIUtils.getWindowHandle(androidInstance.getName(), port);
- androidInstance.setWindowHandle(windowHandle);
-
- NativeUIUtils.hideWindow(windowHandle);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.swt.widgets.Widget#dispose()
- */
- @Override
- public void dispose() {
- if (androidInput != null) {
- androidInput.dispose();
- }
-
- keyListener = null;
- mouseListener = null;
- mouseMoveListener = null;
-
- if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
- long hnd = androidInstance.getWindowHandle();
- if (hnd > 0) {
- NativeUIUtils.showWindow(hnd);
- NativeUIUtils.restoreWindow(hnd);
- }
-
- // Force update on redrawing
- androidInstance.setWindowHandle(0);
- }
-
- super.dispose();
- }
-
- /**
- * Updates the composite size when zoom is changed.
- *
- * @param zoom
- * the zoom factor
- */
- @Override
- public void setZoomFactor(double zoomFactor) {
- info("Update detached view composite size");
- if (zoomFactor == ZOOM_FIT) {
- isFitToWindow = true;
- } else {
- isFitToWindow = false;
- }
- this.zoomFactor = zoomFactor;
- }
-
- /**
- * Gets the zoom factor.
- *
- * @return zoom the zoom factor.
- */
- @Override
- public double getZoomFactor() {
- return zoomFactor;
- }
-
- /**
- * Applies the zoom factor to the components of the composite, updating the
- * composite size to hold totally the main display.
- */
- @Override
- public void applyZoomFactor() {
-
- SWTRemoteDisplay mainDisplay = UIHelper.getRemoteDisplayAssociatedToControl(this);
- IRemoteDisplay.Rotation rotation = mainDisplay.getRotation();
-
- int baseHeight;
- int baseWidth;
-
- switch (rotation) {
- case ROTATION_90DEG_COUNTERCLOCKWISE:
- baseHeight = mainDisplay.getScreenWidth();
- baseWidth = mainDisplay.getScreenHeight();
- break;
- default:
- baseHeight = mainDisplay.getScreenHeight();
- baseWidth = mainDisplay.getScreenWidth();
-
- }
-
- int width;
- int height;
- if (isFitToWindow) {
- Rectangle clientArea = getParent().getClientArea();
- if ((clientArea.width == 0) || (clientArea.height == 0)) {
- // zoom factor cannot be zero, otherwise an
- // IllegalArgumentException
- // is raised in some SWT methods
- fitZoomfactor = MINIMUM_ZOOM_FACTOR;
- } else {
- double widthRatio = (double) (clientArea.width) / baseWidth;
- double heightRatio = (double) (clientArea.height) / baseHeight;
- fitZoomfactor = Math.min(widthRatio, heightRatio);
- }
- width = new Double(baseWidth * fitZoomfactor).intValue();
- height = new Double(baseHeight * fitZoomfactor).intValue();
-
- if (mainDisplay != null) {
- mainDisplay.setZoomFactor(fitZoomfactor);
- }
- } else {
- width = new Double(baseWidth * zoomFactor).intValue();
- height = new Double(baseHeight * zoomFactor).intValue();
-
- if (mainDisplay != null) {
- mainDisplay.setZoomFactor(zoomFactor);
- }
- }
-
- setSize(width, height);
- }
-
- /**
- * Adds listener for SWT events.
- */
- private void addListener() {
- // add listener to handle keyboard key pressing
- keyListener = new KeyListener() {
-
- @Override
- public void keyPressed(KeyEvent arg0) {
-
- int keyCode = arg0.keyCode;
-
- if (keyCode == SWT.CTRL) {
- ctrlPressed = true;
- } else {
- // send message to emulator
- androidInput.sendKey(arg0.character, keyCode, keyMap);
- }
-
- }
-
- @Override
- public void keyReleased(KeyEvent arg0) {
- int keyCode = arg0.keyCode;
-
- if (keyCode == SWT.CTRL) {
- ctrlPressed = false;
- }
- }
-
- };
-
- // listener to change the zoom factor using Ctrl + Mouse Wheel
- addMouseWheelListener(new MouseWheelListener() {
-
- @Override
- public void mouseScrolled(MouseEvent event) {
- if (ctrlPressed) {
-
- if ((event.count > 0) && (zoomFactor < IHandlerConstants.MAXIMUM_ZOOM)) {
- // increase zoom factor
- setZoomFactor(zoomFactor + IHandlerConstants.STEP_ZOOM);
- applyZoomFactor();
- }
-
- else if ((event.count < 0) && (zoomFactor > IHandlerConstants.MINIMUM_ZOOM)) {
- // decrease zoom factor
- setZoomFactor(zoomFactor - IHandlerConstants.STEP_ZOOM);
- applyZoomFactor();
- }
- }
- }
- });
-
- mouseListener = new MouseAdapter() {
- /**
- * @see org.eclipse.swt.events.MouseListener#mouseUp(MouseEvent)
- */
- @Override
- public void mouseUp(MouseEvent e) {
- handleMouseUp(e);
- }
-
- /**
- * @see org.eclipse.swt.events.MouseListener#mouseDown(MouseEvent)
- */
- @Override
- public void mouseDown(MouseEvent e) {
- setFocus();
- handleMouseDown(e);
- }
- };
-
- mouseMoveListener = new MouseMoveListener() {
- /**
- * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(MouseEvent)
- */
- @Override
- public void mouseMove(MouseEvent e) {
- handleMouseMove(e);
- }
- };
-
- getParent().addControlListener(new ControlAdapter() {
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse
- * .swt.events.ControlEvent)
- */
- @Override
- public void controlResized(ControlEvent event) {
- if (isFitToWindow) {
- applyZoomFactor();
- }
- }
- });
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite#
- * applyLayout(java.lang.String)
- */
- @Override
- public void applyLayout(String layoutName) {
- // do nothing
- }
-
- /**
- * Gets the listener that handles SWT key pressing and releasing events.
- *
- * @return the KeyListener object
- */
- @Override
- public KeyListener getKeyListener() {
- return keyListener;
- }
-
- /**
- * Gets the listener that handles SWT mouse clicking events.
- *
- * @return the MouseListener object
- */
- @Override
- public MouseListener getMouseListener() {
- return mouseListener;
- }
-
- /**
- * Gets the listener that handles SWT mouse moving events.
- *
- * @return the MouseMoveListener object
- */
- @Override
- public MouseMoveListener getMouseMoveListener() {
- return mouseMoveListener;
- }
-
- /**
- * Handles the mouse up event on the skin composite
- *
- * @param e
- * The mouse up event
- */
- private void handleMouseUp(MouseEvent e) {
- if (e.button == 1) {
- isMouseLeftButtonPressed = false;
- UIHelper.ajustCoordinates(e, this);
- androidInput.sendMouseUp(e.x, e.y);
- }
- }
-
- /**
- * Handles the mouse down event on the skin composite
- *
- * @param e
- * The mouse down event
- */
- private void handleMouseDown(MouseEvent e) {
- if (e.button == 1) {
- UIHelper.ajustCoordinates(e, this);
- androidInput.sendMouseDown(e.x, e.y);
- isMouseLeftButtonPressed = true;
- }
-
- }
-
- /**
- * Handles the mouse move event on the skin composite
- *
- * @param e
- * The mouse move event
- */
- private void handleMouseMove(MouseEvent e) {
- if (isMouseLeftButtonPressed) {
- UIHelper.ajustCoordinates(e, this);
- androidInput.sendMouseMove(e.x, e.y);
- }
- }
-
- @Override
- public boolean isFitToWindowSelected() {
- return isFitToWindow;
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.ui.controls.maindisplay;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
+
+import java.util.Properties;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
+import org.eclipse.andmore.android.emulator.core.model.IInputLogic;
+import org.eclipse.andmore.android.emulator.logic.AndroidLogicUtils;
+import org.eclipse.andmore.android.emulator.skin.android.AndroidSkinTranslator;
+import org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite;
+import org.eclipse.andmore.android.emulator.ui.controls.UIHelper;
+import org.eclipse.andmore.android.emulator.ui.handlers.IHandlerConstants;
+import org.eclipse.andmore.android.nativeos.NativeUIUtils;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.sequoyah.vnc.vncviewer.graphics.IRemoteDisplay;
+import org.eclipse.sequoyah.vnc.vncviewer.graphics.swt.SWTRemoteDisplay;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * This class is the composite that holds the main display and it is shown by
+ * the Emulator Main Display View.
+ */
+public class MainDisplayComposite extends Composite implements IAndroidComposite {
+
+ /**
+ * The zoom factor whose default value is 1.0 (100%)
+ */
+ private double zoomFactor = 1.0;
+
+ private double fitZoomfactor;
+
+ // Minimum value to be used as zoom factor. This is necessary to avoid
+ // divisions to zero
+ private static final double MINIMUM_ZOOM_FACTOR = 0.0001;
+
+ private static final double ZOOM_FIT = 0.0;
+
+ /**
+ * The flag indicating that Ctrl key is pressed
+ */
+ private boolean ctrlPressed = false;
+
+ /**
+ * SWT key pressed/released events listener.
+ */
+ private KeyListener keyListener;
+
+ private MouseListener mouseListener;
+
+ private MouseMoveListener mouseMoveListener;
+
+ private IInputLogic androidInput;
+
+ private boolean isMouseLeftButtonPressed;
+
+ private boolean isFitToWindow;
+
+ private IAndroidEmulatorInstance androidInstance;
+
+ private Properties keyMap;
+
+ /**
+ * Constructor
+ *
+ * @param parent
+ * composite
+ * @param style
+ * style
+ * @param baseWidth
+ * the default main display width
+ * @param baseHeight
+ * the default main display height
+ */
+ public MainDisplayComposite(Composite parent, int style, int baseWidth, int baseHeight,
+ IAndroidEmulatorInstance instance) {
+ super(parent, style);
+
+ androidInput = instance.getInputLogic();
+
+ androidInstance = instance;
+
+ isMouseLeftButtonPressed = false;
+
+ keyMap = AndroidSkinTranslator.getQwertyKeyMap();
+
+ addListener();
+
+ if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
+ hideEmulatorWindow();
+ }
+
+ }
+
+ private void hideEmulatorWindow() {
+ int port = AndroidLogicUtils.getEmulatorPort(DeviceMonitor.instance().getSerialNumberByName(androidInstance.getName()));
+ long windowHandle = NativeUIUtils.getWindowHandle(androidInstance.getName(), port);
+ androidInstance.setWindowHandle(windowHandle);
+
+ NativeUIUtils.hideWindow(windowHandle);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ @Override
+ public void dispose() {
+ if (androidInput != null) {
+ androidInput.dispose();
+ }
+
+ keyListener = null;
+ mouseListener = null;
+ mouseMoveListener = null;
+
+ if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
+ long hnd = androidInstance.getWindowHandle();
+ if (hnd > 0) {
+ NativeUIUtils.showWindow(hnd);
+ NativeUIUtils.restoreWindow(hnd);
+ }
+
+ // Force update on redrawing
+ androidInstance.setWindowHandle(0);
+ }
+
+ super.dispose();
+ }
+
+ /**
+ * Updates the composite size when zoom is changed.
+ *
+ * @param zoom
+ * the zoom factor
+ */
+ @Override
+ public void setZoomFactor(double zoomFactor) {
+ info("Update detached view composite size");
+ if (zoomFactor == ZOOM_FIT) {
+ isFitToWindow = true;
+ } else {
+ isFitToWindow = false;
+ }
+ this.zoomFactor = zoomFactor;
+ }
+
+ /**
+ * Gets the zoom factor.
+ *
+ * @return zoom the zoom factor.
+ */
+ @Override
+ public double getZoomFactor() {
+ return zoomFactor;
+ }
+
+ /**
+ * Applies the zoom factor to the components of the composite, updating the
+ * composite size to hold totally the main display.
+ */
+ @Override
+ public void applyZoomFactor() {
+
+ SWTRemoteDisplay mainDisplay = UIHelper.getRemoteDisplayAssociatedToControl(this);
+ IRemoteDisplay.Rotation rotation = mainDisplay.getRotation();
+
+ int baseHeight;
+ int baseWidth;
+
+ switch (rotation) {
+ case ROTATION_90DEG_COUNTERCLOCKWISE:
+ baseHeight = mainDisplay.getScreenWidth();
+ baseWidth = mainDisplay.getScreenHeight();
+ break;
+ default:
+ baseHeight = mainDisplay.getScreenHeight();
+ baseWidth = mainDisplay.getScreenWidth();
+
+ }
+
+ int width;
+ int height;
+ if (isFitToWindow) {
+ Rectangle clientArea = getParent().getClientArea();
+ if ((clientArea.width == 0) || (clientArea.height == 0)) {
+ // zoom factor cannot be zero, otherwise an
+ // IllegalArgumentException
+ // is raised in some SWT methods
+ fitZoomfactor = MINIMUM_ZOOM_FACTOR;
+ } else {
+ double widthRatio = (double) (clientArea.width) / baseWidth;
+ double heightRatio = (double) (clientArea.height) / baseHeight;
+ fitZoomfactor = Math.min(widthRatio, heightRatio);
+ }
+ width = new Double(baseWidth * fitZoomfactor).intValue();
+ height = new Double(baseHeight * fitZoomfactor).intValue();
+
+ if (mainDisplay != null) {
+ mainDisplay.setZoomFactor(fitZoomfactor);
+ }
+ } else {
+ width = new Double(baseWidth * zoomFactor).intValue();
+ height = new Double(baseHeight * zoomFactor).intValue();
+
+ if (mainDisplay != null) {
+ mainDisplay.setZoomFactor(zoomFactor);
+ }
+ }
+
+ setSize(width, height);
+ }
+
+ /**
+ * Adds listener for SWT events.
+ */
+ private void addListener() {
+ // add listener to handle keyboard key pressing
+ keyListener = new KeyListener() {
+
+ @Override
+ public void keyPressed(KeyEvent arg0) {
+
+ int keyCode = arg0.keyCode;
+
+ if (keyCode == SWT.CTRL) {
+ ctrlPressed = true;
+ } else {
+ // send message to emulator
+ androidInput.sendKey(arg0.character, keyCode, keyMap);
+ }
+
+ }
+
+ @Override
+ public void keyReleased(KeyEvent arg0) {
+ int keyCode = arg0.keyCode;
+
+ if (keyCode == SWT.CTRL) {
+ ctrlPressed = false;
+ }
+ }
+
+ };
+
+ // listener to change the zoom factor using Ctrl + Mouse Wheel
+ addMouseWheelListener(new MouseWheelListener() {
+
+ @Override
+ public void mouseScrolled(MouseEvent event) {
+ if (ctrlPressed) {
+
+ if ((event.count > 0) && (zoomFactor < IHandlerConstants.MAXIMUM_ZOOM)) {
+ // increase zoom factor
+ setZoomFactor(zoomFactor + IHandlerConstants.STEP_ZOOM);
+ applyZoomFactor();
+ }
+
+ else if ((event.count < 0) && (zoomFactor > IHandlerConstants.MINIMUM_ZOOM)) {
+ // decrease zoom factor
+ setZoomFactor(zoomFactor - IHandlerConstants.STEP_ZOOM);
+ applyZoomFactor();
+ }
+ }
+ }
+ });
+
+ mouseListener = new MouseAdapter() {
+ /**
+ * @see org.eclipse.swt.events.MouseListener#mouseUp(MouseEvent)
+ */
+ @Override
+ public void mouseUp(MouseEvent e) {
+ handleMouseUp(e);
+ }
+
+ /**
+ * @see org.eclipse.swt.events.MouseListener#mouseDown(MouseEvent)
+ */
+ @Override
+ public void mouseDown(MouseEvent e) {
+ setFocus();
+ handleMouseDown(e);
+ }
+ };
+
+ mouseMoveListener = new MouseMoveListener() {
+ /**
+ * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(MouseEvent)
+ */
+ @Override
+ public void mouseMove(MouseEvent e) {
+ handleMouseMove(e);
+ }
+ };
+
+ getParent().addControlListener(new ControlAdapter() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse
+ * .swt.events.ControlEvent)
+ */
+ @Override
+ public void controlResized(ControlEvent event) {
+ if (isFitToWindow) {
+ applyZoomFactor();
+ }
+ }
+ });
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite#
+ * applyLayout(java.lang.String)
+ */
+ @Override
+ public void applyLayout(String layoutName) {
+ // do nothing
+ }
+
+ /**
+ * Gets the listener that handles SWT key pressing and releasing events.
+ *
+ * @return the KeyListener object
+ */
+ @Override
+ public KeyListener getKeyListener() {
+ return keyListener;
+ }
+
+ /**
+ * Gets the listener that handles SWT mouse clicking events.
+ *
+ * @return the MouseListener object
+ */
+ @Override
+ public MouseListener getMouseListener() {
+ return mouseListener;
+ }
+
+ /**
+ * Gets the listener that handles SWT mouse moving events.
+ *
+ * @return the MouseMoveListener object
+ */
+ @Override
+ public MouseMoveListener getMouseMoveListener() {
+ return mouseMoveListener;
+ }
+
+ /**
+ * Handles the mouse up event on the skin composite
+ *
+ * @param e
+ * The mouse up event
+ */
+ private void handleMouseUp(MouseEvent e) {
+ if (e.button == 1) {
+ isMouseLeftButtonPressed = false;
+ UIHelper.ajustCoordinates(e, this);
+ androidInput.sendMouseUp(e.x, e.y);
+ }
+ }
+
+ /**
+ * Handles the mouse down event on the skin composite
+ *
+ * @param e
+ * The mouse down event
+ */
+ private void handleMouseDown(MouseEvent e) {
+ if (e.button == 1) {
+ UIHelper.ajustCoordinates(e, this);
+ androidInput.sendMouseDown(e.x, e.y);
+ isMouseLeftButtonPressed = true;
+ }
+
+ }
+
+ /**
+ * Handles the mouse move event on the skin composite
+ *
+ * @param e
+ * The mouse move event
+ */
+ private void handleMouseMove(MouseEvent e) {
+ if (isMouseLeftButtonPressed) {
+ UIHelper.ajustCoordinates(e, this);
+ androidInput.sendMouseMove(e.x, e.y);
+ }
+ }
+
+ @Override
+ public boolean isFitToWindowSelected() {
+ return isFitToWindow;
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/nativewindow/NativeWindowComposite.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/nativewindow/NativeWindowComposite.java
index 23728e6e..56aba05c 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/nativewindow/NativeWindowComposite.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/nativewindow/NativeWindowComposite.java
@@ -1,536 +1,536 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.ui.controls.nativewindow;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.eclipse.andmore.android.AndroidPlugin;
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.common.preferences.DialogWithToggleUtils;
-import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
-import org.eclipse.andmore.android.emulator.core.model.IInputLogic;
-import org.eclipse.andmore.android.emulator.core.skin.IAndroidSkin;
-import org.eclipse.andmore.android.emulator.core.utils.TelnetAndroidInput;
-import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
-import org.eclipse.andmore.android.emulator.logic.AndroidLogicUtils;
-import org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite;
-import org.eclipse.andmore.android.nativeos.NativeUIUtils;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.SWTException;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.MouseMoveListener;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.PlatformUI;
-
-public class NativeWindowComposite extends ScrolledComposite implements IAndroidComposite {
- /**
- * Preference key of the Question Dialog about changing zoom
- *
- */
- private static String LOOSE_ORIGINAL_SCALE_KEY_PREFERENCE = "loose.original.scale";
-
- // Constants
- private static final double MINIMUM_ZOOM_FACTOR = 0.10;
-
- private static final double ZOOM_FIT = 0.0;
-
- private Composite contentComposite;
-
- private IAndroidEmulatorInstance androidInstance;
-
- private long windowHandle;
-
- private long originalParentHandle;
-
- private long windowProperties;
-
- private Point windowSize;
-
- private Point nativeWindowSize;
-
- private NativeWindowMonitor nativeWindowMonitor;
-
- protected boolean resizing;
-
- private boolean isFitToWindow;
-
- private double zoomFactor = 0.99;
-
- private double fitZoomFactor = ZOOM_FIT;
-
- private boolean forceNativeWindowSizeUpdate;
-
- private boolean isOriginalScale;
-
- private boolean zoomLocked;
-
- private class NativeWindowMonitor extends Timer {
- private Timer timer;
-
- private MonitorTask monitorTask;
-
- public NativeWindowMonitor(long interval) {
- timer = new Timer();
- monitorTask = new MonitorTask();
- timer.schedule(monitorTask, interval, interval);
- }
-
- private class MonitorTask extends TimerTask {
- @Override
- public void run() {
- Point newWindowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
- if ((windowHandle <= 0) || !newWindowSize.equals(windowSize)) {
- Display display = Display.getDefault();
- if (!display.isDisposed()) {
- try {
- display.syncExec(new Runnable() {
- @Override
- public void run() {
- updateContentComposite();
- }
- });
- } catch (SWTException e) {
- // Do nothing in case the widget is disposed, occurs
- // when the tool is closing.
- }
- }
- }
-
- if (NativeUIUtils.isWindowEnabled(windowHandle)) {
- Display display = Display.getDefault();
- if (!display.isDisposed()) {
- try {
- display.syncExec(new Runnable() {
- @Override
- public void run() {
- if (!contentComposite.isDisposed()) {
- contentComposite.forceFocus();
- }
- }
- });
- } catch (SWTException e) {
- // Do nothing in case the widget is disposed, occurs
- // when the tool is closing.
- }
- }
- }
- }
- }
-
- public void stopMonitoring() {
- timer.cancel();
- timer = null;
- monitorTask = null;
- }
- }
-
- public NativeWindowComposite(Composite parent, IAndroidSkin androidSkin, final IAndroidEmulatorInstance instance) {
- super(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
-
- info("Creating Native Window Composite for " + instance.getName());
-
- getVerticalBar().setEnabled(true);
- getHorizontalBar().setEnabled(true);
- this.setLayout(new FillLayout());
-
- androidInstance = instance;
-
- nativeWindowMonitor = new NativeWindowMonitor(500);
-
- addControlListener(new ControlAdapter() {
- final boolean[] running = new boolean[1];
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse
- * .swt.events.ControlEvent)
- */
- @Override
- public void controlResized(ControlEvent event) {
- if (isFitToWindow) {
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- // do nothing
- }
-
- if (running[0]) {
- return;
- }
- running[0] = true;
- Display.getCurrent().asyncExec(new Runnable() {
- @Override
- public void run() {
- running[0] = false;
- if (!getShell().isDisposed()) {
- calculateFitZoomFactor(forceNativeWindowSizeUpdate);
- applyZoomFactor();
- }
-
- }
- });
- }
- }
- });
-
- createContentComposite(instance);
- info("Created Native Window Composite for " + instance.getName());
- }
-
- /**
- * Creates the content composite that will be parent of emulator native
- * window
- *
- * @param instance
- * A android instance from which the composite could be retrieved
- * if it is already created
- */
- public void createContentComposite(IAndroidEmulatorInstance instance) {
- contentComposite = instance.getComposite();
- if (contentComposite != null) {
- info("Instance already has a composite");
- contentComposite.setParent(this);
- contentComposite.setVisible(true);
- } else {
- contentComposite = new Composite(this, SWT.EMBEDDED | SWT.NO_BACKGROUND);
- }
-
- this.setContent(contentComposite);
- if (instance.getProperties().getProperty("Command_Line").contains("-scale")) {
- isOriginalScale = true;
- }
-
- // Force to update native window size at 100% when first using
- // nativeWindowSize field
- forceNativeWindowSizeUpdate = true;
-
- // Avoid perform apply zoom factor when creating composite
- zoomLocked = true;
- draw();
- }
-
- /**
- * Changes the parent from OS to content composite keeping the original
- * properties and parent window reference
- */
- private void draw() {
- if (contentComposite != null) {
- windowHandle = androidInstance.getWindowHandle();
-
- // If the instance does not contain the window handle, it should be
- // retrieved
- // from native emulator window and assigned to instance
- if (windowHandle <= 0) {
- int port = AndroidLogicUtils
- .getEmulatorPort(DDMSFacade.getSerialNumberByName(androidInstance.getName()));
- windowHandle = NativeUIUtils.getWindowHandle(androidInstance.getName(), port);
-
- androidInstance.setWindowHandle(windowHandle);
- }
-
- if ((windowProperties <= 0) && (windowHandle > 0)) {
- windowProperties = NativeUIUtils.getWindowProperties(windowHandle);
- info("Native Window Properties:" + windowProperties);
- }
-
- // Set Window Style
- if (windowHandle > 0) {
- NativeUIUtils.setWindowStyle(windowHandle);
- }
-
- if (originalParentHandle <= 0) {
- originalParentHandle = windowHandle;
- }
-
- // Retrieve window size before changing parent
- if (windowHandle > 0) {
- windowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
- }
-
- // Set the new Parent and store the original parent
- if ((originalParentHandle <= 0) || (originalParentHandle == windowHandle)) {
- if (windowHandle > 0) {
- originalParentHandle = NativeUIUtils.embedWindow(windowHandle, contentComposite);
- info("Native Window Parent:" + originalParentHandle);
- }
- } else {
- NativeUIUtils.embedWindow(windowHandle, contentComposite);
- }
-
- if (windowSize == null) {
- windowSize = new Point(700, 500);
- }
-
- // Update composite size
- contentComposite.setSize(contentComposite.computeSize(windowSize.x, windowSize.y, true));
- contentComposite.redraw();
- this.update();
-
- this.setMinSize(contentComposite.computeSize(windowSize.x, windowSize.y));
- this.layout();
- } else {
- createContentComposite(androidInstance);
- }
- }
-
- public void changeToNextLayout() {
- contentComposite.setVisible(false);
-
- contentComposite.setLocation(0, 0);
-
- NativeUIUtils.sendNextLayoutCommand(originalParentHandle, windowHandle);
-
- updateContentComposite();
-
- forceNativeWindowSizeUpdate = true;
- if (isFitToWindow) {
- // Force update to fit zoom factor
- setZoomFactor(ZOOM_FIT);
- }
- applyZoomFactor();
-
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- // do nothing
- }
-
- contentComposite.setVisible(true);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.swt.widgets.Widget#dispose()
- */
- @Override
- public void dispose() {
- info("Disposing Native Window Composite");
- if (nativeWindowMonitor != null) {
- nativeWindowMonitor.stopMonitoring();
- nativeWindowMonitor = null;
- info("Disposed Native Window Monitor");
- }
- if (windowHandle > 0) {
- info("Restoring original properties for window: " + windowHandle);
- NativeUIUtils.setWindowProperties(windowHandle, windowProperties);
-
- boolean shallUnembed = AndroidPlugin.getDefault().getPreferenceStore()
- .getBoolean(AndroidPlugin.SHALL_UNEMBED_EMULATORS_PREF_KEY);
- if ((originalParentHandle > 0) && shallUnembed) {
- info("Setting original parent: " + originalParentHandle + " for window" + windowHandle);
- NativeUIUtils.unembedWindow(windowHandle, originalParentHandle);
- // Force update when redrawing
- androidInstance.setWindowHandle(0);
- info("Restoring window: " + windowHandle);
- NativeUIUtils.restoreWindow(windowHandle);
- }
-
- }
-
- if (!Platform.getOS().equals(Platform.OS_WIN32)) {
- info("Trying to store the content composite in instance");
- if (contentComposite != null) {
- info("Is instance started? :" + androidInstance.isStarted());
- if (androidInstance.isStarted()) {
- try {
- contentComposite.setParent(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
- this.setContent(null);
- contentComposite.setVisible(true);
- androidInstance.setComposite(contentComposite);
- } catch (Exception e) {
- error("Error trying to store the content composite :" + e.getMessage());
- }
- }
- }
- }
- super.dispose();
- }
-
- /**
- * Apply the zoom factor to the instance
- */
- @Override
- public void applyZoomFactor() {
- if (!isOriginalScale && !zoomLocked) {
- contentComposite.setLocation(0, 0);
- IInputLogic inputLogic = androidInstance.getInputLogic();
- TelnetAndroidInput telnetAndroidInput = (TelnetAndroidInput) inputLogic;
- NativeUIUtils.hideWindow(windowHandle);
-
- if (isFitToWindow) {
- telnetAndroidInput.sendWindowScale(fitZoomFactor);
- } else {
- telnetAndroidInput.sendWindowScale(zoomFactor);
- }
-
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- // do nothing
- }
- telnetAndroidInput.dispose();
- NativeUIUtils.showWindow(windowHandle);
- updateContentComposite();
- }
- }
-
- void calculateFitZoomFactor(boolean requireNativeSizeUpdate) {
- // Compute new zoom factor if the zoom mode is "Fit to Window"
- Rectangle clientArea = getClientArea();
- if ((clientArea.width == 0) || (clientArea.height == 0)) {
- // zoom factor cannot be zero, otherwise an
- // IllegalArgumentException
- // is raised in some SWT methods
- fitZoomFactor = MINIMUM_ZOOM_FACTOR;
- } else {
- // if the layout was changed, it is needed to retrieve the native
- // window size at 100%
- // that size is required to the correct ratio calculus
- if (requireNativeSizeUpdate) {
- forceNativeWindowSizeUpdate = false;
- updateNativeWindowSize();
- } else {
- double widthRatio = (double) (clientArea.width) / nativeWindowSize.x;
- double heightRatio = (double) (clientArea.height) / nativeWindowSize.y;
- fitZoomFactor = (Math.min(widthRatio, heightRatio) > MINIMUM_ZOOM_FACTOR ? Math.min(widthRatio,
- heightRatio) : MINIMUM_ZOOM_FACTOR);
- }
- }
- }
-
- /**
- * This method brings the emulator window to 100% zoom factor to retrieve
- * their native size
- */
- private void updateNativeWindowSize() {
- info("Updating Native Window Size");
- setZoomFactor(1.0d);
- applyZoomFactor();
-
- nativeWindowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
-
- setZoomFactor(ZOOM_FIT);
- applyZoomFactor();
- info("Updated Native Window Size");
- }
-
- private void updateContentComposite() {
- if (!this.isDisposed()) {
- windowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
- if (windowSize != null) {
- if ((contentComposite != null) && !contentComposite.isDisposed()) {
- contentComposite.setSize(windowSize.x, windowSize.y);
- contentComposite.redraw();
- }
- this.setMinSize(windowSize.x, windowSize.y);
- draw();
- this.redraw();
- info("Updated Content Composite");
- }
- }
- }
-
- /**
- * Gets the current zoom factor.
- *
- * @return the zoom factor
- */
- @Override
- public double getZoomFactor() {
- if (isFitToWindow) {
- return fitZoomFactor;
- }
- return zoomFactor;
- }
-
- /**
- * Sets the zoom factor.
- *
- * @param zoom
- * the zoom factor
- *
- */
- @Override
- public void setZoomFactor(double zoom) {
- boolean execute = true;
- zoomLocked = false;
- if (isOriginalScale) {
- execute = DialogWithToggleUtils.showQuestion(LOOSE_ORIGINAL_SCALE_KEY_PREFERENCE,
- EmulatorNLS.QUESTION_NativeWindow_LooseOriginalScale_Title,
- EmulatorNLS.QUESTION_NativeWindow_LooseOriginalScale_Text);
- }
- if (execute) {
- isOriginalScale = false;
-
- if (zoom == ZOOM_FIT) {
- isFitToWindow = true;
- calculateFitZoomFactor(forceNativeWindowSizeUpdate);
- } else {
- isOriginalScale = false;
- isFitToWindow = false;
- }
- zoomFactor = zoom;
- }
- }
-
- @Override
- public boolean setFocus() {
- NativeUIUtils.setWindowFocus(windowHandle);
- return super.setFocus();
- }
-
- @Override
- public void applyLayout(String layoutName) {
- setLayout(new FillLayout());
- draw();
- }
-
- @Override
- public KeyListener getKeyListener() {
- return null;
- }
-
- @Override
- public MouseListener getMouseListener() {
- return null;
- }
-
- @Override
- public MouseMoveListener getMouseMoveListener() {
- return null;
- }
-
- @Override
- public boolean isFitToWindowSelected() {
- return isFitToWindow;
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.ui.controls.nativewindow;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.andmore.android.AndroidPlugin;
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.common.preferences.DialogWithToggleUtils;
+import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
+import org.eclipse.andmore.android.emulator.core.model.IInputLogic;
+import org.eclipse.andmore.android.emulator.core.skin.IAndroidSkin;
+import org.eclipse.andmore.android.emulator.core.utils.TelnetAndroidInput;
+import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
+import org.eclipse.andmore.android.emulator.logic.AndroidLogicUtils;
+import org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite;
+import org.eclipse.andmore.android.nativeos.NativeUIUtils;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+
+public class NativeWindowComposite extends ScrolledComposite implements IAndroidComposite {
+ /**
+ * Preference key of the Question Dialog about changing zoom
+ *
+ */
+ private static String LOOSE_ORIGINAL_SCALE_KEY_PREFERENCE = "loose.original.scale";
+
+ // Constants
+ private static final double MINIMUM_ZOOM_FACTOR = 0.10;
+
+ private static final double ZOOM_FIT = 0.0;
+
+ private Composite contentComposite;
+
+ private IAndroidEmulatorInstance androidInstance;
+
+ private long windowHandle;
+
+ private long originalParentHandle;
+
+ private long windowProperties;
+
+ private Point windowSize;
+
+ private Point nativeWindowSize;
+
+ private NativeWindowMonitor nativeWindowMonitor;
+
+ protected boolean resizing;
+
+ private boolean isFitToWindow;
+
+ private double zoomFactor = 0.99;
+
+ private double fitZoomFactor = ZOOM_FIT;
+
+ private boolean forceNativeWindowSizeUpdate;
+
+ private boolean isOriginalScale;
+
+ private boolean zoomLocked;
+
+ private class NativeWindowMonitor extends Timer {
+ private Timer timer;
+
+ private MonitorTask monitorTask;
+
+ public NativeWindowMonitor(long interval) {
+ timer = new Timer();
+ monitorTask = new MonitorTask();
+ timer.schedule(monitorTask, interval, interval);
+ }
+
+ private class MonitorTask extends TimerTask {
+ @Override
+ public void run() {
+ Point newWindowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
+ if ((windowHandle <= 0) || !newWindowSize.equals(windowSize)) {
+ Display display = Display.getDefault();
+ if (!display.isDisposed()) {
+ try {
+ display.syncExec(new Runnable() {
+ @Override
+ public void run() {
+ updateContentComposite();
+ }
+ });
+ } catch (SWTException e) {
+ // Do nothing in case the widget is disposed, occurs
+ // when the tool is closing.
+ }
+ }
+ }
+
+ if (NativeUIUtils.isWindowEnabled(windowHandle)) {
+ Display display = Display.getDefault();
+ if (!display.isDisposed()) {
+ try {
+ display.syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!contentComposite.isDisposed()) {
+ contentComposite.forceFocus();
+ }
+ }
+ });
+ } catch (SWTException e) {
+ // Do nothing in case the widget is disposed, occurs
+ // when the tool is closing.
+ }
+ }
+ }
+ }
+ }
+
+ public void stopMonitoring() {
+ timer.cancel();
+ timer = null;
+ monitorTask = null;
+ }
+ }
+
+ public NativeWindowComposite(Composite parent, IAndroidSkin androidSkin, final IAndroidEmulatorInstance instance) {
+ super(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+
+ info("Creating Native Window Composite for " + instance.getName());
+
+ getVerticalBar().setEnabled(true);
+ getHorizontalBar().setEnabled(true);
+ this.setLayout(new FillLayout());
+
+ androidInstance = instance;
+
+ nativeWindowMonitor = new NativeWindowMonitor(500);
+
+ addControlListener(new ControlAdapter() {
+ final boolean[] running = new boolean[1];
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse
+ * .swt.events.ControlEvent)
+ */
+ @Override
+ public void controlResized(ControlEvent event) {
+ if (isFitToWindow) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+
+ if (running[0]) {
+ return;
+ }
+ running[0] = true;
+ Display.getCurrent().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ running[0] = false;
+ if (!getShell().isDisposed()) {
+ calculateFitZoomFactor(forceNativeWindowSizeUpdate);
+ applyZoomFactor();
+ }
+
+ }
+ });
+ }
+ }
+ });
+
+ createContentComposite(instance);
+ info("Created Native Window Composite for " + instance.getName());
+ }
+
+ /**
+ * Creates the content composite that will be parent of emulator native
+ * window
+ *
+ * @param instance
+ * A android instance from which the composite could be retrieved
+ * if it is already created
+ */
+ public void createContentComposite(IAndroidEmulatorInstance instance) {
+ contentComposite = instance.getComposite();
+ if (contentComposite != null) {
+ info("Instance already has a composite");
+ contentComposite.setParent(this);
+ contentComposite.setVisible(true);
+ } else {
+ contentComposite = new Composite(this, SWT.EMBEDDED | SWT.NO_BACKGROUND);
+ }
+
+ this.setContent(contentComposite);
+ if (instance.getProperties().getProperty("Command_Line").contains("-scale")) {
+ isOriginalScale = true;
+ }
+
+ // Force to update native window size at 100% when first using
+ // nativeWindowSize field
+ forceNativeWindowSizeUpdate = true;
+
+ // Avoid perform apply zoom factor when creating composite
+ zoomLocked = true;
+ draw();
+ }
+
+ /**
+ * Changes the parent from OS to content composite keeping the original
+ * properties and parent window reference
+ */
+ private void draw() {
+ if (contentComposite != null) {
+ windowHandle = androidInstance.getWindowHandle();
+
+ // If the instance does not contain the window handle, it should be
+ // retrieved
+ // from native emulator window and assigned to instance
+ if (windowHandle <= 0) {
+ int port = AndroidLogicUtils
+ .getEmulatorPort(DeviceMonitor.instance().getSerialNumberByName(androidInstance.getName()));
+ windowHandle = NativeUIUtils.getWindowHandle(androidInstance.getName(), port);
+
+ androidInstance.setWindowHandle(windowHandle);
+ }
+
+ if ((windowProperties <= 0) && (windowHandle > 0)) {
+ windowProperties = NativeUIUtils.getWindowProperties(windowHandle);
+ info("Native Window Properties:" + windowProperties);
+ }
+
+ // Set Window Style
+ if (windowHandle > 0) {
+ NativeUIUtils.setWindowStyle(windowHandle);
+ }
+
+ if (originalParentHandle <= 0) {
+ originalParentHandle = windowHandle;
+ }
+
+ // Retrieve window size before changing parent
+ if (windowHandle > 0) {
+ windowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
+ }
+
+ // Set the new Parent and store the original parent
+ if ((originalParentHandle <= 0) || (originalParentHandle == windowHandle)) {
+ if (windowHandle > 0) {
+ originalParentHandle = NativeUIUtils.embedWindow(windowHandle, contentComposite);
+ info("Native Window Parent:" + originalParentHandle);
+ }
+ } else {
+ NativeUIUtils.embedWindow(windowHandle, contentComposite);
+ }
+
+ if (windowSize == null) {
+ windowSize = new Point(700, 500);
+ }
+
+ // Update composite size
+ contentComposite.setSize(contentComposite.computeSize(windowSize.x, windowSize.y, true));
+ contentComposite.redraw();
+ this.update();
+
+ this.setMinSize(contentComposite.computeSize(windowSize.x, windowSize.y));
+ this.layout();
+ } else {
+ createContentComposite(androidInstance);
+ }
+ }
+
+ public void changeToNextLayout() {
+ contentComposite.setVisible(false);
+
+ contentComposite.setLocation(0, 0);
+
+ NativeUIUtils.sendNextLayoutCommand(originalParentHandle, windowHandle);
+
+ updateContentComposite();
+
+ forceNativeWindowSizeUpdate = true;
+ if (isFitToWindow) {
+ // Force update to fit zoom factor
+ setZoomFactor(ZOOM_FIT);
+ }
+ applyZoomFactor();
+
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+
+ contentComposite.setVisible(true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ @Override
+ public void dispose() {
+ info("Disposing Native Window Composite");
+ if (nativeWindowMonitor != null) {
+ nativeWindowMonitor.stopMonitoring();
+ nativeWindowMonitor = null;
+ info("Disposed Native Window Monitor");
+ }
+ if (windowHandle > 0) {
+ info("Restoring original properties for window: " + windowHandle);
+ NativeUIUtils.setWindowProperties(windowHandle, windowProperties);
+
+ boolean shallUnembed = AndroidPlugin.getDefault().getPreferenceStore()
+ .getBoolean(AndroidPlugin.SHALL_UNEMBED_EMULATORS_PREF_KEY);
+ if ((originalParentHandle > 0) && shallUnembed) {
+ info("Setting original parent: " + originalParentHandle + " for window" + windowHandle);
+ NativeUIUtils.unembedWindow(windowHandle, originalParentHandle);
+ // Force update when redrawing
+ androidInstance.setWindowHandle(0);
+ info("Restoring window: " + windowHandle);
+ NativeUIUtils.restoreWindow(windowHandle);
+ }
+
+ }
+
+ if (!Platform.getOS().equals(Platform.OS_WIN32)) {
+ info("Trying to store the content composite in instance");
+ if (contentComposite != null) {
+ info("Is instance started? :" + androidInstance.isStarted());
+ if (androidInstance.isStarted()) {
+ try {
+ contentComposite.setParent(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
+ this.setContent(null);
+ contentComposite.setVisible(true);
+ androidInstance.setComposite(contentComposite);
+ } catch (Exception e) {
+ error("Error trying to store the content composite :" + e.getMessage());
+ }
+ }
+ }
+ }
+ super.dispose();
+ }
+
+ /**
+ * Apply the zoom factor to the instance
+ */
+ @Override
+ public void applyZoomFactor() {
+ if (!isOriginalScale && !zoomLocked) {
+ contentComposite.setLocation(0, 0);
+ IInputLogic inputLogic = androidInstance.getInputLogic();
+ TelnetAndroidInput telnetAndroidInput = (TelnetAndroidInput) inputLogic;
+ NativeUIUtils.hideWindow(windowHandle);
+
+ if (isFitToWindow) {
+ telnetAndroidInput.sendWindowScale(fitZoomFactor);
+ } else {
+ telnetAndroidInput.sendWindowScale(zoomFactor);
+ }
+
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ telnetAndroidInput.dispose();
+ NativeUIUtils.showWindow(windowHandle);
+ updateContentComposite();
+ }
+ }
+
+ void calculateFitZoomFactor(boolean requireNativeSizeUpdate) {
+ // Compute new zoom factor if the zoom mode is "Fit to Window"
+ Rectangle clientArea = getClientArea();
+ if ((clientArea.width == 0) || (clientArea.height == 0)) {
+ // zoom factor cannot be zero, otherwise an
+ // IllegalArgumentException
+ // is raised in some SWT methods
+ fitZoomFactor = MINIMUM_ZOOM_FACTOR;
+ } else {
+ // if the layout was changed, it is needed to retrieve the native
+ // window size at 100%
+ // that size is required to the correct ratio calculus
+ if (requireNativeSizeUpdate) {
+ forceNativeWindowSizeUpdate = false;
+ updateNativeWindowSize();
+ } else {
+ double widthRatio = (double) (clientArea.width) / nativeWindowSize.x;
+ double heightRatio = (double) (clientArea.height) / nativeWindowSize.y;
+ fitZoomFactor = (Math.min(widthRatio, heightRatio) > MINIMUM_ZOOM_FACTOR ? Math.min(widthRatio,
+ heightRatio) : MINIMUM_ZOOM_FACTOR);
+ }
+ }
+ }
+
+ /**
+ * This method brings the emulator window to 100% zoom factor to retrieve
+ * their native size
+ */
+ private void updateNativeWindowSize() {
+ info("Updating Native Window Size");
+ setZoomFactor(1.0d);
+ applyZoomFactor();
+
+ nativeWindowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
+
+ setZoomFactor(ZOOM_FIT);
+ applyZoomFactor();
+ info("Updated Native Window Size");
+ }
+
+ private void updateContentComposite() {
+ if (!this.isDisposed()) {
+ windowSize = NativeUIUtils.getWindowSize(originalParentHandle, windowHandle);
+ if (windowSize != null) {
+ if ((contentComposite != null) && !contentComposite.isDisposed()) {
+ contentComposite.setSize(windowSize.x, windowSize.y);
+ contentComposite.redraw();
+ }
+ this.setMinSize(windowSize.x, windowSize.y);
+ draw();
+ this.redraw();
+ info("Updated Content Composite");
+ }
+ }
+ }
+
+ /**
+ * Gets the current zoom factor.
+ *
+ * @return the zoom factor
+ */
+ @Override
+ public double getZoomFactor() {
+ if (isFitToWindow) {
+ return fitZoomFactor;
+ }
+ return zoomFactor;
+ }
+
+ /**
+ * Sets the zoom factor.
+ *
+ * @param zoom
+ * the zoom factor
+ *
+ */
+ @Override
+ public void setZoomFactor(double zoom) {
+ boolean execute = true;
+ zoomLocked = false;
+ if (isOriginalScale) {
+ execute = DialogWithToggleUtils.showQuestion(LOOSE_ORIGINAL_SCALE_KEY_PREFERENCE,
+ EmulatorNLS.QUESTION_NativeWindow_LooseOriginalScale_Title,
+ EmulatorNLS.QUESTION_NativeWindow_LooseOriginalScale_Text);
+ }
+ if (execute) {
+ isOriginalScale = false;
+
+ if (zoom == ZOOM_FIT) {
+ isFitToWindow = true;
+ calculateFitZoomFactor(forceNativeWindowSizeUpdate);
+ } else {
+ isOriginalScale = false;
+ isFitToWindow = false;
+ }
+ zoomFactor = zoom;
+ }
+ }
+
+ @Override
+ public boolean setFocus() {
+ NativeUIUtils.setWindowFocus(windowHandle);
+ return super.setFocus();
+ }
+
+ @Override
+ public void applyLayout(String layoutName) {
+ setLayout(new FillLayout());
+ draw();
+ }
+
+ @Override
+ public KeyListener getKeyListener() {
+ return null;
+ }
+
+ @Override
+ public MouseListener getMouseListener() {
+ return null;
+ }
+
+ @Override
+ public MouseMoveListener getMouseMoveListener() {
+ return null;
+ }
+
+ @Override
+ public boolean isFitToWindowSelected() {
+ return isFitToWindow;
+ }
+}
diff --git a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/skin/SkinComposite.java b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/skin/SkinComposite.java
index b2dfa339..33aceb80 100644
--- a/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/skin/SkinComposite.java
+++ b/andmore-core/plugins/emulator/src/org/eclipse/andmore/android/emulator/ui/controls/skin/SkinComposite.java
@@ -1,1174 +1,1174 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.ui.controls.skin;
-
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.debug;
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
-import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
-
-import java.util.Collection;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.common.utilities.EclipseUtils;
-import org.eclipse.andmore.android.emulator.core.exception.InstanceStopException;
-import org.eclipse.andmore.android.emulator.core.exception.SkinException;
-import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
-import org.eclipse.andmore.android.emulator.core.model.IInputLogic;
-import org.eclipse.andmore.android.emulator.core.skin.AndroidPressKey;
-import org.eclipse.andmore.android.emulator.core.skin.AndroidSkinBean;
-import org.eclipse.andmore.android.emulator.core.skin.IAndroidKey;
-import org.eclipse.andmore.android.emulator.core.skin.IAndroidSkin;
-import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
-import org.eclipse.andmore.android.emulator.logic.AndroidLogicUtils;
-import org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite;
-import org.eclipse.andmore.android.emulator.ui.controls.UIHelper;
-import org.eclipse.andmore.android.emulator.ui.handlers.IHandlerConstants;
-import org.eclipse.andmore.android.nativeos.NativeUIUtils;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.MouseMoveListener;
-import org.eclipse.swt.events.MouseTrackAdapter;
-import org.eclipse.swt.events.MouseWheelListener;
-import org.eclipse.swt.events.PaintEvent;
-import org.eclipse.swt.events.PaintListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.RGB;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Layout;
-import org.eclipse.swt.widgets.ScrollBar;
-import org.eclipse.ui.PlatformUI;
-
-/**
- * DESCRIPTION: This class implements the UI part of the skin
- *
- * RESPONSIBILITY: - Provide the skin image with correct layout - Provide means
- * for the user to send events to the emulator through the phone emulated
- * keyboard - Provide means for the user to change the zoom and window scrolling
- * properties
- *
- * COLABORATORS: None.
- *
- * USAGE: Create an instance of this class every time an phone instance is to be
- * displayed Call the public methods to interact with the skin.
- */
-public class SkinComposite extends Composite implements IAndroidComposite {
- // Constants for defining interval between keystrokes
- // when using long mouse click
- public static final int FIRST_REFRESH_DELAY_MS = 300;
-
- public static final int REFRESH_DELAY_PERIOD_MS = 100;
-
- // Minimum value to be used as zoom factor. This is necessary to avoid
- // divisions to zero
- private static final double MINIMUM_ZOOM_FACTOR = 0.0001;
-
- // The step increased or decreased from the zoom factor using mouse wheel
- private static final double ZOOM_STEP = 0.5;
-
- /**
- * A rectangle that represents the part of the currentSkin image that fits
- * into the view/screen. It must fit inside the currentSkinImage borders (0,
- * 0, current skin image width, current skin image height)
- */
- private final Rectangle displayRectangle = new Rectangle(0, 0, 0, 0);
-
- /**
- * The skin elements provider
- */
- private IAndroidSkin skin;
-
- /**
- * The image that is currently drawn at screen. It is one image provided by
- * the skin that is scaled by the current zoom factor
- */
- private Image currentSkinImage;
-
- /**
- * The key that mouse is over at the current moment
- */
- private IAndroidKey currentKey;
-
- /**
- * The flag indicating that Ctrl key is pressed
- */
- private boolean ctrlPressed = false;
-
- /**
- * SWT key pressed/released events listener
- */
- private KeyListener keyListener;
-
- private MouseListener mainDisplayMouseListener;
-
- private MouseMoveListener mainDisplayMouseMoveListener;
-
- /**
- * Flag that indicates if the skin can use the scroll bars to draw itself
- * bigger than the view client area
- */
- private boolean scrollBarsUsed = true;
-
- /**
- * True if the mouse left button is pressed. False otherwise
- */
- private boolean isMouseLeftButtonPressed;
-
- /**
- * True if the mouse right button is pressed. False otherwise
- */
- private boolean isMouseRightButtonPressed;
-
- /**
- * The zoom factor whose default value is 1.0 (100%)
- */
- private double zoomFactor = 1.0;
-
- private double embeddedViewScale = 1.0;
-
- private IInputLogic androidInput;
-
- private boolean isMouseMainDisplayLeftButtonPressed;
-
- IAndroidEmulatorInstance androidInstance;
-
- /**
- * Creates a SkinComposite This composite holds the screens in the correct
- * positions and maps the keys
- *
- * @param parent
- * The parent composite in which the UI part of the instance
- * shall be created
- * @param androidSkin
- * The skin object that contain data for getting skin information
- */
- public SkinComposite(Composite parent, IAndroidSkin androidSkin, IAndroidEmulatorInstance instance) {
- super(parent, SWT.BACKGROUND | SWT.H_SCROLL | SWT.V_SCROLL);
- skin = androidSkin;
- androidInstance = instance;
-
- // Add listeners
- addListeners();
- createListenersForMainDisplay();
-
- setToolTipText(null);
-
- androidInput = instance.getInputLogic();
-
- // Init the scroll bars
- initScrollBars();
-
- if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
- hideEmulatorWindow();
- }
- }
-
- private void hideEmulatorWindow() {
- int port = AndroidLogicUtils.getEmulatorPort(DDMSFacade.getSerialNumberByName(androidInstance.getName()));
- long windowHandle = NativeUIUtils.getWindowHandle(androidInstance.getName(), port);
- androidInstance.setWindowHandle(windowHandle);
- NativeUIUtils.hideWindow(windowHandle);
- }
-
- /**
- * Add listeners to the skin composite
- */
- private void addListeners() {
-
- addPaintListener(new PaintListener() {
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.swt.events.PaintListener#paintControl(org.eclipse
- * .swt.events.PaintEvent)
- */
- @Override
- public void paintControl(PaintEvent e) {
- // This listener is invoked when a regular SWT redraw is
- // invoked. In this case, no keys
- // have changed. That's why we pass "null" as parameter
- drawSkin(e.gc, null);
- }
- });
-
- addMouseListener(new MouseAdapter() {
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.swt.events.MouseAdapter#mouseUp(org.eclipse.swt.events
- * .MouseEvent)
- */
- @Override
- public void mouseUp(MouseEvent e) {
- if (e.button == 1) {
- isMouseLeftButtonPressed = false;
-
- } else if (e.button == 3) {
- isMouseRightButtonPressed = false;
- }
-
- // Handle left button mouse up event
- if (e.button == 1) {
- cancelMouseSelection();
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt
- * .events.MouseEvent)
- */
- @Override
- public void mouseDown(MouseEvent e) {
- setFocus();
- if (e.button == 1) {
- isMouseLeftButtonPressed = true;
- } else if (e.button == 3) {
- isMouseRightButtonPressed = true;
- }
-
- if (currentKey != null) {
- ImageData mergedImage = getKeyImageData(currentKey, false);
- setSkinImage(mergedImage, currentKey, true);
-
- // Handle left button mouse down event
- if ((e.button == 1) && (!isMouseRightButtonPressed) && (currentKey != null)) {
- androidInput.sendClick(currentKey.getKeysym(), true);
- }
-
- // Handle right button mouse down event
- else if (e.button == 3) {
- cancelMouseSelection();
- }
-
- }
- }
- });
-
- addMouseMoveListener(new MouseMoveListener() {
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse
- * .swt.events.MouseEvent)
- */
- @Override
- public void mouseMove(MouseEvent e) {
- int posX = (int) ((e.x + displayRectangle.x) / zoomFactor);
- int posY = (int) ((e.y + displayRectangle.y) / zoomFactor);
- IAndroidKey keyData = getSkinKey(posX, posY);
-
- if ((isMouseLeftButtonPressed) && (keyData != currentKey)) {
- cancelMouseSelection();
- }
-
- if (!isMouseLeftButtonPressed && (currentKey != keyData)) {
- changeCurrentKey(keyData);
- }
- }
- });
-
- // listener to change the zoom factor using Ctrl + Mouse Wheel
- addMouseWheelListener(new MouseWheelListener() {
- @Override
- public void mouseScrolled(MouseEvent event) {
- if (ctrlPressed) {
-
- // the floor and ceil are required if "fits to window" was
- // checked.
- double roundedZoomFactor = Math.floor(zoomFactor / ZOOM_STEP) * ZOOM_STEP;
-
- if ((event.count > 0) && (roundedZoomFactor < IHandlerConstants.MAXIMUM_ZOOM)) {
- // increase zoom factor
- setZoomFactor(roundedZoomFactor + ZOOM_STEP);
- applyZoomFactor();
- }
-
- else if ((event.count < 0) && (roundedZoomFactor > IHandlerConstants.MINIMUM_ZOOM)) {
- // decrease zoom factor
- setZoomFactor(roundedZoomFactor - ZOOM_STEP);
- applyZoomFactor();
- }
-
- }
- }
- });
-
- addMouseTrackListener(new MouseTrackAdapter() {
- @Override
- public void mouseExit(MouseEvent mouseevent) {
- changeCurrentKey(null);
- }
- });
-
- addControlListener(new ControlAdapter() {
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse
- * .swt.events.ControlEvent)
- */
- @Override
- public void controlResized(ControlEvent event) {
- if (scrollBarsUsed) {
- synchronizeScrollBars();
- } else {
- ImageData imageData = getImageData(false, false);
- setSkinImage(imageData, null, false);
- }
- }
- });
-
- }
-
- @Override
- public void applyLayout(String layoutName) {
- // Populate the attributes with information from skin
- AndroidSkinBean skinBean = null;
-
- try {
- skinBean = skin.getSkinBean(layoutName);
- } catch (SkinException e) {
- error("The skin data could not be retrieved from skin files. Cause: " + e.getMessage());
- EclipseUtils.showErrorDialog(e);
- }
-
- // Create layout and set it to composite
- if (skinBean != null) {
- // When changing to a new layout, the key may move to another
- // position
- // It does not make sense to keep the old key object
- currentKey = null;
-
- // Change the background color to the one that applies to the layout
- // being set
- RGB color = skin.getBackgroundColor(layoutName);
- setBackground(new Color(PlatformUI.getWorkbench().getDisplay(), color));
-
- Layout prevLayout = getLayout();
- if (prevLayout instanceof AndroidSkinLayout) {
- ((AndroidSkinLayout) prevLayout).dispose();
- }
-
- AndroidSkinLayout androidLayout = new AndroidSkinLayout(skinBean, skin.isFlipSupported());
- setLayout(androidLayout);
-
- embeddedViewScale = skinBean.getEmbeddedViewScale();
-
- layout();
- redraw();
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.swt.widgets.Widget#dispose()
- */
- @Override
- public void dispose() {
- if (androidInput != null) {
- androidInput.dispose();
- }
-
- if (currentSkinImage != null) {
- currentSkinImage.dispose();
- }
-
- Layout layout = getLayout();
- if (layout instanceof AndroidSkinLayout) {
- ((AndroidSkinLayout) layout).dispose();
- }
-
- skin = null;
- currentKey = null;
- keyListener = null;
- mainDisplayMouseListener = null;
- mainDisplayMouseMoveListener = null;
-
- if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
- long hnd = androidInstance.getWindowHandle();
- if (hnd > 0) {
- NativeUIUtils.showWindow(hnd);
- NativeUIUtils.restoreWindow(hnd);
- }
-
- // Force update on redrawing
- androidInstance.setWindowHandle(0);
- }
-
- super.dispose();
- }
-
- /**
- * Sets the zoom factor to use in the instance
- */
- @Override
- public void applyZoomFactor() {
- if (getZoomFactor() == 0) {
- scrollBarsUsed = false;
- getVerticalBar().setEnabled(false);
- getHorizontalBar().setEnabled(false);
- } else {
- scrollBarsUsed = true;
- getVerticalBar().setEnabled(true);
- getHorizontalBar().setEnabled(true);
- }
-
- // Resets translation
- displayRectangle.x = 0;
- displayRectangle.y = 0;
-
- redrawReleasedImage();
-
- }
-
- /**
- * Sets the flip/slide status of the phone
- */
- private void redrawReleasedImage() {
- if (currentSkinImage != null) {
- ImageData imageData = getImageData(false, false);
- setSkinImage(imageData, null, false);
- layout();
- redraw();
- }
-
- if (scrollBarsUsed) {
- synchronizeScrollBars();
- }
- }
-
- /**
- * Performs the skin draw operation.
- *
- * @param gcUsedToDraw
- * The gc object associated with the skin composite that is used
- * to draw the images
- */
- private void drawSkin(GC gcUsedToDraw, IAndroidKey changedKey) {
- if (currentSkinImage == null) {
- IAndroidEmulatorInstance instance = UIHelper.getInstanceAssociatedToControl(this);
- ImageData initialSkinImage = getImageData(false, false);
- setSkinImage(initialSkinImage, null, false);
- applyLayout(instance.getCurrentLayout());
-
- if (scrollBarsUsed) {
- synchronizeScrollBars();
- }
- }
-
- if (displayRectangle != null) {
- int srcXPos, srcYPos, srcWidth, srcHeight;
- int destXPos, destYPos, destWidth, destHeight;
- if (changedKey == null) {
- srcXPos = displayRectangle.x;
- srcYPos = displayRectangle.y;
- srcWidth = displayRectangle.width;
- srcHeight = displayRectangle.height;
- destXPos = 0;
- destYPos = 0;
- destWidth = Math.min(currentSkinImage.getImageData().width, displayRectangle.width);
- destHeight = Math.min(currentSkinImage.getImageData().height, displayRectangle.height);
- } else {
- srcXPos = ((int) (changedKey.getKeyArea().x > 0 ? changedKey.getKeyArea().x * zoomFactor : 0));
- srcYPos = ((int) (changedKey.getKeyArea().y > 0 ? changedKey.getKeyArea().y * zoomFactor : 0));
- srcWidth = ((int) (changedKey.getKeyArea().width * zoomFactor));
- srcHeight = ((int) (changedKey.getKeyArea().height * zoomFactor));
- destXPos = srcXPos - displayRectangle.x;
- destYPos = srcYPos - displayRectangle.y;
- destWidth = srcWidth;
- destHeight = srcHeight;
- }
-
- gcUsedToDraw.drawImage(currentSkinImage, srcXPos, srcYPos, srcWidth, srcHeight, destXPos, destYPos,
- destWidth, destHeight);
- }
- }
-
- /**
- * Loads a new screen image to the currentSkin attribute. This action
- * updates the skin image that is drawn as skin
- *
- * @param imageToSet
- * The new skin pixel data, as retrieved from the skin plugin
- * @param changedKey
- * The key that has changed, if any. If one if provided, only the
- * key area should be redrawn. Can be null.
- * @param forceDraw
- * true if a draw is needed after setting the new image; false if
- * replacing skin image only will be performed.
- */
- private void setSkinImage(ImageData imageToSet, IAndroidKey changedKey, boolean forceDraw) {
-
- recalculateZoomFactor();
-
- if (imageToSet != null) {
- if (currentSkinImage != null) {
- currentSkinImage.dispose();
- }
-
- // Scales the chosen image and sets to currentSkin attribute
- //
- // NOTE: width and height cannot be equal to MINIMUM_ZOOM_FACTOR,
- // because this
- // will raise an IllegalArgumentException when constructing the
- // Image object
- int width = (zoomFactor == MINIMUM_ZOOM_FACTOR ? 1 : (int) (imageToSet.width * zoomFactor));
- int height = (zoomFactor == MINIMUM_ZOOM_FACTOR ? 1 : (int) (imageToSet.height * zoomFactor));
- currentSkinImage = new Image(getDisplay(), imageToSet.scaledTo(width, height));
-
- // It only makes sense to reset the translation if the skin image is
- // really being changed
- // It will happen if we set a image data without specifying a
- // changed key
- if (changedKey == null) {
- displayRectangle.x = 0;
- displayRectangle.y = 0;
- }
-
- if (forceDraw) {
- layout();
-
- GC gc = new GC(this);
- drawSkin(gc, changedKey);
- gc.dispose();
- }
- } else {
- info("It was requested to set a skin image that was null. Operation aborted.");
- }
- }
-
- /**
- * This method is responsible to set the scroll bar attributes so that they
- * reflect the size of the current image at the current zoom factor
- */
- private void synchronizeScrollBars() {
- // Syncronizing only makes sense if there is a skin being drawn
- if (currentSkinImage != null) {
-
- // Retrieves the current image and client area sizes
- Rectangle imageBound = currentSkinImage.getBounds();
- int cw = getClientArea().width;
- int ch = getClientArea().height;
-
- // Updates horizontal scroll bar attributes
- ScrollBar horizontal = getHorizontalBar();
- horizontal.setIncrement((cw / 100));
- horizontal.setPageIncrement((cw / 2));
- horizontal.setMaximum(imageBound.width);
- horizontal.setThumb(cw);
- horizontal.setSelection(displayRectangle.x);
-
- // Updates vertical scroll bar attributes
- ScrollBar vertical = getVerticalBar();
- vertical.setIncrement((ch / 100));
- vertical.setPageIncrement((ch / 2));
- vertical.setMaximum(imageBound.height);
- vertical.setThumb(ch);
- vertical.setSelection(displayRectangle.y);
-
- if (horizontal.getMaximum() > cw) // Image is wider than client area
- {
- horizontal.setEnabled(true);
- } else {
- horizontal.setEnabled(false);
- }
-
- if (vertical.getMaximum() > ch) // Image is wider than client area
- {
- vertical.setEnabled(true);
- } else {
- vertical.setEnabled(false);
- }
-
- }
- }
-
- /**
- * Initialize the scroll bars This include: a) setting the initial enabled
- * state b) adding the necessary listeners
- */
- private void initScrollBars() {
-
- ScrollBar horizontal = getHorizontalBar();
- horizontal.setEnabled(false);
- horizontal.addSelectionListener(new SelectionAdapter() {
- /**
- * @see org.eclipse.swt.events.SelectionListener#widgetSelected(SelectionEvent)
- */
- @Override
- public void widgetSelected(SelectionEvent event) {
- // Updates the translation
- displayRectangle.x = ((ScrollBar) event.widget).getSelection();
-
- // Update the UI
- layout();
- redraw();
- }
- });
-
- ScrollBar vertical = getVerticalBar();
- vertical.setEnabled(false);
- vertical.addSelectionListener(new SelectionAdapter() {
- /**
- * @see org.eclipse.swt.events.SelectionListener#widgetSelected(SelectionEvent)
- */
- @Override
- public void widgetSelected(SelectionEvent event) {
- // Updates the translation
- displayRectangle.y = ((ScrollBar) event.widget).getSelection();
-
- // Update the UI
- layout();
- redraw();
- }
- });
-
- debug("Initialized scroll bars");
- }
-
- /**
- * This method retrieves the key that is placed at the given x,y
- * coordinates, considering the flip status
- *
- * @param x
- * The X coordinate to use at key lookup
- * @param y
- * The Y coordinate to use at key lookup
- *
- * @return The key placed at the given coordinate, or null if none is found
- */
- private IAndroidKey getSkinKey(int x, int y) {
- IAndroidKey keyToReturn = null;
- IAndroidEmulatorInstance instance = UIHelper.getInstanceAssociatedToControl(this);
-
- Collection keyAreas = skin.getKeyDataCollection(instance.getCurrentLayout());
- if (keyAreas != null) {
- for (IAndroidKey key : keyAreas) {
- if (key.isInsideKey(x, y)) {
- if (key instanceof AndroidPressKey) {
- AndroidPressKey defaultKeyData = (AndroidPressKey) key;
-
- // if
- // (!defaultKeyData.isFlipSlideValid(instance.isFlipSlideClosed()))
- if (!defaultKeyData.isFlipSlideValid(false)) {
- continue;
- }
-
- }
-
- keyToReturn = key;
- break;
- }
- }
- }
-
- return keyToReturn;
- }
-
- /**
- * Retrieves an image data. If it has never been used at the current
- * session, loads it from skin. Released image is retrieved if both
- * parameters are false.
- *
- * @param isPressed
- * true if the image to be retrieved is the pressed image
- * @param isEnter
- * true if the image to be retrieved is the enter image. It only
- * has effect if isPressed == false
- *
- * @return An image data containing the desired image pixels
- */
- private ImageData getImageData(boolean isPressed, boolean isEnter) {
-
- ImageData imageData = null;
-
- IAndroidEmulatorInstance instance = UIHelper.getInstanceAssociatedToControl(this);
-
- try {
- if (isPressed) {
- imageData = skin.getPressedImageData(instance.getCurrentLayout());
-
- } else {
- if (isEnter) {
- imageData = skin.getEnterImageData(instance.getCurrentLayout());
-
- } else {
- imageData = skin.getReleasedImageData(instance.getCurrentLayout());
-
- }
- }
- } catch (SkinException e) {
- error("The image requested from skin could not be retrieved. isPressed=" + isPressed + "; message="
- + e.getMessage());
- EclipseUtils.showErrorDialog(e);
- error("The skin could not provide an important resource. Stopping the instance");
- try {
- instance.stop(true);
- } catch (InstanceStopException e1) {
- error("Error while running service for stopping virtual machine");
- EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error, EmulatorNLS.EXC_General_CannotRunStopService);
- }
- }
-
- return imageData;
- }
-
- /**
- * Builds an image data that is based on the released image but has the
- * pressed/enter key area painted with data from the pressed/enter image
- *
- * @param key
- * The pressed key
- * @param isEnter
- * Whether the image being retrieved will be used for enter or
- * pressed
- *
- * @return An image data built the way described at method description
- */
- private ImageData getKeyImageData(IAndroidKey key, boolean isEnter) {
-
- ImageData resultingImage;
- ImageData releasedImage = getImageData(false, false);
- ImageData keyImage = isEnter ? getImageData(false, true) : getImageData(true, false);
-
- resultingImage = (ImageData) releasedImage.clone();
-
- Rectangle keyArea = key.getKeyArea();
- int resultingImageSize = resultingImage.width * keyArea.height;
- int[] keyPixelBuffer = new int[resultingImageSize];
-
- int startY = keyArea.y < 0 ? 0 : keyArea.y;
-
- keyImage.getPixels(0, startY, resultingImageSize, keyPixelBuffer, 0);
-
- for (int line = 0; line < keyArea.height; line++) {
- int pos = (line * resultingImage.width) + Math.abs(keyArea.x);
- int startX = Math.abs(keyArea.x);
- startY = (keyArea.y < 0 ? 0 : keyArea.y) + line;
- if (startY < 0) {
- continue;
- }
-
- int putWidth = keyArea.x < 0 ? keyArea.width - startX : keyArea.width;
- resultingImage.setPixels(startX, startY, putWidth, keyPixelBuffer, pos);
- }
-
- return resultingImage;
- }
-
- /**
- * This method is called when a mouse selection needs to be canceled.
- * Pressing the right button, releasing the left button or leaving the key
- * area are examples of typical conditions.
- */
- private void cancelMouseSelection() {
- // If the mouse timer is different from null, that means that a key is
- // pressed
- // This check is important so that event messages are not sent by
- // mistake
-
- if (currentKey != null) {
-
- ImageData newImageData = getImageData(false, true);
- setSkinImage(newImageData, currentKey, true);
- androidInput.sendClick(currentKey.getKeysym(), false);
- }
- }
-
- private void changeCurrentKey(IAndroidKey newKey) {
- // The following actions are executed only if the key has changed since
- // the last
- // time a mouse move event has happened.
- ImageData newImage;
-
- if (currentKey != null) {
- // If currentKey is different from null, we know that the mouse
- // cursor has
- // left the area defined by currentKey. That is because from the
- // previous
- // if clause we know that the key has changed, and currentKey
- // attribute
- // state is out-dated until we reach the "currentKey = keyData"
- // statement.
- // In this case, we must draw the RELEASED image version of the key
- // at the
- // key location
- newImage = getImageData(false, false);
- setSkinImage(newImage, currentKey, true);
- setToolTipText(null);
- }
-
- if (newKey != null) {
- // If keyData is different from null, we know that the mouse cursor
- // has
- // entered the area defined by keyData.
- // In this case, we must draw the ENTER image version of the key at
- // the
- // key location
- newImage = getKeyImageData(newKey, true);
- setSkinImage(newImage, newKey, true);
- setToolTipText(newKey.getToolTip());
- }
- currentKey = newKey;
- }
-
- /**
- * Retrieves the display rectangle defined at the current moment.
- *
- * @return The display rectangle
- */
- Rectangle getDisplayRectangle() {
- return displayRectangle;
- }
-
- /**
- * Updates the size and location of the display rectangle, based on the
- * current attributes of the skin (such as skin size and zoom factor) and
- * view size
- */
- void updateDisplayRectangle() {
- // Updating the display rectangle only makes sense if we have a skin
- // being drawn
- if (currentSkinImage != null) {
-
- // Collect the variables used in computation
- //
- // - clientAreaWidth, clientAreaHeight: dimensions of the view,
- // measured from
- // the upper left corner point (0,0) to the lower right corner point
- // (width, height)
- // - currentSkinWidth, currentSkinHeight: dimensions of the skin
- // picture, already scaled
- // by the zoom factor
- int clientAreaWidth = getClientArea().width;
- int clientAreaHeight = getClientArea().height;
- int currentSkinHeight = currentSkinImage.getImageData().height;
- int currentSkinWidth = currentSkinImage.getImageData().width;
-
- // Updates the display rectangle y and height
- //
- // FIRST STEP: determine the position of the rectangle's y
- // coordinate.
- // - It starts by calculating if there is any blank area at the
- // bottom
- // of the view.
- // - If there is blank space (blankY > 0) then calculate which
- // point,
- // if set as the display rectangle's y coordinate, would make the
- // blank
- // space to disappear. Store this as a candidate Y.
- // - Check if the candidate Y is valid. If not valid (candidateY <
- // 0)
- // then use the image origin as the final y coordinate
- //
- // SECOND STEP: determine the width dimension of the rectangle
- // - It starts by calculating which would be the coordinate of the
- // lower point, assuming that the image is big enough to contain
- // that
- // coordinate. That value (vEdge) is the sum of the Y coordinate and
- // the view height.
- // - If vEdge is bigger than the current view height, that means
- // that the image will occupy part of the view. Itis necessary to
- // make the rectangle fit in the skin image by making it smaller in
- // height than the view height itself.
- // - If vEdge is smaller than the current view height, that means
- // that
- // the image will not fit in the view. The solution is to make the
- // display rectangle height the same size as the view height. In
- // this
- // second case, the display rectangle will fit in the view height,
- // but
- // will not be bigger than the skin image height itself
- int blankY = clientAreaHeight - (currentSkinHeight - displayRectangle.y);
- if (blankY > 0) {
- int candidateY = displayRectangle.y - blankY;
- if (candidateY > 0) {
- displayRectangle.y = candidateY;
- } else {
- displayRectangle.y = 0;
- }
- }
- int vEdge = displayRectangle.y + clientAreaHeight;
- if (vEdge > currentSkinHeight) {
- displayRectangle.height = currentSkinHeight - displayRectangle.y;
- } else {
- displayRectangle.height = clientAreaHeight;
- }
-
- // Updates the display rectangle x and width
- // NOTE: a similar logic to the previous one was applied in this
- // case
- int blankX = clientAreaWidth - (currentSkinWidth - displayRectangle.x);
- if (blankX > 0) {
- int candidateX = displayRectangle.x - blankX;
- if (candidateX > 0) {
- displayRectangle.x = candidateX;
- } else {
- displayRectangle.x = 0;
- }
- }
- int hEdge = displayRectangle.x + clientAreaWidth;
- if (hEdge > currentSkinWidth) {
- displayRectangle.width = currentSkinWidth - displayRectangle.x;
- } else {
- displayRectangle.width = clientAreaWidth;
- }
-
- }
- }
-
- /**
- * Recalculates the zoom factor. This is necessary when the screen or image
- * dimensions change.
- */
- void recalculateZoomFactor() {
-
- if (!scrollBarsUsed) {
- // Compute new zoom factor if the zoom mode is "Fit to Window"
- Rectangle clientArea = getClientArea();
- if ((clientArea.width == 0) || (clientArea.height == 0)) {
- // zoom factor cannot be zero, otherwise an
- // IllegalArgumentException
- // is raised in some SWT methods
- setZoomFactor(MINIMUM_ZOOM_FACTOR);
- } else {
- ImageData currentSkin = getImageData(false, false);
- double widthRatio = (double) (clientArea.width) / currentSkin.width;
- double heightRatio = (double) (clientArea.height) / currentSkin.height;
- setZoomFactor(Math.min(widthRatio, heightRatio));
- }
- }
-
- }
-
- /**
- * Gets the current zoom factor.
- *
- * @return the zoom factor
- */
- @Override
- public double getZoomFactor() {
- return zoomFactor;
- }
-
- /**
- * Checks if the current zoom configuration is "fit to screen";
- *
- * @return
- */
- @Override
- public boolean isFitToWindowSelected() {
- return !scrollBarsUsed;
- }
-
- /**
- * Sets the zoom factor.
- *
- * @param zoom
- * the zoom factor
- */
- @Override
- public void setZoomFactor(double zoom) {
- zoomFactor = zoom;
- }
-
- /**
- * Gets the listener that handles SWT key pressing and releasing events.
- *
- * @return the KeyListener object
- */
- @Override
- public KeyListener getKeyListener() {
- return keyListener;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite#
- * getMouseListener()
- */
- @Override
- public MouseListener getMouseListener() {
- return mainDisplayMouseListener;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite#
- * getMouseMoveListener()
- */
- @Override
- public MouseMoveListener getMouseMoveListener() {
- return mainDisplayMouseMoveListener;
- }
-
- private void createListenersForMainDisplay() {
- // create listener to handle keyboard key pressing highlighting the key
- // in the skin.
- keyListener = new KeyAdapter() {
-
- @Override
- public void keyPressed(KeyEvent arg0) {
-
- int keyCode = arg0.keyCode;
-
- if (keyCode == SWT.CTRL) {
- ctrlPressed = true;
- } else {
- if (keyCode == SWT.ARROW_DOWN || keyCode == SWT.ARROW_LEFT || keyCode == SWT.ARROW_RIGHT
- || keyCode == SWT.ARROW_UP) {
- int dpadRotation = skin.getDpadRotation(androidInstance.getCurrentLayout());
- keyCode = getRotatedKeyCode(keyCode, dpadRotation);
- }
- // send message to emulator
- androidInput.sendKey(arg0.character, keyCode, skin.getKeyCodes());
- }
-
- }
-
- @Override
- public void keyReleased(KeyEvent arg0) {
- int keyCode = arg0.keyCode;
-
- if (keyCode == SWT.CTRL) {
- ctrlPressed = false;
- }
- }
-
- };
-
- mainDisplayMouseMoveListener = new MouseMoveListener() {
- /**
- * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(MouseEvent)
- */
- @Override
- public void mouseMove(MouseEvent e) {
- if (isMouseMainDisplayLeftButtonPressed) {
- UIHelper.ajustCoordinates(e, SkinComposite.this);
- androidInput.sendMouseMove((int) (e.x / embeddedViewScale), (int) (e.y / embeddedViewScale));
- }
- }
- };
-
- mainDisplayMouseListener = new MouseAdapter() {
- /**
- * @see org.eclipse.swt.events.MouseListener#mouseUp(MouseEvent)
- */
- @Override
- public void mouseUp(MouseEvent e) {
- if (e.button == 1) {
- isMouseMainDisplayLeftButtonPressed = false;
-
- UIHelper.ajustCoordinates(e, SkinComposite.this);
- androidInput.sendMouseUp((int) (e.x / embeddedViewScale), (int) (e.y / embeddedViewScale));
- }
- }
-
- /**
- * @see org.eclipse.swt.events.MouseListener#mouseDown(MouseEvent)
- */
- @Override
- public void mouseDown(MouseEvent e) {
- if (e.button == 1) {
- UIHelper.ajustCoordinates(e, SkinComposite.this);
- androidInput.sendMouseDown((int) (e.x / embeddedViewScale), (int) (e.y / embeddedViewScale));
-
- isMouseMainDisplayLeftButtonPressed = true;
- }
- }
- };
- }
-
- private int getRotatedKeyCode(int keyCode, int dpadRotation) {
- switch (dpadRotation % 4) {
- case 1:
- switch (keyCode) {
- case SWT.ARROW_DOWN:
- keyCode = SWT.ARROW_RIGHT;
- break;
- case SWT.ARROW_LEFT:
- keyCode = SWT.ARROW_DOWN;
- break;
- case SWT.ARROW_RIGHT:
- keyCode = SWT.ARROW_UP;
- break;
- case SWT.ARROW_UP:
- keyCode = SWT.ARROW_LEFT;
- break;
- }
- break;
- case 2:
- switch (keyCode) {
- case SWT.ARROW_DOWN:
- keyCode = SWT.ARROW_UP;
- break;
- case SWT.ARROW_LEFT:
- keyCode = SWT.ARROW_RIGHT;
- break;
- case SWT.ARROW_RIGHT:
- keyCode = SWT.ARROW_LEFT;
- break;
- case SWT.ARROW_UP:
- keyCode = SWT.ARROW_DOWN;
- break;
- }
- break;
- case 3:
- switch (keyCode) {
- case SWT.ARROW_DOWN:
- keyCode = SWT.ARROW_LEFT;
- break;
- case SWT.ARROW_LEFT:
- keyCode = SWT.ARROW_UP;
- break;
- case SWT.ARROW_RIGHT:
- keyCode = SWT.ARROW_DOWN;
- break;
- case SWT.ARROW_UP:
- keyCode = SWT.ARROW_RIGHT;
- break;
- }
- break;
- default:
- // Does nothing, no rotation needed.
- break;
- }
- return keyCode;
- }
-}
+/*
+ * Copyright (C) 2012 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 org.eclipse.andmore.android.emulator.ui.controls.skin;
+
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.debug;
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.error;
+import static org.eclipse.andmore.android.common.log.AndmoreLogger.info;
+
+import java.util.Collection;
+
+import org.eclipse.andmore.android.DeviceMonitor;
+import org.eclipse.andmore.android.common.utilities.EclipseUtils;
+import org.eclipse.andmore.android.emulator.core.exception.InstanceStopException;
+import org.eclipse.andmore.android.emulator.core.exception.SkinException;
+import org.eclipse.andmore.android.emulator.core.model.IAndroidEmulatorInstance;
+import org.eclipse.andmore.android.emulator.core.model.IInputLogic;
+import org.eclipse.andmore.android.emulator.core.skin.AndroidPressKey;
+import org.eclipse.andmore.android.emulator.core.skin.AndroidSkinBean;
+import org.eclipse.andmore.android.emulator.core.skin.IAndroidKey;
+import org.eclipse.andmore.android.emulator.core.skin.IAndroidSkin;
+import org.eclipse.andmore.android.emulator.i18n.EmulatorNLS;
+import org.eclipse.andmore.android.emulator.logic.AndroidLogicUtils;
+import org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite;
+import org.eclipse.andmore.android.emulator.ui.controls.UIHelper;
+import org.eclipse.andmore.android.emulator.ui.handlers.IHandlerConstants;
+import org.eclipse.andmore.android.nativeos.NativeUIUtils;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * DESCRIPTION: This class implements the UI part of the skin
+ *
+ * RESPONSIBILITY: - Provide the skin image with correct layout - Provide means
+ * for the user to send events to the emulator through the phone emulated
+ * keyboard - Provide means for the user to change the zoom and window scrolling
+ * properties
+ *
+ * COLABORATORS: None.
+ *
+ * USAGE: Create an instance of this class every time an phone instance is to be
+ * displayed Call the public methods to interact with the skin.
+ */
+public class SkinComposite extends Composite implements IAndroidComposite {
+ // Constants for defining interval between keystrokes
+ // when using long mouse click
+ public static final int FIRST_REFRESH_DELAY_MS = 300;
+
+ public static final int REFRESH_DELAY_PERIOD_MS = 100;
+
+ // Minimum value to be used as zoom factor. This is necessary to avoid
+ // divisions to zero
+ private static final double MINIMUM_ZOOM_FACTOR = 0.0001;
+
+ // The step increased or decreased from the zoom factor using mouse wheel
+ private static final double ZOOM_STEP = 0.5;
+
+ /**
+ * A rectangle that represents the part of the currentSkin image that fits
+ * into the view/screen. It must fit inside the currentSkinImage borders (0,
+ * 0, current skin image width, current skin image height)
+ */
+ private final Rectangle displayRectangle = new Rectangle(0, 0, 0, 0);
+
+ /**
+ * The skin elements provider
+ */
+ private IAndroidSkin skin;
+
+ /**
+ * The image that is currently drawn at screen. It is one image provided by
+ * the skin that is scaled by the current zoom factor
+ */
+ private Image currentSkinImage;
+
+ /**
+ * The key that mouse is over at the current moment
+ */
+ private IAndroidKey currentKey;
+
+ /**
+ * The flag indicating that Ctrl key is pressed
+ */
+ private boolean ctrlPressed = false;
+
+ /**
+ * SWT key pressed/released events listener
+ */
+ private KeyListener keyListener;
+
+ private MouseListener mainDisplayMouseListener;
+
+ private MouseMoveListener mainDisplayMouseMoveListener;
+
+ /**
+ * Flag that indicates if the skin can use the scroll bars to draw itself
+ * bigger than the view client area
+ */
+ private boolean scrollBarsUsed = true;
+
+ /**
+ * True if the mouse left button is pressed. False otherwise
+ */
+ private boolean isMouseLeftButtonPressed;
+
+ /**
+ * True if the mouse right button is pressed. False otherwise
+ */
+ private boolean isMouseRightButtonPressed;
+
+ /**
+ * The zoom factor whose default value is 1.0 (100%)
+ */
+ private double zoomFactor = 1.0;
+
+ private double embeddedViewScale = 1.0;
+
+ private IInputLogic androidInput;
+
+ private boolean isMouseMainDisplayLeftButtonPressed;
+
+ IAndroidEmulatorInstance androidInstance;
+
+ /**
+ * Creates a SkinComposite This composite holds the screens in the correct
+ * positions and maps the keys
+ *
+ * @param parent
+ * The parent composite in which the UI part of the instance
+ * shall be created
+ * @param androidSkin
+ * The skin object that contain data for getting skin information
+ */
+ public SkinComposite(Composite parent, IAndroidSkin androidSkin, IAndroidEmulatorInstance instance) {
+ super(parent, SWT.BACKGROUND | SWT.H_SCROLL | SWT.V_SCROLL);
+ skin = androidSkin;
+ androidInstance = instance;
+
+ // Add listeners
+ addListeners();
+ createListenersForMainDisplay();
+
+ setToolTipText(null);
+
+ androidInput = instance.getInputLogic();
+
+ // Init the scroll bars
+ initScrollBars();
+
+ if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
+ hideEmulatorWindow();
+ }
+ }
+
+ private void hideEmulatorWindow() {
+ int port = AndroidLogicUtils.getEmulatorPort(DeviceMonitor.instance().getSerialNumberByName(androidInstance.getName()));
+ long windowHandle = NativeUIUtils.getWindowHandle(androidInstance.getName(), port);
+ androidInstance.setWindowHandle(windowHandle);
+ NativeUIUtils.hideWindow(windowHandle);
+ }
+
+ /**
+ * Add listeners to the skin composite
+ */
+ private void addListeners() {
+
+ addPaintListener(new PaintListener() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.PaintListener#paintControl(org.eclipse
+ * .swt.events.PaintEvent)
+ */
+ @Override
+ public void paintControl(PaintEvent e) {
+ // This listener is invoked when a regular SWT redraw is
+ // invoked. In this case, no keys
+ // have changed. That's why we pass "null" as parameter
+ drawSkin(e.gc, null);
+ }
+ });
+
+ addMouseListener(new MouseAdapter() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.MouseAdapter#mouseUp(org.eclipse.swt.events
+ * .MouseEvent)
+ */
+ @Override
+ public void mouseUp(MouseEvent e) {
+ if (e.button == 1) {
+ isMouseLeftButtonPressed = false;
+
+ } else if (e.button == 3) {
+ isMouseRightButtonPressed = false;
+ }
+
+ // Handle left button mouse up event
+ if (e.button == 1) {
+ cancelMouseSelection();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt
+ * .events.MouseEvent)
+ */
+ @Override
+ public void mouseDown(MouseEvent e) {
+ setFocus();
+ if (e.button == 1) {
+ isMouseLeftButtonPressed = true;
+ } else if (e.button == 3) {
+ isMouseRightButtonPressed = true;
+ }
+
+ if (currentKey != null) {
+ ImageData mergedImage = getKeyImageData(currentKey, false);
+ setSkinImage(mergedImage, currentKey, true);
+
+ // Handle left button mouse down event
+ if ((e.button == 1) && (!isMouseRightButtonPressed) && (currentKey != null)) {
+ androidInput.sendClick(currentKey.getKeysym(), true);
+ }
+
+ // Handle right button mouse down event
+ else if (e.button == 3) {
+ cancelMouseSelection();
+ }
+
+ }
+ }
+ });
+
+ addMouseMoveListener(new MouseMoveListener() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse
+ * .swt.events.MouseEvent)
+ */
+ @Override
+ public void mouseMove(MouseEvent e) {
+ int posX = (int) ((e.x + displayRectangle.x) / zoomFactor);
+ int posY = (int) ((e.y + displayRectangle.y) / zoomFactor);
+ IAndroidKey keyData = getSkinKey(posX, posY);
+
+ if ((isMouseLeftButtonPressed) && (keyData != currentKey)) {
+ cancelMouseSelection();
+ }
+
+ if (!isMouseLeftButtonPressed && (currentKey != keyData)) {
+ changeCurrentKey(keyData);
+ }
+ }
+ });
+
+ // listener to change the zoom factor using Ctrl + Mouse Wheel
+ addMouseWheelListener(new MouseWheelListener() {
+ @Override
+ public void mouseScrolled(MouseEvent event) {
+ if (ctrlPressed) {
+
+ // the floor and ceil are required if "fits to window" was
+ // checked.
+ double roundedZoomFactor = Math.floor(zoomFactor / ZOOM_STEP) * ZOOM_STEP;
+
+ if ((event.count > 0) && (roundedZoomFactor < IHandlerConstants.MAXIMUM_ZOOM)) {
+ // increase zoom factor
+ setZoomFactor(roundedZoomFactor + ZOOM_STEP);
+ applyZoomFactor();
+ }
+
+ else if ((event.count < 0) && (roundedZoomFactor > IHandlerConstants.MINIMUM_ZOOM)) {
+ // decrease zoom factor
+ setZoomFactor(roundedZoomFactor - ZOOM_STEP);
+ applyZoomFactor();
+ }
+
+ }
+ }
+ });
+
+ addMouseTrackListener(new MouseTrackAdapter() {
+ @Override
+ public void mouseExit(MouseEvent mouseevent) {
+ changeCurrentKey(null);
+ }
+ });
+
+ addControlListener(new ControlAdapter() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse
+ * .swt.events.ControlEvent)
+ */
+ @Override
+ public void controlResized(ControlEvent event) {
+ if (scrollBarsUsed) {
+ synchronizeScrollBars();
+ } else {
+ ImageData imageData = getImageData(false, false);
+ setSkinImage(imageData, null, false);
+ }
+ }
+ });
+
+ }
+
+ @Override
+ public void applyLayout(String layoutName) {
+ // Populate the attributes with information from skin
+ AndroidSkinBean skinBean = null;
+
+ try {
+ skinBean = skin.getSkinBean(layoutName);
+ } catch (SkinException e) {
+ error("The skin data could not be retrieved from skin files. Cause: " + e.getMessage());
+ EclipseUtils.showErrorDialog(e);
+ }
+
+ // Create layout and set it to composite
+ if (skinBean != null) {
+ // When changing to a new layout, the key may move to another
+ // position
+ // It does not make sense to keep the old key object
+ currentKey = null;
+
+ // Change the background color to the one that applies to the layout
+ // being set
+ RGB color = skin.getBackgroundColor(layoutName);
+ setBackground(new Color(PlatformUI.getWorkbench().getDisplay(), color));
+
+ Layout prevLayout = getLayout();
+ if (prevLayout instanceof AndroidSkinLayout) {
+ ((AndroidSkinLayout) prevLayout).dispose();
+ }
+
+ AndroidSkinLayout androidLayout = new AndroidSkinLayout(skinBean, skin.isFlipSupported());
+ setLayout(androidLayout);
+
+ embeddedViewScale = skinBean.getEmbeddedViewScale();
+
+ layout();
+ redraw();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.widgets.Widget#dispose()
+ */
+ @Override
+ public void dispose() {
+ if (androidInput != null) {
+ androidInput.dispose();
+ }
+
+ if (currentSkinImage != null) {
+ currentSkinImage.dispose();
+ }
+
+ Layout layout = getLayout();
+ if (layout instanceof AndroidSkinLayout) {
+ ((AndroidSkinLayout) layout).dispose();
+ }
+
+ skin = null;
+ currentKey = null;
+ keyListener = null;
+ mainDisplayMouseListener = null;
+ mainDisplayMouseMoveListener = null;
+
+ if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
+ long hnd = androidInstance.getWindowHandle();
+ if (hnd > 0) {
+ NativeUIUtils.showWindow(hnd);
+ NativeUIUtils.restoreWindow(hnd);
+ }
+
+ // Force update on redrawing
+ androidInstance.setWindowHandle(0);
+ }
+
+ super.dispose();
+ }
+
+ /**
+ * Sets the zoom factor to use in the instance
+ */
+ @Override
+ public void applyZoomFactor() {
+ if (getZoomFactor() == 0) {
+ scrollBarsUsed = false;
+ getVerticalBar().setEnabled(false);
+ getHorizontalBar().setEnabled(false);
+ } else {
+ scrollBarsUsed = true;
+ getVerticalBar().setEnabled(true);
+ getHorizontalBar().setEnabled(true);
+ }
+
+ // Resets translation
+ displayRectangle.x = 0;
+ displayRectangle.y = 0;
+
+ redrawReleasedImage();
+
+ }
+
+ /**
+ * Sets the flip/slide status of the phone
+ */
+ private void redrawReleasedImage() {
+ if (currentSkinImage != null) {
+ ImageData imageData = getImageData(false, false);
+ setSkinImage(imageData, null, false);
+ layout();
+ redraw();
+ }
+
+ if (scrollBarsUsed) {
+ synchronizeScrollBars();
+ }
+ }
+
+ /**
+ * Performs the skin draw operation.
+ *
+ * @param gcUsedToDraw
+ * The gc object associated with the skin composite that is used
+ * to draw the images
+ */
+ private void drawSkin(GC gcUsedToDraw, IAndroidKey changedKey) {
+ if (currentSkinImage == null) {
+ IAndroidEmulatorInstance instance = UIHelper.getInstanceAssociatedToControl(this);
+ ImageData initialSkinImage = getImageData(false, false);
+ setSkinImage(initialSkinImage, null, false);
+ applyLayout(instance.getCurrentLayout());
+
+ if (scrollBarsUsed) {
+ synchronizeScrollBars();
+ }
+ }
+
+ if (displayRectangle != null) {
+ int srcXPos, srcYPos, srcWidth, srcHeight;
+ int destXPos, destYPos, destWidth, destHeight;
+ if (changedKey == null) {
+ srcXPos = displayRectangle.x;
+ srcYPos = displayRectangle.y;
+ srcWidth = displayRectangle.width;
+ srcHeight = displayRectangle.height;
+ destXPos = 0;
+ destYPos = 0;
+ destWidth = Math.min(currentSkinImage.getImageData().width, displayRectangle.width);
+ destHeight = Math.min(currentSkinImage.getImageData().height, displayRectangle.height);
+ } else {
+ srcXPos = ((int) (changedKey.getKeyArea().x > 0 ? changedKey.getKeyArea().x * zoomFactor : 0));
+ srcYPos = ((int) (changedKey.getKeyArea().y > 0 ? changedKey.getKeyArea().y * zoomFactor : 0));
+ srcWidth = ((int) (changedKey.getKeyArea().width * zoomFactor));
+ srcHeight = ((int) (changedKey.getKeyArea().height * zoomFactor));
+ destXPos = srcXPos - displayRectangle.x;
+ destYPos = srcYPos - displayRectangle.y;
+ destWidth = srcWidth;
+ destHeight = srcHeight;
+ }
+
+ gcUsedToDraw.drawImage(currentSkinImage, srcXPos, srcYPos, srcWidth, srcHeight, destXPos, destYPos,
+ destWidth, destHeight);
+ }
+ }
+
+ /**
+ * Loads a new screen image to the currentSkin attribute. This action
+ * updates the skin image that is drawn as skin
+ *
+ * @param imageToSet
+ * The new skin pixel data, as retrieved from the skin plugin
+ * @param changedKey
+ * The key that has changed, if any. If one if provided, only the
+ * key area should be redrawn. Can be null.
+ * @param forceDraw
+ * true if a draw is needed after setting the new image; false if
+ * replacing skin image only will be performed.
+ */
+ private void setSkinImage(ImageData imageToSet, IAndroidKey changedKey, boolean forceDraw) {
+
+ recalculateZoomFactor();
+
+ if (imageToSet != null) {
+ if (currentSkinImage != null) {
+ currentSkinImage.dispose();
+ }
+
+ // Scales the chosen image and sets to currentSkin attribute
+ //
+ // NOTE: width and height cannot be equal to MINIMUM_ZOOM_FACTOR,
+ // because this
+ // will raise an IllegalArgumentException when constructing the
+ // Image object
+ int width = (zoomFactor == MINIMUM_ZOOM_FACTOR ? 1 : (int) (imageToSet.width * zoomFactor));
+ int height = (zoomFactor == MINIMUM_ZOOM_FACTOR ? 1 : (int) (imageToSet.height * zoomFactor));
+ currentSkinImage = new Image(getDisplay(), imageToSet.scaledTo(width, height));
+
+ // It only makes sense to reset the translation if the skin image is
+ // really being changed
+ // It will happen if we set a image data without specifying a
+ // changed key
+ if (changedKey == null) {
+ displayRectangle.x = 0;
+ displayRectangle.y = 0;
+ }
+
+ if (forceDraw) {
+ layout();
+
+ GC gc = new GC(this);
+ drawSkin(gc, changedKey);
+ gc.dispose();
+ }
+ } else {
+ info("It was requested to set a skin image that was null. Operation aborted.");
+ }
+ }
+
+ /**
+ * This method is responsible to set the scroll bar attributes so that they
+ * reflect the size of the current image at the current zoom factor
+ */
+ private void synchronizeScrollBars() {
+ // Syncronizing only makes sense if there is a skin being drawn
+ if (currentSkinImage != null) {
+
+ // Retrieves the current image and client area sizes
+ Rectangle imageBound = currentSkinImage.getBounds();
+ int cw = getClientArea().width;
+ int ch = getClientArea().height;
+
+ // Updates horizontal scroll bar attributes
+ ScrollBar horizontal = getHorizontalBar();
+ horizontal.setIncrement((cw / 100));
+ horizontal.setPageIncrement((cw / 2));
+ horizontal.setMaximum(imageBound.width);
+ horizontal.setThumb(cw);
+ horizontal.setSelection(displayRectangle.x);
+
+ // Updates vertical scroll bar attributes
+ ScrollBar vertical = getVerticalBar();
+ vertical.setIncrement((ch / 100));
+ vertical.setPageIncrement((ch / 2));
+ vertical.setMaximum(imageBound.height);
+ vertical.setThumb(ch);
+ vertical.setSelection(displayRectangle.y);
+
+ if (horizontal.getMaximum() > cw) // Image is wider than client area
+ {
+ horizontal.setEnabled(true);
+ } else {
+ horizontal.setEnabled(false);
+ }
+
+ if (vertical.getMaximum() > ch) // Image is wider than client area
+ {
+ vertical.setEnabled(true);
+ } else {
+ vertical.setEnabled(false);
+ }
+
+ }
+ }
+
+ /**
+ * Initialize the scroll bars This include: a) setting the initial enabled
+ * state b) adding the necessary listeners
+ */
+ private void initScrollBars() {
+
+ ScrollBar horizontal = getHorizontalBar();
+ horizontal.setEnabled(false);
+ horizontal.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionListener#widgetSelected(SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ // Updates the translation
+ displayRectangle.x = ((ScrollBar) event.widget).getSelection();
+
+ // Update the UI
+ layout();
+ redraw();
+ }
+ });
+
+ ScrollBar vertical = getVerticalBar();
+ vertical.setEnabled(false);
+ vertical.addSelectionListener(new SelectionAdapter() {
+ /**
+ * @see org.eclipse.swt.events.SelectionListener#widgetSelected(SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ // Updates the translation
+ displayRectangle.y = ((ScrollBar) event.widget).getSelection();
+
+ // Update the UI
+ layout();
+ redraw();
+ }
+ });
+
+ debug("Initialized scroll bars");
+ }
+
+ /**
+ * This method retrieves the key that is placed at the given x,y
+ * coordinates, considering the flip status
+ *
+ * @param x
+ * The X coordinate to use at key lookup
+ * @param y
+ * The Y coordinate to use at key lookup
+ *
+ * @return The key placed at the given coordinate, or null if none is found
+ */
+ private IAndroidKey getSkinKey(int x, int y) {
+ IAndroidKey keyToReturn = null;
+ IAndroidEmulatorInstance instance = UIHelper.getInstanceAssociatedToControl(this);
+
+ Collection keyAreas = skin.getKeyDataCollection(instance.getCurrentLayout());
+ if (keyAreas != null) {
+ for (IAndroidKey key : keyAreas) {
+ if (key.isInsideKey(x, y)) {
+ if (key instanceof AndroidPressKey) {
+ AndroidPressKey defaultKeyData = (AndroidPressKey) key;
+
+ // if
+ // (!defaultKeyData.isFlipSlideValid(instance.isFlipSlideClosed()))
+ if (!defaultKeyData.isFlipSlideValid(false)) {
+ continue;
+ }
+
+ }
+
+ keyToReturn = key;
+ break;
+ }
+ }
+ }
+
+ return keyToReturn;
+ }
+
+ /**
+ * Retrieves an image data. If it has never been used at the current
+ * session, loads it from skin. Released image is retrieved if both
+ * parameters are false.
+ *
+ * @param isPressed
+ * true if the image to be retrieved is the pressed image
+ * @param isEnter
+ * true if the image to be retrieved is the enter image. It only
+ * has effect if isPressed == false
+ *
+ * @return An image data containing the desired image pixels
+ */
+ private ImageData getImageData(boolean isPressed, boolean isEnter) {
+
+ ImageData imageData = null;
+
+ IAndroidEmulatorInstance instance = UIHelper.getInstanceAssociatedToControl(this);
+
+ try {
+ if (isPressed) {
+ imageData = skin.getPressedImageData(instance.getCurrentLayout());
+
+ } else {
+ if (isEnter) {
+ imageData = skin.getEnterImageData(instance.getCurrentLayout());
+
+ } else {
+ imageData = skin.getReleasedImageData(instance.getCurrentLayout());
+
+ }
+ }
+ } catch (SkinException e) {
+ error("The image requested from skin could not be retrieved. isPressed=" + isPressed + "; message="
+ + e.getMessage());
+ EclipseUtils.showErrorDialog(e);
+ error("The skin could not provide an important resource. Stopping the instance");
+ try {
+ instance.stop(true);
+ } catch (InstanceStopException e1) {
+ error("Error while running service for stopping virtual machine");
+ EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error, EmulatorNLS.EXC_General_CannotRunStopService);
+ }
+ }
+
+ return imageData;
+ }
+
+ /**
+ * Builds an image data that is based on the released image but has the
+ * pressed/enter key area painted with data from the pressed/enter image
+ *
+ * @param key
+ * The pressed key
+ * @param isEnter
+ * Whether the image being retrieved will be used for enter or
+ * pressed
+ *
+ * @return An image data built the way described at method description
+ */
+ private ImageData getKeyImageData(IAndroidKey key, boolean isEnter) {
+
+ ImageData resultingImage;
+ ImageData releasedImage = getImageData(false, false);
+ ImageData keyImage = isEnter ? getImageData(false, true) : getImageData(true, false);
+
+ resultingImage = (ImageData) releasedImage.clone();
+
+ Rectangle keyArea = key.getKeyArea();
+ int resultingImageSize = resultingImage.width * keyArea.height;
+ int[] keyPixelBuffer = new int[resultingImageSize];
+
+ int startY = keyArea.y < 0 ? 0 : keyArea.y;
+
+ keyImage.getPixels(0, startY, resultingImageSize, keyPixelBuffer, 0);
+
+ for (int line = 0; line < keyArea.height; line++) {
+ int pos = (line * resultingImage.width) + Math.abs(keyArea.x);
+ int startX = Math.abs(keyArea.x);
+ startY = (keyArea.y < 0 ? 0 : keyArea.y) + line;
+ if (startY < 0) {
+ continue;
+ }
+
+ int putWidth = keyArea.x < 0 ? keyArea.width - startX : keyArea.width;
+ resultingImage.setPixels(startX, startY, putWidth, keyPixelBuffer, pos);
+ }
+
+ return resultingImage;
+ }
+
+ /**
+ * This method is called when a mouse selection needs to be canceled.
+ * Pressing the right button, releasing the left button or leaving the key
+ * area are examples of typical conditions.
+ */
+ private void cancelMouseSelection() {
+ // If the mouse timer is different from null, that means that a key is
+ // pressed
+ // This check is important so that event messages are not sent by
+ // mistake
+
+ if (currentKey != null) {
+
+ ImageData newImageData = getImageData(false, true);
+ setSkinImage(newImageData, currentKey, true);
+ androidInput.sendClick(currentKey.getKeysym(), false);
+ }
+ }
+
+ private void changeCurrentKey(IAndroidKey newKey) {
+ // The following actions are executed only if the key has changed since
+ // the last
+ // time a mouse move event has happened.
+ ImageData newImage;
+
+ if (currentKey != null) {
+ // If currentKey is different from null, we know that the mouse
+ // cursor has
+ // left the area defined by currentKey. That is because from the
+ // previous
+ // if clause we know that the key has changed, and currentKey
+ // attribute
+ // state is out-dated until we reach the "currentKey = keyData"
+ // statement.
+ // In this case, we must draw the RELEASED image version of the key
+ // at the
+ // key location
+ newImage = getImageData(false, false);
+ setSkinImage(newImage, currentKey, true);
+ setToolTipText(null);
+ }
+
+ if (newKey != null) {
+ // If keyData is different from null, we know that the mouse cursor
+ // has
+ // entered the area defined by keyData.
+ // In this case, we must draw the ENTER image version of the key at
+ // the
+ // key location
+ newImage = getKeyImageData(newKey, true);
+ setSkinImage(newImage, newKey, true);
+ setToolTipText(newKey.getToolTip());
+ }
+ currentKey = newKey;
+ }
+
+ /**
+ * Retrieves the display rectangle defined at the current moment.
+ *
+ * @return The display rectangle
+ */
+ Rectangle getDisplayRectangle() {
+ return displayRectangle;
+ }
+
+ /**
+ * Updates the size and location of the display rectangle, based on the
+ * current attributes of the skin (such as skin size and zoom factor) and
+ * view size
+ */
+ void updateDisplayRectangle() {
+ // Updating the display rectangle only makes sense if we have a skin
+ // being drawn
+ if (currentSkinImage != null) {
+
+ // Collect the variables used in computation
+ //
+ // - clientAreaWidth, clientAreaHeight: dimensions of the view,
+ // measured from
+ // the upper left corner point (0,0) to the lower right corner point
+ // (width, height)
+ // - currentSkinWidth, currentSkinHeight: dimensions of the skin
+ // picture, already scaled
+ // by the zoom factor
+ int clientAreaWidth = getClientArea().width;
+ int clientAreaHeight = getClientArea().height;
+ int currentSkinHeight = currentSkinImage.getImageData().height;
+ int currentSkinWidth = currentSkinImage.getImageData().width;
+
+ // Updates the display rectangle y and height
+ //
+ // FIRST STEP: determine the position of the rectangle's y
+ // coordinate.
+ // - It starts by calculating if there is any blank area at the
+ // bottom
+ // of the view.
+ // - If there is blank space (blankY > 0) then calculate which
+ // point,
+ // if set as the display rectangle's y coordinate, would make the
+ // blank
+ // space to disappear. Store this as a candidate Y.
+ // - Check if the candidate Y is valid. If not valid (candidateY <
+ // 0)
+ // then use the image origin as the final y coordinate
+ //
+ // SECOND STEP: determine the width dimension of the rectangle
+ // - It starts by calculating which would be the coordinate of the
+ // lower point, assuming that the image is big enough to contain
+ // that
+ // coordinate. That value (vEdge) is the sum of the Y coordinate and
+ // the view height.
+ // - If vEdge is bigger than the current view height, that means
+ // that the image will occupy part of the view. Itis necessary to
+ // make the rectangle fit in the skin image by making it smaller in
+ // height than the view height itself.
+ // - If vEdge is smaller than the current view height, that means
+ // that
+ // the image will not fit in the view. The solution is to make the
+ // display rectangle height the same size as the view height. In
+ // this
+ // second case, the display rectangle will fit in the view height,
+ // but
+ // will not be bigger than the skin image height itself
+ int blankY = clientAreaHeight - (currentSkinHeight - displayRectangle.y);
+ if (blankY > 0) {
+ int candidateY = displayRectangle.y - blankY;
+ if (candidateY > 0) {
+ displayRectangle.y = candidateY;
+ } else {
+ displayRectangle.y = 0;
+ }
+ }
+ int vEdge = displayRectangle.y + clientAreaHeight;
+ if (vEdge > currentSkinHeight) {
+ displayRectangle.height = currentSkinHeight - displayRectangle.y;
+ } else {
+ displayRectangle.height = clientAreaHeight;
+ }
+
+ // Updates the display rectangle x and width
+ // NOTE: a similar logic to the previous one was applied in this
+ // case
+ int blankX = clientAreaWidth - (currentSkinWidth - displayRectangle.x);
+ if (blankX > 0) {
+ int candidateX = displayRectangle.x - blankX;
+ if (candidateX > 0) {
+ displayRectangle.x = candidateX;
+ } else {
+ displayRectangle.x = 0;
+ }
+ }
+ int hEdge = displayRectangle.x + clientAreaWidth;
+ if (hEdge > currentSkinWidth) {
+ displayRectangle.width = currentSkinWidth - displayRectangle.x;
+ } else {
+ displayRectangle.width = clientAreaWidth;
+ }
+
+ }
+ }
+
+ /**
+ * Recalculates the zoom factor. This is necessary when the screen or image
+ * dimensions change.
+ */
+ void recalculateZoomFactor() {
+
+ if (!scrollBarsUsed) {
+ // Compute new zoom factor if the zoom mode is "Fit to Window"
+ Rectangle clientArea = getClientArea();
+ if ((clientArea.width == 0) || (clientArea.height == 0)) {
+ // zoom factor cannot be zero, otherwise an
+ // IllegalArgumentException
+ // is raised in some SWT methods
+ setZoomFactor(MINIMUM_ZOOM_FACTOR);
+ } else {
+ ImageData currentSkin = getImageData(false, false);
+ double widthRatio = (double) (clientArea.width) / currentSkin.width;
+ double heightRatio = (double) (clientArea.height) / currentSkin.height;
+ setZoomFactor(Math.min(widthRatio, heightRatio));
+ }
+ }
+
+ }
+
+ /**
+ * Gets the current zoom factor.
+ *
+ * @return the zoom factor
+ */
+ @Override
+ public double getZoomFactor() {
+ return zoomFactor;
+ }
+
+ /**
+ * Checks if the current zoom configuration is "fit to screen";
+ *
+ * @return
+ */
+ @Override
+ public boolean isFitToWindowSelected() {
+ return !scrollBarsUsed;
+ }
+
+ /**
+ * Sets the zoom factor.
+ *
+ * @param zoom
+ * the zoom factor
+ */
+ @Override
+ public void setZoomFactor(double zoom) {
+ zoomFactor = zoom;
+ }
+
+ /**
+ * Gets the listener that handles SWT key pressing and releasing events.
+ *
+ * @return the KeyListener object
+ */
+ @Override
+ public KeyListener getKeyListener() {
+ return keyListener;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite#
+ * getMouseListener()
+ */
+ @Override
+ public MouseListener getMouseListener() {
+ return mainDisplayMouseListener;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.andmore.android.emulator.ui.controls.IAndroidComposite#
+ * getMouseMoveListener()
+ */
+ @Override
+ public MouseMoveListener getMouseMoveListener() {
+ return mainDisplayMouseMoveListener;
+ }
+
+ private void createListenersForMainDisplay() {
+ // create listener to handle keyboard key pressing highlighting the key
+ // in the skin.
+ keyListener = new KeyAdapter() {
+
+ @Override
+ public void keyPressed(KeyEvent arg0) {
+
+ int keyCode = arg0.keyCode;
+
+ if (keyCode == SWT.CTRL) {
+ ctrlPressed = true;
+ } else {
+ if (keyCode == SWT.ARROW_DOWN || keyCode == SWT.ARROW_LEFT || keyCode == SWT.ARROW_RIGHT
+ || keyCode == SWT.ARROW_UP) {
+ int dpadRotation = skin.getDpadRotation(androidInstance.getCurrentLayout());
+ keyCode = getRotatedKeyCode(keyCode, dpadRotation);
+ }
+ // send message to emulator
+ androidInput.sendKey(arg0.character, keyCode, skin.getKeyCodes());
+ }
+
+ }
+
+ @Override
+ public void keyReleased(KeyEvent arg0) {
+ int keyCode = arg0.keyCode;
+
+ if (keyCode == SWT.CTRL) {
+ ctrlPressed = false;
+ }
+ }
+
+ };
+
+ mainDisplayMouseMoveListener = new MouseMoveListener() {
+ /**
+ * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(MouseEvent)
+ */
+ @Override
+ public void mouseMove(MouseEvent e) {
+ if (isMouseMainDisplayLeftButtonPressed) {
+ UIHelper.ajustCoordinates(e, SkinComposite.this);
+ androidInput.sendMouseMove((int) (e.x / embeddedViewScale), (int) (e.y / embeddedViewScale));
+ }
+ }
+ };
+
+ mainDisplayMouseListener = new MouseAdapter() {
+ /**
+ * @see org.eclipse.swt.events.MouseListener#mouseUp(MouseEvent)
+ */
+ @Override
+ public void mouseUp(MouseEvent e) {
+ if (e.button == 1) {
+ isMouseMainDisplayLeftButtonPressed = false;
+
+ UIHelper.ajustCoordinates(e, SkinComposite.this);
+ androidInput.sendMouseUp((int) (e.x / embeddedViewScale), (int) (e.y / embeddedViewScale));
+ }
+ }
+
+ /**
+ * @see org.eclipse.swt.events.MouseListener#mouseDown(MouseEvent)
+ */
+ @Override
+ public void mouseDown(MouseEvent e) {
+ if (e.button == 1) {
+ UIHelper.ajustCoordinates(e, SkinComposite.this);
+ androidInput.sendMouseDown((int) (e.x / embeddedViewScale), (int) (e.y / embeddedViewScale));
+
+ isMouseMainDisplayLeftButtonPressed = true;
+ }
+ }
+ };
+ }
+
+ private int getRotatedKeyCode(int keyCode, int dpadRotation) {
+ switch (dpadRotation % 4) {
+ case 1:
+ switch (keyCode) {
+ case SWT.ARROW_DOWN:
+ keyCode = SWT.ARROW_RIGHT;
+ break;
+ case SWT.ARROW_LEFT:
+ keyCode = SWT.ARROW_DOWN;
+ break;
+ case SWT.ARROW_RIGHT:
+ keyCode = SWT.ARROW_UP;
+ break;
+ case SWT.ARROW_UP:
+ keyCode = SWT.ARROW_LEFT;
+ break;
+ }
+ break;
+ case 2:
+ switch (keyCode) {
+ case SWT.ARROW_DOWN:
+ keyCode = SWT.ARROW_UP;
+ break;
+ case SWT.ARROW_LEFT:
+ keyCode = SWT.ARROW_RIGHT;
+ break;
+ case SWT.ARROW_RIGHT:
+ keyCode = SWT.ARROW_LEFT;
+ break;
+ case SWT.ARROW_UP:
+ keyCode = SWT.ARROW_DOWN;
+ break;
+ }
+ break;
+ case 3:
+ switch (keyCode) {
+ case SWT.ARROW_DOWN:
+ keyCode = SWT.ARROW_LEFT;
+ break;
+ case SWT.ARROW_LEFT:
+ keyCode = SWT.ARROW_UP;
+ break;
+ case SWT.ARROW_RIGHT:
+ keyCode = SWT.ARROW_DOWN;
+ break;
+ case SWT.ARROW_UP:
+ keyCode = SWT.ARROW_RIGHT;
+ break;
+ }
+ break;
+ default:
+ // Does nothing, no rotation needed.
+ break;
+ }
+ return keyCode;
+ }
+}
diff --git a/andmore-core/plugins/handset/src/org/eclipse/andmore/android/handset/DummyServiceHandler.java b/andmore-core/plugins/handset/src/org/eclipse/andmore/android/handset/DummyServiceHandler.java
index a110fb7c..d92fcb60 100644
--- a/andmore-core/plugins/handset/src/org/eclipse/andmore/android/handset/DummyServiceHandler.java
+++ b/andmore-core/plugins/handset/src/org/eclipse/andmore/android/handset/DummyServiceHandler.java
@@ -1,100 +1,101 @@
-/*
- * Copyright (C) 2012 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 org.eclipse.andmore.android.handset;
-
-import java.util.Map;
-import java.util.Properties;
-
-import org.eclipse.andmore.android.DDMSFacade;
-import org.eclipse.andmore.android.handset.i18n.AndroidHandsetNLS;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.sequoyah.device.framework.events.InstanceEvent;
-import org.eclipse.sequoyah.device.framework.events.InstanceEvent.InstanceEventType;
-import org.eclipse.sequoyah.device.framework.events.InstanceEventManager;
-import org.eclipse.sequoyah.device.framework.model.IInstance;
-import org.eclipse.sequoyah.device.framework.model.handler.IServiceHandler;
-import org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler;
-
-/**
- * DESCRIPTION:
- * This class is a handler for the 0FF->Online transition. It always returns OK
- * RESPONSIBILITY:
- * Fill in the gap for the 0FF->Online transition for handsets
- * COLABORATORS:
- * None
- * USAGE:
- * This class is intended to be used by TmL only
- */
-public class DummyServiceHandler extends ServiceHandler {
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#
- * newInstance()
- */
- @Override
- public IServiceHandler newInstance() {
- return new DummyServiceHandler();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#runService
- * (org.eclipse.sequoyah.device.framework.model.IInstance, java.util.Map,
- * org.eclipse.core.runtime.IProgressMonitor)
- */
- @Override
- public IStatus runService(IInstance arg0, Map