diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.ddms')
25 files changed, 2496 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/.classpath b/eclipse/plugins/com.android.ide.eclipse.ddms/.classpath new file mode 100644 index 0000000..280621c --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/.classpath @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="lib" path="libs/jfreechart-1.0.9.jar"/> + <classpathentry kind="lib" path="libs/jcommon-1.0.12.jar"/> + <classpathentry kind="lib" path="libs/jfreechart-1.0.9-swt.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/.project b/eclipse/plugins/com.android.ide.eclipse.ddms/.project new file mode 100644 index 0000000..2e9f996 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>ddms-plugin</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF new file mode 100644 index 0000000..09b8085 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF @@ -0,0 +1,23 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Dalvik Debug Monitor Service +Bundle-SymbolicName: com.android.ide.eclipse.ddms;singleton:=true +Bundle-Version: 0.9.0.qualifier +Bundle-Activator: com.android.ide.eclipse.ddms.DdmsPlugin +Bundle-Vendor: The Android Open Source Project +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.ui.console +Eclipse-LazyStart: true +Export-Package: com.android.ddmlib, + com.android.ddmlib.log, + com.android.ddmlib.testrunner, + com.android.ddmuilib, + com.android.ddmuilib.console, + com.android.ide.eclipse.ddms, + com.android.ide.eclipse.ddms.views +Bundle-ClassPath: libs/jcommon-1.0.12.jar, + libs/jfreechart-1.0.9.jar, + libs/jfreechart-1.0.9-swt.jar, + . diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/MODULE_LICENSE_APACHE2 b/eclipse/plugins/com.android.ide.eclipse.ddms/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/MODULE_LICENSE_APACHE2 diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/build.properties b/eclipse/plugins/com.android.ide.eclipse.ddms/build.properties new file mode 100644 index 0000000..1c4c896 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/build.properties @@ -0,0 +1,10 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + icons/,\ + plugin.xml,\ + ., \ + libs/jcommon-1.0.12.jar,\ + libs/jfreechart-1.0.9-swt.jar,\ + libs/jfreechart-1.0.9.jar + diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/icons/android.png b/eclipse/plugins/com.android.ide.eclipse.ddms/icons/android.png Binary files differnew file mode 100644 index 0000000..3779d4d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/icons/android.png diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/icons/capture.png b/eclipse/plugins/com.android.ide.eclipse.ddms/icons/capture.png Binary files differnew file mode 100644 index 0000000..d75e7a9 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/icons/capture.png diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml new file mode 100644 index 0000000..27fadf2 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.2"?> +<plugin> + <extension + point="org.eclipse.ui.views"> + <category + name="Android" + id="com.android.ide.eclipse.ddms.views.category"> + </category> + <view + allowMultiple="false" + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.DeviceView" + icon="icons/device.png" + id="com.android.ide.eclipse.ddms.views.DeviceView" + name="Devices"> + </view> + <view + allowMultiple="false" + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.LogCatView" + icon="icons/android.png" + id="com.android.ide.eclipse.ddms.views.LogCatView" + name="LogCat"/> + <!-- Disabled for now due to AWT/SWT bridge issue on Leopard. + <view + allowMultiple="false" + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.EventLogView" + icon="icons/android.png" + id="com.android.ide.eclipse.ddms.views.EventLogView" + name="Event Log"/> --> + <view + allowMultiple="false" + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.ThreadView" + icon="icons/thread.png" + id="com.android.ide.eclipse.ddms.views.ThreadView" + name="Threads"/> + <view + allowMultiple="false" + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.HeapView" + icon="icons/heap.png" + id="com.android.ide.eclipse.ddms.views.HeapView" + name="Heap"/> + <view + allowMultiple="false" + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.FileExplorerView" + icon="icons/android.png" + id="com.android.ide.eclipse.ddms.views.FileExplorerView" + name="File Explorer"/> + <view + allowMultiple="false" + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.EmulatorControlView" + icon="icons/emulator.png" + id="com.android.ide.eclipse.ddms.views.EmulatorControlView" + name="Emulator Control"/> + </extension> + <extension + point="org.eclipse.ui.perspectives"> + <perspective + class="com.android.ide.eclipse.ddms.Perspective" + icon="icons/android.png" + id="com.android.ide.eclipse.ddms.Perspective" + name="DDMS"/> + </extension> + <extension + point="org.eclipse.core.runtime.preferences"> + <initializer class="com.android.ide.eclipse.ddms.preferences.PreferenceInitializer"/> + </extension> + <extension + point="org.eclipse.ui.perspectiveExtensions"> + <perspectiveExtension targetID="org.eclipse.jdt.ui.JavaPerspective"> + <perspectiveShortcut id="com.android.ide.eclipse.ddms.Perspective"/> + </perspectiveExtension> + <perspectiveExtension targetID="org.eclipse.ui.resourcePerspective"> + <perspectiveShortcut id="com.android.ide.eclipse.ddms.Perspective"/> + </perspectiveExtension> + <perspectiveExtension targetID="org.eclipse.debug.ui.DebugPerspective"> + <perspectiveShortcut id="com.android.ide.eclipse.ddms.Perspective"/> + <view id="com.android.ide.eclipse.ddms.views.LogCatView" + relative="org.eclipse.ui.views.ProblemView" + relationship="stack" /> + </perspectiveExtension> + </extension> + <extension + point="org.eclipse.ui.preferencePages"> + <page + category="com.android.ide.eclipse.preferences.main" + class="com.android.ide.eclipse.ddms.preferences.PreferencePage" + id="com.android.ide.eclipse.ddms.preferences.PreferencePage" + name="DDMS"/> + <page + category="com.android.ide.eclipse.preferences.main" + class="com.android.ide.eclipse.ddms.preferences.LogCatPreferencePage" + id="com.android.ide.eclipse.ddms.preferences.LogCatPreferencePage" + name="LogCat"/> + </extension> +</plugin> diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/CommonAction.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/CommonAction.java new file mode 100644 index 0000000..30ca4cb --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/CommonAction.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.eclipse.ddms; + +import com.android.ddmuilib.actions.ICommonAction; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; + +/** + * Basic action extending the jFace Action class in order to implement + * ICommonAction. + */ +public class CommonAction extends Action implements ICommonAction { + + private Runnable mRunnable; + + public CommonAction() { + super(); + } + + public CommonAction(String text) { + super(text); + } + + /** + * @param text + * @param image + */ + public CommonAction(String text, ImageDescriptor image) { + super(text, image); + } + + /** + * @param text + * @param style + */ + public CommonAction(String text, int style) { + super(text, style); + } + + @Override + public void run() { + if (mRunnable != null) { + mRunnable.run(); + } + } + + /** + * Sets the {@link Runnable}. + * @see ICommonAction#setRunnable(Runnable) + */ + public void setRunnable(Runnable runnable) { + mRunnable = runnable; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java new file mode 100644 index 0000000..ccadce6 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java @@ -0,0 +1,565 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms; + +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.Client; +import com.android.ddmlib.DdmPreferences; +import com.android.ddmlib.Device; +import com.android.ddmlib.Log; +import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; +import com.android.ddmlib.Log.ILogOutput; +import com.android.ddmlib.Log.LogLevel; +import com.android.ddmuilib.DdmUiPreferences; +import com.android.ddmuilib.DevicePanel.IUiSelectionListener; +import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer; +import com.android.ide.eclipse.ddms.views.DeviceView; + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.core.runtime.Preferences.IPropertyChangeListener; +import org.eclipse.core.runtime.Preferences.PropertyChangeEvent; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.console.ConsolePlugin; +import org.eclipse.ui.console.IConsole; +import org.eclipse.ui.console.MessageConsole; +import org.eclipse.ui.console.MessageConsoleStream; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +import java.util.ArrayList; +import java.util.Calendar; + +/** + * The activator class controls the plug-in life cycle + */ +public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeListener, + IUiSelectionListener { + + // The plug-in ID + public static final String PLUGIN_ID = "com.android.ide.eclipse.ddms"; // $NON-NLS-1$ + + private static final String ADB_LOCATION = PLUGIN_ID + ".adb"; // $NON-NLS-1$ + + /** The singleton instance */ + private static DdmsPlugin sPlugin; + + /** Location of the adb command line executable */ + private static String sAdbLocation; + + /** + * Debug Launcher for already running apps + */ + private static IDebugLauncher sRunningAppDebugLauncher; + + /** Console for DDMS log message */ + private MessageConsole mDdmsConsole; + + /** Image loader object */ + private ImageLoader mLoader; + + private Device mCurrentDevice; + private Client mCurrentClient; + private boolean mListeningToUiSelection = false; + + private final ArrayList<ISelectionListener> mListeners = new ArrayList<ISelectionListener>(); + + private Color mRed; + + private boolean mDdmlibInitialized; + + /** + * Interface to provide debugger launcher for running apps. + */ + public interface IDebugLauncher { + public boolean debug(String packageName, int port); + } + + /** + * Classes which implement this interface provide methods that deals + * with {@link Device} and {@link Client} selectionchanges. + */ + public interface ISelectionListener { + + /** + * Sent when a new {@link Client} is selected. + * @param selectedClient The selected client. If null, no clients are selected. + */ + public void selectionChanged(Client selectedClient); + + /** + * Sent when a new {@link Device} is selected. + * @param selectedDevice the selected device. If null, no devices are selected. + */ + public void selectionChanged(Device selectedDevice); + } + + /** + * The constructor + */ + public DdmsPlugin() { + sPlugin = this; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + + final Display display = getDisplay(); + + // get the eclipse store + final IPreferenceStore eclipseStore = getPreferenceStore(); + + AndroidDebugBridge.addDeviceChangeListener(this); + + DdmUiPreferences.setStore(eclipseStore); + + //DdmUiPreferences.displayCharts(); + + // set the consoles. + mDdmsConsole = new MessageConsole("DDMS", null); // $NON-NLS-1$ + ConsolePlugin.getDefault().getConsoleManager().addConsoles( + new IConsole[] { + mDdmsConsole + }); + + final MessageConsoleStream consoleStream = mDdmsConsole.newMessageStream(); + final MessageConsoleStream errorConsoleStream = mDdmsConsole.newMessageStream(); + mRed = new Color(display, 0xFF, 0x00, 0x00); + + // because this can be run, in some cases, by a non UI thread, and because + // changing the console properties update the UI, we need to make this change + // in the UI thread. + display.asyncExec(new Runnable() { + public void run() { + errorConsoleStream.setColor(mRed); + } + }); + + // set up the ddms log to use the ddms console. + Log.setLogOutput(new ILogOutput() { + public void printLog(LogLevel logLevel, String tag, String message) { + if (logLevel.getPriority() >= LogLevel.ERROR.getPriority()) { + printToStream(errorConsoleStream, tag, message); + ConsolePlugin.getDefault().getConsoleManager().showConsoleView(mDdmsConsole); + } else { + printToStream(consoleStream, tag, message); + } + } + + public void printAndPromptLog(final LogLevel logLevel, final String tag, + final String message) { + printLog(logLevel, tag, message); + // dialog box only run in UI thread.. + display.asyncExec(new Runnable() { + public void run() { + Shell shell = display.getActiveShell(); + if (logLevel == LogLevel.ERROR) { + MessageDialog.openError(shell, tag, message); + } else { + MessageDialog.openWarning(shell, tag, message); + } + } + }); + } + + }); + + // create the loader that's able to load the images + mLoader = new ImageLoader(this); + + // set the listener for the preference change + Preferences prefs = getPluginPreferences(); + prefs.addPropertyChangeListener(new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + // get the name of the property that changed. + String property = event.getProperty(); + + if (PreferenceInitializer.ATTR_DEBUG_PORT_BASE.equals(property)) { + DdmPreferences.setDebugPortBase( + eclipseStore.getInt(PreferenceInitializer.ATTR_DEBUG_PORT_BASE)); + } else if (PreferenceInitializer.ATTR_SELECTED_DEBUG_PORT.equals(property)) { + DdmPreferences.setSelectedDebugPort( + eclipseStore.getInt(PreferenceInitializer.ATTR_SELECTED_DEBUG_PORT)); + } else if (PreferenceInitializer.ATTR_THREAD_INTERVAL.equals(property)) { + DdmUiPreferences.setThreadRefreshInterval( + eclipseStore.getInt(PreferenceInitializer.ATTR_THREAD_INTERVAL)); + } else if (PreferenceInitializer.ATTR_LOG_LEVEL.equals(property)) { + DdmPreferences.setLogLevel( + eclipseStore.getString(PreferenceInitializer.ATTR_LOG_LEVEL)); + } + } + }); + + // read the adb location from the prefs to attempt to start it properly without + // having to wait for ADT to start + sAdbLocation = eclipseStore.getString(ADB_LOCATION); + + // start it in a thread to return from start() asap. + new Thread() { + @Override + public void run() { + // init ddmlib if needed + getDefault().initDdmlib(); + + // create and start the first bridge + AndroidDebugBridge.createBridge(sAdbLocation, true /* forceNewBridge */); + } + }.start(); + } + + public static Display getDisplay() { + IWorkbench bench = sPlugin.getWorkbench(); + if (bench != null) { + return bench.getDisplay(); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + AndroidDebugBridge.removeDeviceChangeListener(this); + + AndroidDebugBridge.terminate(); + + mRed.dispose(); + + sPlugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static DdmsPlugin getDefault() { + return sPlugin; + } + + /** Return the image loader for the plugin */ + public static ImageLoader getImageLoader() { + if (sPlugin != null) { + return sPlugin.mLoader; + } + return null; + } + + public static String getAdb() { + return sAdbLocation; + } + + /** + * Set the location of the adb executable and optionally starts adb + * @param adb location of adb + * @param startAdb flag to start adb + */ + public static void setAdb(String adb, boolean startAdb) { + sAdbLocation = adb; + + // store the location for future ddms only start. + sPlugin.getPreferenceStore().setValue(ADB_LOCATION, sAdbLocation); + + // starts the server in a thread in case this is blocking. + if (startAdb) { + new Thread() { + @Override + public void run() { + // init ddmlib if needed + getDefault().initDdmlib(); + + // create and start the bridge + AndroidDebugBridge.createBridge(sAdbLocation, false /* forceNewBridge */); + } + }.start(); + } + } + + private synchronized void initDdmlib() { + if (mDdmlibInitialized == false) { + // set the preferences. + PreferenceInitializer.setupPreferences(); + + // init the lib + AndroidDebugBridge.init(true /* debugger support */); + + mDdmlibInitialized = true; + } + } + + /** + * Sets the launcher responsible for connecting the debugger to running applications. + * @param launcher The launcher. + */ + public static void setRunningAppDebugLauncher(IDebugLauncher launcher) { + sRunningAppDebugLauncher = launcher; + + // if the process view is already running, give it the launcher. + // This method could be called from a non ui thread, so we make sure to do that + // in the ui thread. + Display display = getDisplay(); + if (display != null && display.isDisposed() == false) { + display.asyncExec(new Runnable() { + public void run() { + DeviceView dv = DeviceView.getInstance(); + if (dv != null) { + dv.setDebugLauncher(sRunningAppDebugLauncher); + } + } + }); + } + } + + public static IDebugLauncher getRunningAppDebugLauncher() { + return sRunningAppDebugLauncher; + } + + public synchronized void addSelectionListener(ISelectionListener listener) { + mListeners.add(listener); + + // notify the new listener of the current selection + listener.selectionChanged(mCurrentDevice); + listener.selectionChanged(mCurrentClient); + } + + public synchronized void removeSelectionListener(ISelectionListener listener) { + mListeners.remove(listener); + } + + public synchronized void setListeningState(boolean state) { + mListeningToUiSelection = state; + } + + /** + * Sent when the a device is connected to the {@link AndroidDebugBridge}. + * <p/> + * This is sent from a non UI thread. + * @param device the new device. + * + * @see IDeviceChangeListener#deviceConnected(Device) + */ + public void deviceConnected(Device device) { + // if we are listening to selection coming from the ui, then we do nothing, as + // any change in the devices/clients, will be handled by the UI, and we'll receive + // selection notification through our implementation of IUiSelectionListener. + if (mListeningToUiSelection == false) { + if (mCurrentDevice == null) { + handleDefaultSelection(device); + } + } + } + + /** + * Sent when the a device is disconnected to the {@link AndroidDebugBridge}. + * <p/> + * This is sent from a non UI thread. + * @param device the new device. + * + * @see IDeviceChangeListener#deviceDisconnected(Device) + */ + public void deviceDisconnected(Device device) { + // if we are listening to selection coming from the ui, then we do nothing, as + // any change in the devices/clients, will be handled by the UI, and we'll receive + // selection notification through our implementation of IUiSelectionListener. + if (mListeningToUiSelection == false) { + // test if the disconnected device was the default selection. + if (mCurrentDevice == device) { + // try to find a new device + AndroidDebugBridge bridge = AndroidDebugBridge.getBridge(); + if (bridge != null) { + // get the device list + Device[] devices = bridge.getDevices(); + + // check if we still have devices + if (devices.length == 0) { + handleDefaultSelection((Device)null); + } else { + handleDefaultSelection(devices[0]); + } + } else { + handleDefaultSelection((Device)null); + } + } + } + } + + /** + * Sent when a device data changed, or when clients are started/terminated on the device. + * <p/> + * This is sent from a non UI thread. + * @param device the device that was updated. + * @param changeMask the mask indicating what changed. + * + * @see IDeviceChangeListener#deviceChanged(Device) + */ + public void deviceChanged(Device device, int changeMask) { + // if we are listening to selection coming from the ui, then we do nothing, as + // any change in the devices/clients, will be handled by the UI, and we'll receive + // selection notification through our implementation of IUiSelectionListener. + if (mListeningToUiSelection == false) { + + // check if this is our device + if (device == mCurrentDevice) { + if (mCurrentClient == null) { + handleDefaultSelection(device); + } else { + // get the clients and make sure ours is still in there. + Client[] clients = device.getClients(); + boolean foundClient = false; + for (Client client : clients) { + if (client == mCurrentClient) { + foundClient = true; + break; + } + } + + // if we haven't found our client, lets look for a new one + if (foundClient == false) { + mCurrentClient = null; + handleDefaultSelection(device); + } + } + } + } + } + + /** + * Sent when a new {@link Device} and {@link Client} are selected. + * @param selectedDevice the selected device. If null, no devices are selected. + * @param selectedClient The selected client. If null, no clients are selected. + */ + public synchronized void selectionChanged(Device selectedDevice, Client selectedClient) { + if (mCurrentDevice != selectedDevice) { + mCurrentDevice = selectedDevice; + + // notify of the new default device + for (ISelectionListener listener : mListeners) { + listener.selectionChanged(mCurrentDevice); + } + } + + if (mCurrentClient != selectedClient) { + mCurrentClient = selectedClient; + + // notify of the new default client + for (ISelectionListener listener : mListeners) { + listener.selectionChanged(mCurrentClient); + } + } + } + + /** + * Handles a default selection of a {@link Device} and {@link Client}. + * @param device the selected device + */ + private void handleDefaultSelection(final Device device) { + // because the listener expect to receive this from the UI thread, and this is called + // from the AndroidDebugBridge notifications, we need to run this in the UI thread. + try { + Display display = getDisplay(); + + display.asyncExec(new Runnable() { + public void run() { + // set the new device if different. + boolean newDevice = false; + if (mCurrentDevice != device) { + mCurrentDevice = device; + newDevice = true; + + // notify of the new default device + for (ISelectionListener listener : mListeners) { + listener.selectionChanged(mCurrentDevice); + } + } + + if (device != null) { + // if this is a device switch or the same device but we didn't find a valid + // client the last time, we go look for a client to use again. + if (newDevice || mCurrentClient == null) { + // now get the new client + Client[] clients = device.getClients(); + if (clients.length > 0) { + handleDefaultSelection(clients[0]); + } else { + handleDefaultSelection((Client)null); + } + } + } else { + handleDefaultSelection((Client)null); + } + } + }); + } catch (SWTException e) { + // display is disposed. Do nothing since we're quitting anyway. + } + } + + private void handleDefaultSelection(Client client) { + mCurrentClient = client; + + // notify of the new default client + for (ISelectionListener listener : mListeners) { + listener.selectionChanged(mCurrentClient); + } + } + + /** + * Prints a message, associated with a project to the specified stream + * @param stream The stream to write to + * @param tag The tag associated to the message. Can be null + * @param message The message to print. + */ + private static synchronized void printToStream(MessageConsoleStream stream, String tag, + String message) { + String dateTag = getMessageTag(tag); + + stream.print(dateTag); + stream.println(message); + } + + /** + * Creates a string containing the current date/time, and the tag + * @param tag The tag associated to the message. Can be null + * @return The dateTag + */ + private static String getMessageTag(String tag) { + Calendar c = Calendar.getInstance(); + + if (tag == null) { + return String.format("[%1$tF %1$tT]", c); + } + + return String.format("[%1$tF %1$tT - %2$s]", c, tag); + } + + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/ImageLoader.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/ImageLoader.java new file mode 100644 index 0000000..a70405d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/ImageLoader.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.eclipse.ddms; + +import com.android.ddmuilib.IImageLoader; + +import org.eclipse.core.runtime.Plugin; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Implementation of the IImageLoader interface for the eclipse plugin. + */ +public class ImageLoader implements IImageLoader { + + private URL mBaseUrl; + + public ImageLoader(Plugin plugin) { + mBaseUrl = plugin.getBundle().getEntry("/"); // $NON-NLS-1$ + } + + /** + * default method. only need a filename. the 2 interface methods call this one. + * @param filename the filename of the image to load. The filename is searched for under /icons. + * @return + */ + public ImageDescriptor loadDescriptor(String filename) { + try { + URL newUrl = new URL(mBaseUrl, "/icons/" + filename); // $NON-NLS-1$ + return ImageDescriptor.createFromURL(newUrl); + } catch (MalformedURLException e) { + // we'll just return null; + } + return null; + } + + public ImageDescriptor loadDescriptor(String filename, Display display) { + return loadDescriptor(filename); + } + + + public Image loadImage(String filename, Display display) { + ImageDescriptor descriptor = loadDescriptor(filename); + if (descriptor !=null) { + return descriptor.createImage(); + } + return null; + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/Perspective.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/Perspective.java new file mode 100644 index 0000000..4c01e9b --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/Perspective.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.eclipse.ddms; + +import com.android.ide.eclipse.ddms.views.DeviceView; +import com.android.ide.eclipse.ddms.views.EmulatorControlView; +import com.android.ide.eclipse.ddms.views.FileExplorerView; +import com.android.ide.eclipse.ddms.views.HeapView; +import com.android.ide.eclipse.ddms.views.LogCatView; +import com.android.ide.eclipse.ddms.views.ThreadView; + +import org.eclipse.ui.IFolderLayout; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +public class Perspective implements IPerspectiveFactory { + + public void createInitialLayout(IPageLayout layout) { + // create a default layout that looks like the stand alone DDMS. + + // no editor window + layout.setEditorAreaVisible(false); + + String editorArea = layout.getEditorArea(); + IFolderLayout folder; + + folder = layout.createFolder("logcat", IPageLayout.BOTTOM, 0.8f, //$NON-NLS-1$ + editorArea); + folder.addPlaceholder(LogCatView.ID + ":*"); //$NON-NLS-1$ + folder.addView(LogCatView.ID); + + folder = layout.createFolder("devices", IPageLayout.LEFT, 0.3f, //$NON-NLS-1$ + editorArea); + folder.addPlaceholder(DeviceView.ID + ":*"); //$NON-NLS-1$ + folder.addView(DeviceView.ID); + + folder = layout.createFolder("emulator", IPageLayout.BOTTOM, 0.5f, //$NON-NLS-1$ + "devices"); + folder.addPlaceholder(EmulatorControlView.ID + ":*"); //$NON-NLS-1$ + folder.addView(EmulatorControlView.ID); + + folder = layout.createFolder("ddms-detail", IPageLayout.RIGHT, 0.5f, //$NON-NLS-1$ + editorArea); + folder.addPlaceholder(ThreadView.ID + ":*"); //$NON-NLS-1$ + folder.addView(ThreadView.ID); + folder.addView(HeapView.ID); + folder.addView(FileExplorerView.ID); + + layout.addPerspectiveShortcut("org.eclipse.ui.resourcePerspective"); //$NON-NLS-1$ + layout.addPerspectiveShortcut("org.eclipse.debug.ui.DebugPerspective"); //$NON-NLS-1$ + layout.addPerspectiveShortcut("org.eclipse.jdt.ui.JavaPerspective"); //$NON-NLS-1$ + + layout.addShowViewShortcut(DeviceView.ID); + layout.addShowViewShortcut(FileExplorerView.ID); + layout.addShowViewShortcut(HeapView.ID); + layout.addShowViewShortcut(LogCatView.ID); + layout.addShowViewShortcut(ThreadView.ID); + + layout.addShowViewShortcut(IPageLayout.ID_RES_NAV); + layout.addShowViewShortcut(IPageLayout.ID_BOOKMARKS); + layout.addShowViewShortcut(IPageLayout.ID_OUTLINE); + layout.addShowViewShortcut(IPageLayout.ID_PROP_SHEET); + layout.addShowViewShortcut(IPageLayout.ID_PROBLEM_VIEW); + layout.addShowViewShortcut(IPageLayout.ID_PROGRESS_VIEW); + layout.addShowViewShortcut(IPageLayout.ID_TASK_LIST); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/LogCatPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/LogCatPreferencePage.java new file mode 100644 index 0000000..909207d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/LogCatPreferencePage.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.preferences; + +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.views.LogCatView; + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.core.runtime.Preferences.IPropertyChangeListener; +import org.eclipse.core.runtime.Preferences.PropertyChangeEvent; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.FontFieldEditor; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +/** + * Preference Pane for LogCat. + */ +public class LogCatPreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + + public LogCatPreferencePage() { + super(GRID); + setPreferenceStore(DdmsPlugin.getDefault().getPreferenceStore()); + } + + @Override + protected void createFieldEditors() { + FontFieldEditor ffe = new FontFieldEditor(PreferenceInitializer.ATTR_LOGCAT_FONT, + "Display Font:", getFieldEditorParent()); + addField(ffe); + + Preferences prefs = DdmsPlugin.getDefault().getPluginPreferences(); + prefs.addPropertyChangeListener(new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + // get the name of the property that changed. + String property = event.getProperty(); + + if (PreferenceInitializer.ATTR_LOGCAT_FONT.equals(property)) { + try { + FontData fdat = new FontData((String)event.getNewValue()); + LogCatView.setFont(new Font(getFieldEditorParent().getDisplay(), fdat)); + } catch (IllegalArgumentException e) { + // Looks like the data from the store is not valid. + // We do nothing (default font will be used). + } catch (SWTError e2) { + // Looks like the Font() constructor failed. + // We do nothing in this case, the logcat view will use the default font. + } + } + } + }); + } + + public void init(IWorkbench workbench) { + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferenceInitializer.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferenceInitializer.java new file mode 100644 index 0000000..b53d85c --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferenceInitializer.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.preferences; + +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ddmlib.DdmPreferences; +import com.android.ddmuilib.DdmUiPreferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.FontData; + +/** + * Class used to initialize default preference values. + */ +public class PreferenceInitializer extends AbstractPreferenceInitializer { + + public final static String ATTR_LOG_LEVEL = + DdmsPlugin.PLUGIN_ID + ".logLevel"; //$NON-NLS-1$ + + public final static String ATTR_DEBUG_PORT_BASE = + DdmsPlugin.PLUGIN_ID + ".adbDebugBasePort"; //$NON-NLS-1$ + + public final static String ATTR_SELECTED_DEBUG_PORT = + DdmsPlugin.PLUGIN_ID + ".debugSelectedPort"; //$NON-NLS-1$ + + public final static String ATTR_DEFAULT_THREAD_UPDATE = + DdmsPlugin.PLUGIN_ID + ".defaultThreadUpdateEnabled"; //$NON-NLS-1$ + + public final static String ATTR_DEFAULT_HEAP_UPDATE = + DdmsPlugin.PLUGIN_ID + ".defaultHeapUpdateEnabled"; //$NON-NLS-1$ + + public final static String ATTR_THREAD_INTERVAL = + DdmsPlugin.PLUGIN_ID + ".threadStatusInterval"; //$NON-NLS-1$ + + public final static String ATTR_IMAGE_SAVE_DIR = + DdmsPlugin.PLUGIN_ID + ".imageSaveDir"; //$NON-NLS-1$ + + public final static String ATTR_LAST_IMAGE_SAVE_DIR = + DdmsPlugin.PLUGIN_ID + ".lastImageSaveDir"; //$NON-NLS-1$ + + public final static String ATTR_LOGCAT_FONT = + DdmsPlugin.PLUGIN_ID + ".logcatFont"; //$NON-NLS-1$ + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer + * #initializeDefaultPreferences() + */ + @Override + public void initializeDefaultPreferences() { + IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore(); + + store.setDefault(ATTR_DEBUG_PORT_BASE, DdmPreferences.DEFAULT_DEBUG_PORT_BASE); + + store.setDefault(ATTR_SELECTED_DEBUG_PORT, DdmPreferences.DEFAULT_SELECTED_DEBUG_PORT); + + store.setDefault(ATTR_DEFAULT_THREAD_UPDATE, DdmPreferences.DEFAULT_INITIAL_THREAD_UPDATE); + store.setDefault(ATTR_DEFAULT_HEAP_UPDATE, + DdmPreferences.DEFAULT_INITIAL_HEAP_UPDATE); + + store.setDefault(ATTR_THREAD_INTERVAL, DdmUiPreferences.DEFAULT_THREAD_REFRESH_INTERVAL); + + String homeDir = System.getProperty("user.home"); //$NON-NLS-1$ + store.setDefault(ATTR_IMAGE_SAVE_DIR, homeDir); + + store.setDefault(ATTR_LOG_LEVEL, DdmPreferences.DEFAULT_LOG_LEVEL.getStringValue()); + + store.setDefault(ATTR_LOGCAT_FONT, + new FontData("Courier", 10, SWT.NORMAL).toString()); //$NON-NLS-1$ + } + + /** + * Initializes the preferences of ddmlib and ddmuilib with values from the eclipse store. + */ + public synchronized static void setupPreferences() { + IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore(); + + DdmPreferences.setDebugPortBase(store.getInt(ATTR_DEBUG_PORT_BASE)); + DdmPreferences.setSelectedDebugPort(store.getInt(ATTR_SELECTED_DEBUG_PORT)); + DdmPreferences.setLogLevel(store.getString(ATTR_LOG_LEVEL)); + DdmPreferences.setInitialThreadUpdate(store.getBoolean(ATTR_DEFAULT_THREAD_UPDATE)); + DdmPreferences.setInitialHeapUpdate(store.getBoolean(ATTR_DEFAULT_HEAP_UPDATE)); + DdmUiPreferences.setThreadRefreshInterval(store.getInt(ATTR_THREAD_INTERVAL)); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferencePage.java new file mode 100644 index 0000000..86e87c7 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/preferences/PreferencePage.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.preferences; + +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ddmlib.Log.LogLevel; +import com.android.ddmuilib.PortFieldEditor; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IntegerFieldEditor; +import org.eclipse.jface.preference.RadioGroupFieldEditor; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +public class PreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + + public PreferencePage() { + super(GRID); + setPreferenceStore(DdmsPlugin.getDefault().getPreferenceStore()); + } + + /** + * Creates the field editors. Field editors are abstractions of the common + * GUI blocks needed to manipulate various types of preferences. Each field + * editor knows how to save and restore itself. + */ + @Override + public void createFieldEditors() { + IntegerFieldEditor ife; + + ife = new PortFieldEditor(PreferenceInitializer.ATTR_DEBUG_PORT_BASE, + "ADB debugger base port:", getFieldEditorParent()); + addField(ife); + + BooleanFieldEditor bfe; + + bfe = new BooleanFieldEditor(PreferenceInitializer.ATTR_DEFAULT_THREAD_UPDATE, + "Thread updates enabled by default", getFieldEditorParent()); + addField(bfe); + + bfe = new BooleanFieldEditor(PreferenceInitializer.ATTR_DEFAULT_HEAP_UPDATE, + "Heap updates enabled by default", getFieldEditorParent()); + addField(bfe); + + ife = new IntegerFieldEditor(PreferenceInitializer.ATTR_THREAD_INTERVAL, + "Thread status refresh interval (seconds):", getFieldEditorParent()); + ife.setValidRange(1, 60); + addField(ife); + + RadioGroupFieldEditor rgfe = new RadioGroupFieldEditor(PreferenceInitializer.ATTR_LOG_LEVEL, + "Logging Level", 1, new String[][] { + { "Verbose", LogLevel.VERBOSE.getStringValue() }, + { "Debug", LogLevel.DEBUG.getStringValue() }, + { "Info", LogLevel.INFO.getStringValue() }, + { "Warning", LogLevel.WARN.getStringValue() }, + { "Error", LogLevel.ERROR.getStringValue() }, + { "Assert", LogLevel.ASSERT.getStringValue() } + }, + getFieldEditorParent(), true); + addField(rgfe); + + } + + public void init(IWorkbench workbench) { + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java new file mode 100644 index 0000000..62a528a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmlib.Client; +import com.android.ddmlib.ClientData; +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.Device; +import com.android.ddmuilib.DevicePanel; +import com.android.ddmuilib.ScreenShotDialog; +import com.android.ddmuilib.DevicePanel.IUiSelectionListener; +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.DdmsPlugin.IDebugLauncher; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; + +public class DeviceView extends ViewPart implements IUiSelectionListener { + + private final static boolean USE_SELECTED_DEBUG_PORT = true; + + public static final String ID = + "com.android.ide.eclipse.ddms.views.DeviceView"; //$NON-NLS-1$ + + private DevicePanel mDeviceList; + private Action mResetAdbAction; + private Action mCaptureAction; + private Action mUpdateThreadAction; + private Action mUpdateHeapAction; + private Action mGcAction; + private Action mKillAppAction; + private Action mDebugAction; + private IDebugLauncher mDebugLauncher; + + private static DeviceView sThis; + + public DeviceView() { + // the view is declared with allowMultiple="false" so we + // can safely do this. + sThis = this; + } + + public static DeviceView getInstance() { + return sThis; + } + + /** + * Sets the {@link IDebugLauncher}. + * @param debugLauncher + */ + public void setDebugLauncher(DdmsPlugin.IDebugLauncher debugLauncher) { + mDebugLauncher = debugLauncher; + if (mDebugAction != null && mDeviceList != null) { + Client currentClient = mDeviceList.getSelectedClient(); + if (currentClient != null) { + mDebugAction.setEnabled(true); + } + } + } + + @Override + public void createPartControl(Composite parent) { + mDeviceList = new DevicePanel(DdmsPlugin.getImageLoader(), USE_SELECTED_DEBUG_PORT); + mDeviceList.createPanel(parent); + mDeviceList.addSelectionListener(this); + + DdmsPlugin plugin = DdmsPlugin.getDefault(); + mDeviceList.addSelectionListener(plugin); + plugin.setListeningState(true); + + mCaptureAction = new Action("Screen Capture") { + @Override + public void run() { + ScreenShotDialog dlg = new ScreenShotDialog( + DdmsPlugin.getDisplay().getActiveShell()); + dlg.open(mDeviceList.getSelectedDevice()); + } + }; + mCaptureAction.setToolTipText("Screen Capture"); + mCaptureAction.setImageDescriptor( + DdmsPlugin.getImageLoader().loadDescriptor("capture.png")); //$NON-NLS-1$ + + mResetAdbAction = new Action("Reset adb") { + @Override + public void run() { + AndroidDebugBridge bridge = AndroidDebugBridge.getBridge(); + if (bridge != null) { + if (bridge.restart() == false) { + // get the current Display + final Display display = DdmsPlugin.getDisplay(); + + // dialog box only run in ui thread.. + display.asyncExec(new Runnable() { + public void run() { + Shell shell = display.getActiveShell(); + MessageDialog.openError(shell, "Adb Error", + "Adb failed to restart!\n\nMake sure the plugin is properly configured."); + } + }); + } + } + } + }; + mResetAdbAction.setToolTipText("Reset the adb host daemon"); + mResetAdbAction.setImageDescriptor(PlatformUI.getWorkbench() + .getSharedImages().getImageDescriptor( + ISharedImages.IMG_OBJS_WARN_TSK)); + + mKillAppAction = new Action() { + @Override + public void run() { + mDeviceList.killSelectedClient(); + } + }; + + mKillAppAction.setText("Stop Process"); + mKillAppAction.setToolTipText("Stop Process"); + mKillAppAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor(DevicePanel.ICON_HALT)); + + mGcAction = new Action() { + @Override + public void run() { + mDeviceList.forceGcOnSelectedClient(); + } + }; + + mGcAction.setText("Cause GC"); + mGcAction.setToolTipText("Cause GC"); + mGcAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor(DevicePanel.ICON_GC)); + + mUpdateHeapAction = new Action("Update Heap", IAction.AS_CHECK_BOX) { + @Override + public void run() { + boolean enable = mUpdateHeapAction.isChecked(); + mDeviceList.setEnabledHeapOnSelectedClient(enable); + } + }; + mUpdateHeapAction.setToolTipText("Update Heap"); + mUpdateHeapAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor(DevicePanel.ICON_HEAP)); + + mUpdateThreadAction = new Action("Update Threads", IAction.AS_CHECK_BOX) { + @Override + public void run() { + boolean enable = mUpdateThreadAction.isChecked(); + mDeviceList.setEnabledThreadOnSelectedClient(enable); + } + }; + mUpdateThreadAction.setToolTipText("Update Threads"); + mUpdateThreadAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor(DevicePanel.ICON_THREAD)); + + // check if there's already a debug launcher set up in the plugin class + mDebugLauncher = DdmsPlugin.getRunningAppDebugLauncher(); + + mDebugAction = new Action("Debug Process") { + @Override + public void run() { + if (mDebugLauncher != null) { + Client currentClient = mDeviceList.getSelectedClient(); + if (currentClient != null) { + ClientData clientData = currentClient.getClientData(); + + // make sure the client can be debugged + switch (clientData.getDebuggerConnectionStatus()) { + case ClientData.DEBUGGER_ERROR: { + Display display = DdmsPlugin.getDisplay(); + Shell shell = display.getActiveShell(); + MessageDialog.openError(shell, "Process Debug", + "The process debug port is already in use!"); + return; + } + case ClientData.DEBUGGER_ATTACHED: { + Display display = DdmsPlugin.getDisplay(); + Shell shell = display.getActiveShell(); + MessageDialog.openError(shell, "Process Debug", + "The process is already being debugged!"); + return; + } + } + + // get the name of the client + String packageName = clientData.getClientDescription(); + if (packageName != null) { + if (mDebugLauncher.debug(packageName, + currentClient.getDebuggerListenPort()) == false) { + + // if we get to this point, then we failed to find a project + // that matched the application to debug + Display display = DdmsPlugin.getDisplay(); + Shell shell = display.getActiveShell(); + MessageDialog.openError(shell, "Process Debug", + String.format( + "No opened project found for %1$s. Debug session failed!", + packageName)); + } + } + } + } + } + }; + mDebugAction.setToolTipText("Debug the selected process, provided its source project is present and opened in the workspace."); + mDebugAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor("debug-attach.png")); //$NON-NLS-1$ + if (mDebugLauncher == null) { + mDebugAction.setEnabled(false); + } + + placeActions(); + } + + @Override + public void setFocus() { + mDeviceList.setFocus(); + } + + /** + * Sent when a new {@link Device} and {@link Client} are selected. + * @param selectedDevice the selected device. If null, no devices are selected. + * @param selectedClient The selected client. If null, no clients are selected. + */ + public void selectionChanged(Device selectedDevice, Client selectedClient) { + // update the buttons + doSelectionChanged(selectedClient); + doSelectionChanged(selectedDevice); + } + + private void doSelectionChanged(Client selectedClient) { + // update the buttons + if (selectedClient != null) { + if (USE_SELECTED_DEBUG_PORT) { + // set the client as the debug client + selectedClient.setAsSelectedClient(); + } + + mDebugAction.setEnabled(mDebugLauncher != null); + mKillAppAction.setEnabled(true); + mGcAction.setEnabled(true); + + mUpdateHeapAction.setEnabled(true); + mUpdateHeapAction.setChecked(selectedClient.isHeapUpdateEnabled()); + + mUpdateThreadAction.setEnabled(true); + mUpdateThreadAction.setChecked(selectedClient.isThreadUpdateEnabled()); + } else { + if (USE_SELECTED_DEBUG_PORT) { + // set the client as the debug client + AndroidDebugBridge bridge = AndroidDebugBridge.getBridge(); + if (bridge != null) { + bridge.setSelectedClient(null); + } + } + + mDebugAction.setEnabled(false); + mKillAppAction.setEnabled(false); + mGcAction.setEnabled(false); + mUpdateHeapAction.setChecked(false); + mUpdateHeapAction.setEnabled(false); + mUpdateThreadAction.setEnabled(false); + mUpdateThreadAction.setChecked(false); + } + } + + private void doSelectionChanged(Device selectedDevice) { + mCaptureAction.setEnabled(selectedDevice != null); + } + + /** + * Place the actions in the ui. + */ + private final void placeActions() { + IActionBars actionBars = getViewSite().getActionBars(); + + // first in the menu + IMenuManager menuManager = actionBars.getMenuManager(); + menuManager.add(mDebugAction); + menuManager.add(new Separator()); + menuManager.add(mUpdateThreadAction); + menuManager.add(mUpdateHeapAction); + menuManager.add(new Separator()); + menuManager.add(mGcAction); + menuManager.add(new Separator()); + menuManager.add(mKillAppAction); + menuManager.add(new Separator()); + menuManager.add(mCaptureAction); + menuManager.add(new Separator()); + menuManager.add(mResetAdbAction); + + // and then in the toolbar + IToolBarManager toolBarManager = actionBars.getToolBarManager(); + toolBarManager.add(mDebugAction); + toolBarManager.add(new Separator()); + toolBarManager.add(mUpdateThreadAction); + toolBarManager.add(mUpdateHeapAction); + toolBarManager.add(new Separator()); + toolBarManager.add(mKillAppAction); + toolBarManager.add(new Separator()); + toolBarManager.add(mCaptureAction); + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/EmulatorControlView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/EmulatorControlView.java new file mode 100644 index 0000000..ca9a691 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/EmulatorControlView.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmuilib.EmulatorControlPanel; +import com.android.ide.eclipse.ddms.DdmsPlugin; + +import org.eclipse.swt.widgets.Composite; + +public class EmulatorControlView extends SelectionDependentViewPart { + + public static final String ID = + "com.android.ide.eclipse.ddms.views.EmulatorControlView"; //$NON-NLS-1$ + + private EmulatorControlPanel mPanel; + + @Override + public void createPartControl(Composite parent) { + mPanel = new EmulatorControlPanel(DdmsPlugin.getImageLoader()); + mPanel.createPanel(parent); + setSelectionDependentPanel(mPanel); + } + + @Override + public void setFocus() { + mPanel.setFocus(); + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/EventLogView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/EventLogView.java new file mode 100644 index 0000000..3a74e42 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/EventLogView.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmuilib.log.event.EventLogPanel; +import com.android.ide.eclipse.ddms.CommonAction; +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.ImageLoader; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; + +public class EventLogView extends SelectionDependentViewPart { + + private EventLogPanel mLogPanel; + + @Override + public void createPartControl(Composite parent) { + ImageLoader loader = DdmsPlugin.getImageLoader(); + + // create the external actions + CommonAction optionsAction = new CommonAction("Options..."); + optionsAction.setToolTipText("Opens the options panel"); + optionsAction.setImageDescriptor(loader + .loadDescriptor("edit.png")); // $NON-NLS-1$ + + CommonAction clearLogAction = new CommonAction("Clear Log"); + clearLogAction.setToolTipText("Clears the event log"); + clearLogAction.setImageDescriptor(loader + .loadDescriptor("clear.png")); // $NON-NLS-1$ + + CommonAction saveAction = new CommonAction("Save Log"); + saveAction.setToolTipText("Saves the event log"); + saveAction.setImageDescriptor(loader + .loadDescriptor("save.png")); // $NON-NLS-1$ + + CommonAction loadAction = new CommonAction("Load Log"); + loadAction.setToolTipText("Loads an event log"); + loadAction.setImageDescriptor(loader + .loadDescriptor("load.png")); // $NON-NLS-1$ + + CommonAction importBugAction = new CommonAction("Import Bug Report Log"); + importBugAction.setToolTipText("Imports a bug report."); + importBugAction.setImageDescriptor(loader + .loadDescriptor("importBug.png")); // $NON-NLS-1$ + + placeActions(optionsAction, clearLogAction, saveAction, loadAction, importBugAction); + + mLogPanel = new EventLogPanel(DdmsPlugin.getImageLoader()); + mLogPanel.setActions(optionsAction, clearLogAction, saveAction, loadAction, importBugAction); + mLogPanel.createPanel(parent); + setSelectionDependentPanel(mLogPanel); + } + + @Override + public void setFocus() { + mLogPanel.setFocus(); + } + + @Override + public void dispose() { + if (mLogPanel != null) { + mLogPanel.stopEventLog(true); + } + } + + /** + * Places the actions in the toolbar and in the menu. + * @param importBugAction + */ + private void placeActions(IAction optionAction, IAction clearAction, IAction saveAction, + IAction loadAction, CommonAction importBugAction) { + IActionBars actionBars = getViewSite().getActionBars(); + + // first in the menu + IMenuManager menuManager = actionBars.getMenuManager(); + menuManager.add(clearAction); + menuManager.add(new Separator()); + menuManager.add(saveAction); + menuManager.add(loadAction); + menuManager.add(importBugAction); + menuManager.add(new Separator()); + menuManager.add(optionAction); + + // and then in the toolbar + IToolBarManager toolBarManager = actionBars.getToolBarManager(); + toolBarManager.add(clearAction); + toolBarManager.add(new Separator()); + toolBarManager.add(saveAction); + toolBarManager.add(loadAction); + toolBarManager.add(importBugAction); + toolBarManager.add(new Separator()); + toolBarManager.add(optionAction); + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/FileExplorerView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/FileExplorerView.java new file mode 100644 index 0000000..4f0dd2e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/FileExplorerView.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmlib.Client; +import com.android.ddmlib.Device; +import com.android.ddmuilib.explorer.DeviceExplorer; +import com.android.ide.eclipse.ddms.CommonAction; +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.DdmsPlugin.ISelectionListener; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; + +public class FileExplorerView extends ViewPart implements ISelectionListener { + + public static final String ID = + "com.android.ide.eclipse.ddms.views.FileExplorerView"; //$NON-NLS-1$ + + private final static String COLUMN_NAME = + DdmsPlugin.PLUGIN_ID + ".explorer.name"; //$NON-NLS-1S + private final static String COLUMN_SIZE = + DdmsPlugin.PLUGIN_ID + ".explorer.size"; //$NON-NLS-1S + private final static String COLUMN_DATE = + DdmsPlugin.PLUGIN_ID + ".explorer.data"; //$NON-NLS-1S + private final static String COLUMN_TIME = + DdmsPlugin.PLUGIN_ID + ".explorer.time"; //$NON-NLS-1S + private final static String COLUMN_PERMISSIONS = + DdmsPlugin.PLUGIN_ID +".explorer.permissions"; //$NON-NLS-1S + private final static String COLUMN_INFO = + DdmsPlugin.PLUGIN_ID + ".explorer.info"; //$NON-NLS-1$ + + private DeviceExplorer mExplorer; + + public FileExplorerView() { + } + + @Override + public void createPartControl(Composite parent) { + DeviceExplorer.COLUMN_NAME = COLUMN_NAME; + DeviceExplorer.COLUMN_SIZE = COLUMN_SIZE; + DeviceExplorer.COLUMN_DATE = COLUMN_DATE; + DeviceExplorer.COLUMN_TIME = COLUMN_TIME; + DeviceExplorer.COLUMN_PERMISSIONS = COLUMN_PERMISSIONS; + DeviceExplorer.COLUMN_INFO = COLUMN_INFO; + + // device explorer + mExplorer = new DeviceExplorer(); + + + mExplorer.setImages(PlatformUI.getWorkbench() + .getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE), + PlatformUI.getWorkbench() .getSharedImages().getImage( + ISharedImages.IMG_OBJ_FOLDER), + DdmsPlugin.getImageLoader().loadDescriptor("android.png") //$NON-NLS-1$ + .createImage(), + PlatformUI.getWorkbench() .getSharedImages().getImage( + ISharedImages.IMG_OBJ_ELEMENT)); + + // creates the actions + CommonAction pushAction = new CommonAction("Push File...") { + @Override + public void run() { + mExplorer.pushIntoSelection(); + } + }; + pushAction.setToolTipText("Push a file onto the device"); + pushAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor("push.png")); //$NON-NLS-1$ + pushAction.setEnabled(false); + + CommonAction pullAction = new CommonAction("Pull File...") { + @Override + public void run() { + mExplorer.pullSelection(); + } + }; + pullAction.setToolTipText("Pull a file from the device"); + pullAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor("pull.png")); //$NON-NLS-1$ + pullAction.setEnabled(false); + + CommonAction deleteAction = new CommonAction("Delete") { + @Override + public void run() { + mExplorer.deleteSelection(); + } + }; + deleteAction.setToolTipText("Delete the selection"); + deleteAction.setImageDescriptor(DdmsPlugin.getImageLoader() + .loadDescriptor("delete.png")); //$NON-NLS-1$ + deleteAction.setEnabled(false); + + // set up the actions in the explorer + mExplorer.setActions(pushAction, pullAction, deleteAction); + + // and in the ui + IActionBars actionBars = getViewSite().getActionBars(); + IMenuManager menuManager = actionBars.getMenuManager(); + IToolBarManager toolBarManager = actionBars.getToolBarManager(); + + menuManager.add(pullAction); + menuManager.add(pushAction); + menuManager.add(new Separator()); + menuManager.add(deleteAction); + + toolBarManager.add(pullAction); + toolBarManager.add(pushAction); + toolBarManager.add(new Separator()); + toolBarManager.add(deleteAction); + + mExplorer.createPanel(parent); + + DdmsPlugin.getDefault().addSelectionListener(this); + } + + @Override + public void setFocus() { + mExplorer.setFocus(); + } + + /** + * Sent when a new {@link Client} is selected. + * @param selectedClient The selected client. + */ + public void selectionChanged(Client selectedClient) { + // pass + } + + /** + * Sent when a new {@link Device} is selected. + * @param selectedDevice the selected device. + */ + public void selectionChanged(Device selectedDevice) { + mExplorer.switchDevice(selectedDevice); + } + + /** + * Sent when there is no current selection. + */ + public void selectionRemoved() { + + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/HeapView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/HeapView.java new file mode 100644 index 0000000..5745e8e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/HeapView.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmuilib.HeapPanel; + +import org.eclipse.swt.widgets.Composite; + +public class HeapView extends TableView { + + public static final String ID = "com.android.ide.eclipse.ddms.views.HeapView"; //$NON-NLS-1$ + private HeapPanel mPanel; + + public HeapView() { + } + + @Override + public void createPartControl(Composite parent) { + mPanel = new HeapPanel(); + mPanel.createPanel(parent); + + setSelectionDependentPanel(mPanel); + + // listen to focus changes for table(s) of the panel. + setupTableFocusListener(mPanel, parent); + } + + @Override + public void setFocus() { + mPanel.setFocus(); + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java new file mode 100644 index 0000000..d3053f1 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ide.eclipse.ddms.CommonAction; +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.ImageLoader; +import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer; +import com.android.ddmlib.Log.LogLevel; +import com.android.ddmuilib.logcat.LogColors; +import com.android.ddmuilib.logcat.LogFilter; +import com.android.ddmuilib.logcat.LogPanel; +import com.android.ddmuilib.logcat.LogPanel.ILogFilterStorageManager; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.actions.ActionFactory; + +import java.util.ArrayList; + +/** + * The log cat view displays log output from the current device selection. + * + */ +public final class LogCatView extends SelectionDependentViewPart { + + public static final String ID = + "com.android.ide.eclipse.ddms.views.LogCatView"; // $NON-NLS-1$ + + private static final String PREFS_COL_TIME = + DdmsPlugin.PLUGIN_ID + ".logcat.time"; // $NON-NLS-1$ + private static final String PREFS_COL_LEVEL = + DdmsPlugin.PLUGIN_ID + ".logcat.level"; // $NON-NLS-1$ + private static final String PREFS_COL_PID = + DdmsPlugin.PLUGIN_ID + ".logcat.pid"; // $NON-NLS-1$ + private static final String PREFS_COL_TAG = + DdmsPlugin.PLUGIN_ID + ".logcat.tag"; // $NON-NLS-1$ + private static final String PREFS_COL_MESSAGE = + DdmsPlugin.PLUGIN_ID + ".logcat.message"; // $NON-NLS-1$ + + private static final String PREFS_FILTERS = + DdmsPlugin.PLUGIN_ID + ".logcat.filters"; // $NON-NLS-1$ + + private static LogCatView sThis; + private LogPanel mLogPanel; + + private CommonAction mCreateFilterAction; + private CommonAction mDeleteFilterAction; + private CommonAction mEditFilterAction; + private CommonAction mExportAction; + + private CommonAction[] mLogLevelActions; + private String[] mLogLevelIcons = { + "v.png", //$NON-NLS-1S + "d.png", //$NON-NLS-1S + "i.png", //$NON-NLS-1S + "w.png", //$NON-NLS-1S + "e.png", //$NON-NLS-1S + }; + + private Action mClearAction; + + private Clipboard mClipboard; + + /** + * An implementation of {@link ILogFilterStorageManager} to bridge to the eclipse preference + * store, and saves the log filters. + */ + private final class FilterStorage implements ILogFilterStorageManager { + + public LogFilter[] getFilterFromStore() { + String filterPrefs = DdmsPlugin.getDefault().getPreferenceStore().getString( + PREFS_FILTERS); + + // split in a string per filter + String[] filters = filterPrefs.split("\\|"); // $NON-NLS-1$ + + ArrayList<LogFilter> list = + new ArrayList<LogFilter>(filters.length); + + for (String f : filters) { + if (f.length() > 0) { + LogFilter logFilter = new LogFilter(); + if (logFilter.loadFromString(f)) { + list.add(logFilter); + } + } + } + + return list.toArray(new LogFilter[list.size()]); + } + + public void saveFilters(LogFilter[] filters) { + StringBuilder sb = new StringBuilder(); + for (LogFilter f : filters) { + String filterString = f.toString(); + sb.append(filterString); + sb.append('|'); + } + + DdmsPlugin.getDefault().getPreferenceStore().setValue(PREFS_FILTERS, sb.toString()); + } + + public boolean requiresDefaultFilter() { + return true; + } + } + + public LogCatView() { + sThis = this; + LogPanel.PREFS_TIME = PREFS_COL_TIME; + LogPanel.PREFS_LEVEL = PREFS_COL_LEVEL; + LogPanel.PREFS_PID = PREFS_COL_PID; + LogPanel.PREFS_TAG = PREFS_COL_TAG; + LogPanel.PREFS_MESSAGE = PREFS_COL_MESSAGE; + } + + /** + * Returns the singleton instance. + */ + public static LogCatView getInstance() { + return sThis; + } + + /** + * Sets the display font. + * @param font The font. + */ + public static void setFont(Font font) { + if (sThis != null && sThis.mLogPanel != null) { + sThis.mLogPanel.setFont(font); + } + } + + @Override + public void createPartControl(Composite parent) { + Display d = parent.getDisplay(); + LogColors colors = new LogColors(); + + ImageLoader loader = DdmsPlugin.getImageLoader(); + + colors.infoColor = new Color(d, 0, 127, 0); + colors.debugColor = new Color(d, 0, 0, 127); + colors.errorColor = new Color(d, 255, 0, 0); + colors.warningColor = new Color(d, 255, 127, 0); + colors.verboseColor = new Color(d, 0, 0, 0); + + mCreateFilterAction = new CommonAction("Create Filter") { + @Override + public void run() { + mLogPanel.addFilter(); + } + }; + mCreateFilterAction.setToolTipText("Create Filter"); + mCreateFilterAction.setImageDescriptor(loader + .loadDescriptor("add.png")); // $NON-NLS-1$ + + mEditFilterAction = new CommonAction("Edit Filter") { + @Override + public void run() { + mLogPanel.editFilter(); + } + }; + mEditFilterAction.setToolTipText("Edit Filter"); + mEditFilterAction.setImageDescriptor(loader + .loadDescriptor("edit.png")); // $NON-NLS-1$ + + mDeleteFilterAction = new CommonAction("Delete Filter") { + @Override + public void run() { + mLogPanel.deleteFilter(); + } + }; + mDeleteFilterAction.setToolTipText("Delete Filter"); + mDeleteFilterAction.setImageDescriptor(loader + .loadDescriptor("delete.png")); // $NON-NLS-1$ + + mExportAction = new CommonAction("Export Selection As Text...") { + @Override + public void run() { + mLogPanel.save(); + } + }; + mExportAction.setToolTipText("Export Selection As Text..."); + mExportAction.setImageDescriptor(loader.loadDescriptor("save.png")); // $NON-NLS-1$ + + LogLevel[] levels = LogLevel.values(); + mLogLevelActions = new CommonAction[mLogLevelIcons.length]; + for (int i = 0 ; i < mLogLevelActions.length; i++) { + String name = levels[i].getStringValue(); + mLogLevelActions[i] = new CommonAction(name, IAction.AS_CHECK_BOX) { + @Override + public void run() { + // disable the other actions and record current index + for (int i = 0 ; i < mLogLevelActions.length; i++) { + Action a = mLogLevelActions[i]; + if (a == this) { + a.setChecked(true); + + // set the log level + mLogPanel.setCurrentFilterLogLevel(i+2); + } else { + a.setChecked(false); + } + } + } + }; + + mLogLevelActions[i].setToolTipText(name); + mLogLevelActions[i].setImageDescriptor(loader.loadDescriptor(mLogLevelIcons[i])); + } + + mClearAction = new Action("Clear Log") { + @Override + public void run() { + mLogPanel.clear(); + } + }; + mClearAction.setImageDescriptor(loader + .loadDescriptor("clear.png")); // $NON-NLS-1$ + + + // now create the log view + mLogPanel = new LogPanel(loader, colors, new FilterStorage(), LogPanel.FILTER_MANUAL); + mLogPanel.setActions(mDeleteFilterAction, mEditFilterAction, mLogLevelActions); + + // get the font + String fontStr = DdmsPlugin.getDefault().getPreferenceStore().getString( + PreferenceInitializer.ATTR_LOGCAT_FONT); + if (fontStr != null) { + FontData data = new FontData(fontStr); + + if (fontStr != null) { + mLogPanel.setFont(new Font(parent.getDisplay(), data)); + } + } + + mLogPanel.createPanel(parent); + setSelectionDependentPanel(mLogPanel); + + // place the actions. + placeActions(); + + // setup the copy action + mClipboard = new Clipboard(d); + IActionBars actionBars = getViewSite().getActionBars(); + actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), new Action("Copy") { + @Override + public void run() { + mLogPanel.copy(mClipboard); + } + }); + + // setup the select all action + actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), + new Action("Select All") { + @Override + public void run() { + mLogPanel.selectAll(); + } + }); + } + + @Override + public void dispose() { + mLogPanel.stopLogCat(true); + mClipboard.dispose(); + } + + @Override + public void setFocus() { + mLogPanel.setFocus(); + } + + /** + * Place the actions in the ui. + */ + private void placeActions() { + IActionBars actionBars = getViewSite().getActionBars(); + + // first in the menu + IMenuManager menuManager = actionBars.getMenuManager(); + menuManager.add(mCreateFilterAction); + menuManager.add(mEditFilterAction); + menuManager.add(mDeleteFilterAction); + menuManager.add(new Separator()); + menuManager.add(mClearAction); + menuManager.add(new Separator()); + menuManager.add(mExportAction); + + // and then in the toolbar + IToolBarManager toolBarManager = actionBars.getToolBarManager(); + for (CommonAction a : mLogLevelActions) { + toolBarManager.add(a); + } + toolBarManager.add(new Separator()); + toolBarManager.add(mCreateFilterAction); + toolBarManager.add(mEditFilterAction); + toolBarManager.add(mDeleteFilterAction); + toolBarManager.add(new Separator()); + toolBarManager.add(mClearAction); + } + } + diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/NativeHeapView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/NativeHeapView.java new file mode 100644 index 0000000..ed5aacb --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/NativeHeapView.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmuilib.NativeHeapPanel; + +import org.eclipse.swt.widgets.Composite; + +public class NativeHeapView extends TableView { + + public static final String ID = + "com.android.ide.eclipse.ddms.views.NativeHeapView"; // $NON-NLS-1$ + private NativeHeapPanel mPanel; + + public NativeHeapView() { + } + + @Override + public void createPartControl(Composite parent) { + mPanel = new NativeHeapPanel(); + mPanel.createPanel(parent); + + setSelectionDependentPanel(mPanel); + + // listen to focus changes for table(s) of the panel. + setupTableFocusListener(mPanel, parent); + } + + @Override + public void setFocus() { + mPanel.setFocus(); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/SelectionDependentViewPart.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/SelectionDependentViewPart.java new file mode 100644 index 0000000..48b2689 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/SelectionDependentViewPart.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.ide.eclipse.ddms.DdmsPlugin.ISelectionListener; +import com.android.ddmlib.Client; +import com.android.ddmlib.Device; +import com.android.ddmuilib.SelectionDependentPanel; + +import org.eclipse.ui.part.ViewPart; + +/** + * A Workbench {@link ViewPart} that requires {@link Device}/{@link Client} selection notifications + * from {@link DdmsPlugin} through the {@link ISelectionListener} interface. + */ +public abstract class SelectionDependentViewPart extends ViewPart implements ISelectionListener { + + private SelectionDependentPanel mPanel; + + protected final void setSelectionDependentPanel(SelectionDependentPanel panel) { + // remember the panel + mPanel = panel; + + // and add ourself as listener of selection events. + DdmsPlugin.getDefault().addSelectionListener(this); + } + + @Override + public void dispose() { + DdmsPlugin.getDefault().removeSelectionListener(this); + super.dispose(); + } + + /** + * Sent when a new {@link Client} is selected. + * @param selectedClient The selected client. + * + * @see ISelectionListener + */ + public final void selectionChanged(Client selectedClient) { + mPanel.clientSelected(selectedClient); + } + + /** + * Sent when a new {@link Device} is selected. + * @param selectedDevice the selected device. + * + * @see ISelectionListener + */ + public final void selectionChanged(Device selectedDevice) { + mPanel.deviceSelected(selectedDevice); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/TableView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/TableView.java new file mode 100644 index 0000000..0fda35d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/TableView.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmuilib.ITableFocusListener; +import com.android.ddmuilib.TablePanel; +import com.android.ddmuilib.ITableFocusListener.IFocusedTableActivator; + +import org.eclipse.jface.action.Action; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.actions.ActionFactory; + +/** + * Base class for view containing Table that needs to support copy, and select all. + */ +public abstract class TableView extends SelectionDependentViewPart { + + /** Activator for the current Table that has the focus */ + IFocusedTableActivator mActivator = null; + + private Clipboard mClipboard; + + private Action mCopyAction; + private Action mSelectAllAction; + + /** + * Setup the listener for the Table objects of <code>Panel</code>, and setup + * the copy and select all actions. + * @param panel The panel to setup + * @param parent The parent composite of the Panel's content. + */ + void setupTableFocusListener(TablePanel panel, Composite parent) { + panel.setTableFocusListener(new ITableFocusListener() { + public void focusGained(IFocusedTableActivator activator) { + mActivator = activator; + mCopyAction.setEnabled(true); + mSelectAllAction.setEnabled(true); + } + + public void focusLost(IFocusedTableActivator activator) { + if (activator == mActivator) { + mActivator = null; + mCopyAction.setEnabled(false); + mSelectAllAction.setEnabled(false); + } + } + }); + + // setup the copy action + mClipboard = new Clipboard(parent.getDisplay()); + IActionBars actionBars = getViewSite().getActionBars(); + actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), + mCopyAction = new Action("Copy") { + @Override + public void run() { + if (mActivator != null) { + mActivator.copy(mClipboard); + } + } + }); + + // setup the select all action + actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), + mSelectAllAction = new Action("Select All") { + @Override + public void run() { + if (mActivator != null) { + mActivator.selectAll(); + } + } + }); + + } + + @Override + public void dispose() { + super.dispose(); + mClipboard.dispose(); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/ThreadView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/ThreadView.java new file mode 100644 index 0000000..cd24458 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/ThreadView.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.ddms.views; + +import com.android.ddmuilib.ThreadPanel; + +import org.eclipse.swt.widgets.Composite; + +public class ThreadView extends TableView { + + public static final String ID = + "com.android.ide.eclipse.ddms.views.ThreadView"; // $NON-NLS-1$ + private ThreadPanel mPanel; + + public ThreadView() { + } + + @Override + public void createPartControl(Composite parent) { + mPanel = new ThreadPanel(); + mPanel.createPanel(parent); + + setSelectionDependentPanel(mPanel); + + // listen to focus changes for table(s) of the panel. + setupTableFocusListener(mPanel, parent); + } + + @Override + public void setFocus() { + mPanel.setFocus(); + } +} |