blob: e08080bf09aefba28bebf23d2573ceb095e0f6d8 [file] [log] [blame]
/*
* 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);
}
}