/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.builder.testing;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.builder.testing.api.DeviceConfig;
import com.android.builder.testing.api.DeviceConnector;
import com.android.builder.testing.api.DeviceException;
import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.ShellCommandUnresponsiveException;
import com.android.ddmlib.SyncException;
import com.android.ddmlib.TimeoutException;
import com.android.utils.ILogger;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* Local device connected to with ddmlib. This is a wrapper around {@link IDevice}.
*/
public class ConnectedDevice extends DeviceConnector {
private final IDevice iDevice;
public ConnectedDevice(@NonNull IDevice iDevice) {
this.iDevice = iDevice;
}
@NonNull
@Override
public String getName() {
String version = iDevice.getProperty(IDevice.PROP_BUILD_VERSION);
boolean emulator = iDevice.isEmulator();
String name;
if (emulator) {
name = iDevice.getAvdName() != null ?
iDevice.getAvdName() + "(AVD)" :
iDevice.getSerialNumber();
} else {
String model = iDevice.getProperty(IDevice.PROP_DEVICE_MODEL);
name = model != null ? model : iDevice.getSerialNumber();
}
return version != null ? name + " - " + version : name;
}
@Override
public void connect(int timeout, ILogger logger) throws TimeoutException {
// nothing to do here
}
@Override
public void disconnect(int timeout, ILogger logger) throws TimeoutException {
// nothing to do here
}
@Override
public void installPackage(@NonNull File apkFile,
@NonNull Collection<String> options,
int timeout,
ILogger logger) throws DeviceException {
try {
iDevice.installPackage(apkFile.getAbsolutePath(), true /*reinstall*/,
options.isEmpty() ? null : options.toArray(new String[options.size()]));
} catch (Exception e) {
logger.error(e, "Unable to install " + apkFile.getAbsolutePath());
throw new DeviceException(e);
}
}
@Override
public void installPackages(@NonNull List<File> splitApkFiles,
@NonNull Collection<String> options,
int timeoutInMs,
ILogger logger)
throws DeviceException {
List<String> apkFileNames = Lists.transform(splitApkFiles, new Function<File, String>() {
@Override
public String apply(@Nullable File input) {
return input != null ? input.getAbsolutePath() : null;
}
});
try {
iDevice.installPackages(apkFileNames, timeoutInMs, true /*reinstall*/,
options.isEmpty() ? null : options.toArray(new String[options.size()]));
} catch (Exception e) {
logger.error(e, "Unable to install " + Joiner.on(',').join(apkFileNames));
throw new DeviceException(e);
}
}
@Override
public void uninstallPackage(@NonNull String packageName, int timeout, ILogger logger) throws DeviceException {
try {
iDevice.uninstallPackage(packageName);
} catch (Exception e) {
logger.error(e, "Unable to uninstall " + packageName);
throw new DeviceException(e);
}
}
@Override
public void executeShellCommand(String command, IShellOutputReceiver receiver,
long maxTimeToOutputResponse, TimeUnit maxTimeUnits)
throws TimeoutException, AdbCommandRejectedException,
ShellCommandUnresponsiveException, IOException {
iDevice.executeShellCommand(command, receiver, maxTimeToOutputResponse, maxTimeUnits);
}
@NonNull
@Override
public Future<String> getSystemProperty(@NonNull String name) {
return iDevice.getSystemProperty(name);
}
@Override
public void pullFile(String remote, String local) throws IOException {
try {
iDevice.pullFile(remote, local);
} catch (TimeoutException e) {
throw new IOException(String.format("Failed to pull %s from device", remote), e);
} catch (AdbCommandRejectedException e) {
throw new IOException(String.format("Failed to pull %s from device", remote), e);
} catch (SyncException e) {
throw new IOException(String.format("Failed to pull %s from device", remote), e);
}
}
@NonNull
@Override
public String getSerialNumber() {
return iDevice.getSerialNumber();
}
@Override
public int getApiLevel() {
String sdkVersion = iDevice.getProperty(IDevice.PROP_BUILD_API_LEVEL);
if (sdkVersion != null) {
try {
return Integer.valueOf(sdkVersion);
} catch (NumberFormatException e) {
}
}
// can't get it, return 0.
return 0;
}
@Override
public String getApiCodeName() {
String codeName = iDevice.getProperty(IDevice.PROP_BUILD_CODENAME);
if (codeName != null) {
// if this is a release platform return null.
if ("REL".equals(codeName)) {
return null;
}
// else return the codename
return codeName;
}
// can't get it, return 0.
return null;
}
@Nullable
@Override
public IDevice.DeviceState getState() {
return iDevice.getState();
}
@NonNull
@Override
public List<String> getAbis() {
return iDevice.getAbis();
}
@Override
public int getDensity() {
return iDevice.getDensity();
}
@Override
public int getHeight() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public int getWidth() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public String getLanguage() {
return iDevice.getLanguage();
}
@Override
public String getRegion() {
return iDevice.getRegion();
}
@Override
@NonNull
public String getProperty(@NonNull String propertyName) {
return iDevice.getProperty(propertyName);
}
@NonNull
@Override
public DeviceConfig getDeviceConfig() throws DeviceException {
final List<String> output = new ArrayList<String>();
final MultiLineReceiver receiver = new MultiLineReceiver() {
@Override
public void processNewLines(String[] lines) {
output.addAll(Arrays.asList(lines));
}
@Override
public boolean isCancelled() {
return false;
}
};
try {
executeShellCommand("am get-config", receiver, 5, TimeUnit.SECONDS);
return DeviceConfig.Builder.parse(output);
} catch (Exception e) {
throw new DeviceException(e);
}
}
}