blob: b4de3d1512a86d043602f14079d35a01ffc15381 [file] [log] [blame]
/*
* Copyright (C) 2011 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.gltrace;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.osgi.service.prefs.BackingStoreException;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/** Dialog displaying all the trace options before the user initiates tracing. */
public class GLTraceOptionsDialog extends TitleAreaDialog {
private static final String TITLE = "OpenGL ES Trace Options";
private static final String DEFAULT_MESSAGE = "Provide the application and activity to be traced.";
private static final String PREF_APP_PACKAGE = "gl.trace.apppackage"; //$NON-NLS-1$
private static final String PREF_ACTIVITY = "gl.trace.activity"; //$NON-NLS-1$
private static final String PREF_TRACEFILE = "gl.trace.destfile"; //$NON-NLS-1$
private static final String PREF_DEVICE = "gl.trace.device"; //$NON-NLS-1$
private String mLastUsedDevice;
private static String sSaveToFolder = System.getProperty("user.home"); //$NON-NLS-1$
private Button mOkButton;
private Combo mDeviceCombo;
private Text mAppPackageToTraceText;
private Text mActivityToTraceText;
private Button mIsActivityFullyQualifiedButton;
private Text mTraceFilePathText;
private String mSelectedDevice = "";
private String mAppPackageToTrace = "";
private String mActivityToTrace = "";
private String mTraceFilePath = "";
private boolean mAllowAppSelection;
private static boolean sCollectFbOnEglSwap = true;
private static boolean sCollectFbOnGlDraw = false;
private static boolean sCollectTextureData = false;
private static boolean sIsActivityFullyQualified = false;
private IDevice[] mDevices;
public GLTraceOptionsDialog(Shell parentShell) {
this(parentShell, true, null);
}
/**
* Constructs a dialog displaying options for the tracer.
* @param allowAppSelection true if user can change the application to trace
* @param appToTrace default application package to trace
*/
public GLTraceOptionsDialog(Shell parentShell, boolean allowAppSelection,
String appToTrace) {
super(parentShell);
loadPreferences();
mAllowAppSelection = allowAppSelection;
if (appToTrace != null) {
mAppPackageToTrace = appToTrace;
}
}
@Override
protected Control createDialogArea(Composite shell) {
setTitle(TITLE);
setMessage(DEFAULT_MESSAGE);
Composite parent = (Composite) super.createDialogArea(shell);
Composite c = new Composite(parent, SWT.BORDER);
c.setLayout(new GridLayout(2, false));
c.setLayoutData(new GridData(GridData.FILL_BOTH));
createLabel(c, "Device:");
mDevices = AndroidDebugBridge.getBridge().getDevices();
createDeviceDropdown(c, mDevices);
createSeparator(c);
createLabel(c, "Application Package:");
createAppToTraceText(c, "e.g. com.example.package");
createLabel(c, "Activity to launch:");
createActivityToTraceText(c, "Leave blank to launch default activity");
createLabel(c, "");
createIsFullyQualifedActivityButton(c,
"Activity name is fully qualified, do not prefix with package name");
if (!mAllowAppSelection) {
mAppPackageToTraceText.setEnabled(false);
mActivityToTraceText.setEnabled(false);
mIsActivityFullyQualifiedButton.setEnabled(false);
}
createSeparator(c);
createLabel(c, "Data Collection Options:");
createCaptureImageOptions(c);
createSeparator(c);
createLabel(c, "Destination File: ");
createSaveToField(c);
return c;
}
@Override
protected void createButtonsForButtonBar(Composite parent) {
super.createButtonsForButtonBar(parent);
mOkButton = getButton(IDialogConstants.OK_ID);
mOkButton.setText("Trace");
DialogStatus status = validateDialog();
mOkButton.setEnabled(status.valid);
}
private void createSeparator(Composite c) {
Label l = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
l.setLayoutData(gd);
}
private void createSaveToField(Composite parent) {
Composite c = new Composite(parent, SWT.NONE);
c.setLayout(new GridLayout(2, false));
c.setLayoutData(new GridData(GridData.FILL_BOTH));
mTraceFilePathText = new Text(c, SWT.BORDER);
mTraceFilePathText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mTraceFilePathText.setText(mTraceFilePath);
mTraceFilePathText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
validateAndSetMessage();
}
});
Button browse = new Button(c, SWT.PUSH);
browse.setText("Browse...");
browse.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String fName = openBrowseDialog();
if (fName == null) {
return;
}
mTraceFilePathText.setText(fName);
validateAndSetMessage();
}
});
}
private String openBrowseDialog() {
FileDialog fd = new FileDialog(Display.getDefault().getActiveShell(), SWT.SAVE);
fd.setText("Save To");
fd.setFileName("trace1.gltrace");
fd.setFilterPath(sSaveToFolder);
fd.setFilterExtensions(new String[] { "*.gltrace" });
String fname = fd.open();
if (fname == null || fname.trim().length() == 0) {
return null;
}
sSaveToFolder = fd.getFilterPath();
return fname;
}
/** Options controlling when the FB should be captured. */
private void createCaptureImageOptions(Composite parent) {
Composite c = new Composite(parent, SWT.NONE);
c.setLayout(new GridLayout(1, false));
c.setLayoutData(new GridData(GridData.FILL_BOTH));
final Button readFbOnEglSwapCheckBox = new Button(c, SWT.CHECK);
readFbOnEglSwapCheckBox.setText("Read back framebuffer 0 on eglSwapBuffers()");
readFbOnEglSwapCheckBox.setSelection(sCollectFbOnEglSwap);
final Button readFbOnGlDrawCheckBox = new Button(c, SWT.CHECK);
readFbOnGlDrawCheckBox.setText("Read back currently bound framebuffer On glDraw*()");
readFbOnGlDrawCheckBox.setSelection(sCollectFbOnGlDraw);
final Button readTextureDataCheckBox = new Button(c, SWT.CHECK);
readTextureDataCheckBox.setText("Collect texture data submitted using glTexImage*()");
readTextureDataCheckBox.setSelection(sCollectTextureData);
SelectionListener l = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
sCollectFbOnEglSwap = readFbOnEglSwapCheckBox.getSelection();
sCollectFbOnGlDraw = readFbOnGlDrawCheckBox.getSelection();
sCollectTextureData = readTextureDataCheckBox.getSelection();
}
};
readFbOnEglSwapCheckBox.addSelectionListener(l);
readFbOnGlDrawCheckBox.addSelectionListener(l);
readTextureDataCheckBox.addSelectionListener(l);
}
private Text createAppToTraceText(Composite parent, String defaultMessage) {
mAppPackageToTraceText = new Text(parent, SWT.BORDER);
mAppPackageToTraceText.setMessage(defaultMessage);
mAppPackageToTraceText.setText(mAppPackageToTrace);
mAppPackageToTraceText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mAppPackageToTraceText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
validateAndSetMessage();
}
});
return mActivityToTraceText;
}
private Text createActivityToTraceText(Composite parent, String defaultMessage) {
mActivityToTraceText = new Text(parent, SWT.BORDER);
mActivityToTraceText.setMessage(defaultMessage);
mActivityToTraceText.setText(mActivityToTrace);
mActivityToTraceText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mActivityToTraceText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
validateAndSetMessage();
}
});
return mActivityToTraceText;
}
private Button createIsFullyQualifedActivityButton(Composite parent, String message) {
mIsActivityFullyQualifiedButton = new Button(parent, SWT.CHECK);
mIsActivityFullyQualifiedButton.setText(message);
mIsActivityFullyQualifiedButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mIsActivityFullyQualifiedButton.setSelection(sIsActivityFullyQualified);
return mIsActivityFullyQualifiedButton;
}
private void validateAndSetMessage() {
DialogStatus status = validateDialog();
mOkButton.setEnabled(status.valid);
setErrorMessage(status.message);
}
private Combo createDeviceDropdown(Composite parent, IDevice[] devices) {
mDeviceCombo = new Combo(parent, SWT.READ_ONLY | SWT.BORDER);
List<String> items = new ArrayList<String>(devices.length);
for (IDevice d : devices) {
items.add(d.getName());
}
mDeviceCombo.setItems(items.toArray(new String[items.size()]));
int index = 0;
if (items.contains(mLastUsedDevice)) {
index = items.indexOf(mLastUsedDevice);
}
if (index >= 0 && index < items.size()) {
mDeviceCombo.select(index);
}
return mDeviceCombo;
}
private void createLabel(Composite parent, String text) {
Label l = new Label(parent, SWT.NONE);
l.setText(text);
GridData gd = new GridData();
gd.horizontalAlignment = SWT.RIGHT;
gd.verticalAlignment = SWT.CENTER;
l.setLayoutData(gd);
}
/**
* A tuple that specifies whether the current state of the inputs
* on the dialog is valid or not. If it is not valid, the message
* field stores the reason why it isn't.
*/
private final class DialogStatus {
final boolean valid;
final String message;
private DialogStatus(boolean isValid, String errMessage) {
valid = isValid;
message = errMessage;
}
}
private DialogStatus validateDialog() {
if (mDevices.length == 0) {
return new DialogStatus(false, "No connected devices.");
}
if (mAppPackageToTraceText.getText().trim().isEmpty()) {
return new DialogStatus(false, "Provide an application name");
}
String traceFile = mTraceFilePathText.getText().trim();
if (traceFile.isEmpty()) {
return new DialogStatus(false, "Specify the location where the trace will be saved.");
}
File f = new File(traceFile).getParentFile();
if (f != null && !f.exists()) {
return new DialogStatus(false,
String.format("Folder %s does not exist", f.getAbsolutePath()));
}
return new DialogStatus(true, null);
}
@Override
protected void okPressed() {
mAppPackageToTrace = mAppPackageToTraceText.getText().trim();
mActivityToTrace = mActivityToTraceText.getText().trim();
if (mActivityToTrace.startsWith(".")) { //$NON-NLS-1$
mActivityToTrace = mActivityToTrace.substring(1);
}
sIsActivityFullyQualified = mIsActivityFullyQualifiedButton.getSelection();
mTraceFilePath = mTraceFilePathText.getText().trim();
mSelectedDevice = mDeviceCombo.getText();
savePreferences();
super.okPressed();
}
private void savePreferences() {
IEclipsePreferences prefs = new InstanceScope().getNode(GlTracePlugin.PLUGIN_ID);
prefs.put(PREF_APP_PACKAGE, mAppPackageToTrace);
prefs.put(PREF_ACTIVITY, mActivityToTrace);
prefs.put(PREF_TRACEFILE, mTraceFilePath);
prefs.put(PREF_DEVICE, mSelectedDevice);
try {
prefs.flush();
} catch (BackingStoreException e) {
// ignore issues while persisting preferences
}
}
private void loadPreferences() {
IEclipsePreferences prefs = new InstanceScope().getNode(GlTracePlugin.PLUGIN_ID);
mAppPackageToTrace = prefs.get(PREF_APP_PACKAGE, "");
mActivityToTrace = prefs.get(PREF_ACTIVITY, "");
mTraceFilePath = prefs.get(PREF_TRACEFILE, "");
mLastUsedDevice = prefs.get(PREF_DEVICE, "");
}
public TraceOptions getTraceOptions() {
return new TraceOptions(mSelectedDevice, mAppPackageToTrace, mActivityToTrace,
sIsActivityFullyQualified, mTraceFilePath, sCollectFbOnEglSwap,
sCollectFbOnGlDraw, sCollectTextureData);
}
}