blob: d98b0798872eba4bd850c2525f1d147b8be34ea8 [file] [log] [blame]
/*
* 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.motorola.studio.android.adt;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.ILaunchGroup;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.IOConsoleOutputStream;
import com.android.ddmlib.FileListingService;
import com.android.ddmlib.FileListingService.FileEntry;
import com.android.ddmlib.IDevice;
import com.android.ddmuilib.ScreenShotDialog;
import com.android.sdklib.IAndroidTarget;
import com.motorola.studio.android.AndroidPlugin;
import com.motorola.studio.android.adt.StudioAndroidEventManager.EventType;
import com.motorola.studio.android.common.log.StudioLogger;
import com.motorola.studio.android.common.log.UsageDataConstants;
import com.motorola.studio.android.common.utilities.EclipseUtils;
import com.motorola.studio.android.common.utilities.FileUtil;
import com.motorola.studio.android.i18n.AndroidNLS;
import com.motorola.studio.android.wizards.installapp.DeployWizard;
import com.motorola.studio.android.wizards.installapp.DeployWizard.INSTALL_TYPE;
import com.motorola.studio.android.wizards.installapp.UninstallAppWizard;
import com.motorola.studio.android.wizards.mat.DumpHPROFWizard;
import com.motorola.studio.android.wizards.monkey.IMonkeyConfigurationConstants;
public class DDMSUtils
{
private static final Map<String, FileListingService> deviceFileListingServiceMap =
new HashMap<String, FileListingService>();
/**
* The APK extension
*/
private static final String APK_FILE_EXTENSION = "apk";
/**
* Parameter for overwriting existing applications, if any
*/
private static final String ADB_INSTALL_OVERWRITE = "-r";
/**
* Options to be used with adb to indicate package manager application
*/
private static final String PM_CMD = "pm";
/**
* Options to be used with adb to run monkey application
*/
private static final String MONKEY_CMD = "monkey";
/**
* Uninstall directive to the package manager
*/
private static final String PM_UNINSTALL_DIRECTIVE = "uninstall";
/**
* List packages directive
*/
private static final String PM_LIST_DIRECTIVE = "list";
/**
* List packages directive
*/
private static final String PM_PACKAGES_DIRECTIVE = "packages";
/**
* List packages force directive
*/
private static final String PM_PACKAGES_DIRECTIVE_FORCE = "-f";
/**
* Monkey packages directive
*/
private static final String MONKEY_PACKAGES_DIRECTIVE = " -p ";
/**
* Options to be used with adb to indicate install operation
*/
private static final String INSTALL_CMD = "install";
/**
* This word must exist in the adb install commmand answer to indicate
* succefull installation
*/
private static final String SUCCESS_CONSTANT = "Success";
private static final DdmsRunnable disconnectedListener = new DdmsRunnable()
{
public void run(String serialNumber)
{
synchronized (deviceFileListingServiceMap)
{
deviceFileListingServiceMap.remove(serialNumber);
}
}
};
static
{
StudioAndroidEventManager.asyncAddDeviceChangeListeners(null, disconnectedListener);
}
public static void takeScreenshot(final String serialNumber)
{
Display.getDefault().asyncExec(new Runnable()
{
public void run()
{
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
ScreenShotDialog sshot = new ScreenShotDialog(new Shell(shell));
sshot.open(DDMSFacade.getDeviceBySerialNumber(serialNumber));
}
});
}
public static void getApplicationDatabases(String serialNumber, String applicationName,
IDatabaseListingListener listener)
{
LinkedList<String> pathSegments = new LinkedList<String>();
pathSegments.add("data");
pathSegments.add("data");
pathSegments.add(applicationName);
pathSegments.add("databases");
FileListingService fileListing = getFileListingService(serialNumber);
if (fileListing != null)
{
FileEntry root = fileListing.getRoot();
FileEntry[] children = null;
children =
fileListing.getChildren(root, true, new FileListingReceiver(pathSegments,
fileListing, listener));
/*
* If children isn't null means that file listing service found the
* files in it cache to speed up the operation
*/
if (children != null)
{
List<String> databases = new ArrayList<String>();
FileEntry temp1 = null, temp2 = root;
// start from root
while ((children != null))
{
// if we have something to search for
if (pathSegments.size() > 0)
{
String theSegment = pathSegments.remove(0);
temp1 = temp2.findChild(theSegment);
if (temp1 != null)
{
temp2 = temp1;
children =
fileListing.getChildren(temp2, true, new FileListingReceiver(
pathSegments, fileListing, listener));
}
else
{
children = null;
listener.databasesFound(databases);
}
}
// else just notify the listener
else
{
if (children != null)
{
for (FileEntry child : children)
{
if (child.getName().endsWith(".db"))
{
databases.add(child.getName());
}
}
children = null;
}
listener.databasesFound(databases);
}
}
}
}
}
public static List<String> getApplicationDatabases(String serialNumber, String applicationName)
throws IOException
{
List<String> dbs = new ArrayList<String>();
String appDbPath = "/data/data/" + applicationName + "/databases/";
Collection<String> commandOutput =
DDMSFacade
.execRemoteApp(serialNumber, "ls " + appDbPath, new NullProgressMonitor());
List<String> dbPathCandidates = new ArrayList(commandOutput.size() + 10);
for (String commandOutline : commandOutput)
{
String[] strings = commandOutline.split(" ");
for (String string : strings)
{
if (string.trim().endsWith(".db"))
{
dbPathCandidates.add(string);
}
}
}
return dbPathCandidates;
}
/**
* @param serialNumber
* @return
*/
private static FileListingService getFileListingService(String serialNumber)
{
FileListingService fileListing = null;
IDevice dev = DDMSFacade.getDeviceBySerialNumber(serialNumber);
if (dev != null)
{
synchronized (dev)
{
fileListing = deviceFileListingServiceMap.get(serialNumber);
}
if (fileListing == null)
{
fileListing = dev.getFileListingService();
synchronized (deviceFileListingServiceMap)
{
deviceFileListingServiceMap.put(serialNumber, fileListing);
}
}
}
return fileListing;
}
/**
* This method returns the current language and country in use by given
* emulation instance.
*
* @param serialNumber The serial number of emulation instance
* @return An array of Strings containing the command results.
*/
public static String[] getCurrentEmulatorLanguageAndCountry(final String serialNumber)
{
ArrayList<String[]> commands = createCurrentEmulatorLanguageAndCountryCommand(serialNumber);
String[] responses = new String[2];
String[] languageCommand = commands.get(0);
String[] countryCommand = commands.get(1);
String languageCommandResult = null;
String countryCommandResult = null;
try
{
// Do not write the command output to the console
languageCommandResult = DDMSFacade.executeCommand(languageCommand, null);
countryCommandResult = DDMSFacade.executeCommand(countryCommand, null);
responses[0] = languageCommandResult.replaceAll("\\n$", "");
responses[1] = countryCommandResult.replaceAll("\\n$", "");
}
catch (IOException e)
{
StudioLogger.error("Deploy: Could not execute adb current language command.");
}
return responses;
}
public static InstallPackageBean installPackageWizard()
{
final InstallPackageBean bean = new InstallPackageBean();
final Display display = PlatformUI.getWorkbench().getDisplay();
display.syncExec(new Runnable()
{
public void run()
{
try
{
String defaultPath = null;
DeployWizard wizard;
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null)
{
ISelection selection = window.getSelectionService().getSelection();
if (selection instanceof IStructuredSelection)
{
IStructuredSelection workbenchSSelection =
(IStructuredSelection) selection;
for (Object o : workbenchSSelection.toList())
{
if (o instanceof IFile)
{
IFile file = (IFile) o;
if (file.getFileExtension()
.equalsIgnoreCase(APK_FILE_EXTENSION))
{
defaultPath = file.getLocation().toOSString();
}
}
}
}
}
wizard = new DeployWizard(defaultPath);
wizard.init(PlatformUI.getWorkbench(), new StructuredSelection());
WizardDialog dialog =
new WizardDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell(), wizard);
dialog.setPageSize(500, 200);
if (dialog.open() == IDialogConstants.OK_ID)
{
bean.setPackagePath(wizard.getPackagePath());
bean.setCanOverwrite(wizard.canOverwrite());
}
}
catch (Throwable e)
{
StudioLogger.error(DDMSFacade.class, "Error executing deploy wizard", e);
}
}
});
return bean;
}
public static IStatus installPackage(final String serialNumber, InstallPackageBean bean)
{
IStatus status = Status.CANCEL_STATUS;
if ((bean.getPackagePath() != null) && (bean.getCanOverwrite() != null))
{
OutputStream consoleOut = null;
try
{
consoleOut = EclipseUtils.getStudioConsoleOutputStream(true);
status =
installPackage(serialNumber, bean.getPackagePath(), bean.getCanOverwrite(),
consoleOut);
}
finally
{
try
{
if (consoleOut != null)
{
consoleOut.close();
}
}
catch (IOException e)
{
StudioLogger.error("Install App: could not close console stream"
+ e.getMessage());
}
}
}
if (status.isOK())
{
StudioAndroidEventManager.fireEvent(EventType.PACKAGE_INSTALLED, serialNumber);
}
return status;
}
/**
* Install an application on an emulator instance
*
* @param serialNumber
* The serial number of the device where the application will be
* installed
* @param path
* Path of the package containing the application to be installed
* @param installationType
* one of the {@link INSTALL_TYPE} install types available
* @param force
* Perform the operation without asking for user intervention
*
* @return the status of the operation (OK, Cancel or Error+ErrorMessage)
*/
public static IStatus installPackage(String serialNumber, String path,
INSTALL_TYPE installationType, OutputStream processOut)
{
IStatus status = null;
if (installationType.equals(INSTALL_TYPE.UNINSTALL))
{
status = uninstallPackage(new File(path), serialNumber, processOut);
}
boolean overwrite = installationType.equals(INSTALL_TYPE.OVERWRITE);
status = installPackage(serialNumber, path, overwrite, processOut);
return status;
}
/**
* Uninstall the given package (if installed) in the given serialNumber
* device
*
* @param path
* the package path
* @param serialNumber
* the device serial number
*/
public static IStatus uninstallPackage(File path, String serialNumber, OutputStream processOut)
{
IStatus returnStatus = null;
if ((path != null) && path.exists() && path.isFile())
{
IDevice dev = DDMSFacade.getDeviceBySerialNumber(serialNumber);
String apiLevel = dev.getProperty("ro.build.version.sdk");
IAndroidTarget target = SdkUtils.getTargetByAPILevel(Integer.parseInt(apiLevel));
String aaptPath = SdkUtils.getTargetAAPTPath(target);
if (aaptPath != null)
{
// resolve package name
String[] aaptComm = new String[]
{
aaptPath, "d", "badging", path.toString()
};
InputStreamReader reader = null;
BufferedReader bufferedReader = null;
try
{
Process aapt = Runtime.getRuntime().exec(aaptComm);
reader = new InputStreamReader(aapt.getInputStream());
bufferedReader = new BufferedReader(reader);
String infoLine = bufferedReader.readLine();
infoLine = infoLine.split(" ")[1].split("=")[1].replaceAll("'", "");
returnStatus = uninstallPackage(serialNumber, infoLine, processOut);
}
catch (Exception e)
{
returnStatus =
new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
AndroidNLS.ERR_DDMSFacade_UninstallPackageException, e);
}
finally
{
try
{
if (reader != null)
{
reader.close();
}
if (bufferedReader != null)
{
bufferedReader.close();
}
}
catch (IOException e)
{
StudioLogger.error("Uninstall app could not close stream. "
+ e.getMessage());
}
}
}
else
{
StudioLogger
.error(DDMSFacade.class,
"Impossible to check APK package name. No android targets found inside SDK");
}
}
else
{
returnStatus =
new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
AndroidNLS.ERR_DDMSFacade_UninstallPackage);
}
return returnStatus;
}
/**
* Uninstall the given package within device with given serial number
*
* @param serialNumber
* @param packageName
* @param processOutput
* outputStream to write output of the process
*/
public static IStatus uninstallPackage(String serialNumber, String packageName,
OutputStream processOutput)
{
IStatus status = Status.OK_STATUS;
String command[] = createUninstallCommand(serialNumber, packageName);
try
{
String commandResult = DDMSFacade.executeCommand(command, processOutput);
if (!commandResult.toLowerCase().contains(SUCCESS_CONSTANT.toLowerCase()))
{
status =
new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
AndroidNLS.ERR_DDMSFacade_UninstallPackageError + ": "
+ packageName);
}
}
catch (Exception e)
{
status =
new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
AndroidNLS.ERR_DDMSFacade_UninstallPackageException, e);
StudioLogger.error(DDMSFacade.class, "Failed to remove package: " + packageName + ". "
+ e.getMessage());
}
return status;
}
/**
* Run the Monkey command for the given package within device with given serial number
*
* @param serialNumber
* @param packageName
* @param processOutput
* @param otherCmd
* @return the status of the monkey process
*/
public static IStatus runMonkey(String serialNumber, String allPackages,
OutputStream processOutput, String otherCmd)
{
IStatus status = Status.OK_STATUS;
String command[] = createMonkeyCommand(serialNumber, allPackages, otherCmd);
try
{
DDMSFacade.executeCommand(command, processOutput);
}
catch (Exception e)
{
EclipseUtils.showErrorDialog(AndroidNLS.UI_MonkeyError_Title,
AndroidNLS.UI_MonkeyError_Msg);
StudioLogger.error(DDMSFacade.class, "Failed to run monkey command: " + command + " "
+ e.getMessage());
}
return status;
}
/**
* Uninstall packages from the given serialNumber device
*
* @param serialNumber
* @param packagesToUninstall
* @param outputStream
* @return the status of the uninstall process or null if no packages were
* uninstalled
*/
private static IStatus uninstallPackages(String serialNumber,
ArrayList<String> packagesToUninstall, OutputStream outputStream)
{
IStatus returnStatus = null;
for (String packageToUninstall : packagesToUninstall)
{
StudioLogger.info(DDMSUtils.class, "Removing package: " + packageToUninstall);
IStatus temp = uninstallPackage(serialNumber, packageToUninstall, outputStream);
if (!temp.isOK())
{
if (returnStatus == null)
{
returnStatus =
new MultiStatus(AndroidPlugin.PLUGIN_ID, 0,
AndroidNLS.ERR_DDMSFacade_UninstallPackageError, null);
}
((MultiStatus) returnStatus).add(temp);
}
}
return returnStatus == null ? Status.OK_STATUS : returnStatus;
}
/**
* Run monkey command on the given packages with the specified commands.
*
* @param serialNumber
* @param packagesToRunMonkey
* @param outputStream
* @param otherCmds
* @return the status of the monkey process or null if the process was not successful
*/
private static IStatus runMonkey(String serialNumber, ArrayList<String> packagesToRunMonkey,
OutputStream outputStream, String otherCmds)
{
IStatus returnStatus = null;
String allPackages = "";
for (String packageToRunMonkey : packagesToRunMonkey)
{
allPackages += MONKEY_PACKAGES_DIRECTIVE + packageToRunMonkey;
}
StudioLogger.info(DDMSUtils.class, "Running monkey for: " + allPackages);
IStatus temp = runMonkey(serialNumber, allPackages, outputStream, otherCmds);
if (!temp.isOK())
{
if (returnStatus == null)
{
returnStatus =
new MultiStatus(AndroidPlugin.PLUGIN_ID, 0,
AndroidNLS.ERR_DDMSFacade_MonkeyError, null);
}
((MultiStatus) returnStatus).add(temp);
}
return returnStatus == null ? Status.OK_STATUS : returnStatus;
}
/**
* Uninstall packages from the given device. A Wizard will be opened asking
* the user which packages to uninstall
*
* @param serialNumber
* @return the status of the operation
*/
public static IStatus uninstallPackage(final String serialNumber)
{
final ArrayList<String> packagesToUninstall = new ArrayList<String>();
IStatus status = null;
//wrap the dialog within a final variable
final UninstallAppWizard[] wizard = new UninstallAppWizard[1];
// do package listing async
Thread listingThread = new Thread("listPackages")
{
@Override
public void run()
{
Map<String, String> installedPackages = null;
try
{
installedPackages = listInstalledPackages(serialNumber);
}
catch (IOException e1)
{
installedPackages = new HashMap<String, String>(0);
}
while (wizard[0] == null)
{
try
{
sleep(100);
}
catch (InterruptedException e)
{
//do nothing
}
}
wizard[0].setAvailablePackages(installedPackages);
};
};
listingThread.start();
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
{
public void run()
{
UninstallAppWizard unAppWiz = new UninstallAppWizard();
WizardDialog dialog =
new WizardDialog(new Shell(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell()), unAppWiz);
wizard[0] = unAppWiz;
dialog.open();
List<String> selectedPackages = wizard[0].getSelectedPackages();
if (selectedPackages != null)
{
for (String aPackage : selectedPackages)
{
packagesToUninstall.add(aPackage);
}
}
}
});
if (packagesToUninstall.size() > 0)
{
OutputStream consoleOut = null;
try
{
consoleOut = EclipseUtils.getStudioConsoleOutputStream(true);
status = uninstallPackages(serialNumber, packagesToUninstall, consoleOut);
}
finally
{
try
{
if (consoleOut != null)
{
consoleOut.close();
}
}
catch (IOException e)
{
StudioLogger.error("Uninstall App: could not close console stream"
+ e.getMessage());
}
}
}
if (status != null)
{
if (status.isOK())
{
Display.getDefault().asyncExec(new Runnable()
{
public void run()
{
MessageDialog.openInformation(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell(),
AndroidNLS.UI_UninstallApp_SucessDialogTitle,
AndroidNLS.UI_UninstallApp_Message);
}
});
StudioAndroidEventManager.fireEvent(EventType.PACKAGE_UNINSTALLED, serialNumber);
}
else
{
EclipseUtils.showErrorDialog(AndroidNLS.UI_UninstallApp_ERRDialogTitle,
AndroidNLS.UI_UninstallApp_ERRUninstallApp, status);
}
}
// all return is successful since operations are async
return Status.OK_STATUS;
}
/**
* If there is no Monkey Launch configuration for the given deviceName, it is created.
* @param deviceName
*/
private static ILaunchConfiguration createLaunchConfiguration(String deviceName)
{
ILaunchConfiguration config = null;
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType motodevLaunchType =
launchManager
.getLaunchConfigurationType(IMonkeyConfigurationConstants.LAUNCH_CONFIGURATION_TYPE_EXTENSION_ID);
String launchConfigurationName =
launchManager
.generateUniqueLaunchConfigurationNameFrom(IMonkeyConfigurationConstants.NEW_CONFIGURATION_NAME);
try
{
ILaunchConfigurationWorkingCopy workingCopy =
motodevLaunchType.newInstance(null, launchConfigurationName);
workingCopy.setAttribute(IMonkeyConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME,
deviceName);
config = workingCopy.doSave();
}
catch (CoreException e)
{
EclipseUtils.showErrorDialog(AndroidNLS.UI_MonkeyError_Title, e.getMessage());
}
return config;
}
/**
* Run adb monkey.
*
* @param serialNumber
* @param deviceName
* @return the status of the operation
*/
public static IStatus runMonkey(final String serialNumber, final String deviceName)
{
ILaunchConfigurationType type =
DebugPlugin
.getDefault()
.getLaunchManager()
.getLaunchConfigurationType(
IMonkeyConfigurationConstants.LAUNCH_CONFIGURATION_TYPE_EXTENSION_ID);
ILaunchConfiguration[] launchs;
try
{
launchs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(type);
ILaunchConfiguration launchConfig = null;
for (int i = 0; i < launchs.length; i++)
{
launchConfig = launchs[i];
String configDeviceName =
launchConfig.getAttribute(
IMonkeyConfigurationConstants.ATTR_DEVICE_INSTANCE_NAME, "");
if (configDeviceName.equals(deviceName))
{
break;
}
else
{
launchConfig = null;
}
}
if (launchConfig == null)
{
launchConfig = createLaunchConfiguration(deviceName);
}
final ILaunchGroup lc =
DebugUITools.getLaunchGroup(launchConfig, ILaunchManager.RUN_MODE);
final IStructuredSelection selection = new StructuredSelection(launchConfig);
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
{
public void run()
{
DebugUITools.openLaunchConfigurationDialogOnGroup(new Shell(PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getShell()), selection,
lc.getIdentifier(), null);
}
});
}
catch (CoreException e)
{
StudioLogger.error("Monkey: could not open the launch configuration dialog "
+ e.getMessage());
}
// UDC log for monkey execution
StudioLogger.collectUsageData(UsageDataConstants.WHAT_MONKEY_EXEC, //$NON-NLS-1$
UsageDataConstants.KIND_MONKEY_EXEC, "Monkey executed", //$NON-NLS-1$
AndroidPlugin.PLUGIN_ID, AndroidPlugin.getDefault().getBundle().getBundleContext()
.getBundle().getVersion().toString());
// all return is successful since operations are async
return Status.OK_STATUS;
}
/**
* Run adb monkey.
*
* @param serialNumber
* @param packagesToRunMonkey
* @param otherCmds
* @return the status of the operation
*/
public static IStatus runMonkey(final String serialNumber,
ArrayList<String> packagesToRunMonkey, String otherCmds)
{
if (packagesToRunMonkey.size() > 0)
{
OutputStream consoleOut = null;
try
{
consoleOut = EclipseUtils.getStudioConsoleOutputStream(true);
runMonkey(serialNumber, packagesToRunMonkey, consoleOut, otherCmds);
}
finally
{
try
{
if (consoleOut != null)
{
consoleOut.close();
}
}
catch (IOException e)
{
StudioLogger.error("Monkey: could not close console stream" + e.getMessage());
}
}
}
// all return is successful since operations are async
return Status.OK_STATUS;
}
/**
* List the installed packages in the device with the serial number Each
* package entry carries their package location
*
* @param serialNumber
* @return a HashMap where keys are the package names and values are package
* location
* @throws IOException
*/
public static Map<String, String> listInstalledPackages(String serialNumber) throws IOException
{
Map<String, String> packages = new LinkedHashMap<String, String>();
String sdkPath = SdkUtils.getSdkPath();
String command[] =
new String[]
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, DDMSFacade.SHELL_CMD, PM_CMD, PM_LIST_DIRECTIVE,
PM_PACKAGES_DIRECTIVE, PM_PACKAGES_DIRECTIVE_FORCE
};
String commResult = DDMSFacade.executeCommand(command, null);
String[] packageList = null;
if ((commResult != null) && (commResult.length() > 0)
&& !commResult.contains("system running?"))
{
packageList = commResult.trim().replaceAll("\n\n", "\n").split("\n");
int i = 0;
String aPackage = null;
String[] packageUnit = null;
while (i < packageList.length)
{
if (packageList[i].toLowerCase().contains("package:"))
{
String[] splittedPackage = packageList[i].split(":");
if (splittedPackage.length >= 2)
{
aPackage = splittedPackage[1].trim();
packageUnit = aPackage.split("=");
if (packageUnit.length > 1)
{
packages.put(packageUnit[1], packageUnit[0]);
}
}
}
i++;
}
}
return packages;
}
/**
* Install an application on an emulator instance
*
* @param serialNumber
* The serial number of the device where the application will be
* installed
* @param path
* Path of the package containing the application to be installed
* @param canOverwrite
* If the application will be installed even if there is a
* previous installation
* @param force
* Perform the operation without asking for user intervention
*
* @return the status of the operation (OK, Cancel or Error+ErrorMessage)
*/
public static IStatus installPackage(String serialNumber, String path, boolean canOverwrite,
OutputStream processOut)
{
IStatus status = Status.OK_STATUS;
// Return if no instance is selected
if (serialNumber == null)
{
StudioLogger.error("Abort deploy operation. Serial number is null.");
status =
new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
AndroidNLS.ERR_DDMSFacade_SerialNumberNullPointer);
}
// Return if instance is not started
if (status.isOK() && !DDMSFacade.isDeviceOnline(serialNumber))
{
StudioLogger.error("Abort deploy operation. Device is not online.");
status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, "");
}
String command_results = "";
if (status.isOK())
{
try
{
String[] cmd = createInstallCommand(canOverwrite, path, serialNumber);
command_results = DDMSFacade.executeCommand(cmd, processOut, serialNumber);
// Check if the result has a success message
if (!command_results.contains(SUCCESS_CONSTANT))
{
status =
new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
"Error executing the operation. Execution results: "
+ command_results);
}
}
catch (IOException e)
{
StudioLogger.error("Deploy: Could not execute adb install command.");
status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage());
}
}
return status;
}
/**
* Change the emulator language
*
* @param serialNumber
* The serial number of the device
* @param language
* the language id
* @param country
* the country id
* @return the status of the operation (OK, Error+ErrorMessage)
*/
public static void changeLanguage(final String serialNumber, final String language,
final String country)
{
if ((language != null) || (country != null))
{
/*
* A new thread is used since this command takes too long to be executed
*/
Thread thead = new Thread(new Runnable()
{
public void run()
{
String[] cmd = createChangeLanguageCommand(serialNumber, language, country);
try
{
IOConsoleOutputStream consoleOut =
EclipseUtils.getStudioConsoleOutputStream(true);
if (language != null)
{
consoleOut.write(AndroidNLS.UI_ChangeLang_Language + " " + language
+ "\n");
}
if (country != null)
{
consoleOut.write(AndroidNLS.UI_ChangeLang_Country + " " + country
+ "\n");
}
DDMSFacade.executeCommand(cmd, consoleOut);
consoleOut.write("\n " + serialNumber + ":"
+ AndroidNLS.UI_ChangeLang_Restart_Device_Manually + "\n\n");
StudioAndroidEventManager.fireEvent(EventType.LANGUAGE_CHANGED,
serialNumber);
}
catch (IOException e)
{
StudioLogger
.error("Language: Could not execute adb change language command.");
}
}
});
thead.start();
}
}
/**
* Creates a string with the command that should be called in order to
* change the device language
*
* @param serialNumber
* The serial number of the device
* @param language
* the language id
* @param country
* the country id
* @return the command to be used to change the device language
*/
private static String[] createChangeLanguageCommand(String serialNumber, String language,
String country)
{
String cmd[];
String sdkPath = SdkUtils.getSdkPath();
String CHANGE_LANGUAGE_CMD = "";
if (language != null)
{
CHANGE_LANGUAGE_CMD += "setprop persist.sys.language " + language;
}
if (country != null)
{
CHANGE_LANGUAGE_CMD +=
((CHANGE_LANGUAGE_CMD.length() > 0) ? ";" : "")
+ "setprop persist.sys.country " + country;
}
// The tools folder should exist and be here, but double-checking
// once more wont kill
File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists())
{
StudioLogger.error("Language: Could not find tools folder on " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
else
{
if (!f.isDirectory())
{
StudioLogger.error("Language: Invalid tools folder " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
}
String cmdTemp[] =
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, "shell", CHANGE_LANGUAGE_CMD
};
cmd = cmdTemp;
return cmd;
}
/**
* Creates strings with the command that should be called in order to
* retrieve the current language and country in use by given emulator instance.
*
* @param serialNumber The serial number of the device
* @return An ArrayList with command strings to be used to get the
* current emulator language and country.
*/
private static ArrayList<String[]> createCurrentEmulatorLanguageAndCountryCommand(
String serialNumber)
{
String languageCommand[];
String countryCommand[];
String sdkPath = SdkUtils.getSdkPath();
String GET_LANGUAGE_CMD = "getprop persist.sys.language";
String GET_COUNTRY_CMD = "getprop persist.sys.country";
// The tools folder should exist and be here, but double-cheking
// once more wont kill
File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists())
{
StudioLogger.error("Language: Could not find tools folder on " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
else
{
if (!f.isDirectory())
{
StudioLogger.error("Language: Invalid tools folder " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
}
String langCmdTemp[] =
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, "shell", GET_LANGUAGE_CMD
};
String countryCmdTemp[] =
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, "shell", GET_COUNTRY_CMD
};
languageCommand = langCmdTemp;
countryCommand = countryCmdTemp;
ArrayList<String[]> commands = new ArrayList<String[]>();
commands.add(0, languageCommand);
commands.add(1, countryCommand);
return commands;
}
/**
* Creates a string with the command that should be called in order to
* install the application
*
* @param canOverwrite
* If true, than existent application will be overwritten
* @param path
* Location of the package containing the application
* @param serialNumber
* The serial number of the device to be targeted
*
* @return
*/
private static String[] createInstallCommand(boolean canOverwrite, String path,
String serialNumber)
{
String cmd[];
String sdkPath = SdkUtils.getSdkPath();
// The tools folder should exist and be here, but double-checking
// once more wont kill
File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists())
{
StudioLogger.error("Deploy: Could not find tools folder on " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
else
{
if (!f.isDirectory())
{
StudioLogger.error("Deploy: Invalid tools folder " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
}
if (canOverwrite)
{
// If overwrite option is checked, create command with the -r
// paramater
String cmdTemp[] =
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, INSTALL_CMD, ADB_INSTALL_OVERWRITE, path
};
cmd = cmdTemp;
}
else
{
// If overwrite option is unchecked, create command without the -r
// paramater
String cmdTemp[] =
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, INSTALL_CMD, path
};
cmd = cmdTemp;
}
return cmd;
}
private static String[] createUninstallCommand(String serialNumber, String packageName)
{
String sdkPath = SdkUtils.getSdkPath();
// The tools folder should exist and be here, but double-checking
// once more wont kill
File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists())
{
StudioLogger.error("Run: Could not find tools folder on " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
else
{
if (!f.isDirectory())
{
StudioLogger.error("Run: Invalid tools folder " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
}
String cmd[] =
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, DDMSFacade.SHELL_CMD, PM_CMD, PM_UNINSTALL_DIRECTIVE,
packageName
};
return cmd;
}
/**
* Mount the adb monkey command based on the given parameters.
* @param serialNumber
* @param packagesName
* @param otherCmd
* @return the array of strings containing the monkey command to be executed.
*/
private static String[] createMonkeyCommand(String serialNumber, String packagesName,
String otherCmd)
{
String sdkPath = SdkUtils.getSdkPath();
// The tools folder should exist and be here, but double-checking
// once more wont kill
File f = new File(sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
if (!f.exists())
{
StudioLogger.error("Run: Could not find tools folder on " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
else
{
if (!f.isDirectory())
{
StudioLogger.error("Run: Invalid tools folder " + sdkPath
+ DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator);
}
}
String cmd[] =
{
sdkPath + DDMSFacade.PLATFORM_TOOLS_FOLDER + File.separator
+ DDMSFacade.ADB_COMMAND, DDMSFacade.ADB_INSTANCE_PARAMETER,
serialNumber, DDMSFacade.SHELL_CMD, MONKEY_CMD, packagesName, otherCmd
};
return cmd;
}
/**
* Dump HPROF service implementation
* @param serialNumber The device serial number
* @param monitor
* @return A IStatus describing if the service was successful or not
*/
public static IStatus dumpHPROF(final String serialNumber, IProgressMonitor monitor)
{
IStatus status;
// Selected app. The array should have only 1 element
final String[] selectedAppSet = new String[1];
// Instantiate the wizard and populate it with the retrieved process list
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
{
public void run()
{
DumpHPROFWizard dumpHPROFWizard = new DumpHPROFWizard(serialNumber);
WizardDialog dialog =
new WizardDialog(new Shell(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell()), dumpHPROFWizard);
dialog.open();
// Get the selected application
selectedAppSet[0] = dumpHPROFWizard.getSelectedApp();
}
});
if (selectedAppSet[0] != null)
{
// Dump HPROF file based on the selected application
status = DDMSFacade.dumpHprofFile(selectedAppSet[0], serialNumber, monitor);
}
else
{
status = Status.CANCEL_STATUS;
}
return status;
}
public static int getDeviceApiVersion(String serialNumber)
{
int deviceSdkVersion = -1;
String deviceProperty = DDMSFacade.getDeviceProperty(serialNumber, "ro.build.version.sdk");
if (deviceProperty != null)
{
deviceSdkVersion = Integer.parseInt(deviceProperty);
}
return deviceSdkVersion;
}
public static boolean remoteFileExists(String serialNumber, String remotePath)
throws IOException
{
boolean found = false;
Collection<String> results =
DDMSFacade.execRemoteApp(serialNumber,
"ls " + FileUtil.getEscapedPath(remotePath, Platform.OS_LINUX),
new NullProgressMonitor());
for (String result : results)
{
if (result.equals(remotePath))
{
found = true;
break;
}
}
return found;
}
}