| /* |
| * Copyright (C) 2016 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.google.idea.blaze.android.run.runner; |
| |
| import static org.jetbrains.android.actions.RunAndroidAvdManagerAction.getName; |
| |
| import com.android.tools.idea.run.AndroidSessionInfo; |
| import com.android.tools.idea.run.DeviceFutures; |
| import com.android.tools.idea.run.editor.DeployTarget; |
| import com.android.tools.idea.run.editor.DeployTargetState; |
| import com.intellij.execution.ExecutionException; |
| import com.intellij.execution.Executor; |
| import com.intellij.execution.runners.ExecutionEnvironment; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.DialogWrapper; |
| import com.intellij.openapi.ui.Messages; |
| import javax.annotation.Nullable; |
| import org.jetbrains.android.facet.AndroidFacet; |
| |
| /** Selects a device. */ |
| public interface BlazeAndroidDeviceSelector { |
| |
| /** A device session */ |
| class DeviceSession { |
| @Nullable public final DeployTarget deployTarget; |
| @Nullable public final DeviceFutures deviceFutures; |
| @Nullable public final AndroidSessionInfo sessionInfo; |
| |
| public DeviceSession( |
| @Nullable DeployTarget deployTarget, |
| @Nullable DeviceFutures deviceFutures, |
| @Nullable AndroidSessionInfo sessionInfo) { |
| this.deployTarget = deployTarget; |
| this.deviceFutures = deviceFutures; |
| this.sessionInfo = sessionInfo; |
| } |
| } |
| |
| DeviceSession getDevice( |
| Project project, |
| AndroidFacet facet, |
| BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager, |
| Executor executor, |
| ExecutionEnvironment env, |
| AndroidSessionInfo info, |
| boolean debug, |
| int runConfigId) |
| throws ExecutionException; |
| |
| /** Standard device selector */ |
| class NormalDeviceSelector implements BlazeAndroidDeviceSelector { |
| |
| private static final DialogWrapper.DoNotAskOption ourKillLaunchOption = |
| new KillLaunchDialogOption(); |
| private static final Logger LOG = Logger.getInstance(NormalDeviceSelector.class); |
| |
| static class KillLaunchDialogOption implements DialogWrapper.DoNotAskOption { |
| private boolean show; |
| |
| @Override |
| public boolean isToBeShown() { |
| return !show; |
| } |
| |
| @Override |
| public void setToBeShown(boolean toBeShown, int exitCode) { |
| show = !toBeShown; |
| } |
| |
| @Override |
| public boolean canBeHidden() { |
| return true; |
| } |
| |
| @Override |
| public boolean shouldSaveOptionsOnCancel() { |
| return true; |
| } |
| |
| @Override |
| public String getDoNotShowMessage() { |
| return "Do not ask again"; |
| } |
| } |
| |
| @Override |
| public DeviceSession getDevice( |
| Project project, |
| AndroidFacet facet, |
| BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager, |
| Executor executor, |
| ExecutionEnvironment env, |
| AndroidSessionInfo info, |
| boolean debug, |
| int runConfigId) |
| throws ExecutionException { |
| // If there is an existing session, then terminate those sessions |
| if (info != null) { |
| boolean continueLaunch = promptAndKillSession(executor, project, info); |
| if (!continueLaunch) { |
| return null; |
| } |
| } |
| |
| DeployTarget deployTarget = |
| deployTargetManager.getDeployTarget(executor, env, facet, runConfigId); |
| if (deployTarget == null) { |
| return null; |
| } |
| |
| DeviceFutures deviceFutures = null; |
| DeployTargetState deployTargetState = deployTargetManager.getCurrentDeployTargetState(); |
| if (!deployTarget.hasCustomRunProfileState(executor)) { |
| deviceFutures = |
| deployTarget.getDevices( |
| deployTargetState, facet, deployTargetManager.getDeviceCount(), debug, runConfigId); |
| } |
| return new DeviceSession(deployTarget, deviceFutures, info); |
| } |
| |
| private boolean promptAndKillSession( |
| Executor executor, Project project, AndroidSessionInfo info) { |
| String previousExecutor = info.getExecutorId(); |
| String currentExecutor = executor.getId(); |
| |
| if (ourKillLaunchOption.isToBeShown()) { |
| String msg; |
| String noText; |
| if (previousExecutor.equals(currentExecutor)) { |
| msg = |
| String.format( |
| "Restart App?\nThe app is already running. " |
| + "Would you like to kill it and restart the session?"); |
| noText = "Cancel"; |
| } else { |
| msg = |
| String.format( |
| "To switch from %1$s to %2$s, the app has to restart. Continue?", |
| previousExecutor, currentExecutor); |
| noText = "Cancel " + currentExecutor; |
| } |
| |
| String title = "Launching " + getName(); |
| String yesText = "Restart " + getName(); |
| if (Messages.NO |
| == Messages.showYesNoDialog( |
| project, |
| msg, |
| title, |
| yesText, |
| noText, |
| AllIcons.General.QuestionDialog, |
| ourKillLaunchOption)) { |
| return false; |
| } |
| } |
| |
| LOG.info("Disconnecting existing session of the same launch configuration"); |
| info.getProcessHandler().detachProcess(); |
| return true; |
| } |
| } |
| } |