Home | History | Annotate | Download | only in adt
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.motorola.studio.android.adt;
     18 
     19 import java.io.BufferedReader;
     20 import java.io.File;
     21 import java.io.IOException;
     22 import java.io.InputStreamReader;
     23 import java.io.OutputStream;
     24 import java.util.ArrayList;
     25 import java.util.Collection;
     26 import java.util.HashMap;
     27 import java.util.LinkedHashMap;
     28 import java.util.LinkedList;
     29 import java.util.List;
     30 import java.util.Map;
     31 
     32 import org.eclipse.core.resources.IFile;
     33 import org.eclipse.core.runtime.CoreException;
     34 import org.eclipse.core.runtime.IProgressMonitor;
     35 import org.eclipse.core.runtime.IStatus;
     36 import org.eclipse.core.runtime.MultiStatus;
     37 import org.eclipse.core.runtime.NullProgressMonitor;
     38 import org.eclipse.core.runtime.Platform;
     39 import org.eclipse.core.runtime.Status;
     40 import org.eclipse.debug.core.DebugPlugin;
     41 import org.eclipse.debug.core.ILaunchConfiguration;
     42 import org.eclipse.debug.core.ILaunchConfigurationType;
     43 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
     44 import org.eclipse.debug.core.ILaunchManager;
     45 import org.eclipse.debug.ui.DebugUITools;
     46 import org.eclipse.debug.ui.ILaunchGroup;
     47 import org.eclipse.jface.dialogs.IDialogConstants;
     48 import org.eclipse.jface.dialogs.MessageDialog;
     49 import org.eclipse.jface.viewers.ISelection;
     50 import org.eclipse.jface.viewers.IStructuredSelection;
     51 import org.eclipse.jface.viewers.StructuredSelection;
     52 import org.eclipse.jface.wizard.WizardDialog;
     53 import org.eclipse.swt.widgets.Display;
     54 import org.eclipse.swt.widgets.Shell;
     55 import org.eclipse.ui.IWorkbenchWindow;
     56 import org.eclipse.ui.PlatformUI;
     57 import org.eclipse.ui.console.IOConsoleOutputStream;
     58 
     59 import com.android.ddmlib.FileListingService;
     60 import com.android.ddmlib.FileListingService.FileEntry;
     61 import com.android.ddmlib.IDevice;
     62 import com.android.ddmuilib.ScreenShotDialog;
     63 import com.android.sdklib.IAndroidTarget;
     64 import com.motorola.studio.android.AndroidPlugin;
     65 import com.motorola.studio.android.adt.StudioAndroidEventManager.EventType;
     66 import com.motorola.studio.android.common.log.StudioLogger;
     67 import com.motorola.studio.android.common.log.UsageDataConstants;
     68 import com.motorola.studio.android.common.utilities.EclipseUtils;
     69 import com.motorola.studio.android.common.utilities.FileUtil;
     70 import com.motorola.studio.android.i18n.AndroidNLS;
     71 import com.motorola.studio.android.wizards.installapp.DeployWizard;
     72 import com.motorola.studio.android.wizards.installapp.DeployWizard.INSTALL_TYPE;
     73 import com.motorola.studio.android.wizards.installapp.UninstallAppWizard;
     74 import com.motorola.studio.android.wizards.mat.DumpHPROFWizard;
     75 import com.motorola.studio.android.wizards.monkey.IMonkeyConfigurationConstants;
     76 
     77 public class DDMSUtils
     78 {
     79     private static final Map<String, FileListingService> deviceFileListingServiceMap =
     80             new HashMap<String, FileListingService>();
     81 
     82     /**
     83      * The APK extension
     84      */
     85     private static final String APK_FILE_EXTENSION = "apk";
     86 
     87     /**
     88      * Parameter for overwriting existing applications, if any
     89      */
     90     private static final String ADB_INSTALL_OVERWRITE = "-r";
     91 
     92     /**
     93      * Options to be used with adb to indicate package manager application
     94      */
     95     private static final String PM_CMD = "pm";
     96 
     97     /**
     98      * Options to be used with adb to run monkey application
     99      */
    100     private static final String MONKEY_CMD = "monkey";
    101 
    102     /**
    103      * Uninstall directive to the package manager
    104      */
    105     private static final String PM_UNINSTALL_DIRECTIVE = "uninstall";
    106 
    107     /**
    108      * List packages directive
    109      */
    110     private static final String PM_LIST_DIRECTIVE = "list";
    111 
    112     /**
    113      * List packages directive
    114      */
    115     private static final String PM_PACKAGES_DIRECTIVE = "packages";
    116 
    117     /**
    118      * List packages force directive
    119      */
    120     private static final String PM_PACKAGES_DIRECTIVE_FORCE = "-f";
    121 
    122     /**
    123      * Monkey packages directive
    124      */
    125     private static final String MONKEY_PACKAGES_DIRECTIVE = " -p ";
    126 
    127     /**
    128      * Options to be used with adb to indicate install operation
    129      */
    130     private static final String INSTALL_CMD = "install";
    131 
    132     /**
    133      * This word must exist in the adb install commmand answer to indicate
    134      * succefull installation
    135      */
    136     private static final String SUCCESS_CONSTANT = "Success";
    137 
    138     private static final DdmsRunnable disconnectedListener = new DdmsRunnable()
    139     {
    140         public void run(String serialNumber)
    141         {
    142             synchronized (deviceFileListingServiceMap)
    143             {
    144                 deviceFileListingServiceMap.remove(serialNumber);
    145             }
    146         }
    147     };
    148 
    149     static
    150     {
    151         StudioAndroidEventManager.asyncAddDeviceChangeListeners(null, disconnectedListener);
    152     }
    153 
    154     public static void takeScreenshot(final String serialNumber)
    155     {
    156         Display.getDefault().asyncExec(new Runnable()
    157         {
    158 
    159             public void run()
    160             {
    161                 Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
    162                 ScreenShotDialog sshot = new ScreenShotDialog(new Shell(shell));
    163                 sshot.open(DDMSFacade.getDeviceBySerialNumber(serialNumber));
    164             }
    165         });
    166     }
    167 
    168     public static void getApplicationDatabases(String serialNumber, String applicationName,
    169             IDatabaseListingListener listener)
    170     {
    171         LinkedList<String> pathSegments = new LinkedList<String>();
    172         pathSegments.add("data");
    173         pathSegments.add("data");
    174         pathSegments.add(applicationName);
    175         pathSegments.add("databases");
    176 
    177         FileListingService fileListing = getFileListingService(serialNumber);
    178 
    179         if (fileListing != null)
    180         {
    181             FileEntry root = fileListing.getRoot();
    182             FileEntry[] children = null;
    183 
    184             children =
    185                     fileListing.getChildren(root, true, new FileListingReceiver(pathSegments,
    186                             fileListing, listener));
    187             /*
    188              * If children isn't null means that file listing service found the
    189              * files in it cache to speed up the operation
    190              */
    191             if (children != null)
    192             {
    193                 List<String> databases = new ArrayList<String>();
    194                 FileEntry temp1 = null, temp2 = root;
    195                 // start from root
    196                 while ((children != null))
    197                 {
    198                     // if we have something to search for
    199                     if (pathSegments.size() > 0)
    200                     {
    201                         String theSegment = pathSegments.remove(0);
    202                         temp1 = temp2.findChild(theSegment);
    203 
    204                         if (temp1 != null)
    205                         {
    206                             temp2 = temp1;
    207                             children =
    208                                     fileListing.getChildren(temp2, true, new FileListingReceiver(
    209                                             pathSegments, fileListing, listener));
    210                         }
    211                         else
    212                         {
    213                             children = null;
    214                             listener.databasesFound(databases);
    215                         }
    216                     }
    217                     // else just notify the listener
    218                     else
    219                     {
    220                         if (children != null)
    221                         {
    222                             for (FileEntry child : children)
    223                             {
    224                                 if (child.getName().endsWith(".db"))
    225                                 {
    226                                     databases.add(child.getName());
    227                                 }
    228                             }
    229                             children = null;
    230                         }
    231                         listener.databasesFound(databases);
    232                     }
    233                 }
    234             }
    235         }
    236     }
    237 
    238     public static List<String> getApplicationDatabases(String serialNumber, String applicationName)
    239             throws IOException
    240     {
    241         List<String> dbs = new ArrayList<String>();
    242 
    243         String appDbPath = "/data/data/" + applicationName + "/databases/";
    244 
    245         Collection<String> commandOutput =
    246                 DDMSFacade
    247                         .execRemoteApp(serialNumber, "ls " + appDbPath, new NullProgressMonitor());
    248         List<String> dbPathCandidates = new ArrayList(commandOutput.size() + 10);
    249 
    250         for (String commandOutline : commandOutput)
    251         {
    252             String[] strings = commandOutline.split(" ");
    253             for (String string : strings)
    254             {
    255                 if (string.trim().endsWith(".db"))
    256                 {
    257                     dbPathCandidates.add(string);
    258                 }
    259             }
    260         }
    261 
    262         return dbPathCandidates;
    263     }
    264 
    265     /**
    266      * @param serialNumber
    267      * @return
    268      */
    269     private static FileListingService getFileListingService(String serialNumber)
    270     {
    271         FileListingService fileListing = null;
    272         IDevice dev = DDMSFacade.getDeviceBySerialNumber(serialNumber);
    273         if (dev != null)
    274         {
    275             synchronized (dev)
    276             {
    277                 fileListing = deviceFileListingServiceMap.get(serialNumber);
    278             }
    279             if (fileListing == null)
    280             {
    281                 fileListing = dev.getFileListingService();
    282                 synchronized (deviceFileListingServiceMap)
    283                 {
    284                     deviceFileListingServiceMap.put(serialNumber, fileListing);
    285                 }
    286 
    287             }
    288         }
    289         return fileListing;
    290     }
    291 
    292     /**
    293      * This method returns the current language and country in use by given
    294      * emulation instance.
    295      *
    296      * @param serialNumber The serial number of emulation instance
    297      * @return An array of Strings containing the command results.
    298      */
    299     public static String[] getCurrentEmulatorLanguageAndCountry(final String serialNumber)
    300     {
    301         ArrayList<String[]> commands = createCurrentEmulatorLanguageAndCountryCommand(serialNumber);
    302         String[] responses = new String[2];
    303         String[] languageCommand = commands.get(0);
    304         String[] countryCommand = commands.get(1);
    305         String languageCommandResult = null;
    306         String countryCommandResult = null;
    307 
    308         try
    309         {
    310             // Do not write the command output to the console
    311             languageCommandResult = DDMSFacade.executeCommand(languageCommand, null);
    312             countryCommandResult = DDMSFacade.executeCommand(countryCommand, null);
    313             responses[0] = languageCommandResult.replaceAll("\\n$", "");
    314             responses[1] = countryCommandResult.replaceAll("\\n$", "");
    315         }
    316         catch (IOException e)
    317         {
    318             StudioLogger.error("Deploy: Could not execute adb current language command.");
    319         }
    320         return responses;
    321     }
    322 
    323     public static InstallPackageBean installPackageWizard()
    324     {
    325 
    326         final InstallPackageBean bean = new InstallPackageBean();
    327 
    328         final Display display = PlatformUI.getWorkbench().getDisplay();
    329         display.syncExec(new Runnable()
    330         {
    331             public void run()
    332             {
    333                 try
    334                 {
    335                     String defaultPath = null;
    336                     DeployWizard wizard;
    337                     IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
    338                     if (window != null)
    339                     {
    340                         ISelection selection = window.getSelectionService().getSelection();
    341                         if (selection instanceof IStructuredSelection)
    342                         {
    343                             IStructuredSelection workbenchSSelection =
    344                                     (IStructuredSelection) selection;
    345                             for (Object o : workbenchSSelection.toList())
    346                             {
    347                                 if (o instanceof IFile)
    348                                 {
    349                                     IFile file = (IFile) o;
    350                                     if (file.getFileExtension()
    351                                             .equalsIgnoreCase(APK_FILE_EXTENSION))
    352                                     {
    353                                         defaultPath = file.getLocation().toOSString();
    354                                     }
    355                                 }
    356                             }
    357                         }
    358                     }
    359                     wizard = new DeployWizard(defaultPath);
    360                     wizard.init(PlatformUI.getWorkbench(), new StructuredSelection());
    361                     WizardDialog dialog =
    362                             new WizardDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow()
    363                                     .getShell(), wizard);
    364                     dialog.setPageSize(500, 200);
    365                     if (dialog.open() == IDialogConstants.OK_ID)
    366                     {
    367                         bean.setPackagePath(wizard.getPackagePath());
    368                         bean.setCanOverwrite(wizard.canOverwrite());
    369                     }
    370                 }
    371                 catch (Throwable e)
    372                 {
    373                     StudioLogger.error(DDMSFacade.class, "Error executing deploy wizard", e);
    374                 }
    375             }
    376         });
    377 
    378         return bean;
    379     }
    380 
    381     public static IStatus installPackage(final String serialNumber, InstallPackageBean bean)
    382     {
    383         IStatus status = Status.CANCEL_STATUS;
    384 
    385         if ((bean.getPackagePath() != null) && (bean.getCanOverwrite() != null))
    386         {
    387             OutputStream consoleOut = null;
    388             try
    389             {
    390                 consoleOut = EclipseUtils.getStudioConsoleOutputStream(true);
    391                 status =
    392                         installPackage(serialNumber, bean.getPackagePath(), bean.getCanOverwrite(),
    393                                 consoleOut);
    394             }
    395             finally
    396             {
    397                 try
    398                 {
    399                     if (consoleOut != null)
    400                     {
    401                         consoleOut.close();
    402                     }
    403                 }
    404                 catch (IOException e)
    405                 {
    406                     StudioLogger.error("Install App: could not close console stream"
    407                             + e.getMessage());
    408                 }
    409             }
    410         }
    411 
    412         if (status.isOK())
    413         {
    414             StudioAndroidEventManager.fireEvent(EventType.PACKAGE_INSTALLED, serialNumber);
    415         }
    416 
    417         return status;
    418     }
    419 
    420     /**
    421      * Install an application on an emulator instance
    422      *
    423      * @param serialNumber
    424      *            The serial number of the device where the application will be
    425      *            installed
    426      * @param path
    427      *            Path of the package containing the application to be installed
    428      * @param installationType
    429      *            one of the {@link INSTALL_TYPE} install types available
    430      * @param force
    431      *            Perform the operation without asking for user intervention
    432      *
    433      * @return the status of the operation (OK, Cancel or Error+ErrorMessage)
    434      */
    435     public static IStatus installPackage(String serialNumber, String path,
    436             INSTALL_TYPE installationType, OutputStream processOut)
    437     {
    438         IStatus status = null;
    439 
    440         if (installationType.equals(INSTALL_TYPE.UNINSTALL))
    441         {
    442             status = uninstallPackage(new File(path), serialNumber, processOut);
    443         }
    444 
    445         boolean overwrite = installationType.equals(INSTALL_TYPE.OVERWRITE);
    446         status = installPackage(serialNumber, path, overwrite, processOut);
    447 
    448         return status;
    449     }
    450 
    451     /**
    452      * Uninstall the given package (if installed) in the given serialNumber
    453      * device
    454      *
    455      * @param path
    456      *            the package path
    457      * @param serialNumber
    458      *            the device serial number
    459      */
    460     public static IStatus uninstallPackage(File path, String serialNumber, OutputStream processOut)
    461     {
    462         IStatus returnStatus = null;
    463         if ((path != null) && path.exists() && path.isFile())
    464         {
    465             IDevice dev = DDMSFacade.getDeviceBySerialNumber(serialNumber);
    466             String apiLevel = dev.getProperty("ro.build.version.sdk");
    467             IAndroidTarget target = SdkUtils.getTargetByAPILevel(Integer.parseInt(apiLevel));
    468             String aaptPath = SdkUtils.getTargetAAPTPath(target);
    469             if (aaptPath != null)
    470             {
    471 
    472                 // resolve package name
    473                 String[] aaptComm = new String[]
    474                 {
    475                         aaptPath, "d", "badging", path.toString()
    476                 };
    477 
    478                 InputStreamReader reader = null;
    479                 BufferedReader bufferedReader = null;
    480 
    481                 try
    482                 {
    483                     Process aapt = Runtime.getRuntime().exec(aaptComm);
    484 
    485                     reader = new InputStreamReader(aapt.getInputStream());
    486                     bufferedReader = new BufferedReader(reader);
    487                     String infoLine = bufferedReader.readLine();
    488 
    489                     infoLine = infoLine.split(" ")[1].split("=")[1].replaceAll("'", "");
    490                     returnStatus = uninstallPackage(serialNumber, infoLine, processOut);
    491 
    492                 }
    493                 catch (Exception e)
    494                 {
    495                     returnStatus =
    496                             new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
    497                                     AndroidNLS.ERR_DDMSFacade_UninstallPackageException, e);
    498                 }
    499                 finally
    500                 {
    501                     try
    502                     {
    503                         if (reader != null)
    504                         {
    505                             reader.close();
    506                         }
    507                         if (bufferedReader != null)
    508                         {
    509                             bufferedReader.close();
    510                         }
    511                     }
    512                     catch (IOException e)
    513                     {
    514                         StudioLogger.error("Uninstall app could not close stream. "
    515                                 + e.getMessage());
    516                     }
    517 
    518                 }
    519             }
    520             else
    521             {
    522                 StudioLogger
    523                         .error(DDMSFacade.class,
    524                                 "Impossible to check APK package name. No android targets found inside SDK");
    525             }
    526 
    527         }
    528         else
    529         {
    530             returnStatus =
    531                     new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
    532                             AndroidNLS.ERR_DDMSFacade_UninstallPackage);
    533         }
    534         return returnStatus;
    535     }
    536 
    537     /**
    538      * Uninstall the given package within device with given serial number
    539      *
    540      * @param serialNumber
    541      * @param packageName
    542      * @param processOutput
    543      *            outputStream to write output of the process
    544      */
    545     public static IStatus uninstallPackage(String serialNumber, String packageName,
    546             OutputStream processOutput)
    547     {
    548         IStatus status = Status.OK_STATUS;
    549         String command[] = createUninstallCommand(serialNumber, packageName);
    550 
    551         try
    552         {
    553             String commandResult = DDMSFacade.executeCommand(command, processOutput);
    554             if (!commandResult.toLowerCase().contains(SUCCESS_CONSTANT.toLowerCase()))
    555             {
    556                 status =
    557                         new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
    558                                 AndroidNLS.ERR_DDMSFacade_UninstallPackageError + ": "
    559                                         + packageName);
    560             }
    561 
    562         }
    563         catch (Exception e)
    564         {
    565             status =
    566                     new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
    567                             AndroidNLS.ERR_DDMSFacade_UninstallPackageException, e);
    568             StudioLogger.error(DDMSFacade.class, "Failed to remove package: " + packageName + ". "
    569                     + e.getMessage());
    570         }
    571         return status;
    572     }
    573 
    574     /**
    575      * Run the Monkey command for the given package within device with given serial number
    576      *
    577      * @param serialNumber
    578      * @param packageName
    579      * @param processOutput
    580      * @param otherCmd
    581      * @return the status of the monkey process
    582      */
    583     public static IStatus runMonkey(String serialNumber, String allPackages,
    584             OutputStream processOutput, String otherCmd)
    585     {
    586         IStatus status = Status.OK_STATUS;
    587         String command[] = createMonkeyCommand(serialNumber, allPackages, otherCmd);
    588 
    589         try
    590         {
    591             DDMSFacade.executeCommand(command, processOutput);
    592 
    593         }
    594         catch (Exception e)
    595         {
    596             EclipseUtils.showErrorDialog(AndroidNLS.UI_MonkeyError_Title,
    597                     AndroidNLS.UI_MonkeyError_Msg);
    598             StudioLogger.error(DDMSFacade.class, "Failed to run monkey command: " + command + " "
    599                     + e.getMessage());
    600         }
    601         return status;
    602     }
    603 
    604     /**
    605      * Uninstall packages from the given serialNumber device
    606      *
    607      * @param serialNumber
    608      * @param packagesToUninstall
    609      * @param outputStream
    610      * @return the status of the uninstall process or null if no packages were
    611      *         uninstalled
    612      */
    613     private static IStatus uninstallPackages(String serialNumber,
    614             ArrayList<String> packagesToUninstall, OutputStream outputStream)
    615     {
    616 
    617         IStatus returnStatus = null;
    618         for (String packageToUninstall : packagesToUninstall)
    619         {
    620             StudioLogger.info(DDMSUtils.class, "Removing package: " + packageToUninstall);
    621             IStatus temp = uninstallPackage(serialNumber, packageToUninstall, outputStream);
    622             if (!temp.isOK())
    623             {
    624                 if (returnStatus == null)
    625                 {
    626                     returnStatus =
    627                             new MultiStatus(AndroidPlugin.PLUGIN_ID, 0,
    628                                     AndroidNLS.ERR_DDMSFacade_UninstallPackageError, null);
    629                 }
    630 
    631                 ((MultiStatus) returnStatus).add(temp);
    632             }
    633         }
    634         return returnStatus == null ? Status.OK_STATUS : returnStatus;
    635     }
    636 
    637     /**
    638      * Run monkey command on the given packages with the specified commands.
    639      *
    640      * @param serialNumber
    641      * @param packagesToRunMonkey
    642      * @param outputStream
    643      * @param otherCmds
    644      * @return the status of the monkey process or null if the process was not successful
    645      */
    646     private static IStatus runMonkey(String serialNumber, ArrayList<String> packagesToRunMonkey,
    647             OutputStream outputStream, String otherCmds)
    648     {
    649 
    650         IStatus returnStatus = null;
    651         String allPackages = "";
    652         for (String packageToRunMonkey : packagesToRunMonkey)
    653         {
    654             allPackages += MONKEY_PACKAGES_DIRECTIVE + packageToRunMonkey;
    655         }
    656         StudioLogger.info(DDMSUtils.class, "Running monkey for: " + allPackages);
    657         IStatus temp = runMonkey(serialNumber, allPackages, outputStream, otherCmds);
    658         if (!temp.isOK())
    659         {
    660             if (returnStatus == null)
    661             {
    662                 returnStatus =
    663                         new MultiStatus(AndroidPlugin.PLUGIN_ID, 0,
    664                                 AndroidNLS.ERR_DDMSFacade_MonkeyError, null);
    665             }
    666 
    667             ((MultiStatus) returnStatus).add(temp);
    668         }
    669         return returnStatus == null ? Status.OK_STATUS : returnStatus;
    670     }
    671 
    672     /**
    673      * Uninstall packages from the given device. A Wizard will be opened asking
    674      * the user which packages to uninstall
    675      *
    676      * @param serialNumber
    677      * @return the status of the operation
    678      */
    679     public static IStatus uninstallPackage(final String serialNumber)
    680     {
    681         final ArrayList<String> packagesToUninstall = new ArrayList<String>();
    682         IStatus status = null;
    683         //wrap the dialog within a final variable
    684         final UninstallAppWizard[] wizard = new UninstallAppWizard[1];
    685 
    686         // do package listing async
    687         Thread listingThread = new Thread("listPackages")
    688         {
    689 
    690             @Override
    691             public void run()
    692             {
    693                 Map<String, String> installedPackages = null;
    694                 try
    695                 {
    696                     installedPackages = listInstalledPackages(serialNumber);
    697                 }
    698                 catch (IOException e1)
    699                 {
    700                     installedPackages = new HashMap<String, String>(0);
    701                 }
    702 
    703                 while (wizard[0] == null)
    704                 {
    705                     try
    706                     {
    707                         sleep(100);
    708                     }
    709                     catch (InterruptedException e)
    710                     {
    711                         //do nothing
    712                     }
    713                 }
    714                 wizard[0].setAvailablePackages(installedPackages);
    715             };
    716         };
    717 
    718         listingThread.start();
    719 
    720         PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
    721         {
    722             public void run()
    723             {
    724                 UninstallAppWizard unAppWiz = new UninstallAppWizard();
    725                 WizardDialog dialog =
    726                         new WizardDialog(new Shell(PlatformUI.getWorkbench()
    727                                 .getActiveWorkbenchWindow().getShell()), unAppWiz);
    728                 wizard[0] = unAppWiz;
    729                 dialog.open();
    730                 List<String> selectedPackages = wizard[0].getSelectedPackages();
    731                 if (selectedPackages != null)
    732                 {
    733                     for (String aPackage : selectedPackages)
    734                     {
    735                         packagesToUninstall.add(aPackage);
    736                     }
    737                 }
    738             }
    739         });
    740 
    741         if (packagesToUninstall.size() > 0)
    742         {
    743             OutputStream consoleOut = null;
    744 
    745             try
    746             {
    747                 consoleOut = EclipseUtils.getStudioConsoleOutputStream(true);
    748                 status = uninstallPackages(serialNumber, packagesToUninstall, consoleOut);
    749             }
    750             finally
    751             {
    752                 try
    753                 {
    754                     if (consoleOut != null)
    755                     {
    756                         consoleOut.close();
    757                     }
    758                 }
    759                 catch (IOException e)
    760                 {
    761                     StudioLogger.error("Uninstall App: could not close console stream"
    762                             + e.getMessage());
    763                 }
    764             }
    765         }
    766         if (status != null)
    767         {
    768             if (status.isOK())
    769             {
    770                 Display.getDefault().asyncExec(new Runnable()
    771                 {
    772                     public void run()
    773                     {
    774                         MessageDialog.openInformation(PlatformUI.getWorkbench()
    775                                 .getActiveWorkbenchWindow().getShell(),
    776                                 AndroidNLS.UI_UninstallApp_SucessDialogTitle,
    777                                 AndroidNLS.UI_UninstallApp_Message);
    778                     }
    779                 });
    780                 StudioAndroidEventManager.fireEvent(EventType.PACKAGE_UNINSTALLED, serialNumber);
    781             }
    782             else
    783             {
    784                 EclipseUtils.showErrorDialog(AndroidNLS.UI_UninstallApp_ERRDialogTitle,
    785                         AndroidNLS.UI_UninstallApp_ERRUninstallApp, status);
    786             }
    787         }
    788         // all return is successful since operations are async
    789         return Status.OK_STATUS;
    790 
    791     }
    792 
    793     /**
    794      * If there is no Monkey Launch configuration for the given deviceName, it is created.
    795      * @param deviceName
    796      */
    797     private static ILaunchConfiguration createLaunchConfiguration(String deviceName)
    798     {
    799         ILaunchConfiguration config = null;
    800         ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
    801         ILaunchConfigurationType motodevLaunchType =
    802                 launchManager
    803                         .getLaunchConfigurationType(IMonkeyConfigurationConstants.LAUNCH_CONFIGURATION_TYPE_EXTENSION_ID);
    804         String launchConfigurationName =
    805                 launchManager
    806                         .generateUniqueLaunchConfigurationNameFrom(IMonkeyConfigurationConstants.NEW_CONFIGURATION_NAME);
    807         try
    808         {
    809             ILaunchConfigurationWorkingCopy workingCopy =
    810                     motodevLaunchType.newInstance(null, launchConfigurationName);
    811             workingCopy.setAttribute(IMonkeyConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
    812                     deviceName);
    813             config = workingCopy.doSave();
    814         }
    815         catch (CoreException e)
    816         {
    817             EclipseUtils.showErrorDialog(AndroidNLS.UI_MonkeyError_Title, e.getMessage());
    818         }
    819         return config;
    820 
    821     }
    822 
    823     /**
    824      * Run adb monkey.
    825      *
    826      * @param serialNumber
    827      * @param deviceName
    828      * @return the status of the operation
    829      */
    830     public static IStatus runMonkey(final String serialNumber, final String deviceName)
    831     {
    832 
    833         ILaunchConfigurationType type =
    834                 DebugPlugin
    835                         .getDefault()
    836                         .getLaunchManager()
    837                         .getLaunchConfigurationType(
    838                                 IMonkeyConfigurationConstants.LAUNCH_CONFIGURATION_TYPE_EXTENSION_ID);
    839         ILaunchConfiguration[] launchs;
    840         try
    841         {
    842             launchs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(type);
    843 
    844             ILaunchConfiguration launchConfig = null;
    845             for (int i = 0; i < launchs.length; i++)
    846             {
    847                 launchConfig = launchs[i];
    848                 String configDeviceName =
    849                         launchConfig.getAttribute(
    850                                 IMonkeyConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME, "");
    851                 if (configDeviceName.equals(deviceName))
    852                 {
    853                     break;
    854                 }
    855                 else
    856                 {
    857                     launchConfig = null;
    858                 }
    859 
    860             }
    861             if (launchConfig == null)
    862             {
    863                 launchConfig = createLaunchConfiguration(deviceName);
    864 
    865             }
    866 
    867             final ILaunchGroup lc =
    868                     DebugUITools.getLaunchGroup(launchConfig, ILaunchManager.RUN_MODE);
    869 
    870             final IStructuredSelection selection = new StructuredSelection(launchConfig);
    871 
    872             PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
    873             {
    874                 public void run()
    875                 {
    876 
    877                     DebugUITools.openLaunchConfigurationDialogOnGroup(new Shell(PlatformUI
    878                             .getWorkbench().getActiveWorkbenchWindow().getShell()), selection,
    879                             lc.getIdentifier(), null);
    880 
    881                 }
    882             });
    883 
    884         }
    885         catch (CoreException e)
    886         {
    887             StudioLogger.error("Monkey: could not open the launch configuration dialog "
    888                     + e.getMessage());
    889 
    890         }
    891 
    892         // UDC log for monkey execution
    893         StudioLogger.collectUsageData(UsageDataConstants.WHAT_MONKEY_EXEC, //$NON-NLS-1$
    894                 UsageDataConstants.KIND_MONKEY_EXEC, "Monkey executed", //$NON-NLS-1$
    895                 AndroidPlugin.PLUGIN_ID, AndroidPlugin.getDefault().getBundle().getBundleContext()
    896                         .getBundle().getVersion().toString());
    897 
    898         // all return is successful since operations are async
    899         return Status.OK_STATUS;
    900 
    901     }
    902 
    903     /**
    904      * Run adb monkey.
    905      *
    906      * @param serialNumber
    907      * @param packagesToRunMonkey
    908      * @param otherCmds
    909      * @return the status of the operation
    910      */
    911     public static IStatus runMonkey(final String serialNumber,
    912             ArrayList<String> packagesToRunMonkey, String otherCmds)
    913     {
    914 
    915         if (packagesToRunMonkey.size() > 0)
    916         {
    917             OutputStream consoleOut = null;
    918 
    919             try
    920             {
    921                 consoleOut = EclipseUtils.getStudioConsoleOutputStream(true);
    922                 runMonkey(serialNumber, packagesToRunMonkey, consoleOut, otherCmds);
    923             }
    924             finally
    925             {
    926                 try
    927                 {
    928                     if (consoleOut != null)
    929                     {
    930                         consoleOut.close();
    931                     }
    932                 }
    933                 catch (IOException e)
    934                 {
    935                     StudioLogger.error("Monkey: could not close console stream" + e.getMessage());
    936                 }
    937             }
    938         }
    939 
    940         // all return is successful since operations are async
    941         return Status.OK_STATUS;
    942 
    943     }
    944 
    945     /**
    946      * List the installed packages in the device with the serial number Each
    947      * package entry carries their package location
    948      *
    949      * @param serialNumber
    950      * @return a HashMap where keys are the package names and values are package
    951      *         location
    952      * @throws IOException
    953      */
    954     public static Map<String, String> listInstalledPackages(String serialNumber) throws IOException
    955     {
    956         Map<String, String> packages = new LinkedHashMap<String, String>();
    957         String sdkPath = SdkUtils.getSdkPath();
    958         String command[] =
    959                 new String[]
    960                 {
    961                         sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
    962                                 + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
    963                         serialNumber, DDMSFacade.SHELL_CMD, PM_CMD, PM_LIST_DIRECTIVE,
    964                         PM_PACKAGES_DIRECTIVE, PM_PACKAGES_DIRECTIVE_FORCE
    965                 };
    966 
    967         String commResult = DDMSFacade.executeCommand(command, null);
    968         String[] packageList = null;
    969         if ((commResult != null) && (commResult.length() > 0)
    970                 && !commResult.contains("system running?"))
    971         {
    972             packageList = commResult.trim().replaceAll("\n\n", "\n").split("\n");
    973             int i = 0;
    974             String aPackage = null;
    975             String[] packageUnit = null;
    976             while (i < packageList.length)
    977             {
    978                 if (packageList[i].toLowerCase().contains("package:"))
    979                 {
    980                     String[] splittedPackage = packageList[i].split(":");
    981                     if (splittedPackage.length >= 2)
    982                     {
    983                         aPackage = splittedPackage[1].trim();
    984                         packageUnit = aPackage.split("=");
    985                         if (packageUnit.length > 1)
    986                         {
    987                             packages.put(packageUnit[1], packageUnit[0]);
    988                         }
    989                     }
    990                 }
    991                 i++;
    992             }
    993         }
    994         return packages;
    995     }
    996 
    997     /**
    998      * Install an application on an emulator instance
    999      *
   1000      * @param serialNumber
   1001      *            The serial number of the device where the application will be
   1002      *            installed
   1003      * @param path
   1004      *            Path of the package containing the application to be installed
   1005      * @param canOverwrite
   1006      *            If the application will be installed even if there is a
   1007      *            previous installation
   1008      * @param force
   1009      *            Perform the operation without asking for user intervention
   1010      *
   1011      * @return the status of the operation (OK, Cancel or Error+ErrorMessage)
   1012      */
   1013     public static IStatus installPackage(String serialNumber, String path, boolean canOverwrite,
   1014             OutputStream processOut)
   1015     {
   1016         IStatus status = Status.OK_STATUS;
   1017 
   1018         // Return if no instance is selected
   1019         if (serialNumber == null)
   1020         {
   1021             StudioLogger.error("Abort deploy operation. Serial number is null.");
   1022             status =
   1023                     new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
   1024                             AndroidNLS.ERR_DDMSFacade_SerialNumberNullPointer);
   1025         }
   1026 
   1027         // Return if instance is not started
   1028         if (status.isOK() && !DDMSFacade.isDeviceOnline(serialNumber))
   1029         {
   1030             StudioLogger.error("Abort deploy operation. Device is not online.");
   1031             status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, "");
   1032         }
   1033 
   1034         String command_results = "";
   1035         if (status.isOK())
   1036         {
   1037             try
   1038             {
   1039                 String[] cmd = createInstallCommand(canOverwrite, path, serialNumber);
   1040                 command_results = DDMSFacade.executeCommand(cmd, processOut, serialNumber);
   1041 
   1042                 // Check if the result has a success message
   1043                 if (!command_results.contains(SUCCESS_CONSTANT))
   1044                 {
   1045                     status =
   1046                             new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
   1047                                     "Error executing the operation. Execution results: "
   1048                                             + command_results);
   1049                 }
   1050             }
   1051             catch (IOException e)
   1052             {
   1053                 StudioLogger.error("Deploy: Could not execute adb install command.");
   1054                 status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage());
   1055             }
   1056         }
   1057 
   1058         return status;
   1059     }
   1060 
   1061     /**
   1062      * Change the emulator language
   1063      *
   1064      * @param serialNumber
   1065      *            The serial number of the device
   1066      * @param language
   1067      *            the language id
   1068      * @param country
   1069      *            the country id
   1070      * @return the status of the operation (OK, Error+ErrorMessage)
   1071      */
   1072     public static void changeLanguage(final String serialNumber, final String language,
   1073             final String country)
   1074     {
   1075 
   1076         if ((language != null) || (country != null))
   1077         {
   1078             /*
   1079              * A new thread is used since this command takes too long to be executed
   1080              */
   1081             Thread thead = new Thread(new Runnable()
   1082             {
   1083 
   1084                 public void run()
   1085                 {
   1086 
   1087                     String[] cmd = createChangeLanguageCommand(serialNumber, language, country);
   1088                     try
   1089                     {
   1090 
   1091                         IOConsoleOutputStream consoleOut =
   1092                                 EclipseUtils.getStudioConsoleOutputStream(true);
   1093                         if (language != null)
   1094                         {
   1095                             consoleOut.write(AndroidNLS.UI_ChangeLang_Language + " " + language
   1096                                     + "\n");
   1097                         }
   1098                         if (country != null)
   1099                         {
   1100                             consoleOut.write(AndroidNLS.UI_ChangeLang_Country + " " + country
   1101                                     + "\n");
   1102                         }
   1103 
   1104                         DDMSFacade.executeCommand(cmd, consoleOut);
   1105                         consoleOut.write("\n " + serialNumber + ":"
   1106                                 + AndroidNLS.UI_ChangeLang_Restart_Device_Manually + "\n\n");
   1107                         StudioAndroidEventManager.fireEvent(EventType.LANGUAGE_CHANGED,
   1108                                 serialNumber);
   1109                     }
   1110                     catch (IOException e)
   1111                     {
   1112                         StudioLogger
   1113                                 .error("Language: Could not execute adb change language command.");
   1114                     }
   1115 
   1116                 }
   1117             });
   1118             thead.start();
   1119         }
   1120 
   1121     }
   1122 
   1123     /**
   1124      * Creates a string with the command that should be called in order to
   1125      * change the device language
   1126      *
   1127      * @param serialNumber
   1128      *            The serial number of the device
   1129      * @param language
   1130      *            the language id
   1131      * @param country
   1132      *            the country id
   1133      * @return the command to be used to change the device language
   1134      */
   1135     private static String[] createChangeLanguageCommand(String serialNumber, String language,
   1136             String country)
   1137     {
   1138         String cmd[];
   1139         String sdkPath = SdkUtils.getSdkPath();
   1140 
   1141         String CHANGE_LANGUAGE_CMD = "";
   1142         if (language != null)
   1143         {
   1144             CHANGE_LANGUAGE_CMD += "setprop persist.sys.language " + language;
   1145         }
   1146         if (country != null)
   1147         {
   1148             CHANGE_LANGUAGE_CMD +=
   1149                     ((CHANGE_LANGUAGE_CMD.length() > 0) ? ";" : "")
   1150                             + "setprop persist.sys.country " + country;
   1151         }
   1152 
   1153         // The tools folder should exist and be here, but double-checking
   1154         // once more wont kill
   1155         File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1156         if (!f.exists())
   1157         {
   1158             StudioLogger.error("Language: Could not find tools folder on " + sdkPath
   1159                     + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1160         }
   1161         else
   1162         {
   1163             if (!f.isDirectory())
   1164             {
   1165                 StudioLogger.error("Language: Invalid tools folder " + sdkPath
   1166                         + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1167             }
   1168         }
   1169 
   1170         String cmdTemp[] =
   1171                 {
   1172                         sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
   1173                                 + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
   1174                         serialNumber, "shell", CHANGE_LANGUAGE_CMD
   1175                 };
   1176         cmd = cmdTemp;
   1177 
   1178         return cmd;
   1179     }
   1180 
   1181     /**
   1182      * Creates strings with the command that should be called in order to
   1183      * retrieve the current language and country in use by given emulator instance.
   1184      *
   1185      * @param serialNumber The serial number of the device
   1186      * @return An ArrayList with command strings to be used to get the
   1187      * current emulator language and country.
   1188      */
   1189     private static ArrayList<String[]> createCurrentEmulatorLanguageAndCountryCommand(
   1190             String serialNumber)
   1191     {
   1192         String languageCommand[];
   1193         String countryCommand[];
   1194         String sdkPath = SdkUtils.getSdkPath();
   1195         String GET_LANGUAGE_CMD = "getprop persist.sys.language";
   1196         String GET_COUNTRY_CMD = "getprop persist.sys.country";
   1197         // The tools folder should exist and be here, but double-cheking
   1198         // once more wont kill
   1199         File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1200         if (!f.exists())
   1201         {
   1202             StudioLogger.error("Language: Could not find tools folder on " + sdkPath
   1203                     + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1204         }
   1205         else
   1206         {
   1207             if (!f.isDirectory())
   1208             {
   1209                 StudioLogger.error("Language: Invalid tools folder " + sdkPath
   1210                         + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1211             }
   1212         }
   1213         String langCmdTemp[] =
   1214                 {
   1215                         sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
   1216                                 + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
   1217                         serialNumber, "shell", GET_LANGUAGE_CMD
   1218                 };
   1219         String countryCmdTemp[] =
   1220                 {
   1221                         sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
   1222                                 + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
   1223                         serialNumber, "shell", GET_COUNTRY_CMD
   1224                 };
   1225         languageCommand = langCmdTemp;
   1226         countryCommand = countryCmdTemp;
   1227 
   1228         ArrayList<String[]> commands = new ArrayList<String[]>();
   1229         commands.add(0, languageCommand);
   1230         commands.add(1, countryCommand);
   1231         return commands;
   1232     }
   1233 
   1234     /**
   1235      * Creates a string with the command that should be called in order to
   1236      * install the application
   1237      *
   1238      * @param canOverwrite
   1239      *            If true, than existent application will be overwritten
   1240      * @param path
   1241      *            Location of the package containing the application
   1242      * @param serialNumber
   1243      *            The serial number of the device to be targeted
   1244      *
   1245      * @return
   1246      */
   1247     private static String[] createInstallCommand(boolean canOverwrite, String path,
   1248             String serialNumber)
   1249     {
   1250         String cmd[];
   1251         String sdkPath = SdkUtils.getSdkPath();
   1252 
   1253         // The tools folder should exist and be here, but double-checking
   1254         // once more wont kill
   1255         File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1256         if (!f.exists())
   1257         {
   1258             StudioLogger.error("Deploy: Could not find tools folder on " + sdkPath
   1259                     + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1260         }
   1261         else
   1262         {
   1263             if (!f.isDirectory())
   1264             {
   1265                 StudioLogger.error("Deploy: Invalid tools folder " + sdkPath
   1266                         + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1267             }
   1268         }
   1269 
   1270         if (canOverwrite)
   1271         {
   1272             // If overwrite option is checked, create command with the -r
   1273             // paramater
   1274             String cmdTemp[] =
   1275                     {
   1276                             sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
   1277                                     + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
   1278                             serialNumber, INSTALL_CMD, ADB_INSTALL_OVERWRITE, path
   1279                     };
   1280             cmd = cmdTemp;
   1281         }
   1282         else
   1283         {
   1284             // If overwrite option is unchecked, create command without the -r
   1285             // paramater
   1286             String cmdTemp[] =
   1287                     {
   1288                             sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
   1289                                     + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
   1290                             serialNumber, INSTALL_CMD, path
   1291                     };
   1292             cmd = cmdTemp;
   1293         }
   1294 
   1295         return cmd;
   1296     }
   1297 
   1298     private static String[] createUninstallCommand(String serialNumber, String packageName)
   1299     {
   1300         String sdkPath = SdkUtils.getSdkPath();
   1301         // The tools folder should exist and be here, but double-checking
   1302         // once more wont kill
   1303         File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1304         if (!f.exists())
   1305         {
   1306             StudioLogger.error("Run: Could not find tools folder on " + sdkPath
   1307                     + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1308         }
   1309         else
   1310         {
   1311             if (!f.isDirectory())
   1312             {
   1313                 StudioLogger.error("Run: Invalid tools folder " + sdkPath
   1314                         + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1315             }
   1316         }
   1317 
   1318         String cmd[] =
   1319                 {
   1320                         sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
   1321                                 + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
   1322                         serialNumber, DDMSFacade.SHELL_CMD, PM_CMD, PM_UNINSTALL_DIRECTIVE,
   1323                         packageName
   1324                 };
   1325 
   1326         return cmd;
   1327 
   1328     }
   1329 
   1330     /**
   1331      * Mount the adb monkey command based on the given parameters.
   1332      * @param serialNumber
   1333      * @param packagesName
   1334      * @param otherCmd
   1335      * @return the array of strings containing the monkey command to be executed.
   1336      */
   1337     private static String[] createMonkeyCommand(String serialNumber, String packagesName,
   1338             String otherCmd)
   1339     {
   1340         String sdkPath = SdkUtils.getSdkPath();
   1341         // The tools folder should exist and be here, but double-checking
   1342         // once more wont kill
   1343         File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1344         if (!f.exists())
   1345         {
   1346             StudioLogger.error("Run: Could not find tools folder on " + sdkPath
   1347                     + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1348         }
   1349         else
   1350         {
   1351             if (!f.isDirectory())
   1352             {
   1353                 StudioLogger.error("Run: Invalid tools folder " + sdkPath
   1354                         + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
   1355             }
   1356         }
   1357 
   1358         String cmd[] =
   1359                 {
   1360                         sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
   1361                                 + DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
   1362                         serialNumber, DDMSFacade.SHELL_CMD, MONKEY_CMD, packagesName, otherCmd
   1363                 };
   1364 
   1365         return cmd;
   1366 
   1367     }
   1368 
   1369     /**
   1370      * Dump HPROF service implementation
   1371      * @param serialNumber The device serial number
   1372      * @param monitor
   1373      * @return A IStatus describing if the service was successful or not
   1374      */
   1375     public static IStatus dumpHPROF(final String serialNumber, IProgressMonitor monitor)
   1376     {
   1377         IStatus status;
   1378 
   1379         // Selected app. The array should have only 1 element
   1380         final String[] selectedAppSet = new String[1];
   1381 
   1382         // Instantiate the wizard and populate it with the retrieved process list
   1383         PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
   1384         {
   1385             public void run()
   1386             {
   1387                 DumpHPROFWizard dumpHPROFWizard = new DumpHPROFWizard(serialNumber);
   1388                 WizardDialog dialog =
   1389                         new WizardDialog(new Shell(PlatformUI.getWorkbench()
   1390                                 .getActiveWorkbenchWindow().getShell()), dumpHPROFWizard);
   1391                 dialog.open();
   1392 
   1393                 // Get the selected application
   1394                 selectedAppSet[0] = dumpHPROFWizard.getSelectedApp();
   1395 
   1396             }
   1397         });
   1398 
   1399         if (selectedAppSet[0] != null)
   1400         {
   1401             // Dump HPROF file based on the selected application
   1402             status = DDMSFacade.dumpHprofFile(selectedAppSet[0], serialNumber, monitor);
   1403         }
   1404         else
   1405         {
   1406             status = Status.CANCEL_STATUS;
   1407         }
   1408 
   1409         return status;
   1410     }
   1411 
   1412     public static int getDeviceApiVersion(String serialNumber)
   1413     {
   1414         int deviceSdkVersion = -1;
   1415         String deviceProperty = DDMSFacade.getDeviceProperty(serialNumber, "ro.build.version.sdk");
   1416         if (deviceProperty != null)
   1417         {
   1418             deviceSdkVersion = Integer.parseInt(deviceProperty);
   1419         }
   1420 
   1421         return deviceSdkVersion;
   1422     }
   1423 
   1424     public static boolean remoteFileExists(String serialNumber, String remotePath)
   1425             throws IOException
   1426     {
   1427         boolean found = false;
   1428         Collection<String> results =
   1429                 DDMSFacade.execRemoteApp(serialNumber,
   1430                         "ls " + FileUtil.getEscapedPath(remotePath, Platform.OS_LINUX),
   1431                         new NullProgressMonitor());
   1432         for (String result : results)
   1433         {
   1434             if (result.equals(remotePath))
   1435             {
   1436                 found = true;
   1437                 break;
   1438             }
   1439         }
   1440         return found;
   1441     }
   1442 }
   1443