use of com.android.tools.idea.fd.gradle.InstantRunGradleSupport in project android by JetBrains.
the class AndroidRunConfigurationBase method getState.
@Override
public RunProfileState getState(@NotNull final Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
validateBeforeRun(executor);
final Module module = getConfigurationModule().getModule();
assert module != null : "Enforced by fatal validation check in checkConfiguration.";
final AndroidFacet facet = AndroidFacet.getInstance(module);
assert facet != null : "Enforced by fatal validation check in checkConfiguration.";
Project project = env.getProject();
boolean forceColdswap = !InstantRunUtils.isInvokedViaHotswapAction(env);
boolean couldHaveHotswapped = false;
boolean debug = false;
if (executor instanceof DefaultDebugExecutor) {
if (!AndroidSdkUtils.activateDdmsIfNecessary(facet.getModule().getProject())) {
throw new ExecutionException("Unable to obtain debug bridge. Please check if there is a different tool using adb that is active.");
}
debug = true;
}
DeviceFutures deviceFutures = null;
AndroidSessionInfo info = AndroidSessionInfo.findOldSession(project, null, getUniqueID());
if (info != null && supportsInstantRun()) {
// if there is an existing previous session, then see if we can detect devices to fast deploy to
deviceFutures = getFastDeployDevices(executor, facet, info);
// that the ReRun is now a global action and doesn't really know much details about each run (and doing that seems like a hack too.)
if (InstantRunUtils.isReRun(env)) {
killSession(info);
info = null;
}
}
if (info != null && deviceFutures == null) {
// If we should not be fast deploying, but there is an existing session, then terminate those sessions. Otherwise, we might end up
// with 2 active sessions of the same launch, especially if we first think we can do a fast deploy, then end up doing a full launch
boolean continueLaunch = promptAndKillSession(executor, project, info);
if (!continueLaunch) {
return null;
}
} else if (info != null && forceColdswap) {
// the user could have invoked the hotswap action in this scenario, but they chose to force a coldswap (by pressing run)
couldHaveHotswapped = true;
// forcibly kill app in case of run action (which forces a cold swap)
// normally, installing the apk will force kill the app, but we need to forcibly kill it in the case that there were no changes
killSession(info);
}
// If we are not fast deploying, then figure out (prompting user if needed) where to deploy
if (deviceFutures == null) {
DeployTarget deployTarget = getDeployTarget(executor, env, debug, facet);
if (deployTarget == null) {
return null;
}
DeployTargetState deployTargetState = getDeployTargetContext().getCurrentDeployTargetState();
if (deployTarget.hasCustomRunProfileState(executor)) {
return deployTarget.getRunProfileState(executor, env, deployTargetState);
}
deviceFutures = deployTarget.getDevices(deployTargetState, facet, getDeviceCount(debug), debug, getUniqueID());
if (deviceFutures == null) {
// The user deliberately canceled, or some error was encountered and exposed by the chooser. Quietly exit.
return null;
}
}
if (deviceFutures.get().isEmpty()) {
throw new ExecutionException(AndroidBundle.message("deployment.target.not.found"));
}
ApplicationIdProvider applicationIdProvider = getApplicationIdProvider(facet);
InstantRunContext instantRunContext = null;
if (supportsInstantRun() && InstantRunSettings.isInstantRunEnabled()) {
InstantRunGradleSupport gradleSupport = canInstantRun(module, deviceFutures.getDevices());
if (gradleSupport == TARGET_PLATFORM_NOT_INSTALLED) {
AndroidVersion version = deviceFutures.getDevices().get(0).getVersion();
String message = AndroidBundle.message("instant.run.quickfix.missing.platform", SdkVersionInfo.getVersionWithCodename(version));
int result = Messages.showYesNoDialog(project, message, "Instant Run", // yes button
"Install and Continue", // no button
"Proceed without Instant Run", Messages.getQuestionIcon());
if (result == Messages.OK) {
// if ok, install platform and continue with instant run
ModelWizardDialog dialog = SdkQuickfixUtils.createDialogForPaths(project, ImmutableList.of(DetailsTypes.getPlatformPath(version)));
if (dialog == null) {
LOG.warn("Unable to get quick fix wizard to install missing platform required for instant run.");
} else if (dialog.showAndGet()) {
gradleSupport = SUPPORTED;
}
}
}
if (gradleSupport == SUPPORTED) {
if (!AndroidEnableAdbServiceAction.isAdbServiceEnabled()) {
throw new ExecutionException("Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled.");
}
InstantRunUtils.setInstantRunEnabled(env, true);
instantRunContext = InstantRunGradleUtils.createGradleProjectContext(facet);
} else {
InstantRunManager.LOG.warn("Instant Run enabled, but not doing an instant run build since: " + gradleSupport);
String notificationText = gradleSupport.getUserNotification();
if (notificationText != null) {
InstantRunNotificationTask.showNotification(env.getProject(), null, notificationText);
}
}
} else {
String msg = "Not using instant run for this launch: ";
if (InstantRunSettings.isInstantRunEnabled()) {
msg += getType().getDisplayName() + " does not support instant run";
} else {
msg += "instant run is disabled";
}
InstantRunManager.LOG.info(msg);
}
// Store the chosen target on the execution environment so before-run tasks can access it.
AndroidRunConfigContext runConfigContext = new AndroidRunConfigContext();
env.putCopyableUserData(AndroidRunConfigContext.KEY, runConfigContext);
runConfigContext.setTargetDevices(deviceFutures);
runConfigContext.setSameExecutorAsPreviousSession(info != null && executor.getId().equals(info.getExecutorId()));
runConfigContext.setCleanRerun(InstantRunUtils.isCleanReRun(env));
runConfigContext.setForceColdSwap(forceColdswap, couldHaveHotswapped);
// Save the instant run context so that before-run task can access it
env.putCopyableUserData(InstantRunContext.KEY, instantRunContext);
if (debug) {
String error = canDebug(deviceFutures, facet, module.getName());
if (error != null) {
throw new ExecutionException(error);
}
}
LaunchOptions launchOptions = getLaunchOptions().setDebug(debug).build();
ProcessHandler processHandler = null;
if (info != null && info.getExecutorId().equals(executor.getId())) {
processHandler = info.getProcessHandler();
}
ApkProvider apkProvider = getApkProvider(facet, applicationIdProvider);
LaunchTasksProviderFactory providerFactory = new AndroidLaunchTasksProviderFactory(this, env, facet, applicationIdProvider, apkProvider, deviceFutures, launchOptions, processHandler, instantRunContext);
InstantRunStatsService.get(project).notifyBuildStarted();
return new AndroidRunState(env, getName(), module, applicationIdProvider, getConsoleProvider(), deviceFutures, providerFactory, processHandler);
}
use of com.android.tools.idea.fd.gradle.InstantRunGradleSupport in project android by JetBrains.
the class AndroidRunConfigurationBase method getFastDeployDevices.
@Nullable
private static DeviceFutures getFastDeployDevices(@NotNull Executor executor, @NotNull AndroidFacet facet, @NotNull AndroidSessionInfo info) {
if (!InstantRunSettings.isInstantRunEnabled()) {
InstantRunManager.LOG.info("Instant run not enabled in settings");
return null;
}
if (!info.getExecutorId().equals(executor.getId())) {
String msg = String.format("Cannot Instant Run since old executor (%1$s) doesn't match current executor (%2$s)", info.getExecutorId(), executor.getId());
InstantRunManager.LOG.info(msg);
return null;
}
List<IDevice> devices = info.getDevices();
if (devices == null || devices.isEmpty()) {
InstantRunManager.LOG.info("Cannot Instant Run since we could not locate the devices from the existing launch session");
return null;
}
if (devices.size() > 1) {
InstantRunManager.LOG.info("Last run was on > 1 device, not reusing devices and prompting again");
return null;
}
AndroidModuleModel model = AndroidModuleModel.get(facet);
AndroidVersion version = devices.get(0).getVersion();
InstantRunGradleSupport status = InstantRunGradleUtils.getIrSupportStatus(model, version);
if (status != SUPPORTED) {
InstantRunManager.LOG.info("Cannot Instant Run: " + status);
return null;
}
return DeviceFutures.forDevices(devices);
}
use of com.android.tools.idea.fd.gradle.InstantRunGradleSupport in project android by JetBrains.
the class HotswapAction method doUpdate.
@Override
protected void doUpdate(@NotNull AnActionEvent e, @NotNull Project project) {
Presentation presentation = e.getPresentation();
presentation.setEnabled(false);
if (!InstantRunSettings.isInstantRunEnabled()) {
presentation.setText("Apply Changes: Instant Run has been disabled");
return;
}
RunnerAndConfigurationSettings settings = RunManager.getInstance(project).getSelectedConfiguration();
if (settings == null) {
presentation.setText("Apply Changes: No run configuration selected");
return;
}
AndroidSessionInfo session = getAndroidSessionInfo(project, settings);
if (session == null) {
presentation.setText(String.format("Apply Changes: No active '%1$s' launch", settings.getName()));
return;
}
ProcessHandler processHandler = getActiveProcessHandler(project, settings);
if (processHandler == null) {
presentation.setText(String.format("Apply Changes: No active '%1$s' launch", settings.getName()));
return;
}
RunConfiguration configuration = settings.getConfiguration();
if (!(configuration instanceof ModuleBasedConfiguration)) {
presentation.setText(String.format("Apply Changes: '%1$s' is not a module based configuration", settings.getName()));
return;
}
Module module = ((ModuleBasedConfiguration) configuration).getConfigurationModule().getModule();
if (module == null) {
presentation.setText(String.format("Apply Changes: No module specified in '%1$s'", settings.getName()));
return;
}
if (!(configuration instanceof AndroidRunConfigurationBase)) {
presentation.setText(String.format("Apply Changes: '%1$s' is not an Android launch configuration", settings.getName()));
return;
}
if (!((AndroidRunConfigurationBase) configuration).supportsInstantRun()) {
presentation.setText(String.format("Apply Changes: Configuration '%1$s' does not support instant run", settings.getName()));
return;
}
AndroidVersion androidVersion = InstantRunManager.getMinDeviceApiLevel(processHandler);
if (androidVersion == null) {
presentation.setText(String.format("Apply Changes: Cannot locate device from '%1$s'", settings.getName()));
return;
}
if (!InstantRunManager.isInstantRunCapableDeviceVersion(androidVersion)) {
presentation.setText(String.format("Apply Changes: Target device API level (%1$s) too low for Instant Run", androidVersion));
return;
}
InstantRunGradleSupport status = InstantRunGradleUtils.getIrSupportStatus(InstantRunGradleUtils.getAppModel(module), androidVersion);
if (status != SUPPORTED) {
String notification = status.getUserNotification();
if (notification == null) {
notification = status.toString();
}
presentation.setText("Apply Changes: " + notification);
return;
}
presentation.setText("Apply Changes" + getShortcutText());
presentation.setEnabled(true);
}
use of com.android.tools.idea.fd.gradle.InstantRunGradleSupport in project android by JetBrains.
the class AndroidRunConfigurationBase method canInstantRun.
@NotNull
private InstantRunGradleSupport canInstantRun(@NotNull Module module, @NotNull List<AndroidDevice> targetDevices) {
if (targetDevices.size() != 1) {
return CANNOT_BUILD_FOR_MULTIPLE_DEVICES;
}
AndroidDevice device = targetDevices.get(0);
AndroidVersion version = device.getVersion();
if (!InstantRunManager.isInstantRunCapableDeviceVersion(version)) {
return API_TOO_LOW_FOR_INSTANT_RUN;
}
IDevice targetDevice = MakeBeforeRunTaskProvider.getLaunchedDevice(device);
if (targetDevice != null) {
if (MultiUserUtils.hasMultipleUsers(targetDevice, 200, TimeUnit.MILLISECONDS, false)) {
if (// run config explicitly specifies launching as a different user
getUserIdFromAmParameters() != MultiUserUtils.PRIMARY_USERID || !MultiUserUtils.isCurrentUserThePrimaryUser(targetDevice, 200, TimeUnit.MILLISECONDS, true)) {
// activity manager says current user is not primary
return CANNOT_DEPLOY_FOR_SECONDARY_USER;
}
}
}
InstantRunGradleSupport irSupportStatus = InstantRunGradleUtils.getIrSupportStatus(InstantRunGradleUtils.getAppModel(module), version);
if (irSupportStatus != SUPPORTED) {
return irSupportStatus;
}
// Gradle will instrument against the runtime android.jar (see commit 353f46cbc7363e3fca44c53a6dc0b4d17347a6ac).
// This means that the SDK platform corresponding to the device needs to be installed, otherwise the build will fail.
// We do this as the last check because it is actually possible to recover from this failure. In the future, maybe issues
// that have fixes will have to be handled in a more generic way.
AndroidPlatform platform = AndroidPlatform.getInstance(module);
if (platform == null) {
return SUPPORTED;
}
IAndroidTarget[] targets = platform.getSdkData().getTargets();
for (int i = targets.length - 1; i >= 0; i--) {
if (!targets[i].isPlatform()) {
continue;
}
if (targets[i].getVersion().equals(version)) {
return SUPPORTED;
}
}
return TARGET_PLATFORM_NOT_INSTALLED;
}
Aggregations