com.android.tools.idea.welcome.install.CheckSdkOperation.java Source code

Java tutorial

Introduction

Here is the source code for com.android.tools.idea.welcome.install.CheckSdkOperation.java

Source

/*
 * Copyright (C) 2015 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.tools.idea.welcome.install;

import com.android.SdkConstants;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.CapturingAnsiEscapesAwareProcessHandler;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.List;

/**
 * <p>Checks SDK install to ensure install may proceed.</p>
 * <p/>
 * <p>This is done by trying to run the mksdcard executable from the SDK emulator directory (falling back to the older tools directory).
 * This ensures that the tools are installed and that necessary shared libraries are present.</p>
 */
public class CheckSdkOperation extends InstallOperation<File, File> {
    public static final String ERROR_CANT_EXECUTE = "%1$s file is not a valid executable";
    public static final String ERROR_NO_TOOLS_DIR = "SDK tools directory is missing";
    public static final String MESSAGE_CANT_RUN_TOOL;
    public static final String ERROR_CANT_RUN_TOOL;
    public static final String URL_MISSING_LIBRARIES = "https://developer.android.com/studio/troubleshoot.html#linux-libraries";
    public static final String LINK_MISSING_LIBRARIES = "Show Android SDK web page";
    public static final String TOOL_NAME = "mksdcard" + (SystemInfo.isWindows ? ".exe" : "");

    static {
        ERROR_CANT_RUN_TOOL = "Unable to run " + TOOL_NAME + " SDK tool.";
        MESSAGE_CANT_RUN_TOOL = "<html><p>" + Joiner.on("</p><p>").join(getUnableToRunMessage()) + "</p></html>";
    }

    public CheckSdkOperation(InstallContext context) {
        super(context, 0);
    }

    private static Iterable<?> getUnableToRunMessage() {
        boolean isLinux64 = SystemInfo.isLinux && SystemInfo.is64Bit;

        String likelyReason = isLinux64 ? "One common reason for this is missing 32 bit compatibility libraries."
                : "One common reason for this failure is missing required libraries";

        String message = "Unable to run <strong>" + TOOL_NAME + "</strong> SDK tool.";

        List<String> lines = Lists.newArrayList(message, likelyReason,
                "Please fix the underlying issue and retry.");
        if (isLinux64) {
            String docHyperlink = "<a href=\"" + URL_MISSING_LIBRARIES + "\">" + LINK_MISSING_LIBRARIES + "</a>";
            lines.add(docHyperlink);
        }
        return lines;
    }

    private static boolean checkCanRunSdkTool(File executable) throws ExecutionException {
        GeneralCommandLine commandLine = new GeneralCommandLine(executable.getAbsolutePath());
        CapturingAnsiEscapesAwareProcessHandler handler = new CapturingAnsiEscapesAwareProcessHandler(commandLine);
        final int exitCode = handler.runProcess().getExitCode();
        return exitCode == 1; // 1 means help was printed
    }

    private static boolean checkExecutePermission(@NotNull File executable) {
        if (executable.canExecute()) {
            return true;
        } else {
            return SystemInfo.isUnix && executable.setExecutable(true);
        }
    }

    private static boolean retryPrompt() {
        int button = Messages.showOkCancelDialog(MESSAGE_CANT_RUN_TOOL, "Android Studio", "Retry", "Cancel",
                Messages.getErrorIcon());
        return button == Messages.OK;
    }

    private static boolean checkRuns(File executable) {
        try {
            while (!checkCanRunSdkTool(executable)) {
                final boolean[] shouldRetry = { false };
                UIUtil.invokeAndWaitIfNeeded(new Runnable() {
                    @Override
                    public void run() {
                        shouldRetry[0] = retryPrompt();
                    }
                });
                if (!shouldRetry[0]) {
                    return false;
                }
            }
        } catch (ExecutionException e) {
            return false;
        }
        return true;
    }

    @NotNull
    @Override
    protected File perform(@NotNull ProgressIndicator indicator, @NotNull File file)
            throws WizardException, InstallationCancelledException {
        File tool = new File(file, SdkConstants.FD_EMULATOR + File.separator + TOOL_NAME);
        if (!tool.isFile()) {
            tool = new File(file, SdkConstants.FD_TOOLS + File.separator + TOOL_NAME);
        }
        if (!tool.isFile()) {
            throw new WizardException(ERROR_NO_TOOLS_DIR);
        }
        if (!checkExecutePermission(tool)) {
            throw new WizardException(String.format(ERROR_CANT_EXECUTE, tool.getAbsoluteFile()));
        }
        if (!checkRuns(tool)) {
            throw new WizardException(ERROR_CANT_RUN_TOOL);
        }
        return file;
    }

    @Override
    public void cleanup(@NotNull File result) {
        // Nothing to do
    }
}