diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java | 876 |
1 files changed, 876 insertions, 0 deletions
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 000000000..e08080bf0 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java @@ -0,0 +1,876 @@ +/* + * 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.annotations.NonNull; +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; +import com.android.ddmlib.Client; +import com.android.ddmlib.DdmPreferences; +import com.android.ddmlib.IDevice; +import com.android.ddmlib.Log; +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.ddmuilib.StackTracePanel; +import com.android.ddmuilib.console.DdmConsole; +import com.android.ddmuilib.console.IDdmConsole; +import com.android.ide.eclipse.ddms.i18n.Messages; +import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +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.io.File; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +/** + * The activator class controls the plug-in life cycle + */ +public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeListener, + IUiSelectionListener, com.android.ddmuilib.StackTracePanel.ISourceRevealer { + + + // The plug-in ID + public static final String PLUGIN_ID = "com.android.ide.eclipse.ddms"; //$NON-NLS-1$ + + /** The singleton instance */ + private static DdmsPlugin sPlugin; + + /** Location of the adb command line executable */ + private static String sAdbLocation; + private static String sToolsFolder; + private static String sHprofConverter; + + private boolean mHasDebuggerConnectors; + /** debugger connectors for already running apps. + * Initialized from an extension point. + */ + private IDebuggerConnector[] mDebuggerConnectors; + private ITraceviewLauncher[] mTraceviewLaunchers; + private List<IClientAction> mClientSpecificActions = null; + + /** Console for DDMS log message */ + private MessageConsole mDdmsConsole; + + private IDevice mCurrentDevice; + private Client mCurrentClient; + private boolean mListeningToUiSelection = false; + + private final ArrayList<ISelectionListener> mListeners = new ArrayList<ISelectionListener>(); + + private Color mRed; + + + /** + * Classes which implement this interface provide methods that deals + * with {@link IDevice} 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 IDevice} is selected. + * @param selectedDevice the selected device. If null, no devices are selected. + */ + public void selectionChanged(IDevice 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() { + @Override + public void run() { + errorConsoleStream.setColor(mRed); + } + }); + + // set up the ddms log to use the ddms console. + Log.setLogOutput(new ILogOutput() { + @Override + public void printLog(LogLevel logLevel, String tag, String message) { + if (logLevel.getPriority() >= LogLevel.ERROR.getPriority()) { + printToStream(errorConsoleStream, tag, message); + showConsoleView(mDdmsConsole); + } else { + printToStream(consoleStream, tag, message); + } + } + + @Override + 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() { + @Override + public void run() { + Shell shell = display.getActiveShell(); + if (logLevel == LogLevel.ERROR) { + MessageDialog.openError(shell, tag, message); + } else { + MessageDialog.openWarning(shell, tag, message); + } + } + }); + } + + }); + + // set up the ddms console to use this objects + DdmConsole.setConsole(new IDdmConsole() { + @Override + public void printErrorToConsole(String message) { + printToStream(errorConsoleStream, null, message); + showConsoleView(mDdmsConsole); + } + @Override + public void printErrorToConsole(String[] messages) { + for (String m : messages) { + printToStream(errorConsoleStream, null, m); + } + showConsoleView(mDdmsConsole); + } + @Override + public void printToConsole(String message) { + printToStream(consoleStream, null, message); + } + @Override + public void printToConsole(String[] messages) { + for (String m : messages) { + printToStream(consoleStream, null, m); + } + } + }); + + // set the listener for the preference change + eclipseStore.addPropertyChangeListener(new IPropertyChangeListener() { + @Override + 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)); + } else if (PreferenceInitializer.ATTR_TIME_OUT.equals(property)) { + DdmPreferences.setTimeOut( + eclipseStore.getInt(PreferenceInitializer.ATTR_TIME_OUT)); + } else if (PreferenceInitializer.ATTR_USE_ADBHOST.equals(property)) { + DdmPreferences.setUseAdbHost( + eclipseStore.getBoolean(PreferenceInitializer.ATTR_USE_ADBHOST)); + } else if (PreferenceInitializer.ATTR_ADBHOST_VALUE.equals(property)) { + DdmPreferences.setAdbHostValue( + eclipseStore.getString(PreferenceInitializer.ATTR_ADBHOST_VALUE)); + } + } + }); + + // do some last initializations + + // set the preferences. + PreferenceInitializer.setupPreferences(); + + // this class is set as the main source revealer and will look at all the implementations + // of the extension point. see #reveal(String, String, int) + StackTracePanel.setSourceRevealer(this); + + /* + * Load the extension point implementations. + * The first step is to load the IConfigurationElement representing the implementations. + * The 2nd step is to use these objects to instantiate the implementation classes. + * + * Because the 2nd step will trigger loading the plug-ins providing the implementations, + * and those plug-ins could access DDMS classes (like ADT), this 2nd step should be done + * in a Job to ensure that DDMS is loaded, so that the other plug-ins can load. + * + * Both steps could be done in the 2nd step but some of DDMS UI rely on knowing if there + * is an implementation or not (DeviceView), so we do the first steps in start() and, in + * some case, record it. + * + */ + + // get the IConfigurationElement for the debuggerConnector right away. + final IConfigurationElement[] dcce = findConfigElements( + "com.android.ide.eclipse.ddms.debuggerConnector"); //$NON-NLS-1$ + mHasDebuggerConnectors = dcce.length > 0; + + // get the other configElements and instantiante them in a Job. + new Job(Messages.DdmsPlugin_DDMS_Post_Create_Init) { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + // init the lib + AndroidDebugBridge.init(true /* debugger support */); + + // get the available adb locators + IConfigurationElement[] elements = findConfigElements( + "com.android.ide.eclipse.ddms.toolsLocator"); //$NON-NLS-1$ + + IToolsLocator[] locators = instantiateToolsLocators(elements); + + for (IToolsLocator locator : locators) { + try { + String adbLocation = locator.getAdbLocation(); + String traceviewLocation = locator.getTraceViewLocation(); + String hprofConvLocation = locator.getHprofConvLocation(); + if (adbLocation != null && traceviewLocation != null && + hprofConvLocation != null) { + // checks if the location is valid. + if (setToolsLocation(adbLocation, hprofConvLocation, + traceviewLocation)) { + + AndroidDebugBridge.createBridge(sAdbLocation, + true /* forceNewBridge */); + + // no need to look at the other locators. + break; + } + } + } catch (Throwable t) { + // ignore, we'll just not use this implementation. + } + } + + // get the available debugger connectors + mDebuggerConnectors = instantiateDebuggerConnectors(dcce); + + // get the available Traceview Launchers. + elements = findConfigElements("com.android.ide.eclipse.ddms.traceviewLauncher"); //$NON-NLS-1$ + mTraceviewLaunchers = instantiateTraceviewLauncher(elements); + + return Status.OK_STATUS; + } catch (CoreException e) { + return e.getStatus(); + } + } + }.schedule(); + } + + private void showConsoleView(MessageConsole console) { + ConsolePlugin.getDefault().getConsoleManager().showConsoleView(console); + } + + + /** Obtain a list of configuration elements that extend the given extension point. */ + IConfigurationElement[] findConfigElements(String extensionPointId) { + // get the adb location from an implementation of the ADB Locator extension point. + IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); + IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(extensionPointId); + if (extensionPoint != null) { + return extensionPoint.getConfigurationElements(); + } + + // shouldn't happen or it means the plug-in is broken. + return new IConfigurationElement[0]; + } + + /** + * Finds if any other plug-in is extending the exposed Extension Point called adbLocator. + * + * @return an array of all locators found, or an empty array if none were found. + */ + private IToolsLocator[] instantiateToolsLocators(IConfigurationElement[] configElements) + throws CoreException { + ArrayList<IToolsLocator> list = new ArrayList<IToolsLocator>(); + + if (configElements.length > 0) { + // only use the first one, ignore the others. + IConfigurationElement configElement = configElements[0]; + + // instantiate the class + Object obj = configElement.createExecutableExtension("class"); //$NON-NLS-1$ + if (obj instanceof IToolsLocator) { + list.add((IToolsLocator) obj); + } + } + + return list.toArray(new IToolsLocator[list.size()]); + } + + /** + * Finds if any other plug-in is extending the exposed Extension Point called debuggerConnector. + * + * @return an array of all locators found, or an empty array if none were found. + */ + private IDebuggerConnector[] instantiateDebuggerConnectors( + IConfigurationElement[] configElements) throws CoreException { + ArrayList<IDebuggerConnector> list = new ArrayList<IDebuggerConnector>(); + + if (configElements.length > 0) { + // only use the first one, ignore the others. + IConfigurationElement configElement = configElements[0]; + + // instantiate the class + Object obj = configElement.createExecutableExtension("class"); //$NON-NLS-1$ + if (obj instanceof IDebuggerConnector) { + list.add((IDebuggerConnector) obj); + } + } + + return list.toArray(new IDebuggerConnector[list.size()]); + } + + /** + * Finds if any other plug-in is extending the exposed Extension Point called traceviewLauncher. + * + * @return an array of all locators found, or an empty array if none were found. + */ + private ITraceviewLauncher[] instantiateTraceviewLauncher( + IConfigurationElement[] configElements) + throws CoreException { + ArrayList<ITraceviewLauncher> list = new ArrayList<ITraceviewLauncher>(); + + if (configElements.length > 0) { + // only use the first one, ignore the others. + IConfigurationElement configElement = configElements[0]; + + // instantiate the class + Object obj = configElement.createExecutableExtension("class"); //$NON-NLS-1$ + if (obj instanceof ITraceviewLauncher) { + list.add((ITraceviewLauncher) obj); + } + } + + return list.toArray(new ITraceviewLauncher[list.size()]); + } + + /** + * Returns the classes that implement {@link IClientAction} in each of the extensions that + * extend clientAction extension point. + * @throws CoreException + */ + private List<IClientAction> instantiateClientSpecificActions(IConfigurationElement[] elements) + throws CoreException { + if (elements == null || elements.length == 0) { + return Collections.emptyList(); + } + + List<IClientAction> extensions = new ArrayList<IClientAction>(1); + + for (IConfigurationElement e : elements) { + Object o = e.createExecutableExtension("class"); //$NON-NLS-1$ + if (o instanceof IClientAction) { + extensions.add((IClientAction) o); + } + } + + return extensions; + } + + 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; + } + + public static String getAdb() { + return sAdbLocation; + } + + public static File getPlatformToolsFolder() { + return new File(sAdbLocation).getParentFile(); + } + + public static String getToolsFolder() { + return sToolsFolder; + } + + public static String getHprofConverter() { + return sHprofConverter; + } + + /** + * Stores the adb location. This returns true if the location is an existing file. + */ + private static boolean setToolsLocation(String adbLocation, String hprofConvLocation, + String traceViewLocation) { + + File adb = new File(adbLocation); + File hprofConverter = new File(hprofConvLocation); + File traceview = new File(traceViewLocation); + + String missing = ""; + if (adb.isFile() == false) { + missing += adb.getAbsolutePath() + " "; + } + if (hprofConverter.isFile() == false) { + missing += hprofConverter.getAbsolutePath() + " "; + } + if (traceview.isFile() == false) { + missing += traceview.getAbsolutePath() + " "; + } + + if (missing.length() > 0) { + String msg = String.format("DDMS files not found: %1$s", missing); + Log.e("DDMS", msg); + Status status = new Status(IStatus.ERROR, PLUGIN_ID, msg, null /*exception*/); + getDefault().getLog().log(status); + return false; + } + + sAdbLocation = adbLocation; + sHprofConverter = hprofConverter.getAbsolutePath(); + DdmUiPreferences.setTraceviewLocation(traceview.getAbsolutePath()); + + sToolsFolder = traceview.getParent(); + + return true; + } + + /** + * 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 setToolsLocation(String adbLocation, boolean startAdb, + String hprofConvLocation, String traceViewLocation) { + + if (setToolsLocation(adbLocation, hprofConvLocation, traceViewLocation)) { + // starts the server in a thread in case this is blocking. + if (startAdb) { + new Thread() { + @Override + public void run() { + // create and start the bridge + try { + AndroidDebugBridge.createBridge(sAdbLocation, + false /* forceNewBridge */); + } catch (Throwable t) { + Status status = new Status(IStatus.ERROR, PLUGIN_ID, + "Failed to create AndroidDebugBridge", t); + getDefault().getLog().log(status); + } + } + }.start(); + } + } + } + + /** + * Returns whether there are implementations of the debuggerConnectors extension point. + * <p/> + * This is guaranteed to return the correct value as soon as the plug-in is loaded. + */ + public boolean hasDebuggerConnectors() { + return mHasDebuggerConnectors; + } + + /** + * Returns the implementations of {@link IDebuggerConnector}. + * <p/> + * There may be a small amount of time right after the plug-in load where this can return + * null even if there are implementation. + * <p/> + * Since the use of the implementation likely require user input, the UI can use + * {@link #hasDebuggerConnectors()} to know if there are implementations before they are loaded. + */ + public IDebuggerConnector[] getDebuggerConnectors() { + return mDebuggerConnectors; + } + + 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(IDevice) + */ + @Override + public void deviceConnected(IDevice 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(IDevice) + */ + @Override + public void deviceDisconnected(IDevice 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 + IDevice[] devices = bridge.getDevices(); + + // check if we still have devices + if (devices.length == 0) { + handleDefaultSelection((IDevice)null); + } else { + handleDefaultSelection(devices[0]); + } + } else { + handleDefaultSelection((IDevice)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(IDevice) + */ + @Override + public void deviceChanged(IDevice 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 IDevice} 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. + */ + @Override + public synchronized void selectionChanged(IDevice 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 IDevice} and {@link Client}. + * @param device the selected device + */ + private void handleDefaultSelection(final IDevice 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() { + @Override + 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); + if (!dateTag.endsWith(" ")) { + stream.print(" "); //$NON-NLS-1$ + } + 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(Messages.DdmsPlugin_Message_Tag_Mask_1, c); + } + + return String.format(Messages.DdmsPlugin_Message_Tag_Mask_2, c, tag); + } + + /** + * Implementation of com.android.ddmuilib.StackTracePanel.ISourceRevealer. + */ + @Override + public void reveal(String applicationName, String className, int line) { + JavaSourceRevealer.reveal(applicationName, className, line); + } + + public boolean launchTraceview(String osPath) { + if (mTraceviewLaunchers != null) { + for (ITraceviewLauncher launcher : mTraceviewLaunchers) { + try { + if (launcher.openFile(osPath)) { + return true; + } + } catch (Throwable t) { + // ignore, we'll just not use this implementation. + } + } + } + + return false; + } + + /** + * Returns the list of clients that extend the clientAction extension point. + */ + @NonNull + public synchronized List<IClientAction> getClientSpecificActions() { + if (mClientSpecificActions == null) { + // get available client specific action extensions + IConfigurationElement[] elements = + findConfigElements("com.android.ide.eclipse.ddms.clientAction"); //$NON-NLS-1$ + try { + mClientSpecificActions = instantiateClientSpecificActions(elements); + } catch (CoreException e) { + mClientSpecificActions = Collections.emptyList(); + } + } + + return mClientSpecificActions; + } + + private LogCatMonitor mLogCatMonitor; + public void startLogCatMonitor(IDevice device) { + if (mLogCatMonitor == null) { + mLogCatMonitor = new LogCatMonitor(getDebuggerConnectors(), getPreferenceStore()); + } + + mLogCatMonitor.monitorDevice(device); + } + + /** Returns an image descriptor for the image file at the given plug-in relative path */ + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } +} |