diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse')
17 files changed, 1903 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/AndroidPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/AndroidPreferencePage.java new file mode 100644 index 000000000..b85f0163d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/AndroidPreferencePage.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 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.monitor; + +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +public class AndroidPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { + public AndroidPreferencePage() { + super(""); //$NON-NLS-1$ + setPreferenceStore(MonitorPlugin.getDefault().getPreferenceStore()); + } + + @Override + public void init(IWorkbench workbench) { + } + + @Override + protected Control createContents(Composite parent) { + // TODO: This page is empty currently. It is only used as the top level + // to which DDMS & logcat attach their preference pages. + // ADT's root page contains the path to the Android SDK, and we should recreate + // that here once we figure out how to share this across plugins. + return null; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorActionBarAdvisor.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorActionBarAdvisor.java new file mode 100644 index 000000000..e31e45ebe --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorActionBarAdvisor.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 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.monitor; + +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.internal.IWorkbenchGraphicConstants; +import org.eclipse.ui.internal.WorkbenchImages; + +public class MonitorActionBarAdvisor extends ActionBarAdvisor { + private IWorkbenchAction mQuitAction; + private IWorkbenchAction mCopyAction; + private IWorkbenchAction mSelectAllAction; + private IWorkbenchAction mFindAction; + private IWorkbenchAction mOpenPerspectiveAction; + private IWorkbenchAction mResetPerspectiveAction; + private IWorkbenchAction mPreferencesAction; + private IWorkbenchAction mAboutAction; + + public MonitorActionBarAdvisor(IActionBarConfigurer configurer) { + super(configurer); + } + + @Override + protected void makeActions(IWorkbenchWindow window) { + mQuitAction = ActionFactory.QUIT.create(window); + register(mQuitAction); + + mCopyAction = ActionFactory.COPY.create(window); + register(mCopyAction); + + mSelectAllAction = ActionFactory.SELECT_ALL.create(window); + register(mSelectAllAction); + + mFindAction = ActionFactory.FIND.create(window); + mFindAction.setText("Find..."); // replace the default "Find and Replace..." + register(mFindAction); + + mOpenPerspectiveAction = ActionFactory.OPEN_PERSPECTIVE_DIALOG.create(window); + register(mOpenPerspectiveAction); + + mResetPerspectiveAction = ActionFactory.RESET_PERSPECTIVE.create(window); + register(mResetPerspectiveAction); + + mPreferencesAction = ActionFactory.PREFERENCES.create(window); + register(mPreferencesAction); + + mAboutAction = ActionFactory.ABOUT.create(window); + register(mAboutAction); + } + + @Override + protected void fillMenuBar(IMenuManager menuBar) { + MenuManager fileMenu = new MenuManager("&File", IWorkbenchActionConstants.M_FILE); + MenuManager editMenu = new MenuManager("&Edit", IWorkbenchActionConstants.M_EDIT); + MenuManager helpMenu = new MenuManager("&Help", IWorkbenchActionConstants.M_HELP); + MenuManager windowMenu = new MenuManager("&Window", IWorkbenchActionConstants.M_WINDOW); + + menuBar.add(fileMenu); + menuBar.add(editMenu); + menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + menuBar.add(windowMenu); + menuBar.add(helpMenu); + + // contents of File menu + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + fileMenu.add(mQuitAction); + + // contents of Edit menu + editMenu.add(mCopyAction); + editMenu.add(mSelectAllAction); + editMenu.add(mFindAction); + + // contents of Window menu + windowMenu.add(mOpenPerspectiveAction); + windowMenu.add(mResetPerspectiveAction); + windowMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + windowMenu.add(mPreferencesAction); + + // contents of Help menu + helpMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + helpMenu.add(mAboutAction); + }; +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorApplication.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorApplication.java new file mode 100644 index 000000000..425786f6f --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorApplication.java @@ -0,0 +1,179 @@ +/* + * 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.monitor; + +import com.android.ide.eclipse.monitor.SdkToolsLocator.SdkInstallStatus; +import com.android.prefs.AndroidLocation; +import com.android.sdklib.SdkManager; +import com.android.sdkstats.SdkStatsService; +import com.android.sdkuilib.internal.repository.ui.AdtUpdateDialog; +import com.android.utils.ILogger; +import com.android.utils.NullLogger; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; + +import java.io.File; + +public class MonitorApplication implements IApplication { + private static final String SDK_PATH_ENVVAR = "com.android.sdk.path"; + private static final String MONITOR_WORKSPACE_PATH = "monitor-workspace"; + + @Override + public Object start(IApplicationContext context) throws Exception { + Display display = PlatformUI.createDisplay(); + + // set workspace location + Location instanceLoc = Platform.getInstanceLocation(); + IPath workspacePath = new Path(AndroidLocation.getFolder()).append(MONITOR_WORKSPACE_PATH); + instanceLoc.set(workspacePath.toFile().toURI().toURL(), true); + + // figure out path to SDK + String sdkPath = findSdkPath(display); + if (!isValidSdkLocation(sdkPath)) { + // exit with return code -1 + return Integer.valueOf(-1); + } + MonitorPlugin.getDefault().setSdkFolder(new File(sdkPath)); + + // install platform tools if necessary + ILogger sdkLog = NullLogger.getLogger(); + SdkManager manager = SdkManager.createManager(sdkPath, sdkLog); + if (manager.getPlatformToolsVersion() == null) { + boolean install = MessageDialog.openQuestion(new Shell(display), + "Monitor", + "The platform tools package that provides adb is missing from your SDK installation. " + + "Monitor requires this package to work properly. Would you like to install that package now?"); + if (!install) { + return Integer.valueOf(-1); + } + AdtUpdateDialog window = new AdtUpdateDialog(new Shell(display), sdkLog, sdkPath); + window.installPlatformTools(); + } + + // If this is the first time using ddms or adt, open up the stats service + // opt out dialog, and request user for permissions. + // Note that the actual ping is performed in MonitorStartup + SdkStatsService stats = new SdkStatsService(); + stats.checkUserPermissionForPing(new Shell(display)); + + // open up RCP + try { + int returnCode = PlatformUI.createAndRunWorkbench(display, + new MonitorWorkbenchAdvisor()); + if (returnCode == PlatformUI.RETURN_RESTART) { + return IApplication.EXIT_RESTART; + } + return IApplication.EXIT_OK; + } finally { + display.dispose(); + } + } + + @Override + public void stop() { + if (!PlatformUI.isWorkbenchRunning()) + return; + final IWorkbench workbench = PlatformUI.getWorkbench(); + final Display display = workbench.getDisplay(); + display.syncExec(new Runnable() { + @Override + public void run() { + if (!display.isDisposed()) + workbench.close(); + } + }); + } + + private String findSdkPath(Display display) { + // see if there is a system property set (passed in via a command line arg) + String sdkLocation = System.getProperty(SDK_PATH_ENVVAR); + if (isValidSdkLocation(sdkLocation)) { + return sdkLocation; + } + + // see if there is an environment variable set + sdkLocation = System.getenv(SDK_PATH_ENVVAR); + if (isValidSdkLocation(sdkLocation)) { + return sdkLocation; + } + + // The monitor app should be located in "<sdk>/tools/lib/monitor-platform/" + // So see if the folder one level up from the install location is a valid SDK. + Location install = Platform.getInstallLocation(); + if (install != null && install.getURL() != null) { + File libFolder = new File(install.getURL().getFile()).getParentFile(); + if (libFolder != null) { + String toolsFolder = libFolder.getParent(); + if (toolsFolder != null) { + sdkLocation = new File(toolsFolder).getParent(); + if (isValidSdkLocation(sdkLocation)) { + MonitorPlugin.getDdmsPreferenceStore().setLastSdkPath(sdkLocation); + return sdkLocation; + } + } + + } + } + + // check for the last used SDK + sdkLocation = MonitorPlugin.getDdmsPreferenceStore().getLastSdkPath(); + if (isValidSdkLocation(sdkLocation)) { + return sdkLocation; + } + + // if nothing else works, prompt the user + sdkLocation = getSdkLocationFromUser(new Shell(display)); + if (isValidSdkLocation(sdkLocation)) { + MonitorPlugin.getDdmsPreferenceStore().setLastSdkPath(sdkLocation); + } + + return sdkLocation; + } + + private boolean isValidSdkLocation(String sdkLocation) { + if (sdkLocation == null) { + return false; + } + + if (sdkLocation.trim().length() == 0) { + return false; + } + + SdkToolsLocator locator = new SdkToolsLocator(new File(sdkLocation)); + return locator.isValidInstallation() == SdkInstallStatus.VALID; + } + + private String getSdkLocationFromUser(Shell shell) { + SdkLocationChooserDialog dlg = new SdkLocationChooserDialog(shell); + if (dlg.open() == Window.OK) { + return dlg.getPath(); + } else { + return null; + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorPlugin.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorPlugin.java new file mode 100644 index 000000000..a61eb4ab8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorPlugin.java @@ -0,0 +1,65 @@ +/* + * 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.monitor; + +import com.android.sdkstats.DdmsPreferenceStore; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +import java.io.File; + +public class MonitorPlugin extends AbstractUIPlugin { + public static final String PLUGIN_ID = "com.android.ide.eclipse.monitor"; //$NON-NLS-1$ + private static MonitorPlugin sPlugin; + private static final DdmsPreferenceStore sDdmsPreferenceStore = new DdmsPreferenceStore(); + private File mSdkFolder; + + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + + sPlugin = this; + } + + @Override + public void stop(BundleContext context) throws Exception { + sPlugin = null; + super.stop(context); + } + + public static MonitorPlugin getDefault() { + return sPlugin; + } + + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } + + public static DdmsPreferenceStore getDdmsPreferenceStore() { + return sDdmsPreferenceStore; + } + + public void setSdkFolder(File sdkFolder) { + mSdkFolder = sdkFolder; + } + + public File getSdkFolder() { + return mSdkFolder; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorStartup.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorStartup.java new file mode 100644 index 000000000..2de260ee6 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorStartup.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2012 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.monitor; + +import com.android.SdkConstants; +import com.android.sdkstats.SdkStatsService; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ui.IStartup; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Properties; + +public class MonitorStartup implements IStartup { + @Override + public void earlyStartup() { + Job pingJob = new Job("Android SDK Ping") { + @Override + protected IStatus run(IProgressMonitor monitor) { + SdkStatsService stats = new SdkStatsService(); + File sdkFolder = MonitorPlugin.getDefault().getSdkFolder(); + if (sdkFolder == null) { + return Status.OK_STATUS; + } + + String toolsPath = new File(sdkFolder, SdkConstants.FD_TOOLS).getAbsolutePath(); + ping(stats, toolsPath); + return Status.OK_STATUS; + } + }; + pingJob.setPriority(Job.DECORATE); // lowest priority + pingJob.schedule(); + } + + private static void ping(SdkStatsService stats, String toolsLocation) { + Properties p = new Properties(); + try{ + File sourceProp; + if (toolsLocation != null && toolsLocation.length() > 0) { + sourceProp = new File(toolsLocation, "source.properties"); //$NON-NLS-1$ + } else { + sourceProp = new File("source.properties"); //$NON-NLS-1$ + } + FileInputStream fis = null; + try { + fis = new FileInputStream(sourceProp); + p.load(fis); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException ignore) { + } + } + } + + String revision = p.getProperty("Pkg.Revision"); //$NON-NLS-1$ + if (revision != null && revision.length() > 0) { + stats.ping("ddms", revision); //$NON-NLS-1$ + } + } catch (FileNotFoundException e) { + // couldn't find the file? don't ping. + } catch (IOException e) { + // couldn't find the file? don't ping. + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorWorkbenchAdvisor.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorWorkbenchAdvisor.java new file mode 100644 index 000000000..c79803f4d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorWorkbenchAdvisor.java @@ -0,0 +1,43 @@ +/* + * 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.monitor; + +import com.android.ide.eclipse.ddms.Perspective; + +import org.eclipse.ui.application.IWorkbenchConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +public class MonitorWorkbenchAdvisor extends WorkbenchAdvisor { + @Override + public String getInitialWindowPerspectiveId() { + return Perspective.ID; + } + + @Override + public void initialize(IWorkbenchConfigurer configurer) { + super.initialize(configurer); + configurer.setSaveAndRestore(true); + } + + @Override + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( + IWorkbenchWindowConfigurer configurer) { + return new MonitorWorkbenchWindowAdvisor(configurer); + }; +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorWorkbenchWindowAdvisor.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorWorkbenchWindowAdvisor.java new file mode 100644 index 000000000..137d3b184 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/MonitorWorkbenchWindowAdvisor.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 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.monitor; + +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +public class MonitorWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { + public MonitorWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { + super(configurer); + } + + @Override + public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) { + return new MonitorActionBarAdvisor(configurer); + }; + + @Override + public void preWindowOpen() { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + configurer.setShowStatusLine(true); + configurer.setShowPerspectiveBar(true); + configurer.setTitle("Android Device Monitor"); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SdkLocationChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SdkLocationChooserDialog.java new file mode 100644 index 000000000..04f60c796 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SdkLocationChooserDialog.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2012 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.monitor; + +import com.android.ide.eclipse.monitor.SdkToolsLocator.SdkInstallStatus; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.layout.GridDataFactory; +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.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import java.io.File; + +public class SdkLocationChooserDialog extends Dialog { + private static final String TITLE = "Android Device Monitor"; + private static final String DEFAULT_MESSAGE = "Provide the path to the Android SDK"; + + private Label mStatusLabel; + private Text mTextBox; + private String mPath; + + public SdkLocationChooserDialog(Shell parentShell) { + super(parentShell); + } + + @Override + protected Control createDialogArea(Composite parent) { + getShell().setText(TITLE); + + Composite c = new Composite((Composite) super.createDialogArea(parent), SWT.NONE); + c.setLayout(new GridLayout(2, false)); + c.setLayoutData(new GridData(GridData.FILL_BOTH)); + + Label l = new Label(c, SWT.NONE); + l.setText(DEFAULT_MESSAGE); + GridDataFactory.fillDefaults().span(2, 1).applyTo(l); + + mTextBox = new Text(c, SWT.BORDER); + mTextBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + GridDataFactory.fillDefaults() + .hint(SwtUtils.getFontWidth(mTextBox) * 80, SWT.DEFAULT) + .applyTo(mTextBox); + mTextBox.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + validateInstall(); + } + }); + + Button browse = new Button(c, SWT.PUSH); + browse.setText("Browse"); + browse.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + DirectoryDialog dlg = new DirectoryDialog(getShell(), SWT.OPEN); + dlg.setText("Android SDK location"); + String dir = dlg.open(); + if (dir != null) { + mTextBox.setText(dir); + validateInstall(); + } + } + }); + + mStatusLabel = new Label(c, SWT.WRAP); + mStatusLabel.setText(""); + mStatusLabel.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_RED)); + GridDataFactory.fillDefaults().span(2, 1).applyTo(mStatusLabel); + + return super.createDialogArea(parent); + } + + private void validateInstall() { + SdkToolsLocator locator = new SdkToolsLocator(new File(mTextBox.getText())); + SdkInstallStatus status = locator.isValidInstallation(); + if (status.isValid()) { + mStatusLabel.setText(""); + getButton(IDialogConstants.OK_ID).setEnabled(true); + } else { + mStatusLabel.setText(status.getErrorMessage()); + mStatusLabel.pack(); + getButton(IDialogConstants.OK_ID).setEnabled(false); + } + } + + @Override + public boolean close() { + mPath = mTextBox.getText(); + return super.close(); + } + + public String getPath() { + return mPath; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SdkToolsLocator.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SdkToolsLocator.java new file mode 100644 index 000000000..bd8ef60cb --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SdkToolsLocator.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2012 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.monitor; + +import com.android.SdkConstants; +import com.android.ide.eclipse.ddms.IToolsLocator; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +/** + * {@link SdkToolsLocator} has two functions: <ul> + * <li> It implements all the methods of {@link IToolsLocator} interface, and + * so can be used as such. </li> + * <li> It provides the {@link #isValidInstallation()} method to check the validity + * of an installation. </li> + * The only reason this class does not explicitly implement the {@link IToolsLocator} interface + * is that it is used very early during the startup to check the validity of the installation. + * Actually implementing that interface causes other bundles to be activated before the + * Eclipse Platform is fully initialized, resulting in startup error. + */ +public class SdkToolsLocator { + public static final String PLATFORM_EXECUTABLE_EXTENSION = + (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ? + ".exe" : ""; //$NON-NLS-1$ + + public static final String PLATFORM_SCRIPT_EXTENSION = + (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ? + ".bat" : ""; //$NON-NLS-1$ + + public static final String FN_HPROF_CONV = "hprof-conv" + PLATFORM_EXECUTABLE_EXTENSION; //$NON-NLS-1$ + public static final String FN_TRACEVIEW = "traceview" + PLATFORM_SCRIPT_EXTENSION; //$NON-NLS-1$ + + private final File mSdkFolder; + + public SdkToolsLocator(File sdkFolder) { + mSdkFolder = sdkFolder; + } + + public String getAdbLocation() { + return new File(getSdkPlatformToolsFolder(), SdkConstants.FN_ADB).getAbsolutePath(); + } + + public String getTraceViewLocation() { + return new File(getSdkToolsFolder(), FN_TRACEVIEW).getAbsolutePath(); + } + + public String getHprofConvLocation() { + return new File(getSdkPlatformToolsFolder(), FN_HPROF_CONV).getAbsolutePath(); + } + + private String getSdkToolsFolder() { + return new File(mSdkFolder, SdkConstants.FD_TOOLS).getAbsolutePath(); + } + + private String getSdkPlatformToolsFolder() { + return new File(mSdkFolder, SdkConstants.FD_PLATFORM_TOOLS).getAbsolutePath(); + } + + public SdkInstallStatus isValidInstallation() { + List<String> executables = Arrays.asList( + getTraceViewLocation(), + getHprofConvLocation()); + + for (String exe : executables) { + File f = new File(exe); + if (!f.exists()) { + return SdkInstallStatus.invalidInstallation(exe + " not present."); + } + if (!f.canExecute()) { + return SdkInstallStatus.invalidInstallation(exe + " is not executable."); + } + } + + return SdkInstallStatus.VALID; + } + + public static class SdkInstallStatus { + private boolean mValid; + private String mCause; + + private SdkInstallStatus(boolean valid, String errorMessage) { + mValid = valid; + mCause = errorMessage; + } + + public boolean isValid() { + return mValid; + } + + public String getErrorMessage() { + return mCause; + } + + public static final SdkInstallStatus VALID = new SdkInstallStatus(true, ""); + + public static SdkInstallStatus invalidInstallation(String errorMessage) { + return new SdkInstallStatus(false, errorMessage); + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SwtUtils.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SwtUtils.java new file mode 100644 index 000000000..bae7f0b32 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/SwtUtils.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012 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.monitor; + +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.widgets.Control; + +public class SwtUtils { + public static int getFontWidth(Control c) { + GC gc = new GC(c); + int avgCharWidth = gc.getFontMetrics().getAverageCharWidth(); + gc.dispose(); + return avgCharWidth; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ToolsLocator.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ToolsLocator.java new file mode 100644 index 000000000..75971817c --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ToolsLocator.java @@ -0,0 +1,42 @@ +/* + * 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.monitor; + +import com.android.ide.eclipse.ddms.IToolsLocator; + +public class ToolsLocator implements IToolsLocator { + private SdkToolsLocator mLocator; + + public ToolsLocator() { + mLocator = new SdkToolsLocator(MonitorPlugin.getDefault().getSdkFolder()); + } + + @Override + public String getAdbLocation() { + return mLocator.getAdbLocation(); + } + + @Override + public String getTraceViewLocation() { + return mLocator.getTraceViewLocation(); + } + + @Override + public String getHprofConvLocation() { + return mLocator.getHprofConvLocation(); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/actions/AvdManagerAction.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/actions/AvdManagerAction.java new file mode 100644 index 000000000..2510bd34a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/actions/AvdManagerAction.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2012 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.monitor.actions; + +public class AvdManagerAction extends SdkManagerAction { + @Override + protected String getAndroidBatArgument() { + return "avd"; + } +}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/actions/SdkManagerAction.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/actions/SdkManagerAction.java new file mode 100644 index 000000000..573ed7c07 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/actions/SdkManagerAction.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 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.monitor.actions; + +import com.android.SdkConstants; +import com.android.ide.eclipse.monitor.MonitorPlugin; + +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.PlatformUI; + +import java.io.File; +import java.io.IOException; + +public class SdkManagerAction implements IWorkbenchWindowActionDelegate { + @Override + public void run(IAction action) { + File sdk = MonitorPlugin.getDefault().getSdkFolder(); + if (sdk != null) { + File tools = new File(sdk, SdkConstants.FD_TOOLS); + File androidBat = new File(tools, SdkConstants.androidCmdName()); + if (androidBat.exists()) { + String[] cmd = new String[] { + androidBat.getAbsolutePath(), + getAndroidBatArgument(), + }; + try { + Runtime.getRuntime().exec(cmd); + } catch (IOException e) { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window != null) { + ErrorDialog.openError( + window.getShell(), + "Monitor", + "Error while launching SDK Manager", + new Status(Status.ERROR, + MonitorPlugin.PLUGIN_ID, + "Error while launching SDK Manager", + e)); + } + } + } + } + } + + protected String getAndroidBatArgument() { + return "sdk"; + } + + @Override + public void selectionChanged(IAction action, ISelection selection) { + } + + @Override + public void dispose() { + } + + @Override + public void init(IWorkbenchWindow window) { + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/DebugPortProvider.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/DebugPortProvider.java new file mode 100644 index 000000000..a2ffa042b --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/DebugPortProvider.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2012 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.monitor.ddms; + +import com.android.ddmlib.DebugPortManager.IDebugPortProvider; +import com.android.ddmlib.IDevice; +import com.android.ide.eclipse.ddms.DdmsPlugin; + +import org.eclipse.jface.preference.IPreferenceStore; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * DDMS implementation of the IDebugPortProvider interface. + * This class handles saving/loading the list of static debug port from + * the preference store and provides the port number to the Device Monitor. + */ +public class DebugPortProvider implements IDebugPortProvider { + + private static DebugPortProvider sThis = new DebugPortProvider(); + + /** Preference name for the static port list. */ + public static final String PREFS_STATIC_PORT_LIST = "android.staticPortList"; //$NON-NLS-1$ + + /** + * Mapping device serial numbers to maps. The embedded maps are mapping application names to + * debugger ports. + */ + private Map<String, Map<String, Integer>> mMap; + + public static DebugPortProvider getInstance() { + return sThis; + } + + private DebugPortProvider() { + computePortList(); + } + + /** + * Returns a static debug port for the specified application running on the + * specified {@link IDevice}. + * @param device The device the application is running on. + * @param appName The application name, as defined in the + * AndroidManifest.xml package attribute. + * @return The static debug port or {@link #NO_STATIC_PORT} if there is none setup. + * + * @see IDebugPortProvider#getPort(IDevice, String) + */ + @Override + public int getPort(IDevice device, String appName) { + if (mMap != null) { + Map<String, Integer> deviceMap = mMap.get(device.getSerialNumber()); + if (deviceMap != null) { + Integer i = deviceMap.get(appName); + if (i != null) { + return i.intValue(); + } + } + } + return IDebugPortProvider.NO_STATIC_PORT; + } + + /** + * Returns the map of Static debugger ports. The map links device serial numbers to + * a map linking application name to debugger ports. + */ + public Map<String, Map<String, Integer>> getPortList() { + return mMap; + } + + /** + * Create the map member from the values contained in the Preference Store. + */ + private void computePortList() { + mMap = new HashMap<String, Map<String, Integer>>(); + + // get the prefs store + IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore(); + String value = store.getString(PREFS_STATIC_PORT_LIST); + + if (value != null && value.length() > 0) { + // format is + // port1|port2|port3|... + // where port# is + // appPackageName:appPortNumber:device-serial-number + String[] portSegments = value.split("\\|"); //$NON-NLS-1$ + for (String seg : portSegments) { + String[] entry = seg.split(":"); //$NON-NLS-1$ + + // backward compatibility support. if we have only 2 entry, we default + // to the first emulator. + String deviceName = null; + if (entry.length == 3) { + deviceName = entry[2]; + } else { + deviceName = IDevice.FIRST_EMULATOR_SN; + } + + // get the device map + Map<String, Integer> deviceMap = mMap.get(deviceName); + if (deviceMap == null) { + deviceMap = new HashMap<String, Integer>(); + mMap.put(deviceName, deviceMap); + } + + deviceMap.put(entry[0], Integer.valueOf(entry[1])); + } + } + } + + /** + * Sets new [device, app, port] values. + * The values are also sync'ed in the preference store. + * @param map The map containing the new values. + */ + public void setPortList(Map<String, Map<String,Integer>> map) { + // update the member map. + mMap.clear(); + mMap.putAll(map); + + // create the value to store in the preference store. + // see format definition in getPortList + StringBuilder sb = new StringBuilder(); + + Set<String> deviceKeys = map.keySet(); + for (String deviceKey : deviceKeys) { + Map<String, Integer> deviceMap = map.get(deviceKey); + if (deviceMap != null) { + Set<String> appKeys = deviceMap.keySet(); + + for (String appKey : appKeys) { + Integer port = deviceMap.get(appKey); + if (port != null) { + sb.append(appKey).append(':').append(port.intValue()).append(':'). + append(deviceKey).append('|'); + } + } + } + } + + String value = sb.toString(); + + // get the prefs store. + IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore(); + + // and give it the new value. + store.setValue(PREFS_STATIC_PORT_LIST, value); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/StaticPortConfigDialog.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/StaticPortConfigDialog.java new file mode 100644 index 000000000..456cdcf51 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/StaticPortConfigDialog.java @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2012 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.monitor.ddms; + +import com.android.ddmuilib.TableHelper; +import com.android.ide.eclipse.ddms.DdmsPlugin; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Dialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Dialog to configure the static debug ports. + * + */ +public class StaticPortConfigDialog extends Dialog { + + /** Preference name for the 0th column width */ + private static final String PREFS_DEVICE_COL = "spcd.deviceColumn"; //$NON-NLS-1$ + + /** Preference name for the 1st column width */ + private static final String PREFS_APP_COL = "spcd.AppColumn"; //$NON-NLS-1$ + + /** Preference name for the 2nd column width */ + private static final String PREFS_PORT_COL = "spcd.PortColumn"; //$NON-NLS-1$ + + private static final int COL_DEVICE = 0; + private static final int COL_APPLICATION = 1; + private static final int COL_PORT = 2; + + + private static final int DLG_WIDTH = 500; + private static final int DLG_HEIGHT = 300; + + private Shell mShell; + private Shell mParent; + + private Table mPortTable; + + /** + * Array containing the list of already used static port to avoid + * duplication. + */ + private ArrayList<Integer> mPorts = new ArrayList<Integer>(); + + /** + * Basic constructor. + * @param parent + */ + public StaticPortConfigDialog(Shell parent) { + super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL); + } + + /** + * Open and display the dialog. This method returns only when the + * user closes the dialog somehow. + * + */ + public void open() { + createUI(); + + if (mParent == null || mShell == null) { + return; + } + + updateFromStore(); + + // Set the dialog size. + mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT); + Rectangle r = mParent.getBounds(); + // get the center new top left. + int cx = r.x + r.width/2; + int x = cx - DLG_WIDTH / 2; + int cy = r.y + r.height/2; + int y = cy - DLG_HEIGHT / 2; + mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT); + + mShell.pack(); + + // actually open the dialog + mShell.open(); + + // event loop until the dialog is closed. + Display display = mParent.getDisplay(); + while (!mShell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + } + + /** + * Creates the dialog ui. + */ + private void createUI() { + mParent = getParent(); + mShell = new Shell(mParent, getStyle()); + mShell.setText("Static Port Configuration"); + + mShell.setLayout(new GridLayout(1, true)); + + mShell.addListener(SWT.Close, new Listener() { + @Override + public void handleEvent(Event event) { + event.doit = true; + } + }); + + // center part with the list on the left and the buttons + // on the right. + Composite main = new Composite(mShell, SWT.NONE); + main.setLayoutData(new GridData(GridData.FILL_BOTH)); + main.setLayout(new GridLayout(2, false)); + + // left part: list view + mPortTable = new Table(main, SWT.SINGLE | SWT.FULL_SELECTION); + mPortTable.setLayoutData(new GridData(GridData.FILL_BOTH)); + mPortTable.setHeaderVisible(true); + mPortTable.setLinesVisible(true); + + TableHelper.createTableColumn(mPortTable, "Device Serial Number", + SWT.LEFT, "emulator-5554", //$NON-NLS-1$ + PREFS_DEVICE_COL, DdmsPlugin.getDefault().getPreferenceStore()); + + TableHelper.createTableColumn(mPortTable, "Application Package", + SWT.LEFT, "com.android.samples.phone", //$NON-NLS-1$ + PREFS_APP_COL, DdmsPlugin.getDefault().getPreferenceStore()); + + TableHelper.createTableColumn(mPortTable, "Debug Port", + SWT.RIGHT, "Debug Port", //$NON-NLS-1$ + PREFS_PORT_COL, DdmsPlugin.getDefault().getPreferenceStore()); + + // right part: buttons + Composite buttons = new Composite(main, SWT.NONE); + buttons.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + buttons.setLayout(new GridLayout(1, true)); + + Button newButton = new Button(buttons, SWT.NONE); + newButton.setText("New..."); + newButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + StaticPortEditDialog dlg = new StaticPortEditDialog(mShell, + mPorts); + if (dlg.open()) { + // get the text + String device = dlg.getDeviceSN(); + String app = dlg.getAppName(); + int port = dlg.getPortNumber(); + + // add it to the list + addEntry(device, app, port); + } + } + }); + + final Button editButton = new Button(buttons, SWT.NONE); + editButton.setText("Edit..."); + editButton.setEnabled(false); + editButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int index = mPortTable.getSelectionIndex(); + String oldDeviceName = getDeviceName(index); + String oldAppName = getAppName(index); + String oldPortNumber = getPortNumber(index); + StaticPortEditDialog dlg = new StaticPortEditDialog(mShell, + mPorts, oldDeviceName, oldAppName, oldPortNumber); + if (dlg.open()) { + // get the text + String deviceName = dlg.getDeviceSN(); + String app = dlg.getAppName(); + int port = dlg.getPortNumber(); + + // add it to the list + replaceEntry(index, deviceName, app, port); + } + } + }); + + final Button deleteButton = new Button(buttons, SWT.NONE); + deleteButton.setText("Delete"); + deleteButton.setEnabled(false); + deleteButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int index = mPortTable.getSelectionIndex(); + removeEntry(index); + } + }); + + // bottom part with the ok/cancel + Composite bottomComp = new Composite(mShell, SWT.NONE); + bottomComp.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_CENTER)); + bottomComp.setLayout(new GridLayout(2, true)); + + Button okButton = new Button(bottomComp, SWT.NONE); + okButton.setText("OK"); + okButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateStore(); + mShell.close(); + } + }); + + Button cancelButton = new Button(bottomComp, SWT.NONE); + cancelButton.setText("Cancel"); + cancelButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + mShell.close(); + } + }); + + mPortTable.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + // get the selection index + int index = mPortTable.getSelectionIndex(); + + boolean enabled = index != -1; + editButton.setEnabled(enabled); + deleteButton.setEnabled(enabled); + } + }); + + mShell.pack(); + + } + + /** + * Add a new entry in the list. + * @param deviceName the serial number of the device + * @param appName java package for the application + * @param portNumber port number + */ + private void addEntry(String deviceName, String appName, int portNumber) { + // create a new item for the table + TableItem item = new TableItem(mPortTable, SWT.NONE); + + item.setText(COL_DEVICE, deviceName); + item.setText(COL_APPLICATION, appName); + item.setText(COL_PORT, Integer.toString(portNumber)); + + // add the port to the list of port number used. + mPorts.add(portNumber); + } + + /** + * Remove an entry from the list. + * @param index The index of the entry to be removed + */ + private void removeEntry(int index) { + // remove from the ui + mPortTable.remove(index); + + // and from the port list. + mPorts.remove(index); + } + + /** + * Replace an entry in the list with new values. + * @param index The index of the item to be replaced + * @param deviceName the serial number of the device + * @param appName The new java package for the application + * @param portNumber The new port number. + */ + private void replaceEntry(int index, String deviceName, String appName, int portNumber) { + // get the table item by index + TableItem item = mPortTable.getItem(index); + + // set its new value + item.setText(COL_DEVICE, deviceName); + item.setText(COL_APPLICATION, appName); + item.setText(COL_PORT, Integer.toString(portNumber)); + + // and replace the port number in the port list. + mPorts.set(index, portNumber); + } + + + /** + * Returns the device name for a specific index + * @param index The index + * @return the java package name of the application + */ + private String getDeviceName(int index) { + TableItem item = mPortTable.getItem(index); + return item.getText(COL_DEVICE); + } + + /** + * Returns the application name for a specific index + * @param index The index + * @return the java package name of the application + */ + private String getAppName(int index) { + TableItem item = mPortTable.getItem(index); + return item.getText(COL_APPLICATION); + } + + /** + * Returns the port number for a specific index + * @param index The index + * @return the port number + */ + private String getPortNumber(int index) { + TableItem item = mPortTable.getItem(index); + return item.getText(COL_PORT); + } + + /** + * Updates the ui from the value in the preference store. + */ + private void updateFromStore() { + // get the map from the debug port manager + DebugPortProvider provider = DebugPortProvider.getInstance(); + Map<String, Map<String, Integer>> map = provider.getPortList(); + + // we're going to loop on the keys and fill the table. + Set<String> deviceKeys = map.keySet(); + + for (String deviceKey : deviceKeys) { + Map<String, Integer> deviceMap = map.get(deviceKey); + if (deviceMap != null) { + Set<String> appKeys = deviceMap.keySet(); + + for (String appKey : appKeys) { + Integer port = deviceMap.get(appKey); + if (port != null) { + addEntry(deviceKey, appKey, port); + } + } + } + } + } + + /** + * Update the store from the content of the ui. + */ + private void updateStore() { + // create a new Map object and fill it. + HashMap<String, Map<String, Integer>> map = new HashMap<String, Map<String, Integer>>(); + + int count = mPortTable.getItemCount(); + + for (int i = 0 ; i < count ; i++) { + TableItem item = mPortTable.getItem(i); + String deviceName = item.getText(COL_DEVICE); + + Map<String, Integer> deviceMap = map.get(deviceName); + if (deviceMap == null) { + deviceMap = new HashMap<String, Integer>(); + map.put(deviceName, deviceMap); + } + + deviceMap.put(item.getText(COL_APPLICATION), Integer.valueOf(item.getText(COL_PORT))); + } + + // set it in the store through the debug port manager. + DebugPortProvider provider = DebugPortProvider.getInstance(); + provider.setPortList(map); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/StaticPortEditDialog.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/StaticPortEditDialog.java new file mode 100644 index 000000000..a9b0cd45e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/ddms/StaticPortEditDialog.java @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2012 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.monitor.ddms; + +import com.android.ddmlib.IDevice; + +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.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Dialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +import java.util.ArrayList; + +/** + * Small dialog box to edit a static port number. + */ +public class StaticPortEditDialog extends Dialog { + + private static final int DLG_WIDTH = 400; + private static final int DLG_HEIGHT = 200; + + private Shell mParent; + + private Shell mShell; + + private boolean mOk = false; + + private String mAppName; + + private String mPortNumber; + + private Button mOkButton; + + private Label mWarning; + + /** List of ports already in use */ + private ArrayList<Integer> mPorts; + + /** This is the port being edited. */ + private int mEditPort = -1; + private String mDeviceSn; + + /** + * Creates a dialog with empty fields. + * @param parent The parent Shell + * @param ports The list of already used port numbers. + */ + public StaticPortEditDialog(Shell parent, ArrayList<Integer> ports) { + super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL); + mPorts = ports; + mDeviceSn = IDevice.FIRST_EMULATOR_SN; + } + + /** + * Creates a dialog with predefined values. + * @param shell The parent shell + * @param ports The list of already used port numbers. + * @param oldDeviceSN the device serial number to display + * @param oldAppName The application name to display + * @param oldPortNumber The port number to display + */ + public StaticPortEditDialog(Shell shell, ArrayList<Integer> ports, + String oldDeviceSN, String oldAppName, String oldPortNumber) { + this(shell, ports); + + mDeviceSn = oldDeviceSN; + mAppName = oldAppName; + mPortNumber = oldPortNumber; + mEditPort = Integer.valueOf(mPortNumber); + } + + /** + * Opens the dialog. The method will return when the user closes the dialog + * somehow. + * + * @return true if ok was pressed, false if cancelled. + */ + public boolean open() { + createUI(); + + if (mParent == null || mShell == null) { + return false; + } + + mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT); + Rectangle r = mParent.getBounds(); + // get the center new top left. + int cx = r.x + r.width/2; + int x = cx - DLG_WIDTH / 2; + int cy = r.y + r.height/2; + int y = cy - DLG_HEIGHT / 2; + mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT); + + mShell.open(); + + Display display = mParent.getDisplay(); + while (!mShell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + + return mOk; + } + + public String getDeviceSN() { + return mDeviceSn; + } + + public String getAppName() { + return mAppName; + } + + public int getPortNumber() { + return Integer.valueOf(mPortNumber); + } + + private void createUI() { + mParent = getParent(); + mShell = new Shell(mParent, getStyle()); + mShell.setText("Static Port"); + + mShell.setLayout(new GridLayout(1, false)); + + mShell.addListener(SWT.Close, new Listener() { + @Override + public void handleEvent(Event event) { + } + }); + + // center part with the edit field + Composite main = new Composite(mShell, SWT.NONE); + main.setLayoutData(new GridData(GridData.FILL_BOTH)); + main.setLayout(new GridLayout(2, false)); + + Label l0 = new Label(main, SWT.NONE); + l0.setText("Device Name:"); + + final Text deviceSNText = new Text(main, SWT.SINGLE | SWT.BORDER); + deviceSNText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + if (mDeviceSn != null) { + deviceSNText.setText(mDeviceSn); + } + deviceSNText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + mDeviceSn = deviceSNText.getText().trim(); + validate(); + } + }); + + Label l = new Label(main, SWT.NONE); + l.setText("Application Name:"); + + final Text appNameText = new Text(main, SWT.SINGLE | SWT.BORDER); + if (mAppName != null) { + appNameText.setText(mAppName); + } + appNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + appNameText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + mAppName = appNameText.getText().trim(); + validate(); + } + }); + + Label l2 = new Label(main, SWT.NONE); + l2.setText("Debug Port:"); + + final Text debugPortText = new Text(main, SWT.SINGLE | SWT.BORDER); + if (mPortNumber != null) { + debugPortText.setText(mPortNumber); + } + debugPortText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + debugPortText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + mPortNumber = debugPortText.getText().trim(); + validate(); + } + }); + + // warning label + Composite warningComp = new Composite(mShell, SWT.NONE); + warningComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + warningComp.setLayout(new GridLayout(1, true)); + + mWarning = new Label(warningComp, SWT.NONE); + mWarning.setText(""); + mWarning.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + // bottom part with the ok/cancel + Composite bottomComp = new Composite(mShell, SWT.NONE); + bottomComp + .setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); + bottomComp.setLayout(new GridLayout(2, true)); + + mOkButton = new Button(bottomComp, SWT.NONE); + mOkButton.setText("OK"); + mOkButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + mOk = true; + mShell.close(); + } + }); + mOkButton.setEnabled(false); + mShell.setDefaultButton(mOkButton); + + Button cancelButton = new Button(bottomComp, SWT.NONE); + cancelButton.setText("Cancel"); + cancelButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + mShell.close(); + } + }); + + validate(); + } + + /** + * Validates the content of the 2 text fields and enable/disable "ok", while + * setting up the warning/error message. + */ + private void validate() { + // first we reset the warning dialog. This allows us to latter + // display warnings. + mWarning.setText(""); //$NON-NLS-1$ + + // check the device name field is not empty + if (mDeviceSn == null || mDeviceSn.length() == 0) { + mWarning.setText("Device name missing."); + mOkButton.setEnabled(false); + return; + } + + // check the application name field is not empty + if (mAppName == null || mAppName.length() == 0) { + mWarning.setText("Application name missing."); + mOkButton.setEnabled(false); + return; + } + + String packageError = "Application name must be a valid Java package name."; + + // validate the package name as well. It must be a fully qualified + // java package. + String[] packageSegments = mAppName.split("\\."); //$NON-NLS-1$ + for (String p : packageSegments) { + if (p.matches("^[a-zA-Z][a-zA-Z0-9]*") == false) { //$NON-NLS-1$ + mWarning.setText(packageError); + mOkButton.setEnabled(false); + return; + } + + // lets also display a warning if the package contains upper case + // letters. + if (p.matches("^[a-z][a-z0-9]*") == false) { //$NON-NLS-1$ + mWarning.setText("Lower case is recommended for Java packages."); + } + } + + // the split will not detect the last char being a '.' + // so we test it manually + if (mAppName.charAt(mAppName.length()-1) == '.') { + mWarning.setText(packageError); + mOkButton.setEnabled(false); + return; + } + + // now we test the package name field is not empty. + if (mPortNumber == null || mPortNumber.length() == 0) { + mWarning.setText("Port Number missing."); + mOkButton.setEnabled(false); + return; + } + + // then we check it only contains digits. + if (mPortNumber.matches("[0-9]*") == false) { //$NON-NLS-1$ + mWarning.setText("Port Number invalid."); + mOkButton.setEnabled(false); + return; + } + + // get the int from the port number to validate + long port = Long.valueOf(mPortNumber); + if (port >= 32767) { + mOkButton.setEnabled(false); + return; + } + + // check if its in the list of already used ports + if (port != mEditPort) { + for (Integer i : mPorts) { + if (port == i.intValue()) { + mWarning.setText("Port already in use."); + mOkButton.setEnabled(false); + return; + } + } + } + + // at this point there's not error, so we enable the ok button. + mOkButton.setEnabled(true); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/handlers/StaticPortConfigHandler.java b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/handlers/StaticPortConfigHandler.java new file mode 100644 index 000000000..ff63aca2f --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.monitor/src/com/android/ide/eclipse/monitor/handlers/StaticPortConfigHandler.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 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.monitor.handlers; + +import com.android.ide.eclipse.monitor.ddms.StaticPortConfigDialog; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; + +public class StaticPortConfigHandler extends AbstractHandler { + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + StaticPortConfigDialog dlg = new StaticPortConfigDialog(HandlerUtil.getActiveShell(event)); + dlg.open(); + return null; + } +} |