1 /* 2 * Copyright (C) 2007 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.ddmuilib; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.ddmlib.EmulatorConsole; 21 import com.android.ddmlib.EmulatorConsole.GsmMode; 22 import com.android.ddmlib.EmulatorConsole.GsmStatus; 23 import com.android.ddmlib.EmulatorConsole.NetworkStatus; 24 import com.android.ddmuilib.location.CoordinateControls; 25 import com.android.ddmuilib.location.GpxParser; 26 import com.android.ddmuilib.location.KmlParser; 27 import com.android.ddmuilib.location.TrackContentProvider; 28 import com.android.ddmuilib.location.TrackLabelProvider; 29 import com.android.ddmuilib.location.TrackPoint; 30 import com.android.ddmuilib.location.WayPoint; 31 import com.android.ddmuilib.location.WayPointContentProvider; 32 import com.android.ddmuilib.location.WayPointLabelProvider; 33 import com.android.ddmuilib.location.GpxParser.Track; 34 35 import org.eclipse.jface.dialogs.MessageDialog; 36 import org.eclipse.jface.preference.IPreferenceStore; 37 import org.eclipse.jface.viewers.ISelection; 38 import org.eclipse.jface.viewers.ISelectionChangedListener; 39 import org.eclipse.jface.viewers.IStructuredSelection; 40 import org.eclipse.jface.viewers.SelectionChangedEvent; 41 import org.eclipse.jface.viewers.TableViewer; 42 import org.eclipse.swt.SWT; 43 import org.eclipse.swt.SWTException; 44 import org.eclipse.swt.custom.ScrolledComposite; 45 import org.eclipse.swt.custom.StackLayout; 46 import org.eclipse.swt.events.ControlAdapter; 47 import org.eclipse.swt.events.ControlEvent; 48 import org.eclipse.swt.events.ModifyEvent; 49 import org.eclipse.swt.events.ModifyListener; 50 import org.eclipse.swt.events.SelectionAdapter; 51 import org.eclipse.swt.events.SelectionEvent; 52 import org.eclipse.swt.graphics.Image; 53 import org.eclipse.swt.graphics.Rectangle; 54 import org.eclipse.swt.layout.FillLayout; 55 import org.eclipse.swt.layout.GridData; 56 import org.eclipse.swt.layout.GridLayout; 57 import org.eclipse.swt.widgets.Button; 58 import org.eclipse.swt.widgets.Combo; 59 import org.eclipse.swt.widgets.Composite; 60 import org.eclipse.swt.widgets.Control; 61 import org.eclipse.swt.widgets.Display; 62 import org.eclipse.swt.widgets.FileDialog; 63 import org.eclipse.swt.widgets.Group; 64 import org.eclipse.swt.widgets.Label; 65 import org.eclipse.swt.widgets.TabFolder; 66 import org.eclipse.swt.widgets.TabItem; 67 import org.eclipse.swt.widgets.Table; 68 import org.eclipse.swt.widgets.Text; 69 70 /** 71 * Panel to control the emulator using EmulatorConsole objects. 72 */ 73 public class EmulatorControlPanel extends SelectionDependentPanel { 74 75 // default location: Patio outside Charlie's 76 private final static double DEFAULT_LONGITUDE = -122.084095; 77 private final static double DEFAULT_LATITUDE = 37.422006; 78 79 private final static String SPEED_FORMAT = "Speed: %1$dX"; 80 81 82 /** 83 * Map between the display gsm mode and the internal tag used by the display. 84 */ 85 private final static String[][] GSM_MODES = new String[][] { 86 { "unregistered", GsmMode.UNREGISTERED.getTag() }, 87 { "home", GsmMode.HOME.getTag() }, 88 { "roaming", GsmMode.ROAMING.getTag() }, 89 { "searching", GsmMode.SEARCHING.getTag() }, 90 { "denied", GsmMode.DENIED.getTag() }, 91 }; 92 93 private final static String[] NETWORK_SPEEDS = new String[] { 94 "Full", 95 "GSM", 96 "HSCSD", 97 "GPRS", 98 "EDGE", 99 "UMTS", 100 "HSDPA", 101 }; 102 103 private final static String[] NETWORK_LATENCIES = new String[] { 104 "None", 105 "GPRS", 106 "EDGE", 107 "UMTS", 108 }; 109 110 private final static int[] PLAY_SPEEDS = new int[] { 1, 2, 5, 10, 20, 50 }; 111 112 private final static String RE_PHONE_NUMBER = "^[+#0-9]+$"; //$NON-NLS-1$ 113 private final static String PREFS_WAYPOINT_COL_NAME = "emulatorControl.waypoint.name"; //$NON-NLS-1$ 114 private final static String PREFS_WAYPOINT_COL_LONGITUDE = "emulatorControl.waypoint.longitude"; //$NON-NLS-1$ 115 private final static String PREFS_WAYPOINT_COL_LATITUDE = "emulatorControl.waypoint.latitude"; //$NON-NLS-1$ 116 private final static String PREFS_WAYPOINT_COL_ELEVATION = "emulatorControl.waypoint.elevation"; //$NON-NLS-1$ 117 private final static String PREFS_WAYPOINT_COL_DESCRIPTION = "emulatorControl.waypoint.desc"; //$NON-NLS-1$ 118 private final static String PREFS_TRACK_COL_NAME = "emulatorControl.track.name"; //$NON-NLS-1$ 119 private final static String PREFS_TRACK_COL_COUNT = "emulatorControl.track.count"; //$NON-NLS-1$ 120 private final static String PREFS_TRACK_COL_FIRST = "emulatorControl.track.first"; //$NON-NLS-1$ 121 private final static String PREFS_TRACK_COL_LAST = "emulatorControl.track.last"; //$NON-NLS-1$ 122 private final static String PREFS_TRACK_COL_COMMENT = "emulatorControl.track.comment"; //$NON-NLS-1$ 123 124 private EmulatorConsole mEmulatorConsole; 125 126 private Composite mParent; 127 128 private Label mVoiceLabel; 129 private Combo mVoiceMode; 130 private Label mDataLabel; 131 private Combo mDataMode; 132 private Label mSpeedLabel; 133 private Combo mNetworkSpeed; 134 private Label mLatencyLabel; 135 private Combo mNetworkLatency; 136 137 private Label mNumberLabel; 138 private Text mPhoneNumber; 139 140 private Button mVoiceButton; 141 private Button mSmsButton; 142 143 private Label mMessageLabel; 144 private Text mSmsMessage; 145 146 private Button mCallButton; 147 private Button mCancelButton; 148 149 private TabFolder mLocationFolders; 150 151 private Button mDecimalButton; 152 private Button mSexagesimalButton; 153 private CoordinateControls mLongitudeControls; 154 private CoordinateControls mLatitudeControls; 155 private Button mGpxUploadButton; 156 private Table mGpxWayPointTable; 157 private Table mGpxTrackTable; 158 private Button mKmlUploadButton; 159 private Table mKmlWayPointTable; 160 161 private Button mPlayGpxButton; 162 private Button mGpxBackwardButton; 163 private Button mGpxForwardButton; 164 private Button mGpxSpeedButton; 165 private Button mPlayKmlButton; 166 private Button mKmlBackwardButton; 167 private Button mKmlForwardButton; 168 private Button mKmlSpeedButton; 169 170 private Image mPlayImage; 171 private Image mPauseImage; 172 173 private Thread mPlayingThread; 174 private boolean mPlayingTrack; 175 private int mPlayDirection = 1; 176 private int mSpeed; 177 private int mSpeedIndex; 178 179 private final SelectionAdapter mDirectionButtonAdapter = new SelectionAdapter() { 180 @Override 181 public void widgetSelected(SelectionEvent e) { 182 Button b = (Button)e.getSource(); 183 if (b.getSelection() == false) { 184 // basically the button was unselected, which we don't allow. 185 // so we reselect it. 186 b.setSelection(true); 187 return; 188 } 189 190 // now handle selection change. 191 if (b == mGpxForwardButton || b == mKmlForwardButton) { 192 mGpxBackwardButton.setSelection(false); 193 mGpxForwardButton.setSelection(true); 194 mKmlBackwardButton.setSelection(false); 195 mKmlForwardButton.setSelection(true); 196 mPlayDirection = 1; 197 198 } else { 199 mGpxBackwardButton.setSelection(true); 200 mGpxForwardButton.setSelection(false); 201 mKmlBackwardButton.setSelection(true); 202 mKmlForwardButton.setSelection(false); 203 mPlayDirection = -1; 204 } 205 } 206 }; 207 208 private final SelectionAdapter mSpeedButtonAdapter = new SelectionAdapter() { 209 @Override 210 public void widgetSelected(SelectionEvent e) { 211 mSpeedIndex = (mSpeedIndex+1) % PLAY_SPEEDS.length; 212 mSpeed = PLAY_SPEEDS[mSpeedIndex]; 213 214 mGpxSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); 215 mGpxPlayControls.pack(); 216 mKmlSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); 217 mKmlPlayControls.pack(); 218 219 if (mPlayingThread != null) { 220 mPlayingThread.interrupt(); 221 } 222 } 223 }; 224 private Composite mKmlPlayControls; 225 private Composite mGpxPlayControls; 226 227 228 public EmulatorControlPanel() { 229 } 230 231 /** 232 * Sent when a new device is selected. The new device can be accessed 233 * with {@link #getCurrentDevice()} 234 */ 235 @Override 236 public void deviceSelected() { 237 handleNewDevice(getCurrentDevice()); 238 } 239 240 /** 241 * Sent when a new client is selected. The new client can be accessed 242 * with {@link #getCurrentClient()} 243 */ 244 @Override 245 public void clientSelected() { 246 // pass 247 } 248 249 /** 250 * Creates a control capable of displaying some information. This is 251 * called once, when the application is initializing, from the UI thread. 252 */ 253 @Override 254 protected Control createControl(Composite parent) { 255 mParent = parent; 256 257 final ScrolledComposite scollingParent = new ScrolledComposite(parent, SWT.V_SCROLL); 258 scollingParent.setExpandVertical(true); 259 scollingParent.setExpandHorizontal(true); 260 scollingParent.setLayoutData(new GridData(GridData.FILL_BOTH)); 261 262 final Composite top = new Composite(scollingParent, SWT.NONE); 263 scollingParent.setContent(top); 264 top.setLayout(new GridLayout(1, false)); 265 266 // set the resize for the scrolling to work (why isn't that done automatically?!?) 267 scollingParent.addControlListener(new ControlAdapter() { 268 @Override 269 public void controlResized(ControlEvent e) { 270 Rectangle r = scollingParent.getClientArea(); 271 scollingParent.setMinSize(top.computeSize(r.width, SWT.DEFAULT)); 272 } 273 }); 274 275 createRadioControls(top); 276 277 createCallControls(top); 278 279 createLocationControls(top); 280 281 doEnable(false); 282 283 top.layout(); 284 Rectangle r = scollingParent.getClientArea(); 285 scollingParent.setMinSize(top.computeSize(r.width, SWT.DEFAULT)); 286 287 return scollingParent; 288 } 289 290 /** 291 * Create Radio (on/off/roaming, for voice/data) controls. 292 * @param top 293 */ 294 private void createRadioControls(final Composite top) { 295 Group g1 = new Group(top, SWT.NONE); 296 g1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 297 g1.setLayout(new GridLayout(2, false)); 298 g1.setText("Telephony Status"); 299 300 // the inside of the group is 2 composite so that all the column of the controls (mainly 301 // combos) have the same width, while not taking the whole screen width 302 Composite insideGroup = new Composite(g1, SWT.NONE); 303 GridLayout gl = new GridLayout(4, false); 304 gl.marginBottom = gl.marginHeight = gl.marginLeft = gl.marginRight = 0; 305 insideGroup.setLayout(gl); 306 307 mVoiceLabel = new Label(insideGroup, SWT.NONE); 308 mVoiceLabel.setText("Voice:"); 309 mVoiceLabel.setAlignment(SWT.RIGHT); 310 311 mVoiceMode = new Combo(insideGroup, SWT.READ_ONLY); 312 mVoiceMode.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 313 for (String[] mode : GSM_MODES) { 314 mVoiceMode.add(mode[0]); 315 } 316 mVoiceMode.addSelectionListener(new SelectionAdapter() { 317 // called when selection changes 318 @Override 319 public void widgetSelected(SelectionEvent e) { 320 setVoiceMode(mVoiceMode.getSelectionIndex()); 321 } 322 }); 323 324 mSpeedLabel = new Label(insideGroup, SWT.NONE); 325 mSpeedLabel.setText("Speed:"); 326 mSpeedLabel.setAlignment(SWT.RIGHT); 327 328 mNetworkSpeed = new Combo(insideGroup, SWT.READ_ONLY); 329 mNetworkSpeed.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 330 for (String mode : NETWORK_SPEEDS) { 331 mNetworkSpeed.add(mode); 332 } 333 mNetworkSpeed.addSelectionListener(new SelectionAdapter() { 334 // called when selection changes 335 @Override 336 public void widgetSelected(SelectionEvent e) { 337 setNetworkSpeed(mNetworkSpeed.getSelectionIndex()); 338 } 339 }); 340 341 mDataLabel = new Label(insideGroup, SWT.NONE); 342 mDataLabel.setText("Data:"); 343 mDataLabel.setAlignment(SWT.RIGHT); 344 345 mDataMode = new Combo(insideGroup, SWT.READ_ONLY); 346 mDataMode.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 347 for (String[] mode : GSM_MODES) { 348 mDataMode.add(mode[0]); 349 } 350 mDataMode.addSelectionListener(new SelectionAdapter() { 351 // called when selection changes 352 @Override 353 public void widgetSelected(SelectionEvent e) { 354 setDataMode(mDataMode.getSelectionIndex()); 355 } 356 }); 357 358 mLatencyLabel = new Label(insideGroup, SWT.NONE); 359 mLatencyLabel.setText("Latency:"); 360 mLatencyLabel.setAlignment(SWT.RIGHT); 361 362 mNetworkLatency = new Combo(insideGroup, SWT.READ_ONLY); 363 mNetworkLatency.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 364 for (String mode : NETWORK_LATENCIES) { 365 mNetworkLatency.add(mode); 366 } 367 mNetworkLatency.addSelectionListener(new SelectionAdapter() { 368 // called when selection changes 369 @Override 370 public void widgetSelected(SelectionEvent e) { 371 setNetworkLatency(mNetworkLatency.getSelectionIndex()); 372 } 373 }); 374 375 // now an empty label to take the rest of the width of the group 376 Label l = new Label(g1, SWT.NONE); 377 l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 378 } 379 380 /** 381 * Create Voice/SMS call/hang up controls 382 * @param top 383 */ 384 private void createCallControls(final Composite top) { 385 GridLayout gl; 386 Group g2 = new Group(top, SWT.NONE); 387 g2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 388 g2.setLayout(new GridLayout(1, false)); 389 g2.setText("Telephony Actions"); 390 391 // horizontal composite for label + text field 392 Composite phoneComp = new Composite(g2, SWT.NONE); 393 phoneComp.setLayoutData(new GridData(GridData.FILL_BOTH)); 394 gl = new GridLayout(2, false); 395 gl.marginBottom = gl.marginHeight = gl.marginLeft = gl.marginRight = 0; 396 phoneComp.setLayout(gl); 397 398 mNumberLabel = new Label(phoneComp, SWT.NONE); 399 mNumberLabel.setText("Incoming number:"); 400 401 mPhoneNumber = new Text(phoneComp, SWT.BORDER | SWT.LEFT | SWT.SINGLE); 402 mPhoneNumber.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 403 mPhoneNumber.addModifyListener(new ModifyListener() { 404 public void modifyText(ModifyEvent e) { 405 // Reenable the widgets based on the content of the text. 406 // doEnable checks the validity of the phone number to enable/disable some 407 // widgets. 408 // Looks like we're getting a callback at creation time, so we can't 409 // suppose that we are enabled when the text is modified... 410 doEnable(mEmulatorConsole != null); 411 } 412 }); 413 414 mVoiceButton = new Button(phoneComp, SWT.RADIO); 415 GridData gd = new GridData(); 416 gd.horizontalSpan = 2; 417 mVoiceButton.setText("Voice"); 418 mVoiceButton.setLayoutData(gd); 419 mVoiceButton.setEnabled(false); 420 mVoiceButton.setSelection(true); 421 mVoiceButton.addSelectionListener(new SelectionAdapter() { 422 // called when selection changes 423 @Override 424 public void widgetSelected(SelectionEvent e) { 425 doEnable(true); 426 427 if (mVoiceButton.getSelection()) { 428 mCallButton.setText("Call"); 429 } else { 430 mCallButton.setText("Send"); 431 } 432 } 433 }); 434 435 mSmsButton = new Button(phoneComp, SWT.RADIO); 436 mSmsButton.setText("SMS"); 437 gd = new GridData(); 438 gd.horizontalSpan = 2; 439 mSmsButton.setLayoutData(gd); 440 mSmsButton.setEnabled(false); 441 // Since there are only 2 radio buttons, we can put a listener on only one (they 442 // are both called on select and unselect event. 443 444 mMessageLabel = new Label(phoneComp, SWT.NONE); 445 gd = new GridData(); 446 gd.verticalAlignment = SWT.TOP; 447 mMessageLabel.setLayoutData(gd); 448 mMessageLabel.setText("Message:"); 449 mMessageLabel.setEnabled(false); 450 451 mSmsMessage = new Text(phoneComp, SWT.BORDER | SWT.LEFT | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); 452 mSmsMessage.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); 453 gd.heightHint = 70; 454 mSmsMessage.setEnabled(false); 455 456 // composite to put the 2 buttons horizontally 457 Composite g2ButtonComp = new Composite(g2, SWT.NONE); 458 g2ButtonComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 459 gl = new GridLayout(2, false); 460 gl.marginWidth = gl.marginHeight = 0; 461 g2ButtonComp.setLayout(gl); 462 463 // now a button below the phone number 464 mCallButton = new Button(g2ButtonComp, SWT.PUSH); 465 mCallButton.setText("Call"); 466 mCallButton.setEnabled(false); 467 mCallButton.addSelectionListener(new SelectionAdapter() { 468 @Override 469 public void widgetSelected(SelectionEvent e) { 470 if (mEmulatorConsole != null) { 471 if (mVoiceButton.getSelection()) { 472 processCommandResult(mEmulatorConsole.call(mPhoneNumber.getText().trim())); 473 } else { 474 // we need to encode the message. We need to replace the carriage return 475 // character by the 2 character string \n. 476 // Because of this the \ character needs to be escaped as well. 477 // ReplaceAll() expects regexp so \ char are escaped twice. 478 String message = mSmsMessage.getText(); 479 message = message.replaceAll("\\\\", //$NON-NLS-1$ 480 "\\\\\\\\"); //$NON-NLS-1$ 481 482 // While the normal line delimiter is returned by Text.getLineDelimiter() 483 // it seems copy pasting text coming from somewhere else could have another 484 // delimited. For this reason, we'll replace is several steps 485 486 // replace the dual CR-LF 487 message = message.replaceAll("\r\n", "\\\\n"); //$NON-NLS-1$ //$NON-NLS-1$ 488 489 // replace remaining stand alone \n 490 message = message.replaceAll("\n", "\\\\n"); //$NON-NLS-1$ //$NON-NLS-1$ 491 492 // replace remaining stand alone \r 493 message = message.replaceAll("\r", "\\\\n"); //$NON-NLS-1$ //$NON-NLS-1$ 494 495 processCommandResult(mEmulatorConsole.sendSms(mPhoneNumber.getText().trim(), 496 message)); 497 } 498 } 499 } 500 }); 501 502 mCancelButton = new Button(g2ButtonComp, SWT.PUSH); 503 mCancelButton.setText("Hang Up"); 504 mCancelButton.setEnabled(false); 505 mCancelButton.addSelectionListener(new SelectionAdapter() { 506 @Override 507 public void widgetSelected(SelectionEvent e) { 508 if (mEmulatorConsole != null) { 509 if (mVoiceButton.getSelection()) { 510 processCommandResult(mEmulatorConsole.cancelCall( 511 mPhoneNumber.getText().trim())); 512 } 513 } 514 } 515 }); 516 } 517 518 /** 519 * Create Location controls. 520 * @param top 521 */ 522 private void createLocationControls(final Composite top) { 523 Label l = new Label(top, SWT.NONE); 524 l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 525 l.setText("Location Controls"); 526 527 mLocationFolders = new TabFolder(top, SWT.NONE); 528 mLocationFolders.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 529 530 Composite manualLocationComp = new Composite(mLocationFolders, SWT.NONE); 531 TabItem item = new TabItem(mLocationFolders, SWT.NONE); 532 item.setText("Manual"); 533 item.setControl(manualLocationComp); 534 535 createManualLocationControl(manualLocationComp); 536 537 ImageLoader loader = ImageLoader.getDdmUiLibLoader(); 538 mPlayImage = loader.loadImage("play.png", mParent.getDisplay()); //$NON-NLS-1$ 539 mPauseImage = loader.loadImage("pause.png", mParent.getDisplay()); //$NON-NLS-1$ 540 541 Composite gpxLocationComp = new Composite(mLocationFolders, SWT.NONE); 542 item = new TabItem(mLocationFolders, SWT.NONE); 543 item.setText("GPX"); 544 item.setControl(gpxLocationComp); 545 546 createGpxLocationControl(gpxLocationComp); 547 548 Composite kmlLocationComp = new Composite(mLocationFolders, SWT.NONE); 549 kmlLocationComp.setLayout(new FillLayout()); 550 item = new TabItem(mLocationFolders, SWT.NONE); 551 item.setText("KML"); 552 item.setControl(kmlLocationComp); 553 554 createKmlLocationControl(kmlLocationComp); 555 } 556 557 private void createManualLocationControl(Composite manualLocationComp) { 558 final StackLayout sl; 559 GridLayout gl; 560 Label label; 561 562 manualLocationComp.setLayout(new GridLayout(1, false)); 563 mDecimalButton = new Button(manualLocationComp, SWT.RADIO); 564 mDecimalButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 565 mDecimalButton.setText("Decimal"); 566 mSexagesimalButton = new Button(manualLocationComp, SWT.RADIO); 567 mSexagesimalButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 568 mSexagesimalButton.setText("Sexagesimal"); 569 570 // composite to hold and switching between the 2 modes. 571 final Composite content = new Composite(manualLocationComp, SWT.NONE); 572 content.setLayout(sl = new StackLayout()); 573 574 // decimal display 575 final Composite decimalContent = new Composite(content, SWT.NONE); 576 decimalContent.setLayout(gl = new GridLayout(2, false)); 577 gl.marginHeight = gl.marginWidth = 0; 578 579 mLongitudeControls = new CoordinateControls(); 580 mLatitudeControls = new CoordinateControls(); 581 582 label = new Label(decimalContent, SWT.NONE); 583 label.setText("Longitude"); 584 585 mLongitudeControls.createDecimalText(decimalContent); 586 587 label = new Label(decimalContent, SWT.NONE); 588 label.setText("Latitude"); 589 590 mLatitudeControls.createDecimalText(decimalContent); 591 592 // sexagesimal content 593 final Composite sexagesimalContent = new Composite(content, SWT.NONE); 594 sexagesimalContent.setLayout(gl = new GridLayout(7, false)); 595 gl.marginHeight = gl.marginWidth = 0; 596 597 label = new Label(sexagesimalContent, SWT.NONE); 598 label.setText("Longitude"); 599 600 mLongitudeControls.createSexagesimalDegreeText(sexagesimalContent); 601 602 label = new Label(sexagesimalContent, SWT.NONE); 603 label.setText("\u00B0"); // degree character 604 605 mLongitudeControls.createSexagesimalMinuteText(sexagesimalContent); 606 607 label = new Label(sexagesimalContent, SWT.NONE); 608 label.setText("'"); 609 610 mLongitudeControls.createSexagesimalSecondText(sexagesimalContent); 611 612 label = new Label(sexagesimalContent, SWT.NONE); 613 label.setText("\""); 614 615 label = new Label(sexagesimalContent, SWT.NONE); 616 label.setText("Latitude"); 617 618 mLatitudeControls.createSexagesimalDegreeText(sexagesimalContent); 619 620 label = new Label(sexagesimalContent, SWT.NONE); 621 label.setText("\u00B0"); 622 623 mLatitudeControls.createSexagesimalMinuteText(sexagesimalContent); 624 625 label = new Label(sexagesimalContent, SWT.NONE); 626 label.setText("'"); 627 628 mLatitudeControls.createSexagesimalSecondText(sexagesimalContent); 629 630 label = new Label(sexagesimalContent, SWT.NONE); 631 label.setText("\""); 632 633 // set the default display to decimal 634 sl.topControl = decimalContent; 635 mDecimalButton.setSelection(true); 636 637 mDecimalButton.addSelectionListener(new SelectionAdapter() { 638 @Override 639 public void widgetSelected(SelectionEvent e) { 640 if (mDecimalButton.getSelection()) { 641 sl.topControl = decimalContent; 642 } else { 643 sl.topControl = sexagesimalContent; 644 } 645 content.layout(); 646 } 647 }); 648 649 Button sendButton = new Button(manualLocationComp, SWT.PUSH); 650 sendButton.setText("Send"); 651 sendButton.addSelectionListener(new SelectionAdapter() { 652 @Override 653 public void widgetSelected(SelectionEvent e) { 654 if (mEmulatorConsole != null) { 655 processCommandResult(mEmulatorConsole.sendLocation( 656 mLongitudeControls.getValue(), mLatitudeControls.getValue(), 0)); 657 } 658 } 659 }); 660 661 mLongitudeControls.setValue(DEFAULT_LONGITUDE); 662 mLatitudeControls.setValue(DEFAULT_LATITUDE); 663 } 664 665 private void createGpxLocationControl(Composite gpxLocationComp) { 666 GridData gd; 667 668 IPreferenceStore store = DdmUiPreferences.getStore(); 669 670 gpxLocationComp.setLayout(new GridLayout(1, false)); 671 672 mGpxUploadButton = new Button(gpxLocationComp, SWT.PUSH); 673 mGpxUploadButton.setText("Load GPX..."); 674 675 // Table for way point 676 mGpxWayPointTable = new Table(gpxLocationComp, 677 SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); 678 mGpxWayPointTable.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); 679 gd.heightHint = 100; 680 mGpxWayPointTable.setHeaderVisible(true); 681 mGpxWayPointTable.setLinesVisible(true); 682 683 TableHelper.createTableColumn(mGpxWayPointTable, "Name", SWT.LEFT, 684 "Some Name", 685 PREFS_WAYPOINT_COL_NAME, store); 686 TableHelper.createTableColumn(mGpxWayPointTable, "Longitude", SWT.LEFT, 687 "-199.999999", 688 PREFS_WAYPOINT_COL_LONGITUDE, store); 689 TableHelper.createTableColumn(mGpxWayPointTable, "Latitude", SWT.LEFT, 690 "-199.999999", 691 PREFS_WAYPOINT_COL_LATITUDE, store); 692 TableHelper.createTableColumn(mGpxWayPointTable, "Elevation", SWT.LEFT, 693 "99999.9", 694 PREFS_WAYPOINT_COL_ELEVATION, store); 695 TableHelper.createTableColumn(mGpxWayPointTable, "Description", SWT.LEFT, 696 "Some Description", 697 PREFS_WAYPOINT_COL_DESCRIPTION, store); 698 699 final TableViewer gpxWayPointViewer = new TableViewer(mGpxWayPointTable); 700 gpxWayPointViewer.setContentProvider(new WayPointContentProvider()); 701 gpxWayPointViewer.setLabelProvider(new WayPointLabelProvider()); 702 703 gpxWayPointViewer.addSelectionChangedListener(new ISelectionChangedListener() { 704 public void selectionChanged(SelectionChangedEvent event) { 705 ISelection selection = event.getSelection(); 706 if (selection instanceof IStructuredSelection) { 707 IStructuredSelection structuredSelection = (IStructuredSelection)selection; 708 Object selectedObject = structuredSelection.getFirstElement(); 709 if (selectedObject instanceof WayPoint) { 710 WayPoint wayPoint = (WayPoint)selectedObject; 711 712 if (mEmulatorConsole != null && mPlayingTrack == false) { 713 processCommandResult(mEmulatorConsole.sendLocation( 714 wayPoint.getLongitude(), wayPoint.getLatitude(), 715 wayPoint.getElevation())); 716 } 717 } 718 } 719 } 720 }); 721 722 // table for tracks. 723 mGpxTrackTable = new Table(gpxLocationComp, 724 SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); 725 mGpxTrackTable.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); 726 gd.heightHint = 100; 727 mGpxTrackTable.setHeaderVisible(true); 728 mGpxTrackTable.setLinesVisible(true); 729 730 TableHelper.createTableColumn(mGpxTrackTable, "Name", SWT.LEFT, 731 "Some very long name", 732 PREFS_TRACK_COL_NAME, store); 733 TableHelper.createTableColumn(mGpxTrackTable, "Point Count", SWT.RIGHT, 734 "9999", 735 PREFS_TRACK_COL_COUNT, store); 736 TableHelper.createTableColumn(mGpxTrackTable, "First Point Time", SWT.LEFT, 737 "999-99-99T99:99:99Z", 738 PREFS_TRACK_COL_FIRST, store); 739 TableHelper.createTableColumn(mGpxTrackTable, "Last Point Time", SWT.LEFT, 740 "999-99-99T99:99:99Z", 741 PREFS_TRACK_COL_LAST, store); 742 TableHelper.createTableColumn(mGpxTrackTable, "Comment", SWT.LEFT, 743 "-199.999999", 744 PREFS_TRACK_COL_COMMENT, store); 745 746 final TableViewer gpxTrackViewer = new TableViewer(mGpxTrackTable); 747 gpxTrackViewer.setContentProvider(new TrackContentProvider()); 748 gpxTrackViewer.setLabelProvider(new TrackLabelProvider()); 749 750 gpxTrackViewer.addSelectionChangedListener(new ISelectionChangedListener() { 751 public void selectionChanged(SelectionChangedEvent event) { 752 ISelection selection = event.getSelection(); 753 if (selection instanceof IStructuredSelection) { 754 IStructuredSelection structuredSelection = (IStructuredSelection)selection; 755 Object selectedObject = structuredSelection.getFirstElement(); 756 if (selectedObject instanceof Track) { 757 Track track = (Track)selectedObject; 758 759 if (mEmulatorConsole != null && mPlayingTrack == false) { 760 TrackPoint[] points = track.getPoints(); 761 processCommandResult(mEmulatorConsole.sendLocation( 762 points[0].getLongitude(), points[0].getLatitude(), 763 points[0].getElevation())); 764 } 765 766 mPlayGpxButton.setEnabled(true); 767 mGpxBackwardButton.setEnabled(true); 768 mGpxForwardButton.setEnabled(true); 769 mGpxSpeedButton.setEnabled(true); 770 771 return; 772 } 773 } 774 775 mPlayGpxButton.setEnabled(false); 776 mGpxBackwardButton.setEnabled(false); 777 mGpxForwardButton.setEnabled(false); 778 mGpxSpeedButton.setEnabled(false); 779 } 780 }); 781 782 mGpxUploadButton.addSelectionListener(new SelectionAdapter() { 783 @Override 784 public void widgetSelected(SelectionEvent e) { 785 FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.OPEN); 786 787 fileDialog.setText("Load GPX File"); 788 fileDialog.setFilterExtensions(new String[] { "*.gpx" } ); 789 790 String fileName = fileDialog.open(); 791 if (fileName != null) { 792 GpxParser parser = new GpxParser(fileName); 793 if (parser.parse()) { 794 gpxWayPointViewer.setInput(parser.getWayPoints()); 795 gpxTrackViewer.setInput(parser.getTracks()); 796 } 797 } 798 } 799 }); 800 801 mGpxPlayControls = new Composite(gpxLocationComp, SWT.NONE); 802 GridLayout gl; 803 mGpxPlayControls.setLayout(gl = new GridLayout(5, false)); 804 gl.marginHeight = gl.marginWidth = 0; 805 mGpxPlayControls.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 806 807 mPlayGpxButton = new Button(mGpxPlayControls, SWT.PUSH | SWT.FLAT); 808 mPlayGpxButton.setImage(mPlayImage); 809 mPlayGpxButton.addSelectionListener(new SelectionAdapter() { 810 @Override 811 public void widgetSelected(SelectionEvent e) { 812 if (mPlayingTrack == false) { 813 ISelection selection = gpxTrackViewer.getSelection(); 814 if (selection.isEmpty() == false && selection instanceof IStructuredSelection) { 815 IStructuredSelection structuredSelection = (IStructuredSelection)selection; 816 Object selectedObject = structuredSelection.getFirstElement(); 817 if (selectedObject instanceof Track) { 818 Track track = (Track)selectedObject; 819 playTrack(track); 820 } 821 } 822 } else { 823 // if we're playing, then we pause 824 mPlayingTrack = false; 825 if (mPlayingThread != null) { 826 mPlayingThread.interrupt(); 827 } 828 } 829 } 830 }); 831 832 Label separator = new Label(mGpxPlayControls, SWT.SEPARATOR | SWT.VERTICAL); 833 separator.setLayoutData(gd = new GridData( 834 GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL)); 835 gd.heightHint = 0; 836 837 ImageLoader loader = ImageLoader.getDdmUiLibLoader(); 838 mGpxBackwardButton = new Button(mGpxPlayControls, SWT.TOGGLE | SWT.FLAT); 839 mGpxBackwardButton.setImage(loader.loadImage("backward.png", mParent.getDisplay())); //$NON-NLS-1$ 840 mGpxBackwardButton.setSelection(false); 841 mGpxBackwardButton.addSelectionListener(mDirectionButtonAdapter); 842 mGpxForwardButton = new Button(mGpxPlayControls, SWT.TOGGLE | SWT.FLAT); 843 mGpxForwardButton.setImage(loader.loadImage("forward.png", mParent.getDisplay())); //$NON-NLS-1$ 844 mGpxForwardButton.setSelection(true); 845 mGpxForwardButton.addSelectionListener(mDirectionButtonAdapter); 846 847 mGpxSpeedButton = new Button(mGpxPlayControls, SWT.PUSH | SWT.FLAT); 848 849 mSpeedIndex = 0; 850 mSpeed = PLAY_SPEEDS[mSpeedIndex]; 851 852 mGpxSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); 853 mGpxSpeedButton.addSelectionListener(mSpeedButtonAdapter); 854 855 mPlayGpxButton.setEnabled(false); 856 mGpxBackwardButton.setEnabled(false); 857 mGpxForwardButton.setEnabled(false); 858 mGpxSpeedButton.setEnabled(false); 859 860 } 861 862 private void createKmlLocationControl(Composite kmlLocationComp) { 863 GridData gd; 864 865 IPreferenceStore store = DdmUiPreferences.getStore(); 866 867 kmlLocationComp.setLayout(new GridLayout(1, false)); 868 869 mKmlUploadButton = new Button(kmlLocationComp, SWT.PUSH); 870 mKmlUploadButton.setText("Load KML..."); 871 872 // Table for way point 873 mKmlWayPointTable = new Table(kmlLocationComp, 874 SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); 875 mKmlWayPointTable.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); 876 gd.heightHint = 200; 877 mKmlWayPointTable.setHeaderVisible(true); 878 mKmlWayPointTable.setLinesVisible(true); 879 880 TableHelper.createTableColumn(mKmlWayPointTable, "Name", SWT.LEFT, 881 "Some Name", 882 PREFS_WAYPOINT_COL_NAME, store); 883 TableHelper.createTableColumn(mKmlWayPointTable, "Longitude", SWT.LEFT, 884 "-199.999999", 885 PREFS_WAYPOINT_COL_LONGITUDE, store); 886 TableHelper.createTableColumn(mKmlWayPointTable, "Latitude", SWT.LEFT, 887 "-199.999999", 888 PREFS_WAYPOINT_COL_LATITUDE, store); 889 TableHelper.createTableColumn(mKmlWayPointTable, "Elevation", SWT.LEFT, 890 "99999.9", 891 PREFS_WAYPOINT_COL_ELEVATION, store); 892 TableHelper.createTableColumn(mKmlWayPointTable, "Description", SWT.LEFT, 893 "Some Description", 894 PREFS_WAYPOINT_COL_DESCRIPTION, store); 895 896 final TableViewer kmlWayPointViewer = new TableViewer(mKmlWayPointTable); 897 kmlWayPointViewer.setContentProvider(new WayPointContentProvider()); 898 kmlWayPointViewer.setLabelProvider(new WayPointLabelProvider()); 899 900 mKmlUploadButton.addSelectionListener(new SelectionAdapter() { 901 @Override 902 public void widgetSelected(SelectionEvent e) { 903 FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.OPEN); 904 905 fileDialog.setText("Load KML File"); 906 fileDialog.setFilterExtensions(new String[] { "*.kml" } ); 907 908 String fileName = fileDialog.open(); 909 if (fileName != null) { 910 KmlParser parser = new KmlParser(fileName); 911 if (parser.parse()) { 912 kmlWayPointViewer.setInput(parser.getWayPoints()); 913 914 mPlayKmlButton.setEnabled(true); 915 mKmlBackwardButton.setEnabled(true); 916 mKmlForwardButton.setEnabled(true); 917 mKmlSpeedButton.setEnabled(true); 918 } 919 } 920 } 921 }); 922 923 kmlWayPointViewer.addSelectionChangedListener(new ISelectionChangedListener() { 924 public void selectionChanged(SelectionChangedEvent event) { 925 ISelection selection = event.getSelection(); 926 if (selection instanceof IStructuredSelection) { 927 IStructuredSelection structuredSelection = (IStructuredSelection)selection; 928 Object selectedObject = structuredSelection.getFirstElement(); 929 if (selectedObject instanceof WayPoint) { 930 WayPoint wayPoint = (WayPoint)selectedObject; 931 932 if (mEmulatorConsole != null && mPlayingTrack == false) { 933 processCommandResult(mEmulatorConsole.sendLocation( 934 wayPoint.getLongitude(), wayPoint.getLatitude(), 935 wayPoint.getElevation())); 936 } 937 } 938 } 939 } 940 }); 941 942 943 944 mKmlPlayControls = new Composite(kmlLocationComp, SWT.NONE); 945 GridLayout gl; 946 mKmlPlayControls.setLayout(gl = new GridLayout(5, false)); 947 gl.marginHeight = gl.marginWidth = 0; 948 mKmlPlayControls.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 949 950 mPlayKmlButton = new Button(mKmlPlayControls, SWT.PUSH | SWT.FLAT); 951 mPlayKmlButton.setImage(mPlayImage); 952 mPlayKmlButton.addSelectionListener(new SelectionAdapter() { 953 @Override 954 public void widgetSelected(SelectionEvent e) { 955 if (mPlayingTrack == false) { 956 Object input = kmlWayPointViewer.getInput(); 957 if (input instanceof WayPoint[]) { 958 playKml((WayPoint[])input); 959 } 960 } else { 961 // if we're playing, then we pause 962 mPlayingTrack = false; 963 if (mPlayingThread != null) { 964 mPlayingThread.interrupt(); 965 } 966 } 967 } 968 }); 969 970 Label separator = new Label(mKmlPlayControls, SWT.SEPARATOR | SWT.VERTICAL); 971 separator.setLayoutData(gd = new GridData( 972 GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL)); 973 gd.heightHint = 0; 974 975 ImageLoader loader = ImageLoader.getDdmUiLibLoader(); 976 mKmlBackwardButton = new Button(mKmlPlayControls, SWT.TOGGLE | SWT.FLAT); 977 mKmlBackwardButton.setImage(loader.loadImage("backward.png", mParent.getDisplay())); //$NON-NLS-1$ 978 mKmlBackwardButton.setSelection(false); 979 mKmlBackwardButton.addSelectionListener(mDirectionButtonAdapter); 980 mKmlForwardButton = new Button(mKmlPlayControls, SWT.TOGGLE | SWT.FLAT); 981 mKmlForwardButton.setImage(loader.loadImage("forward.png", mParent.getDisplay())); //$NON-NLS-1$ 982 mKmlForwardButton.setSelection(true); 983 mKmlForwardButton.addSelectionListener(mDirectionButtonAdapter); 984 985 mKmlSpeedButton = new Button(mKmlPlayControls, SWT.PUSH | SWT.FLAT); 986 987 mSpeedIndex = 0; 988 mSpeed = PLAY_SPEEDS[mSpeedIndex]; 989 990 mKmlSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); 991 mKmlSpeedButton.addSelectionListener(mSpeedButtonAdapter); 992 993 mPlayKmlButton.setEnabled(false); 994 mKmlBackwardButton.setEnabled(false); 995 mKmlForwardButton.setEnabled(false); 996 mKmlSpeedButton.setEnabled(false); 997 } 998 999 /** 1000 * Sets the focus to the proper control inside the panel. 1001 */ 1002 @Override 1003 public void setFocus() { 1004 } 1005 1006 @Override 1007 protected void postCreation() { 1008 // pass 1009 } 1010 1011 private synchronized void setDataMode(int selectionIndex) { 1012 if (mEmulatorConsole != null) { 1013 processCommandResult(mEmulatorConsole.setGsmDataMode( 1014 GsmMode.getEnum(GSM_MODES[selectionIndex][1]))); 1015 } 1016 } 1017 1018 private synchronized void setVoiceMode(int selectionIndex) { 1019 if (mEmulatorConsole != null) { 1020 processCommandResult(mEmulatorConsole.setGsmVoiceMode( 1021 GsmMode.getEnum(GSM_MODES[selectionIndex][1]))); 1022 } 1023 } 1024 1025 private synchronized void setNetworkLatency(int selectionIndex) { 1026 if (mEmulatorConsole != null) { 1027 processCommandResult(mEmulatorConsole.setNetworkLatency(selectionIndex)); 1028 } 1029 } 1030 1031 private synchronized void setNetworkSpeed(int selectionIndex) { 1032 if (mEmulatorConsole != null) { 1033 processCommandResult(mEmulatorConsole.setNetworkSpeed(selectionIndex)); 1034 } 1035 } 1036 1037 1038 /** 1039 * Callback on device selection change. 1040 * @param device the new selected device 1041 */ 1042 public void handleNewDevice(IDevice device) { 1043 if (mParent.isDisposed()) { 1044 return; 1045 } 1046 // unlink to previous console. 1047 synchronized (this) { 1048 mEmulatorConsole = null; 1049 } 1050 1051 try { 1052 // get the emulator console for this device 1053 // First we need the device itself 1054 if (device != null) { 1055 GsmStatus gsm = null; 1056 NetworkStatus netstatus = null; 1057 1058 synchronized (this) { 1059 mEmulatorConsole = EmulatorConsole.getConsole(device); 1060 if (mEmulatorConsole != null) { 1061 // get the gsm status 1062 gsm = mEmulatorConsole.getGsmStatus(); 1063 netstatus = mEmulatorConsole.getNetworkStatus(); 1064 1065 if (gsm == null || netstatus == null) { 1066 mEmulatorConsole = null; 1067 } 1068 } 1069 } 1070 1071 if (gsm != null && netstatus != null) { 1072 Display d = mParent.getDisplay(); 1073 if (d.isDisposed() == false) { 1074 final GsmStatus f_gsm = gsm; 1075 final NetworkStatus f_netstatus = netstatus; 1076 1077 d.asyncExec(new Runnable() { 1078 public void run() { 1079 if (f_gsm.voice != GsmMode.UNKNOWN) { 1080 mVoiceMode.select(getGsmComboIndex(f_gsm.voice)); 1081 } else { 1082 mVoiceMode.clearSelection(); 1083 } 1084 if (f_gsm.data != GsmMode.UNKNOWN) { 1085 mDataMode.select(getGsmComboIndex(f_gsm.data)); 1086 } else { 1087 mDataMode.clearSelection(); 1088 } 1089 1090 if (f_netstatus.speed != -1) { 1091 mNetworkSpeed.select(f_netstatus.speed); 1092 } else { 1093 mNetworkSpeed.clearSelection(); 1094 } 1095 1096 if (f_netstatus.latency != -1) { 1097 mNetworkLatency.select(f_netstatus.latency); 1098 } else { 1099 mNetworkLatency.clearSelection(); 1100 } 1101 } 1102 }); 1103 } 1104 } 1105 } 1106 } finally { 1107 // enable/disable the ui 1108 boolean enable = false; 1109 synchronized (this) { 1110 enable = mEmulatorConsole != null; 1111 } 1112 1113 enable(enable); 1114 } 1115 } 1116 1117 /** 1118 * Enable or disable the ui. Can be called from non ui threads. 1119 * @param enabled 1120 */ 1121 private void enable(final boolean enabled) { 1122 try { 1123 Display d = mParent.getDisplay(); 1124 d.asyncExec(new Runnable() { 1125 public void run() { 1126 if (mParent.isDisposed() == false) { 1127 doEnable(enabled); 1128 } 1129 } 1130 }); 1131 } catch (SWTException e) { 1132 // disposed. do nothing 1133 } 1134 } 1135 1136 private boolean isValidPhoneNumber() { 1137 String number = mPhoneNumber.getText().trim(); 1138 1139 return number.matches(RE_PHONE_NUMBER); 1140 } 1141 1142 /** 1143 * Enable or disable the ui. Cannot be called from non ui threads. 1144 * @param enabled 1145 */ 1146 protected void doEnable(boolean enabled) { 1147 mVoiceLabel.setEnabled(enabled); 1148 mVoiceMode.setEnabled(enabled); 1149 1150 mDataLabel.setEnabled(enabled); 1151 mDataMode.setEnabled(enabled); 1152 1153 mSpeedLabel.setEnabled(enabled); 1154 mNetworkSpeed.setEnabled(enabled); 1155 1156 mLatencyLabel.setEnabled(enabled); 1157 mNetworkLatency.setEnabled(enabled); 1158 1159 // Calling setEnabled on a text field will trigger a modifyText event, so we don't do it 1160 // if we don't need to. 1161 if (mPhoneNumber.isEnabled() != enabled) { 1162 mNumberLabel.setEnabled(enabled); 1163 mPhoneNumber.setEnabled(enabled); 1164 } 1165 1166 boolean valid = isValidPhoneNumber(); 1167 1168 mVoiceButton.setEnabled(enabled && valid); 1169 mSmsButton.setEnabled(enabled && valid); 1170 1171 boolean smsValid = enabled && valid && mSmsButton.getSelection(); 1172 1173 // Calling setEnabled on a text field will trigger a modifyText event, so we don't do it 1174 // if we don't need to. 1175 if (mSmsMessage.isEnabled() != smsValid) { 1176 mMessageLabel.setEnabled(smsValid); 1177 mSmsMessage.setEnabled(smsValid); 1178 } 1179 if (enabled == false) { 1180 mSmsMessage.setText(""); //$NON-NLs-1$ 1181 } 1182 1183 mCallButton.setEnabled(enabled && valid); 1184 mCancelButton.setEnabled(enabled && valid && mVoiceButton.getSelection()); 1185 1186 if (enabled == false) { 1187 mVoiceMode.clearSelection(); 1188 mDataMode.clearSelection(); 1189 mNetworkSpeed.clearSelection(); 1190 mNetworkLatency.clearSelection(); 1191 if (mPhoneNumber.getText().length() > 0) { 1192 mPhoneNumber.setText(""); //$NON-NLS-1$ 1193 } 1194 } 1195 1196 // location controls 1197 mLocationFolders.setEnabled(enabled); 1198 1199 mDecimalButton.setEnabled(enabled); 1200 mSexagesimalButton.setEnabled(enabled); 1201 mLongitudeControls.setEnabled(enabled); 1202 mLatitudeControls.setEnabled(enabled); 1203 1204 mGpxUploadButton.setEnabled(enabled); 1205 mGpxWayPointTable.setEnabled(enabled); 1206 mGpxTrackTable.setEnabled(enabled); 1207 mKmlUploadButton.setEnabled(enabled); 1208 mKmlWayPointTable.setEnabled(enabled); 1209 } 1210 1211 /** 1212 * Returns the index of the combo item matching a specific GsmMode. 1213 * @param mode 1214 */ 1215 private int getGsmComboIndex(GsmMode mode) { 1216 for (int i = 0 ; i < GSM_MODES.length; i++) { 1217 String[] modes = GSM_MODES[i]; 1218 if (mode.getTag().equals(modes[1])) { 1219 return i; 1220 } 1221 } 1222 return -1; 1223 } 1224 1225 /** 1226 * Processes the result of a command sent to the console. 1227 * @param result the result of the command. 1228 */ 1229 private boolean processCommandResult(final String result) { 1230 if (result != EmulatorConsole.RESULT_OK) { 1231 try { 1232 mParent.getDisplay().asyncExec(new Runnable() { 1233 public void run() { 1234 if (mParent.isDisposed() == false) { 1235 MessageDialog.openError(mParent.getShell(), "Emulator Console", 1236 result); 1237 } 1238 } 1239 }); 1240 } catch (SWTException e) { 1241 // we're quitting, just ignore 1242 } 1243 1244 return false; 1245 } 1246 1247 return true; 1248 } 1249 1250 /** 1251 * @param track 1252 */ 1253 private void playTrack(final Track track) { 1254 // no need to synchronize this check, the worst that can happen, is we start the thread 1255 // for nothing. 1256 if (mEmulatorConsole != null) { 1257 mPlayGpxButton.setImage(mPauseImage); 1258 mPlayKmlButton.setImage(mPauseImage); 1259 mPlayingTrack = true; 1260 1261 mPlayingThread = new Thread() { 1262 @Override 1263 public void run() { 1264 try { 1265 TrackPoint[] trackPoints = track.getPoints(); 1266 int count = trackPoints.length; 1267 1268 // get the start index. 1269 int start = 0; 1270 if (mPlayDirection == -1) { 1271 start = count - 1; 1272 } 1273 1274 for (int p = start; p >= 0 && p < count; p += mPlayDirection) { 1275 if (mPlayingTrack == false) { 1276 return; 1277 } 1278 1279 // get the current point and send its location to 1280 // the emulator. 1281 final TrackPoint trackPoint = trackPoints[p]; 1282 1283 synchronized (EmulatorControlPanel.this) { 1284 if (mEmulatorConsole == null || 1285 processCommandResult(mEmulatorConsole.sendLocation( 1286 trackPoint.getLongitude(), trackPoint.getLatitude(), 1287 trackPoint.getElevation())) == false) { 1288 return; 1289 } 1290 } 1291 1292 // if this is not the final point, then get the next one and 1293 // compute the delta time 1294 int nextIndex = p + mPlayDirection; 1295 if (nextIndex >=0 && nextIndex < count) { 1296 TrackPoint nextPoint = trackPoints[nextIndex]; 1297 1298 long delta = nextPoint.getTime() - trackPoint.getTime(); 1299 if (delta < 0) { 1300 delta = -delta; 1301 } 1302 1303 long startTime = System.currentTimeMillis(); 1304 1305 try { 1306 sleep(delta / mSpeed); 1307 } catch (InterruptedException e) { 1308 if (mPlayingTrack == false) { 1309 return; 1310 } 1311 1312 // we got interrupted, lets make sure we can play 1313 do { 1314 long waited = System.currentTimeMillis() - startTime; 1315 long needToWait = delta / mSpeed; 1316 if (waited < needToWait) { 1317 try { 1318 sleep(needToWait - waited); 1319 } catch (InterruptedException e1) { 1320 // we'll just loop and wait again if needed. 1321 // unless we're supposed to stop 1322 if (mPlayingTrack == false) { 1323 return; 1324 } 1325 } 1326 } else { 1327 break; 1328 } 1329 } while (true); 1330 } 1331 } 1332 } 1333 } finally { 1334 mPlayingTrack = false; 1335 try { 1336 mParent.getDisplay().asyncExec(new Runnable() { 1337 public void run() { 1338 if (mPlayGpxButton.isDisposed() == false) { 1339 mPlayGpxButton.setImage(mPlayImage); 1340 mPlayKmlButton.setImage(mPlayImage); 1341 } 1342 } 1343 }); 1344 } catch (SWTException e) { 1345 // we're quitting, just ignore 1346 } 1347 } 1348 } 1349 }; 1350 1351 mPlayingThread.start(); 1352 } 1353 } 1354 1355 private void playKml(final WayPoint[] trackPoints) { 1356 // no need to synchronize this check, the worst that can happen, is we start the thread 1357 // for nothing. 1358 if (mEmulatorConsole != null) { 1359 mPlayGpxButton.setImage(mPauseImage); 1360 mPlayKmlButton.setImage(mPauseImage); 1361 mPlayingTrack = true; 1362 1363 mPlayingThread = new Thread() { 1364 @Override 1365 public void run() { 1366 try { 1367 int count = trackPoints.length; 1368 1369 // get the start index. 1370 int start = 0; 1371 if (mPlayDirection == -1) { 1372 start = count - 1; 1373 } 1374 1375 for (int p = start; p >= 0 && p < count; p += mPlayDirection) { 1376 if (mPlayingTrack == false) { 1377 return; 1378 } 1379 1380 // get the current point and send its location to 1381 // the emulator. 1382 WayPoint trackPoint = trackPoints[p]; 1383 1384 synchronized (EmulatorControlPanel.this) { 1385 if (mEmulatorConsole == null || 1386 processCommandResult(mEmulatorConsole.sendLocation( 1387 trackPoint.getLongitude(), trackPoint.getLatitude(), 1388 trackPoint.getElevation())) == false) { 1389 return; 1390 } 1391 } 1392 1393 // if this is not the final point, then get the next one and 1394 // compute the delta time 1395 int nextIndex = p + mPlayDirection; 1396 if (nextIndex >=0 && nextIndex < count) { 1397 1398 long delta = 1000; // 1 second 1399 if (delta < 0) { 1400 delta = -delta; 1401 } 1402 1403 long startTime = System.currentTimeMillis(); 1404 1405 try { 1406 sleep(delta / mSpeed); 1407 } catch (InterruptedException e) { 1408 if (mPlayingTrack == false) { 1409 return; 1410 } 1411 1412 // we got interrupted, lets make sure we can play 1413 do { 1414 long waited = System.currentTimeMillis() - startTime; 1415 long needToWait = delta / mSpeed; 1416 if (waited < needToWait) { 1417 try { 1418 sleep(needToWait - waited); 1419 } catch (InterruptedException e1) { 1420 // we'll just loop and wait again if needed. 1421 // unless we're supposed to stop 1422 if (mPlayingTrack == false) { 1423 return; 1424 } 1425 } 1426 } else { 1427 break; 1428 } 1429 } while (true); 1430 } 1431 } 1432 } 1433 } finally { 1434 mPlayingTrack = false; 1435 try { 1436 mParent.getDisplay().asyncExec(new Runnable() { 1437 public void run() { 1438 if (mPlayGpxButton.isDisposed() == false) { 1439 mPlayGpxButton.setImage(mPlayImage); 1440 mPlayKmlButton.setImage(mPlayImage); 1441 } 1442 } 1443 }); 1444 } catch (SWTException e) { 1445 // we're quitting, just ignore 1446 } 1447 } 1448 } 1449 }; 1450 1451 mPlayingThread.start(); 1452 } 1453 } 1454 } 1455