/** * Returns all activities found in the given project (including those in libraries, except for * android.jar itself) * * @param project the project * @return a list of activity classes as fully qualified class names */ @SuppressWarnings("restriction") // BinaryType @NonNull public static List<String> getProjectActivities(IProject project) { final List<String> activities = new ArrayList<String>(); try { final IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); if (javaProject != null) { IType[] activityTypes = new IType[0]; IType activityType = javaProject.findType(SdkConstants.CLASS_ACTIVITY); if (activityType != null) { ITypeHierarchy hierarchy = activityType.newTypeHierarchy(javaProject, new NullProgressMonitor()); activityTypes = hierarchy.getAllSubtypes(activityType); for (IType type : activityTypes) { if (type instanceof BinaryType && (type.getClassFile() == null || type.getClassFile().getResource() == null)) { continue; } activities.add(type.getFullyQualifiedName()); } } } } catch (CoreException e) { AdtPlugin.log(e, null); } return activities; }
private IProject guessProject(IStructuredSelection selection) { if (selection == null) { return null; } for (Object element : selection.toList()) { if (element instanceof IAdaptable) { IResource res = (IResource) ((IAdaptable) element).getAdapter(IResource.class); IProject project = res != null ? res.getProject() : null; // Is this an Android project? try { if (project == null || !project.hasNature(AdtConstants.NATURE_DEFAULT)) { continue; } } catch (CoreException e) { // checking the nature failed, ignore this resource continue; } return project; } else if (element instanceof Pair<?, ?>) { // Pair of Project/String @SuppressWarnings("unchecked") Pair<IProject, String> pair = (Pair<IProject, String>) element; return pair.getFirst(); } } // Try to figure out the project from the active editor IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (window != null) { IWorkbenchPage page = window.getActivePage(); if (page != null) { IEditorPart activeEditor = page.getActiveEditor(); if (activeEditor instanceof AndroidXmlEditor) { Object input = ((AndroidXmlEditor) activeEditor).getEditorInput(); if (input instanceof FileEditorInput) { FileEditorInput fileInput = (FileEditorInput) input; return fileInput.getFile().getProject(); } } } } IJavaProject[] projects = BaseProjectHelper.getAndroidProjects( new IProjectFilter() { public boolean accept(IProject project) { return project.isAccessible(); } }); if (projects != null && projects.length == 1) { return projects[0].getProject(); } return null; }
/** * Returns the activities associated with the given layout file. Makes an educated guess by * peeking at the usages of the R.layout.name field corresponding to the layout and if it finds a * usage. * * @param project the project containing the layout * @param layoutName the layout whose activity we want to look up * @param pkg the package containing activities * @return the activity name */ @NonNull public static List<String> guessActivities(IProject project, String layoutName, String pkg) { final LinkedList<String> activities = new LinkedList<String>(); SearchRequestor requestor = new SearchRequestor() { @Override public void acceptSearchMatch(SearchMatch match) throws CoreException { Object element = match.getElement(); if (element instanceof IMethod) { IMethod method = (IMethod) element; IType declaringType = method.getDeclaringType(); String fqcn = declaringType.getFullyQualifiedName(); if ((declaringType.getSuperclassName() != null && declaringType.getSuperclassName().endsWith("Activity")) // $NON-NLS-1$ || method.getElementName().equals("onCreate")) { // $NON-NLS-1$ activities.addFirst(fqcn); } else { activities.addLast(fqcn); } } } }; try { IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); if (javaProject == null) { return Collections.emptyList(); } // TODO - look around a bit more and see if we can figure out whether the // call if from within a setContentView call! // Search for which java classes call setContentView(R.layout.layoutname); String typeFqcn = "R.layout"; // $NON-NLS-1$ if (pkg != null) { typeFqcn = pkg + '.' + typeFqcn; } IType type = javaProject.findType(typeFqcn); if (type != null) { IField field = type.getField(layoutName); if (field.exists()) { SearchPattern pattern = SearchPattern.createPattern(field, REFERENCES); try { search(requestor, javaProject, pattern); } catch (OperationCanceledException canceled) { // pass } } } } catch (CoreException e) { AdtPlugin.log(e, null); } return activities; }
/** * Returns the first package root for the given java project * * @param javaProject the project to search in * @return the first package root, or null */ @Nullable public static IPackageFragmentRoot getSourcePackageRoot(IJavaProject javaProject) { IPackageFragmentRoot packageRoot = null; List<IPath> sources = BaseProjectHelper.getSourceClasspaths(javaProject); IWorkspace workspace = ResourcesPlugin.getWorkspace(); for (IPath path : sources) { IResource firstSource = workspace.getRoot().findMember(path); if (firstSource != null) { packageRoot = javaProject.getPackageFragmentRoot(firstSource); if (packageRoot != null) { break; } } } return packageRoot; }
/** * Returns the {@link IPackageFragment} for the package registered in the manifest * * @return the {@link IPackageFragment} for the package registered in the manifest */ @Nullable public IPackageFragment getPackageFragment() { sync(); try { IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject); if (javaProject != null) { IPackageFragmentRoot root = ManifestInfo.getSourcePackageRoot(javaProject); if (root != null) { return root.getPackageFragment(mPackage); } } } catch (CoreException e) { AdtPlugin.log(e, null); } return null; }
/** * Returns the activity associated with the given layout file. * * <p>This is an alternative to {@link #guessActivity(IFile, String)}. Whereas guessActivity * simply looks for references to "R.layout.foo", this method searches for all usages of * Activity#setContentView(int), and for each match it looks up the corresponding call text (such * as "setContentView(R.layout.foo)"). From this it uses a regexp to pull out "foo" from this, and * stores the association that layout "foo" is associated with the activity class that contained * the setContentView call. * * <p>This has two potential advantages: * * <ol> * <li>It can be faster. We do the reference search -once-, and we've built a map of all the * layout-to-activity mappings which we can then immediately look up other layouts for, * which is particularly useful at startup when we have to compute the layout activity * associations to populate the theme choosers. * <li>It can be more accurate. Just because an activity references an "R.layout.foo" field * doesn't mean it's setting it as a content view. * </ol> * * However, this second advantage is also its chief problem. There are some common code constructs * which means that the associated layout is not explicitly referenced in a direct setContentView * call; on a couple of sample projects I tested I found patterns like for example * "setContentView(v)" where "v" had been computed earlier. Therefore, for now we're going to * stick with the more general approach of just looking up each field when needed. We're keeping * the code around, though statically compiled out with the "if (false)" construct below in case * we revisit this. * * @param layoutFile the layout whose activity we want to look up * @return the activity name */ @SuppressWarnings("all") @Nullable public String guessActivityBySetContentView(String layoutName) { if (false) { // These should be fields final Pattern LAYOUT_FIELD_PATTERN = Pattern.compile("R\\.layout\\.([a-z0-9_]+)"); // $NON-NLS-1$ Map<String, String> mUsages = null; sync(); if (mUsages == null) { final Map<String, String> usages = new HashMap<String, String>(); mUsages = usages; SearchRequestor requestor = new SearchRequestor() { @Override public void acceptSearchMatch(SearchMatch match) throws CoreException { Object element = match.getElement(); if (element instanceof IMethod) { IMethod method = (IMethod) element; IType declaringType = method.getDeclaringType(); String fqcn = declaringType.getFullyQualifiedName(); IDocumentProvider provider = new TextFileDocumentProvider(); IResource resource = match.getResource(); try { provider.connect(resource); IDocument document = provider.getDocument(resource); if (document != null) { String matchText = document.get(match.getOffset(), match.getLength()); Matcher matcher = LAYOUT_FIELD_PATTERN.matcher(matchText); if (matcher.find()) { usages.put(matcher.group(1), fqcn); } } } catch (Exception e) { AdtPlugin.log(e, "Can't find range information for %1$s", resource.getName()); } finally { provider.disconnect(resource); } } } }; try { IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject); if (javaProject == null) { return null; } // Search for which java classes call setContentView(R.layout.layoutname); String typeFqcn = "R.layout"; // $NON-NLS-1$ if (mPackage != null) { typeFqcn = mPackage + '.' + typeFqcn; } IType activityType = javaProject.findType(SdkConstants.CLASS_ACTIVITY); if (activityType != null) { IMethod method = activityType.getMethod( "setContentView", new String[] {"I"}); // $NON-NLS-1$ //$NON-NLS-2$ if (method.exists()) { SearchPattern pattern = SearchPattern.createPattern(method, REFERENCES); search(requestor, javaProject, pattern); } } } catch (CoreException e) { AdtPlugin.log(e, null); } } return mUsages.get(layoutName); } return null; }
private void buildErrorUi(IProject project) { // Show description the first time setErrorMessage(null); setMessage(null); setPageComplete(true); mHasMessage = false; // composite parent for the warning/error GridLayout gl = null; mErrorComposite = new Composite(mTopComposite, SWT.NONE); mErrorComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); gl = new GridLayout(2, false); gl.marginHeight = gl.marginWidth = 0; gl.verticalSpacing *= 3; // more spacing than normal. mErrorComposite.setLayout(gl); if (project == null) { setErrorMessage("Select project to export."); mHasMessage = true; } else { try { if (project.hasNature(AndroidConstants.NATURE) == false) { addError(mErrorComposite, "Project is not an Android project."); } else { // check for errors if (ProjectHelper.hasError(project, true)) { addError(mErrorComposite, "Project has compilation error(s)"); } // check the project output IFolder outputIFolder = BaseProjectHelper.getOutputFolder(project); if (outputIFolder != null) { String outputOsPath = outputIFolder.getLocation().toOSString(); String apkFilePath = outputOsPath + File.separator + project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE; File f = new File(apkFilePath); if (f.isFile() == false) { addError( mErrorComposite, String.format( "%1$s/%2$s/%1$s%3$s does not exists!", project.getName(), outputIFolder.getName(), AndroidConstants.DOT_ANDROID_PACKAGE)); } } else { addError(mErrorComposite, "Unable to get the output folder of the project!"); } // project is an android project, we check the debuggable attribute. AndroidManifestParser manifestParser = AndroidManifestParser.parse( BaseProjectHelper.getJavaProject(project), null /* errorListener */, true /* gatherData */, false /* markErrors */); Boolean debuggable = manifestParser.getDebuggable(); if (debuggable != null && debuggable == Boolean.TRUE) { addWarning( mErrorComposite, "The manifest 'debuggable' attribute is set to true.\nYou should set it to false for applications that you release to the public."); } // check for mapview stuff } } catch (CoreException e) { // unable to access nature addError(mErrorComposite, "Unable to get project nature"); } } if (mHasMessage == false) { Label label = new Label(mErrorComposite, SWT.NONE); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; label.setLayoutData(gd); label.setText("No errors found. Click Next."); } mTopComposite.layout(); }
private void selectFiles(IProject project, List<? extends IResource> createdFiles) { // Attempt to select the newly created files in the Package Explorer IWorkbench workbench = AdtPlugin.getDefault().getWorkbench(); IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage(); IViewPart viewPart = page.findView(JavaUI.ID_PACKAGES); if (viewPart != null) { IWorkbenchPartSite site = viewPart.getSite(); IJavaProject javaProject = null; try { javaProject = BaseProjectHelper.getJavaProject(project); } catch (CoreException e) { AdtPlugin.log(e, null); } final ISelectionProvider provider = site.getSelectionProvider(); if (provider != null) { List<TreePath> pathList = new ArrayList<TreePath>(); for (IResource file : createdFiles) { // Create a TreePath for the given file, // which should be the JavaProject, followed by the folders down to // the final file. List<Object> segments = new ArrayList<Object>(); segments.add(file); IContainer folder = file.getParent(); if (folder != null && !(folder instanceof IProject)) { segments.add(folder); // res folder folder = folder.getParent(); if (folder != null && !(folder instanceof IProject)) { segments.add(folder); } } // project segments.add(javaProject); Collections.reverse(segments); TreePath path = new TreePath(segments.toArray()); pathList.add(path); // IDEA: Maybe normalize the files backwards (IFile objects aren't unique) // by maybe using the package explorer icons instead } TreePath[] paths = pathList.toArray(new TreePath[pathList.size()]); final TreeSelection selection = new TreeSelection(paths); provider.setSelection(selection); // Workaround: The above doesn't always work; it will frequently select // some siblings of the real files. I've tried a number of workarounds: // normalizing the IFile objects by looking up the canonical ones via // their relative paths from the project; deferring execution with // Display.asyncRun; first calling select on the parents, etc. // However, it turns out a simple workaround works best: Calling this // method TWICE. The first call seems to expand all the necessary parents, // and the second call ensures that the correct children are selected! provider.setSelection(selection); viewPart.setFocus(); } } }
private Pair<List<String>, List<String>> findViews(final boolean layoutsOnly) { final Set<String> customViews = new HashSet<String>(); final Set<String> thirdPartyViews = new HashSet<String>(); ProjectState state = Sdk.getProjectState(mProject); final List<IProject> libraries = state != null ? state.getFullLibraryProjects() : Collections.<IProject>emptyList(); SearchRequestor requestor = new SearchRequestor() { @Override public void acceptSearchMatch(SearchMatch match) throws CoreException { // Ignore matches in comments if (match.isInsideDocComment()) { return; } Object element = match.getElement(); if (element instanceof ResolvedBinaryType) { // Third party view ResolvedBinaryType type = (ResolvedBinaryType) element; IPackageFragment fragment = type.getPackageFragment(); IPath path = fragment.getPath(); String last = path.lastSegment(); // Filter out android.jar stuff if (last.equals(FN_FRAMEWORK_LIBRARY)) { return; } if (!isValidView(type, layoutsOnly)) { return; } IProject matchProject = match.getResource().getProject(); if (mProject == matchProject || libraries.contains(matchProject)) { String fqn = type.getFullyQualifiedName(); thirdPartyViews.add(fqn); } } else if (element instanceof ResolvedSourceType) { // User custom view IProject matchProject = match.getResource().getProject(); if (mProject == matchProject || libraries.contains(matchProject)) { ResolvedSourceType type = (ResolvedSourceType) element; if (!isValidView(type, layoutsOnly)) { return; } String fqn = type.getFullyQualifiedName(); fqn = fqn.replace('$', '.'); customViews.add(fqn); } } } }; try { IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject); if (javaProject != null) { String className = layoutsOnly ? CLASS_VIEWGROUP : CLASS_VIEW; IType viewType = javaProject.findType(className); if (viewType != null) { IJavaSearchScope scope = SearchEngine.createHierarchyScope(viewType); SearchParticipant[] participants = new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()}; int matchRule = SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE; SearchPattern pattern = SearchPattern.createPattern( "*", IJavaSearchConstants.CLASS, IJavaSearchConstants.IMPLEMENTORS, matchRule); SearchEngine engine = new SearchEngine(); engine.search(pattern, participants, scope, requestor, new NullProgressMonitor()); } } } catch (CoreException e) { AdtPlugin.log(e, null); } List<String> custom = new ArrayList<String>(customViews); List<String> thirdParty = new ArrayList<String>(thirdPartyViews); if (!layoutsOnly) { // Update our cached answers (unless we were filtered on only layouts) mCustomViews = custom; mThirdPartyViews = thirdParty; } return Pair.of(custom, thirdParty); }