blob: b40fcb72e76eea5f728f38b882ac5c8694af9546 [file] [log] [blame]
/*
* Copyright (C) 2013 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.startup;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilCore;
import org.intellij.lang.annotations.MagicConstant;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Helper code for attaching the external annotations .jar file
* to the user's Android SDK platforms, if necessary
*/
@SuppressWarnings("SpellCheckingInspection") // "Modificator" in API usage
public class ExternalAnnotationsSupport {
private static final Logger LOG = Logger.getInstance(ExternalAnnotationsSupport.class);
private static final String[] DEVELOPMENT_ANNOTATIONS_PATHS = {
"/../adt/idea/android/annotations",
"/android/android/annotations",
"/community/android/android/annotations"
};
// Based on similar code in MagicConstantInspection
@SuppressWarnings("ALL")
private static void checkAnnotationsJarAttached(@NotNull PsiFile file, @NotNull ProblemsHolder holder) {
// Not yet used
if (false) {
final Project project = file.getProject();
PsiClass actionBar = JavaPsiFacade.getInstance(project).findClass("android.app.ActionBar", GlobalSearchScope.allScope(project));
if (actionBar == null) {
return; // no sdk to attach
}
PsiMethod[] methods = actionBar.findMethodsByName("getNavigationMode", false);
if (methods.length != 1) {
return; // no sdk to attach
}
PsiMethod getModifiers = methods[0];
ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project);
PsiAnnotation annotation = annotationsManager.findExternalAnnotation(getModifiers, MagicConstant.class.getName());
if (annotation != null) {
return;
}
final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(getModifiers);
if (virtualFile == null) {
return; // no sdk to attach
}
final List<OrderEntry> entries = ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(virtualFile);
Sdk sdk = null;
for (OrderEntry orderEntry : entries) {
if (orderEntry instanceof JdkOrderEntry) {
sdk = ((JdkOrderEntry)orderEntry).getJdk();
if (sdk != null) {
break;
}
}
}
if (sdk == null) {
return; // no sdk to attach
}
final Sdk finalSdk = sdk;
String path = finalSdk.getHomePath();
String text = "No IDEA annotations attached to the Android SDK " + finalSdk.getName() + (path == null ? "" : " (" +
FileUtil.toSystemDependentName(path) + ")") + ", some issues will not be found";
holder.registerProblem(file, text, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new LocalQuickFix() {
@NotNull
@Override
public String getName() {
return "Attach annotations";
}
@NotNull
@Override
public String getFamilyName() {
return getName();
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
SdkModificator modifier = finalSdk.getSdkModificator();
attachJdkAnnotations(modifier);
modifier.commitChanges();
}
});
}
});
}
}
// Based on similar code in JavaSdkImpl
public static void attachJdkAnnotations(@NotNull SdkModificator modificator) {
String homePath = FileUtil.toSystemIndependentName(PathManager.getHomePath());
VirtualFileManager fileManager = VirtualFileManager.getInstance();
// release build?
String releaseLocation = homePath + "/plugins/android/lib/androidAnnotations.jar";
VirtualFile root = fileManager.findFileByUrl("jar://" + releaseLocation + "!/");
for (String relativePath : DEVELOPMENT_ANNOTATIONS_PATHS) {
if (root != null) break;
String developmentLocation = homePath + relativePath;
root = LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(developmentLocation));
}
if (root == null) {
// error message tailored for release build file layout
LOG.error("jdk annotations not found in: " + releaseLocation);
return;
}
OrderRootType annoType = AnnotationOrderRootType.getInstance();
modificator.removeRoot(root, annoType);
modificator.addRoot(root, annoType);
}
public static void addAnnotations(@NotNull Sdk sdk) {
SdkModificator modifier = sdk.getSdkModificator();
attachJdkAnnotations(modifier);
modifier.commitChanges();
}
public static void addAnnotationsIfNecessary(@NotNull Sdk sdk) {
// Attempt to insert SDK annotations
VirtualFile[] roots = sdk.getRootProvider().getFiles(AnnotationOrderRootType.getInstance());
if (roots.length > 0) {
return;
}
SdkModificator modifier = sdk.getSdkModificator();
attachJdkAnnotations(modifier);
modifier.commitChanges();
}
}