blob: c70c388030c130f7fe27879f22e108776ec682ca [file] [log] [blame]
/*
* 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.AndroidDebugBridge;
import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
import com.android.ddmlib.Client;
import com.android.ddmlib.ClientData;
import com.android.ddmlib.ClientData.IHprofDumpHandler;
import com.android.ddmlib.ClientData.MethodProfilingStatus;
import com.android.ddmlib.CollectingOutputReceiver;
import com.android.ddmlib.DdmPreferences;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.SyncException;
import com.android.ddmlib.SyncService;
import com.android.ddmlib.SyncService.ISyncProgressMonitor;
import com.android.ddmlib.TimeoutException;
import com.android.ddmuilib.DevicePanel;
import com.android.ddmuilib.DevicePanel.IUiSelectionListener;
import com.android.ddmuilib.ImageLoader;
import com.android.ddmuilib.ScreenShotDialog;
import com.android.ddmuilib.SyncProgressHelper;
import com.android.ddmuilib.SyncProgressHelper.SyncRunnable;
import com.android.ddmuilib.handler.BaseFileHandler;
import com.android.ddmuilib.handler.MethodProfilingHandler;
import com.android.ide.eclipse.ddms.DdmsPlugin;
import com.android.ide.eclipse.ddms.IClientAction;
import com.android.ide.eclipse.ddms.IDebuggerConnector;
import com.android.ide.eclipse.ddms.editors.UiAutomatorViewer;
import com.android.ide.eclipse.ddms.i18n.Messages;
import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer;
import com.android.ide.eclipse.ddms.systrace.ISystraceOptions;
import com.android.ide.eclipse.ddms.systrace.ISystraceOptionsDialog;
import com.android.ide.eclipse.ddms.systrace.SystraceOptionsDialogV1;
import com.android.ide.eclipse.ddms.systrace.SystraceOptionsDialogV2;
import com.android.ide.eclipse.ddms.systrace.SystraceOutputParser;
import com.android.ide.eclipse.ddms.systrace.SystraceTask;
import com.android.ide.eclipse.ddms.systrace.SystraceVersionDetector;
import com.android.uiautomator.UiAutomatorHelper;
import com.android.uiautomator.UiAutomatorHelper.UiAutomatorException;
import com.android.uiautomator.UiAutomatorHelper.UiAutomatorResult;
import com.google.common.io.Files;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
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.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
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.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.ViewPart;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class DeviceView extends ViewPart implements IUiSelectionListener, IClientChangeListener {
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 static DeviceView sThis;
private Shell mParentShell;
private DevicePanel mDeviceList;
private Action mResetAdbAction;
private Action mCaptureAction;
private Action mViewUiAutomatorHierarchyAction;
private Action mSystraceAction;
private Action mUpdateThreadAction;
private Action mUpdateHeapAction;
private Action mGcAction;
private Action mKillAppAction;
private Action mDebugAction;
private Action mHprofAction;
private Action mTracingAction;
private ImageDescriptor mTracingStartImage;
private ImageDescriptor mTracingStopImage;
public class HProfHandler extends BaseFileHandler implements IHprofDumpHandler {
public final static String ACTION_SAVE = "hprof.save"; //$NON-NLS-1$
public final static String ACTION_OPEN = "hprof.open"; //$NON-NLS-1$
public final static String DOT_HPROF = ".hprof"; //$NON-NLS-1$
HProfHandler(Shell parentShell) {
super(parentShell);
}
@Override
protected String getDialogTitle() {
return Messages.DeviceView_HPROF_Error;
}
@Override
public void onEndFailure(final Client client, final String message) {
mParentShell.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
try {
displayErrorFromUiThread(
Messages.DeviceView_Unable_Create_HPROF_For_Application,
client.getClientData().getClientDescription(),
message != null ? message + "\n\n" : ""); //$NON-NLS-1$ //$NON-NLS-2$
} finally {
// this will make sure the dump hprof button is
// re-enabled for the
// current selection. as the client is finished dumping
// an hprof file
doSelectionChanged(mDeviceList.getSelectedClient());
}
}
});
}
@Override
public void onSuccess(final String remoteFilePath, final Client client) {
mParentShell.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
final IDevice device = client.getDevice();
try {
// get the sync service to pull the HPROF file
final SyncService sync = client.getDevice().getSyncService();
if (sync != null) {
// get from the preference what action to take
IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore();
String value = store.getString(PreferenceInitializer.ATTR_HPROF_ACTION);
if (ACTION_OPEN.equals(value)) {
File temp = File.createTempFile("android", DOT_HPROF); //$NON-NLS-1$
final String tempPath = temp.getAbsolutePath();
SyncProgressHelper.run(new SyncRunnable() {
@Override
public void run(ISyncProgressMonitor monitor)
throws SyncException, IOException,
TimeoutException {
sync.pullFile(remoteFilePath, tempPath, monitor);
}
@Override
public void close() {
sync.close();
}
},
String.format(Messages.DeviceView_Pulling_From_Device,
remoteFilePath),
mParentShell);
open(tempPath);
} else {
// default action is ACTION_SAVE
promptAndPull(sync,
client.getClientData().getClientDescription() + DOT_HPROF,
remoteFilePath, Messages.DeviceView_Save_HPROF_File);
}
} else {
displayErrorFromUiThread(
Messages.DeviceView_Unable_Download_HPROF_From_Device_One_Param_First_Message,
device.getSerialNumber());
}
} catch (SyncException e) {
if (e.wasCanceled() == false) {
displayErrorFromUiThread(
Messages.DeviceView_Unable_Download_HPROF_From_Device_Two_Param,
device.getSerialNumber(), e.getMessage());
}
} catch (Exception e) {
displayErrorFromUiThread(
Messages.DeviceView_Unable_Download_HPROF_From_Device_One_Param_Second_Message,
device.getSerialNumber());
} finally {
// this will make sure the dump hprof button is
// re-enabled for the
// current selection. as the client is finished dumping
// an hprof file
doSelectionChanged(mDeviceList.getSelectedClient());
}
}
});
}
@Override
public void onSuccess(final byte[] data, final Client client) {
mParentShell.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
// get from the preference what action to take
IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore();
String value = store.getString(PreferenceInitializer.ATTR_HPROF_ACTION);
if (ACTION_OPEN.equals(value)) {
try {
// no need to give an extension since we're going to
// convert the
// file anyway after.
File tempFile = saveTempFile(data, null /* extension */);
open(tempFile.getAbsolutePath());
} catch (Exception e) {
String errorMsg = e.getMessage();
displayErrorFromUiThread(
Messages.DeviceView_Failed_To_Save_HPROF_Data,
errorMsg != null ? ":\n" + errorMsg : "."); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
// default action is ACTION_SAVE
promptAndSave(client.getClientData().getClientDescription() + DOT_HPROF,
data, Messages.DeviceView_Save_HPROF_File);
}
}
});
}
private void open(String path) throws IOException, InterruptedException, PartInitException {
// make a temp file to convert the hprof into something
// readable by normal tools
File temp = File.createTempFile("android", DOT_HPROF); //$NON-NLS-1$
String tempPath = temp.getAbsolutePath();
String[] command = new String[3];
command[0] = DdmsPlugin.getHprofConverter();
command[1] = path;
command[2] = tempPath;
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
IFileStore fileStore = EFS.getLocalFileSystem().getStore(new Path(tempPath));
if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) {
// before we open the file in an editor window, we make sure the
// current
// workbench page has an editor area (typically the ddms
// perspective doesn't).
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
if (page == null) {
return;
}
if (page.isEditorAreaVisible() == false) {
IAdaptable input;
input = page.getInput();
try {
workbench.showPerspective("org.eclipse.debug.ui.DebugPerspective", //$NON-NLS-1$
window, input);
} catch (WorkbenchException e) {
}
}
IDE.openEditorOnFileStore(page, fileStore);
}
}
}
public DeviceView() {
// the view is declared with allowMultiple="false" so we
// can safely do this.
sThis = this;
}
public static DeviceView getInstance() {
return sThis;
}
@Override
public void createPartControl(Composite parent) {
mParentShell = parent.getShell();
ImageLoader loader = ImageLoader.getDdmUiLibLoader();
mDeviceList = new DevicePanel(USE_SELECTED_DEBUG_PORT);
mDeviceList.createPanel(parent);
mDeviceList.addSelectionListener(this);
DdmsPlugin plugin = DdmsPlugin.getDefault();
mDeviceList.addSelectionListener(plugin);
plugin.setListeningState(true);
mCaptureAction = new Action(Messages.DeviceView_Screen_Capture) {
@Override
public void run() {
ScreenShotDialog dlg = new ScreenShotDialog(
DdmsPlugin.getDisplay().getActiveShell());
dlg.open(mDeviceList.getSelectedDevice());
}
};
mCaptureAction.setToolTipText(Messages.DeviceView_Screen_Capture_Tooltip);
mCaptureAction.setImageDescriptor(loader.loadDescriptor("capture.png")); //$NON-NLS-1$
mViewUiAutomatorHierarchyAction = new Action("Dump View Hierarchy for UI Automator") {
@Override
public void run() {
takeUiAutomatorSnapshot(mDeviceList.getSelectedDevice(),
DdmsPlugin.getDisplay().getActiveShell());
}
};
mViewUiAutomatorHierarchyAction.setToolTipText("Dump View Hierarchy for UI Automator");
mViewUiAutomatorHierarchyAction.setImageDescriptor(
DdmsPlugin.getImageDescriptor("icons/uiautomator.png")); //$NON-NLS-1$
mSystraceAction = new Action("Capture System Wide Trace") {
@Override
public void run() {
launchSystrace(mDeviceList.getSelectedDevice(),
DdmsPlugin.getDisplay().getActiveShell());
}
};
mSystraceAction.setToolTipText("Capture system wide trace using Android systrace");
mSystraceAction.setImageDescriptor(
DdmsPlugin.getImageDescriptor("icons/systrace.png")); //$NON-NLS-1$
mSystraceAction.setEnabled(true);
mResetAdbAction = new Action(Messages.DeviceView_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() {
@Override
public void run() {
Shell shell = display.getActiveShell();
MessageDialog.openError(shell, Messages.DeviceView_ADB_Error,
Messages.DeviceView_ADB_Failed_Restart);
}
});
}
}
}
};
mResetAdbAction.setToolTipText(Messages.DeviceView_Reset_ADB_Host_Deamon);
mResetAdbAction.setImageDescriptor(PlatformUI.getWorkbench()
.getSharedImages().getImageDescriptor(
ISharedImages.IMG_OBJS_WARN_TSK));
mKillAppAction = new Action() {
@Override
public void run() {
mDeviceList.killSelectedClient();
}
};
mKillAppAction.setText(Messages.DeviceView_Stop_Process);
mKillAppAction.setToolTipText(Messages.DeviceView_Stop_Process_Tooltip);
mKillAppAction.setImageDescriptor(loader.loadDescriptor(DevicePanel.ICON_HALT));
mGcAction = new Action() {
@Override
public void run() {
mDeviceList.forceGcOnSelectedClient();
}
};
mGcAction.setText(Messages.DeviceView_Cause_GC);
mGcAction.setToolTipText(Messages.DeviceView_Cause_GC_Tooltip);
mGcAction.setImageDescriptor(loader.loadDescriptor(DevicePanel.ICON_GC));
mHprofAction = new Action() {
@Override
public void run() {
mDeviceList.dumpHprof();
doSelectionChanged(mDeviceList.getSelectedClient());
}
};
mHprofAction.setText(Messages.DeviceView_Dump_HPROF_File);
mHprofAction.setToolTipText(Messages.DeviceView_Dump_HPROF_File_Tooltip);
mHprofAction.setImageDescriptor(loader.loadDescriptor(DevicePanel.ICON_HPROF));
mUpdateHeapAction = new Action(Messages.DeviceView_Update_Heap, IAction.AS_CHECK_BOX) {
@Override
public void run() {
boolean enable = mUpdateHeapAction.isChecked();
mDeviceList.setEnabledHeapOnSelectedClient(enable);
}
};
mUpdateHeapAction.setToolTipText(Messages.DeviceView_Update_Heap_Tooltip);
mUpdateHeapAction.setImageDescriptor(loader.loadDescriptor(DevicePanel.ICON_HEAP));
mUpdateThreadAction = new Action(Messages.DeviceView_Threads, IAction.AS_CHECK_BOX) {
@Override
public void run() {
boolean enable = mUpdateThreadAction.isChecked();
mDeviceList.setEnabledThreadOnSelectedClient(enable);
}
};
mUpdateThreadAction.setToolTipText(Messages.DeviceView_Threads_Tooltip);
mUpdateThreadAction.setImageDescriptor(loader.loadDescriptor(DevicePanel.ICON_THREAD));
mTracingAction = new Action() {
@Override
public void run() {
mDeviceList.toggleMethodProfiling();
}
};
mTracingAction.setText(Messages.DeviceView_Start_Method_Profiling);
mTracingAction.setToolTipText(Messages.DeviceView_Start_Method_Profiling_Tooltip);
mTracingStartImage = loader.loadDescriptor(DevicePanel.ICON_TRACING_START);
mTracingStopImage = loader.loadDescriptor(DevicePanel.ICON_TRACING_STOP);
mTracingAction.setImageDescriptor(mTracingStartImage);
mDebugAction = new Action(Messages.DeviceView_Debug_Process) {
@Override
public void run() {
if (DdmsPlugin.getDefault().hasDebuggerConnectors()) {
Client currentClient = mDeviceList.getSelectedClient();
if (currentClient != null) {
ClientData clientData = currentClient.getClientData();
// make sure the client can be debugged
switch (clientData.getDebuggerConnectionStatus()) {
case ERROR: {
Display display = DdmsPlugin.getDisplay();
Shell shell = display.getActiveShell();
MessageDialog.openError(shell,
Messages.DeviceView_Debug_Process_Title,
Messages.DeviceView_Process_Debug_Already_In_Use);
return;
}
case ATTACHED: {
Display display = DdmsPlugin.getDisplay();
Shell shell = display.getActiveShell();
MessageDialog.openError(shell,
Messages.DeviceView_Debug_Process_Title,
Messages.DeviceView_Process_Already_Being_Debugged);
return;
}
}
// get the name of the client
String packageName = clientData.getClientDescription();
if (packageName != null) {
// try all connectors till one returns true.
IDebuggerConnector[] connectors =
DdmsPlugin.getDefault().getDebuggerConnectors();
if (connectors != null) {
for (IDebuggerConnector connector : connectors) {
try {
if (connector.connectDebugger(packageName,
currentClient.getDebuggerListenPort(),
DdmPreferences.getSelectedDebugPort())) {
return;
}
} catch (Throwable t) {
// ignore, we'll just not use this
// implementation
}
}
}
// 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, Messages.DeviceView_Debug_Process_Title,
String.format(
Messages.DeviceView_Debug_Session_Failed,
packageName));
}
}
}
}
};
mDebugAction.setToolTipText(Messages.DeviceView_Debug_Process_Tooltip);
mDebugAction.setImageDescriptor(loader.loadDescriptor("debug-attach.png")); //$NON-NLS-1$
mDebugAction.setEnabled(DdmsPlugin.getDefault().hasDebuggerConnectors());
placeActions();
// disabling all action buttons
selectionChanged(null, null);
ClientData.setHprofDumpHandler(new HProfHandler(mParentShell));
AndroidDebugBridge.addClientChangeListener(this);
ClientData.setMethodProfilingHandler(new MethodProfilingHandler(mParentShell) {
@Override
protected void open(String tempPath) {
if (DdmsPlugin.getDefault().launchTraceview(tempPath) == false) {
super.open(tempPath);
}
}
});
}
private void takeUiAutomatorSnapshot(final IDevice device, final Shell shell) {
ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
try {
dialog.run(true, false, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
UiAutomatorResult result = null;
try {
result = UiAutomatorHelper.takeSnapshot(device, monitor);
} catch (UiAutomatorException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
UiAutomatorViewer.openEditor(result);
}
});
} catch (Exception e) {
Throwable t = e;
if (e instanceof InvocationTargetException) {
t = ((InvocationTargetException) e).getTargetException();
}
Status s = new Status(IStatus.ERROR, DdmsPlugin.PLUGIN_ID,
"Error obtaining UI hierarchy", t);
ErrorDialog.openError(shell, "UI Automator",
"Unexpected error while obtaining UI hierarchy", s);
}
};
private void launchSystrace(final IDevice device, final Shell parentShell) {
final File systraceAssets = new File(DdmsPlugin.getPlatformToolsFolder(), "systrace"); //$NON-NLS-1$
if (!systraceAssets.isDirectory()) {
MessageDialog.openError(parentShell, "Systrace",
"Updated version of platform-tools (18.0.1 or greater) is required.\n"
+ "Please update your platform-tools using SDK Manager.");
return;
}
SystraceVersionDetector detector = new SystraceVersionDetector(device);
try {
new ProgressMonitorDialog(parentShell).run(true, false, detector);
} catch (InvocationTargetException e) {
MessageDialog.openError(parentShell,
"Systrace",
"Unexpected error while detecting atrace version: " + e);
return;
} catch (InterruptedException e) {
return;
}
final ISystraceOptionsDialog dlg;
if (detector.getVersion() == SystraceVersionDetector.SYSTRACE_V1) {
dlg = new SystraceOptionsDialogV1(parentShell);
} else {
Client[] clients = device.getClients();
List<String> apps = new ArrayList<String>(clients.length);
for (int i = 0; i < clients.length; i++) {
String name = clients[i].getClientData().getClientDescription();
if (name != null && !name.isEmpty()) {
apps.add(name);
}
}
dlg = new SystraceOptionsDialogV2(parentShell, detector.getTags(), apps);
}
if (dlg.open() != SystraceOptionsDialogV1.OK) {
return;
}
final ISystraceOptions options = dlg.getSystraceOptions();
// set trace tag if necessary:
// adb shell setprop debug.atrace.tags.enableflags <tag>
String tag = options.getTags();
if (tag != null) {
CountDownLatch setTagLatch = new CountDownLatch(1);
CollectingOutputReceiver receiver = new CollectingOutputReceiver(setTagLatch);
try {
String cmd = "setprop debug.atrace.tags.enableflags " + tag;
device.executeShellCommand(cmd, receiver);
setTagLatch.await(5, TimeUnit.SECONDS);
} catch (Exception e) {
MessageDialog.openError(parentShell,
"Systrace",
"Unexpected error while setting trace tags: " + e);
return;
}
String shellOutput = receiver.getOutput();
if (shellOutput.contains("Error type")) { //$NON-NLS-1$
throw new RuntimeException(receiver.getOutput());
}
}
// obtain the output of "adb shell atrace <trace-options>" and generate the html file
ProgressMonitorDialog d = new ProgressMonitorDialog(parentShell);
try {
d.run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
boolean COMPRESS_DATA = true;
monitor.setTaskName("Collecting Trace Information");
final String atraceOptions = options.getOptions()
+ (COMPRESS_DATA ? " -z" : "");
SystraceTask task = new SystraceTask(device, atraceOptions);
Thread t = new Thread(task, "Systrace Output Receiver");
t.start();
// check if the user has cancelled tracing every so often
while (true) {
t.join(1000);
if (t.isAlive()) {
if (monitor.isCanceled()) {
task.cancel();
return;
}
} else {
break;
}
}
if (task.getError() != null) {
throw new RuntimeException(task.getError());
}
monitor.setTaskName("Saving trace information");
SystraceOutputParser parser = new SystraceOutputParser(
COMPRESS_DATA,
SystraceOutputParser.getJs(systraceAssets),
SystraceOutputParser.getCss(systraceAssets),
SystraceOutputParser.getHtmlPrefix(systraceAssets),
SystraceOutputParser.getHtmlSuffix(systraceAssets));
parser.parse(task.getAtraceOutput());
String html = parser.getSystraceHtml();
try {
Files.write(html.getBytes(), new File(dlg.getTraceFilePath()));
} catch (IOException e) {
throw new InvocationTargetException(e);
}
}
});
} catch (InvocationTargetException e) {
ErrorDialog.openError(parentShell, "Systrace",
"Unable to collect system trace.",
new Status(Status.ERROR,
DdmsPlugin.PLUGIN_ID,
"Unexpected error while collecting system trace.",
e.getCause()));
} catch (InterruptedException ignore) {
}
}
@Override
public void setFocus() {
mDeviceList.setFocus();
}
/**
* 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 void selectionChanged(IDevice 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(DdmsPlugin.getDefault().hasDebuggerConnectors());
mKillAppAction.setEnabled(true);
mGcAction.setEnabled(true);
mUpdateHeapAction.setEnabled(true);
mUpdateHeapAction.setChecked(selectedClient.isHeapUpdateEnabled());
mUpdateThreadAction.setEnabled(true);
mUpdateThreadAction.setChecked(selectedClient.isThreadUpdateEnabled());
ClientData data = selectedClient.getClientData();
if (data.hasFeature(ClientData.FEATURE_HPROF)) {
mHprofAction.setEnabled(data.hasPendingHprofDump() == false);
mHprofAction.setToolTipText(Messages.DeviceView_Dump_HPROF_File);
} else {
mHprofAction.setEnabled(false);
mHprofAction
.setToolTipText(Messages.DeviceView_Dump_HPROF_File_Not_Supported_By_VM);
}
if (data.hasFeature(ClientData.FEATURE_PROFILING)) {
mTracingAction.setEnabled(true);
if (data.getMethodProfilingStatus() == MethodProfilingStatus.TRACER_ON
|| data.getMethodProfilingStatus() == MethodProfilingStatus.SAMPLER_ON) {
mTracingAction
.setToolTipText(Messages.DeviceView_Stop_Method_Profiling_Tooltip);
mTracingAction.setText(Messages.DeviceView_Stop_Method_Profiling);
mTracingAction.setImageDescriptor(mTracingStopImage);
} else {
mTracingAction
.setToolTipText(Messages.DeviceView_Start_Method_Profiling_Tooltip);
mTracingAction.setImageDescriptor(mTracingStartImage);
mTracingAction.setText(Messages.DeviceView_Start_Method_Profiling);
}
} else {
mTracingAction.setEnabled(false);
mTracingAction.setImageDescriptor(mTracingStartImage);
mTracingAction
.setToolTipText(Messages.DeviceView_Start_Method_Profiling_Not_Suported_By_Vm);
mTracingAction.setText(Messages.DeviceView_Start_Method_Profiling);
}
} 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);
mHprofAction.setEnabled(false);
mHprofAction.setEnabled(false);
mHprofAction.setToolTipText(Messages.DeviceView_Dump_HPROF_File);
mTracingAction.setEnabled(false);
mTracingAction.setImageDescriptor(mTracingStartImage);
mTracingAction.setToolTipText(Messages.DeviceView_Start_Method_Profiling_Tooltip);
mTracingAction.setText(Messages.DeviceView_Start_Method_Profiling);
}
for (IClientAction a : DdmsPlugin.getDefault().getClientSpecificActions()) {
a.selectedClientChanged(selectedClient);
}
}
private void doSelectionChanged(IDevice selectedDevice) {
boolean validDevice = selectedDevice != null;
mCaptureAction.setEnabled(validDevice);
mViewUiAutomatorHierarchyAction.setEnabled(validDevice);
mSystraceAction.setEnabled(validDevice);
}
/**
* Place the actions in the ui.
*/
private final void placeActions() {
IActionBars actionBars = getViewSite().getActionBars();
// first in the menu
IMenuManager menuManager = actionBars.getMenuManager();
menuManager.removeAll();
menuManager.add(mDebugAction);
menuManager.add(new Separator());
menuManager.add(mUpdateHeapAction);
menuManager.add(mHprofAction);
menuManager.add(mGcAction);
menuManager.add(new Separator());
menuManager.add(mUpdateThreadAction);
menuManager.add(mTracingAction);
menuManager.add(new Separator());
menuManager.add(mKillAppAction);
menuManager.add(new Separator());
menuManager.add(mCaptureAction);
menuManager.add(new Separator());
menuManager.add(mViewUiAutomatorHierarchyAction);
menuManager.add(new Separator());
menuManager.add(mSystraceAction);
menuManager.add(new Separator());
menuManager.add(mResetAdbAction);
for (IClientAction a : DdmsPlugin.getDefault().getClientSpecificActions()) {
menuManager.add(a.getAction());
}
// and then in the toolbar
IToolBarManager toolBarManager = actionBars.getToolBarManager();
toolBarManager.removeAll();
toolBarManager.add(mDebugAction);
toolBarManager.add(new Separator());
toolBarManager.add(mUpdateHeapAction);
toolBarManager.add(mHprofAction);
toolBarManager.add(mGcAction);
toolBarManager.add(new Separator());
toolBarManager.add(mUpdateThreadAction);
toolBarManager.add(mTracingAction);
toolBarManager.add(new Separator());
toolBarManager.add(mKillAppAction);
toolBarManager.add(new Separator());
toolBarManager.add(mCaptureAction);
toolBarManager.add(new Separator());
toolBarManager.add(mViewUiAutomatorHierarchyAction);
toolBarManager.add(new Separator());
toolBarManager.add(mSystraceAction);
for (IClientAction a : DdmsPlugin.getDefault().getClientSpecificActions()) {
toolBarManager.add(a.getAction());
}
}
@Override
public void clientChanged(final Client client, int changeMask) {
if ((changeMask & Client.CHANGE_METHOD_PROFILING_STATUS) == Client.CHANGE_METHOD_PROFILING_STATUS) {
if (mDeviceList.getSelectedClient() == client) {
mParentShell.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
// force refresh of the button enabled state.
doSelectionChanged(client);
}
});
}
}
}
}