1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.ddms.systrace; 18 19 import com.android.ddmuilib.TableHelper; 20 import com.google.common.collect.ImmutableSet; 21 import com.google.common.collect.Lists; 22 import com.google.common.collect.Sets; 23 24 import org.eclipse.jface.dialogs.TitleAreaDialog; 25 import org.eclipse.swt.SWT; 26 import org.eclipse.swt.events.ModifyEvent; 27 import org.eclipse.swt.events.ModifyListener; 28 import org.eclipse.swt.events.SelectionAdapter; 29 import org.eclipse.swt.events.SelectionEvent; 30 import org.eclipse.swt.layout.GridData; 31 import org.eclipse.swt.layout.GridLayout; 32 import org.eclipse.swt.widgets.Button; 33 import org.eclipse.swt.widgets.Combo; 34 import org.eclipse.swt.widgets.Composite; 35 import org.eclipse.swt.widgets.Control; 36 import org.eclipse.swt.widgets.FileDialog; 37 import org.eclipse.swt.widgets.Label; 38 import org.eclipse.swt.widgets.Shell; 39 import org.eclipse.swt.widgets.Table; 40 import org.eclipse.swt.widgets.TableItem; 41 import org.eclipse.swt.widgets.Text; 42 43 import java.io.File; 44 import java.util.List; 45 import java.util.Set; 46 47 public class SystraceOptionsDialogV2 extends TitleAreaDialog implements ISystraceOptionsDialog { 48 private static final String TITLE = "Systrace (Android System Trace)"; 49 private static final String DEFAULT_MESSAGE = 50 "Settings to use while capturing system level trace"; 51 private static final String DEFAULT_TRACE_FNAME = "trace.html"; //$NON-NLS-1$ 52 private static final Set<String> sCommonTags = ImmutableSet.of( 53 "am", "app", "dalvik", "disk", "gfx", "input", "res", "sched", "view", "webview", "wm"); 54 55 private Text mDestinationText; 56 private String mDestinationPath; 57 private Text mTraceDurationText; 58 private Text mTraceBufferSizeText; 59 private Combo mTraceAppCombo; 60 61 private static String sSaveToFolder = System.getProperty("user.home"); //$NON-NLS-1$ 62 private static String sTraceDuration = "5"; 63 private static String sTraceBufferSize = "2048"; 64 private static Set<String> sEnabledTags = Sets.newHashSet(sCommonTags); 65 private static String sLastSelectedApp = null; 66 67 private final List<SystraceTag> mCommonSupportedTags; 68 private final List<SystraceTag> mAdvancedSupportedTags; 69 70 private final List<String> mCurrentApps; 71 72 private final SystraceOptions mOptions = new SystraceOptions(); 73 private Table mCommonTagsTable; 74 private Table mAdvancedTagsTable; 75 76 public SystraceOptionsDialogV2(Shell parentShell, List<SystraceTag> tags, List<String> apps) { 77 super(parentShell); 78 mCurrentApps = apps; 79 80 mCommonSupportedTags = Lists.newArrayListWithExpectedSize(tags.size()); 81 mAdvancedSupportedTags = Lists.newArrayListWithExpectedSize(tags.size()); 82 83 for (SystraceTag supportedTag : tags) { 84 if (sCommonTags.contains(supportedTag.tag)) { 85 mCommonSupportedTags.add(supportedTag); 86 } else { 87 mAdvancedSupportedTags.add(supportedTag); 88 } 89 } 90 } 91 92 @Override 93 protected Control createDialogArea(Composite parent) { 94 setTitle(TITLE); 95 setMessage(DEFAULT_MESSAGE); 96 97 Composite c = new Composite(parent, SWT.BORDER); 98 c.setLayout(new GridLayout(3, false)); 99 c.setLayoutData(new GridData(GridData.FILL_BOTH)); 100 101 Label l = new Label(c, SWT.NONE); 102 l.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 103 l.setText("Destination File: "); 104 105 mDestinationText = new Text(c, SWT.BORDER); 106 mDestinationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 107 mDestinationText.setText(sSaveToFolder + File.separator + DEFAULT_TRACE_FNAME); 108 109 final Button browse = new Button(c, SWT.NONE); 110 browse.setText("Browse..."); 111 browse.addSelectionListener(new SelectionAdapter() { 112 @Override 113 public void widgetSelected(SelectionEvent e) { 114 String path = openBrowseDialog(browse.getShell()); 115 if (path != null) mDestinationText.setText(path); 116 } 117 }); 118 119 Label lblTraceDurationseconds = new Label(c, SWT.NONE); 120 lblTraceDurationseconds.setLayoutData( 121 new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 122 lblTraceDurationseconds.setText("Trace duration (seconds): "); 123 124 mTraceDurationText = new Text(c, SWT.BORDER); 125 mTraceDurationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 126 mTraceDurationText.setText(sTraceDuration); 127 128 Label lblTraceBufferSize = new Label(c, SWT.NONE); 129 lblTraceBufferSize.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 130 lblTraceBufferSize.setText("Trace Buffer Size (kb): "); 131 132 mTraceBufferSizeText = new Text(c, SWT.BORDER); 133 mTraceBufferSizeText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 134 mTraceBufferSizeText.setText(sTraceBufferSize); 135 136 Label lblTraceAppName = new Label(c, SWT.NONE); 137 lblTraceAppName.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 138 lblTraceAppName.setText("Enable Application Traces from: "); 139 140 mTraceAppCombo = new Combo(c, SWT.DROP_DOWN | SWT.READ_ONLY); 141 mTraceAppCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 142 String[] items = new String[mCurrentApps.size() + 1]; 143 items[0] = "None"; 144 for (int i = 0; i < mCurrentApps.size(); i++) { 145 items[i+1] = mCurrentApps.get(i); 146 } 147 mTraceAppCombo.setItems(items); 148 if (sLastSelectedApp != null) { 149 mTraceAppCombo.setText(sLastSelectedApp); 150 } else { 151 mTraceAppCombo.select(0); 152 } 153 154 Label separator = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL); 155 GridData gd = new GridData(GridData.FILL_HORIZONTAL); 156 gd.horizontalSpan = 3; 157 separator.setLayoutData(gd); 158 159 ModifyListener m = new ModifyListener() { 160 @Override 161 public void modifyText(ModifyEvent e) { 162 validateFields(); 163 } 164 }; 165 166 mDestinationText.addModifyListener(m); 167 mTraceBufferSizeText.addModifyListener(m); 168 mTraceDurationText.addModifyListener(m); 169 170 mCommonTagsTable = createTable(c, "Commonly Used Tags: ", mCommonSupportedTags); 171 mAdvancedTagsTable = createTable(c, "Advanced Options: ", mAdvancedSupportedTags); 172 173 return c; 174 } 175 176 private Table createTable(Composite c, String label, List<SystraceTag> supportedTags) { 177 Label l = new Label(c, SWT.NONE); 178 l.setText(label); 179 l.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 180 181 Table table = new Table(c, SWT.CHECK | SWT.BORDER); 182 GridData gd = new GridData(GridData.FILL_BOTH); 183 gd.horizontalSpan = 2; 184 table.setLayoutData(gd); 185 table.setHeaderVisible(false); 186 table.setLinesVisible(false); 187 188 for (SystraceTag tag : supportedTags) { 189 TableItem item = new TableItem(table, SWT.NONE); 190 item.setText(tag.info); 191 item.setChecked(sEnabledTags.contains(tag.tag)); 192 } 193 194 TableHelper.createTableColumn(table, 195 "TagHeaderNotDisplayed", //$NON-NLS-1$ 196 SWT.LEFT, 197 "SampleTagForColumnLengthCalculation", //$NON-NLS-1$ 198 null, 199 null); 200 201 return table; 202 } 203 204 private void validateFields() { 205 // validate trace destination path 206 String msg = validatePath(mDestinationText.getText()); 207 if (msg != null) { 208 setErrorMessage(msg); 209 getButton(OK).setEnabled(false); 210 return; 211 } 212 213 // validate the trace duration 214 if (!validateInteger(mTraceDurationText.getText())) { 215 setErrorMessage("Trace Duration should be a valid integer (seconds)"); 216 getButton(OK).setEnabled(false); 217 return; 218 } 219 220 // validate the trace buffer size 221 if (!validateInteger(mTraceBufferSizeText.getText())) { 222 setErrorMessage("Trace Buffer Size should be a valid integer (kilobytes)"); 223 getButton(OK).setEnabled(false); 224 return; 225 } 226 227 getButton(OK).setEnabled(true); 228 setErrorMessage(null); 229 } 230 231 private boolean validateInteger(String text) { 232 if (text == null || text.isEmpty()) { 233 return true; 234 } 235 236 try { 237 Integer.parseInt(text); 238 return true; 239 } catch (NumberFormatException e) { 240 return false; 241 } 242 } 243 244 private String validatePath(String path) { 245 if (path == null || path.isEmpty()) { 246 return null; 247 } 248 249 File f = new File(path); 250 if (f.isDirectory()) { 251 return String.format("The path '%s' points to a folder", path); 252 } 253 254 if (!f.exists()) { // if such a file doesn't exist, make sure the parent folder is valid 255 if (!f.getParentFile().isDirectory()) { 256 return String.format("That path '%s' is not a valid folder.", f.getParent()); 257 } 258 } 259 260 return null; 261 } 262 263 private String openBrowseDialog(Shell parentShell) { 264 FileDialog fd = new FileDialog(parentShell, SWT.SAVE); 265 266 fd.setText("Save To"); 267 fd.setFileName(DEFAULT_TRACE_FNAME); 268 269 fd.setFilterPath(sSaveToFolder); 270 fd.setFilterExtensions(new String[] { "*.html" }); //$NON-NLS-1$ 271 272 String fname = fd.open(); 273 if (fname == null || fname.trim().length() == 0) { 274 return null; 275 } 276 277 sSaveToFolder = fd.getFilterPath(); 278 return fname; 279 } 280 281 @Override 282 protected void okPressed() { 283 mDestinationPath = mDestinationText.getText().trim(); 284 285 sTraceDuration = mTraceDurationText.getText(); 286 if (!sTraceDuration.isEmpty()) { 287 mOptions.mTraceDuration = Integer.parseInt(sTraceDuration); 288 } 289 290 sTraceBufferSize = mTraceBufferSizeText.getText(); 291 if (!sTraceBufferSize.isEmpty()) { 292 mOptions.mTraceBufferSize = Integer.parseInt(sTraceBufferSize); 293 } 294 295 if (mTraceAppCombo.getSelectionIndex() != 0) { 296 mOptions.mTraceApp = sLastSelectedApp = mTraceAppCombo.getText(); 297 } 298 299 sEnabledTags.clear(); 300 sEnabledTags.addAll(getEnabledTags(mCommonTagsTable, mCommonSupportedTags)); 301 sEnabledTags.addAll(getEnabledTags(mAdvancedTagsTable, mAdvancedSupportedTags)); 302 303 super.okPressed(); 304 } 305 306 private static Set<String> getEnabledTags(Table table, List<SystraceTag> tags) { 307 Set<String> enabledTags = Sets.newHashSetWithExpectedSize(tags.size()); 308 309 for (int i = 0; i < table.getItemCount(); i++) { 310 TableItem it = table.getItem(i); 311 if (it.getChecked()) { 312 enabledTags.add(tags.get(i).tag); 313 } 314 } 315 316 return enabledTags; 317 } 318 319 @Override 320 public ISystraceOptions getSystraceOptions() { 321 return mOptions; 322 } 323 324 @Override 325 public String getTraceFilePath() { 326 return mDestinationPath; 327 } 328 329 private class SystraceOptions implements ISystraceOptions { 330 private int mTraceBufferSize; 331 private int mTraceDuration; 332 private String mTraceApp; 333 334 @Override 335 public String getTags() { 336 return null; 337 } 338 339 @Override 340 public String getOptions() { 341 StringBuilder sb = new StringBuilder(5 * mCommonSupportedTags.size()); 342 343 if (mTraceApp != null) { 344 sb.append("-a "); //$NON-NLS-1$ 345 sb.append(mTraceApp); 346 sb.append(' '); 347 } 348 349 if (mTraceDuration > 0) { 350 sb.append("-t"); //$NON-NLS-1$ 351 sb.append(mTraceDuration); 352 sb.append(' '); 353 } 354 355 if (mTraceBufferSize > 0) { 356 sb.append("-b "); //$NON-NLS-1$ 357 sb.append(mTraceBufferSize); 358 sb.append(' '); 359 } 360 361 for (String s : sEnabledTags) { 362 sb.append(s); 363 sb.append(' '); 364 } 365 366 return sb.toString().trim(); 367 } 368 } 369 } 370