blob: 8a2086e4e298577ed87992a6fca17f844fbc633d [file] [log] [blame]
/*
* Copyright (C) 2014 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.build.gradle.internal.tasks
import com.android.build.gradle.internal.LoggerWrapper
import com.android.build.gradle.internal.TaskManager
import com.android.build.gradle.internal.scope.ConventionMappingHelper
import com.android.build.gradle.internal.scope.TaskConfigAction
import com.android.build.gradle.internal.scope.VariantScope
import com.android.build.gradle.internal.variant.ApkVariantData
import com.android.build.gradle.internal.variant.BaseVariantData
import com.android.build.gradle.internal.variant.BaseVariantOutputData
import com.android.builder.core.VariantConfiguration
import com.android.builder.internal.InstallUtils
import com.android.builder.sdk.SdkInfo
import com.android.builder.sdk.TargetInfo
import com.android.builder.testing.ConnectedDeviceProvider
import com.android.builder.testing.api.DeviceConfigProviderImpl
import com.android.builder.testing.api.DeviceConnector
import com.android.builder.testing.api.DeviceProvider
import com.android.ide.common.build.SplitOutputMatcher
import com.android.ide.common.process.ProcessExecutor
import com.android.utils.ILogger
import com.google.common.base.Joiner
import com.google.common.collect.ImmutableList
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
import java.util.concurrent.Callable
import static com.android.sdklib.BuildToolInfo.PathId.SPLIT_SELECT
/**
* Task installing an app variant. It looks at connected device and install the best matching
* variant output on each device.
*/
public class InstallVariantTask extends BaseTask {
@InputFile
File adbExe
@InputFile
@Optional
File splitSelectExe
ProcessExecutor processExecutor;
String projectName
@Input
int timeOutInMs = 0
@Input @Optional
Collection<String> installOptions;
BaseVariantData<? extends BaseVariantOutputData> variantData
InstallVariantTask() {
this.getOutputs().upToDateWhen {
logger.debug("Install task is always run.");
false;
}
}
@TaskAction
void install() {
final ILogger iLogger = new LoggerWrapper(getLogger(), LogLevel.LIFECYCLE)
DeviceProvider deviceProvider = new ConnectedDeviceProvider(getAdbExe(), iLogger)
deviceProvider.init()
VariantConfiguration variantConfig = variantData.variantConfiguration
String variantName = variantConfig.fullName
int successfulInstallCount = 0;
for (DeviceConnector device : deviceProvider.getDevices()) {
if (InstallUtils.checkDeviceApiLevel(
device, variantConfig.minSdkVersion, iLogger, projectName, variantName)) {
// When InstallUtils.checkDeviceApiLevel returns false, it logs the reason.
List<File> apkFiles = SplitOutputMatcher.computeBestOutput(processExecutor,
getSplitSelectExe(),
new DeviceConfigProviderImpl(device),
variantData.outputs,
variantData.variantConfiguration.getSupportedAbis())
if (apkFiles.isEmpty()) {
logger.lifecycle(
"Skipping device '${device.getName()}' for " +
"'${projectName}:${variantName}': " +
"Could not find build of variant which supports " +
"density " + "${device.getDensity()} " +
"and an ABI in " + Joiner.on(", ").join(device.getAbis()));
} else {
logger.lifecycle(
"Installing APK '${Joiner.on(", ").join(apkFiles*.getName())}'" +
" on '${device.getName()}'")
List<String> extraArgs = installOptions == null ? ImmutableList.of() :
installOptions;
if (apkFiles.size() > 1 || device.getApiLevel() >= 21) {
device.installPackages(apkFiles, extraArgs, getTimeOutInMs(), getILogger());
successfulInstallCount++
} else {
device.installPackage(apkFiles.get(0), extraArgs, getTimeOutInMs(),
getILogger())
successfulInstallCount++
}
}
}
}
if (successfulInstallCount == 0) {
throw new GradleException("Failed to install on any devices.")
} else {
logger.quiet("Installed on ${successfulInstallCount} " +
"${successfulInstallCount==1?'device':'devicess'}.");
}
}
public static class ConfigAction implements TaskConfigAction<InstallVariantTask> {
private final VariantScope scope;
public ConfigAction(VariantScope scope) {
this.scope = scope;
}
@Override
String getName() {
return "install${scope.getVariantConfiguration().fullName.capitalize()}";
}
@Override
Class<InstallVariantTask> getType() {
return InstallVariantTask.class
}
@Override
public void execute(InstallVariantTask installTask) {
installTask.setDescription("Installs the " + scope.getVariantData().getDescription() + ".");
installTask.setGroup(TaskManager.INSTALL_GROUP);
installTask.setProjectName(scope.getGlobalScope().getProject().getName());
installTask.setVariantData(scope.getVariantData());
installTask.setTimeOutInMs(scope.getGlobalScope().getExtension().getAdbOptions().getTimeOutInMs());
installTask.setInstallOptions(scope.getGlobalScope().getExtension().getAdbOptions().getInstallOptions());
installTask.setProcessExecutor(scope.getGlobalScope().getAndroidBuilder().getProcessExecutor());
ConventionMappingHelper.map(installTask, "adbExe", new Closure<File>(this, this) {
public File doCall(Object it) {
final SdkInfo info = scope.getGlobalScope().getSdkHandler().getSdkInfo();
return (info == null ? null : info.getAdb());
}
public File doCall() {
return doCall(null);
}
});
ConventionMappingHelper.map(installTask, "splitSelectExe", new Callable<File>() {
@Override
public File call() throws Exception {
final TargetInfo info = scope.getGlobalScope().getAndroidBuilder().getTargetInfo();
String path = info == null ? null : info.getBuildTools().getPath(SPLIT_SELECT);
if (path != null) {
File splitSelectExe = new File(path);
return splitSelectExe.exists() ? splitSelectExe : null;
} else {
return null;
}
}
});
((ApkVariantData) scope.getVariantData()).installTask = installTask;
}
}
}