Merge "Don't suggest making activities/fragments private"
diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java
index 3e9044e..856285a 100644
--- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java
+++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java
@@ -62,6 +62,9 @@
 
   boolean isTestCase();
 
+  /** Returns true if this class extends one of the Android framework classes that must be public */
+  boolean isAndroidPublic();
+
   boolean isLocalClass();
 
   boolean isSelfInheritor(PsiClass psiClass);
diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java
index 51ea666..9ce3a61 100644
--- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java
+++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java
@@ -71,6 +71,19 @@
 
   public abstract PsiClass getServlet();
 
+  // Android Framework APIs that apps extend and where the subclasses must be public
+  // such that the framework can instantiate them
+
+  public abstract PsiClass getAndroidView();
+  public abstract PsiClass getAndroidActivity();
+  public abstract PsiClass getAndroidService();
+  public abstract PsiClass getAndroidBackupAgent();
+  public abstract PsiClass getAndroidContentProvider();
+  public abstract PsiClass getAndroidReceiver();
+  public abstract PsiClass getAndroidFragment(boolean support);
+  public abstract PsiClass getAndroidActionProvider();
+  public abstract PsiClass getAndroidParcelable();
+
   public abstract EntryPointsManager getEntryPointsManager();
 
   @NotNull
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java
index 13a18f0..ddaeeb7 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java
@@ -56,6 +56,7 @@
   private static final int IS_SERVLET_MASK   = 0x400000;
   private static final int IS_TESTCASE_MASK  = 0x800000;
   private static final int IS_LOCAL_MASK     = 0x1000000;
+  private static final int IS_ANDROID_MASK   = 0x2000000;
 
   private Set<RefClass> myBases; // singleton (to conserve the memory) or THashSet
   private Set<RefClass> mySubClasses; // singleton (to conserve the memory) or THashSet
@@ -139,6 +140,26 @@
       }
     }
 
+    // The Android framework has a number of classes that it wants to
+    // instantiate so it requires these classes to be public, even if
+    // code analysis suggests that that these are only referenced from
+    // within the same package.  Unfortunately these do not all extend the
+    // same set of base classes, so we need to check all these cases
+    // independently.
+    RefJavaManager refManager = getRefJavaManager();
+    if (inheritsFrom(psiClass, refManager.getAndroidActivity())
+      || inheritsFrom(psiClass, refManager.getAndroidService())
+      || inheritsFrom(psiClass, refManager.getAndroidView())
+      || inheritsFrom(psiClass, refManager.getAndroidFragment(false))
+      || inheritsFrom(psiClass, refManager.getAndroidFragment(true))
+      || inheritsFrom(psiClass, refManager.getAndroidReceiver())
+      || inheritsFrom(psiClass, refManager.getAndroidContentProvider())
+      || inheritsFrom(psiClass, refManager.getAndroidParcelable())
+      || inheritsFrom(psiClass, refManager.getAndroidBackupAgent())
+      || inheritsFrom(psiClass, refManager.getAndroidActionProvider())) {
+      setAndroidPublic(true);
+    }
+
     for (PsiMethod psiMethod : psiMethods) {
       RefMethod refMethod = (RefMethod)getRefManager().getReference(psiMethod);
 
@@ -187,6 +208,10 @@
     }
   }
 
+  private static boolean inheritsFrom(@NotNull PsiClass c1, @Nullable PsiClass c2) {
+    return c2 != null && c1.isInheritor(c2, true);
+  }
+
   private static ServerPageFile getJspFile(PsiClass psiClass) {
     final PsiFile psiFile = PsiUtilCore.getTemplateLanguageFile(psiClass);
     return psiFile instanceof ServerPageFile ? (ServerPageFile)psiFile : null;
@@ -491,6 +516,11 @@
   }
 
   @Override
+  public boolean isAndroidPublic() {
+    return checkFlag(IS_ANDROID_MASK);
+  }
+
+  @Override
   public boolean isTestCase() {
     return checkFlag(IS_TESTCASE_MASK);
   }
@@ -557,6 +587,10 @@
     setFlag(servlet, IS_SERVLET_MASK);
   }
 
+  private void setAndroidPublic(boolean android) {
+    setFlag(android, IS_ANDROID_MASK);
+  }
+
   private void setTestCase(boolean testCase) {
     setFlag(testCase, IS_TESTCASE_MASK);
   }
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java
index d929166..341f44a 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java
@@ -46,6 +46,16 @@
   private PsiMethod myAppAgentmainPattern;
   private PsiClass myApplet;
   private PsiClass myServlet;
+  private PsiClass myAndroidActivity;
+  private PsiClass myAndroidService;
+  private PsiClass myAndroidBackupAgent;
+  private PsiClass myAndroidFragment;
+  private PsiClass myAndroidV4Fragment;
+  private PsiClass myAndroidContentProvider;
+  private PsiClass myAndroidReceiver;
+  private PsiClass myAndroidView;
+  private PsiClass myAndroidActionProvider;
+  private PsiClass myAndroidParcelable;
   private RefPackage myDefaultPackage;
   private THashMap<String, RefPackage> myPackages;
   private final RefManagerImpl myRefManager;
@@ -66,9 +76,23 @@
       LOG.error(e);
     }
 
-    myApplet = JavaPsiFacade.getInstance(psiManager.getProject()).findClass("java.applet.Applet", GlobalSearchScope.allScope(project));
-    myServlet = JavaPsiFacade.getInstance(psiManager.getProject()).findClass("javax.servlet.Servlet", GlobalSearchScope.allScope(project));
+    GlobalSearchScope scope = GlobalSearchScope.allScope(project);
+    JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(psiManager.getProject());
+    myApplet = psiFacade.findClass("java.applet.Applet", scope);
+    myServlet = psiFacade.findClass("javax.servlet.Servlet", scope);
 
+    // Android Framework APIs that apps extend and where the subclasses must be public
+    // such that the framework can instantiate them
+    myAndroidActivity = psiFacade.findClass("android.app.Activity", scope);
+    myAndroidService = psiFacade.findClass("android.app.Service", scope);
+    myAndroidFragment = psiFacade.findClass("android.app.Fragment", scope);
+    myAndroidV4Fragment = psiFacade.findClass("android.support.v4.app.Fragment", scope);
+    myAndroidContentProvider = psiFacade.findClass("android.content.ContentProvider", scope);
+    myAndroidReceiver = psiFacade.findClass("android.content.BroadcastReceiver", scope);
+    myAndroidView = psiFacade.findClass("android.view.View", scope);
+    myAndroidActionProvider = psiFacade.findClass("android.view.ActionProvider", scope);
+    myAndroidParcelable = psiFacade.findClass("android.os.Parcelable", scope);
+    myAndroidBackupAgent = psiFacade.findClass("android.app.backup.BackupAgent", scope);
   }
 
   @Override
@@ -158,6 +182,51 @@
   }
 
   @Override
+  public PsiClass getAndroidActivity() {
+    return myAndroidActivity;
+  }
+
+  @Override
+  public PsiClass getAndroidService() {
+    return myAndroidService;
+  }
+
+  @Override
+  public PsiClass getAndroidBackupAgent() {
+    return myAndroidBackupAgent;
+  }
+
+  @Override
+  public PsiClass getAndroidFragment(boolean support) {
+    return support ? myAndroidV4Fragment : myAndroidFragment;
+  }
+
+  @Override
+  public PsiClass getAndroidContentProvider() {
+    return myAndroidContentProvider;
+  }
+
+  @Override
+  public PsiClass getAndroidReceiver() {
+    return myAndroidReceiver;
+  }
+
+  @Override
+  public PsiClass getAndroidView() {
+    return myAndroidView;
+  }
+
+  @Override
+  public PsiClass getAndroidActionProvider() {
+    return myAndroidActionProvider;
+  }
+
+  @Override
+  public PsiClass getAndroidParcelable() {
+    return myAndroidParcelable;
+  }
+
+  @Override
   public RefParameter getParameterReference(PsiParameter param, int index) {
     LOG.assertTrue(myRefManager.isValidPointForReference(), "References may become invalid after process is finished");
     RefElement ref = myRefManager.getFromRefTable(param);
@@ -203,6 +272,16 @@
     myAppPremainPattern = null;
     myAppAgentmainPattern = null;
     myServlet = null;
+    myAndroidActivity = null;
+    myAndroidService = null;
+    myAndroidBackupAgent = null;
+    myAndroidFragment = null;
+    myAndroidV4Fragment = null;
+    myAndroidContentProvider = null;
+    myAndroidReceiver = null;
+    myAndroidView = null;
+    myAndroidActionProvider = null;
+    myAndroidParcelable = null;
     myDefaultPackage = null;
     myProjectIterator = null;
   }
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java
index fd66f28..aa772f33 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java
@@ -44,7 +44,6 @@
 import com.intellij.psi.util.PsiUtil;
 import com.intellij.usageView.UsageViewTypeLocation;
 import com.intellij.util.IncorrectOperationException;
-import com.intellij.util.VisibilityUtil;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -179,6 +178,10 @@
         RefClass refClass = (RefClass) refElement;
         if (refClass.isAnonymous() || refClass.isEntry() || refClass.isTestCase() || refClass.isServlet() || refClass.isApplet() || refClass.isLocalClass()) return null;
         if (isTopLevelClass(refClass) && !SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES) return null;
+
+        if (refClass.isAndroidPublic()) {
+          return null;
+        }
       }
 
       //ignore unreferenced code. They could be a potential entry points.