| /* |
| * 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); |
| } |
| } |