com.android.tools.idea.fd.gradle.InstantRunGradleUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.android.tools.idea.fd.gradle.InstantRunGradleUtils.java

Source

/*
 * 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.android.tools.idea.fd.gradle;

import com.android.annotations.NonNull;
import com.android.builder.model.*;
import com.android.ide.common.repository.GradleVersion;
import com.android.sdklib.AndroidVersion;
import com.android.tools.fd.client.InstantRunBuildInfo;
import com.android.tools.idea.fd.InstantRunContext;
import com.android.tools.idea.fd.InstantRunManager;
import com.android.tools.idea.gradle.project.model.AndroidModuleModel;
import com.android.tools.idea.gradle.run.GradleInstantRunContext;
import com.android.tools.idea.run.ApkProviderUtil;
import com.android.tools.idea.run.ApkProvisionException;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;

public class InstantRunGradleUtils {
    @NotNull
    public static InstantRunGradleSupport getIrSupportStatus(@Nullable AndroidModuleModel model,
            @Nullable AndroidVersion deviceVersion) {
        if (model == null) {
            return InstantRunGradleSupport.NO_GRADLE_MODEL;
        }

        try {
            InstantRunGradleSupport modelStatus = InstantRunGradleSupport.fromModel(model);
            if (modelStatus != InstantRunGradleSupport.SUPPORTED) {
                return modelStatus;
            }
        } catch (UnsupportedOperationException e) {
            // If we failed to get details about why IR is not supported, then it is possible we are using an older version of the model
            if (!modelSupportsInstantRun(model)) {
                return InstantRunGradleSupport.GRADLE_PLUGIN_TOO_OLD;
            }

            // If model is high enough that it supports instant run, then check whether the variant supports it as well..
            if (!variantSupportsInstantRun(model)) {
                return InstantRunGradleSupport.VARIANT_DOES_NOT_SUPPORT_INSTANT_RUN;
            }
        }

        if (deviceVersion == null) {
            return InstantRunGradleSupport.SUPPORTED;
        }

        Variant variant = model.getSelectedVariant();
        BuildTypeContainer buildTypeContainer = model.findBuildType(model.getSelectedVariant().getBuildType());
        assert buildTypeContainer != null;
        BuildType buildType = buildTypeContainer.getBuildType();
        ProductFlavor mergedFlavor = variant.getMergedFlavor();

        if (isLegacyMultiDex(buildType, mergedFlavor)) {
            // We don't support legacy multi-dex on Dalvik.
            if (!deviceVersion.isGreaterOrEqualThan(AndroidVersion.ART_RUNTIME.getApiLevel())) {
                return InstantRunGradleSupport.LEGACY_MULTIDEX_REQUIRES_ART;
            }
        }

        return InstantRunGradleSupport.SUPPORTED;
    }

    // TODO: Move this logic to Variant, so we don't have to duplicate it in AS.
    private static boolean isLegacyMultiDex(@NotNull BuildType buildType, @NotNull ProductFlavor mergedFlavor) {
        if (buildType.getMultiDexEnabled() != null) {
            return buildType.getMultiDexEnabled();
        }
        if (mergedFlavor.getMultiDexEnabled() != null) {
            return mergedFlavor.getMultiDexEnabled();
        }
        return false;
    }

    public static boolean variantSupportsInstantRun(@NotNull AndroidModuleModel model) {
        try {
            return model.getSelectedVariant().getMainArtifact().getInstantRun().isSupportedByArtifact();
        } catch (Throwable e) {
            return false;
        }
    }

    /** Returns true if Instant Run is supported for this gradle model (whether or not it's enabled) */
    public static boolean modelSupportsInstantRun(@NotNull AndroidModuleModel model) {
        GradleVersion modelVersion = model.getModelVersion();
        return modelVersion == null || modelVersion.compareTo(InstantRunManager.MINIMUM_GRADLE_PLUGIN_VERSION) >= 0;
    }

    @Nullable
    public static AndroidModuleModel getAppModel(@NotNull Module module) {
        AndroidFacet facet = findAppModule(module, module.getProject());
        if (facet == null) {
            return null;
        }

        return AndroidModuleModel.get(facet);
    }

    @Nullable
    public static AndroidFacet findAppModule(@Nullable Module module, @NotNull Project project) {
        if (module != null) {
            assert module.getProject() == project;
            AndroidFacet facet = AndroidFacet.getInstance(module);
            if (facet != null && facet.isAppProject()) {
                return facet;
            }
        }

        // TODO: Here we should really look for app modules that *depend*
        // on the given module (if non null), not just use the first app
        // module we find.

        for (Module m : ModuleManager.getInstance(project).getModules()) {
            AndroidFacet facet = AndroidFacet.getInstance(m);
            if (facet != null && facet.isAppProject()) {
                return facet;
            }
        }
        return null;
    }

    @Nullable
    public static InstantRunBuildInfo getBuildInfo(@NonNull AndroidModuleModel model) {
        File buildInfo = getLocalBuildInfoFile(model);
        if (!buildInfo.exists()) {
            return null;
        }

        String xml;
        try {
            xml = Files.toString(buildInfo, Charsets.UTF_8);
        } catch (IOException e) {
            return null;
        }

        return InstantRunBuildInfo.get(xml);
    }

    @NotNull
    private static File getLocalBuildInfoFile(@NotNull AndroidModuleModel model) {
        InstantRun instantRun = model.getSelectedVariant().getMainArtifact().getInstantRun();
        return instantRun.getInfoFile();
    }

    @Nullable
    public static InstantRunContext createGradleProjectContext(@NotNull Module module) {
        AndroidFacet appFacet = findAppModule(module, module.getProject());
        if (appFacet == null) {
            return null;
        }

        return createGradleProjectContext(appFacet);
    }

    @Nullable
    public static InstantRunContext createGradleProjectContext(@NotNull AndroidFacet facet) {
        try {
            String pkgName = ApkProviderUtil.computePackageName(facet);
            return new GradleInstantRunContext(pkgName, facet);
        } catch (ApkProvisionException e) {
            return null;
        }
    }
}