diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java | 957 |
1 files changed, 0 insertions, 957 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java deleted file mode 100644 index 6d2d1c1f2..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java +++ /dev/null @@ -1,957 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php - * - * 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.ide.eclipse.adt.internal.editors.manifest; - -import static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX; -import static com.android.SdkConstants.CLASS_ACTIVITY; -import static com.android.SdkConstants.NS_RESOURCES; -import static com.android.xml.AndroidManifest.ATTRIBUTE_ICON; -import static com.android.xml.AndroidManifest.ATTRIBUTE_LABEL; -import static com.android.xml.AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION; -import static com.android.xml.AndroidManifest.ATTRIBUTE_NAME; -import static com.android.xml.AndroidManifest.ATTRIBUTE_PACKAGE; -import static com.android.xml.AndroidManifest.ATTRIBUTE_PARENT_ACTIVITY_NAME; -import static com.android.xml.AndroidManifest.ATTRIBUTE_SUPPORTS_RTL; -import static com.android.xml.AndroidManifest.ATTRIBUTE_TARGET_SDK_VERSION; -import static com.android.xml.AndroidManifest.ATTRIBUTE_THEME; -import static com.android.xml.AndroidManifest.ATTRIBUTE_UI_OPTIONS; -import static com.android.xml.AndroidManifest.ATTRIBUTE_VALUE; -import static com.android.xml.AndroidManifest.NODE_ACTIVITY; -import static com.android.xml.AndroidManifest.NODE_METADATA; -import static com.android.xml.AndroidManifest.NODE_USES_SDK; -import static com.android.xml.AndroidManifest.VALUE_PARENT_ACTIVITY; -import static org.eclipse.jdt.core.search.IJavaSearchConstants.REFERENCES; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.io.IFolderWrapper; -import com.android.io.IAbstractFile; -import com.android.io.StreamException; -import com.android.resources.ScreenSize; -import com.android.sdklib.IAndroidTarget; -import com.android.utils.Pair; -import com.android.xml.AndroidManifest; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.search.IJavaSearchScope; -import org.eclipse.jdt.core.search.SearchEngine; -import org.eclipse.jdt.core.search.SearchMatch; -import org.eclipse.jdt.core.search.SearchParticipant; -import org.eclipse.jdt.core.search.SearchPattern; -import org.eclipse.jdt.core.search.SearchRequestor; -import org.eclipse.jdt.internal.core.BinaryType; -import org.eclipse.jface.text.IDocument; -import org.eclipse.ui.editors.text.TextFileDocumentProvider; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPathExpressionException; - -/** - * Retrieves and caches manifest information such as the themes to be used for - * a given activity. - * - * @see AndroidManifest - */ -public class ManifestInfo { - - public static class ActivityAttributes { - @Nullable - private final String mIcon; - @Nullable - private final String mLabel; - @NonNull - private final String mName; - @Nullable - private final String mParentActivity; - @Nullable - private final String mTheme; - @Nullable - private final String mUiOptions; - - public ActivityAttributes(Element activity, String packageName) { - - // Get activity name. - String name = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_NAME); - if (name == null || name.length() == 0) { - throw new RuntimeException("Activity name cannot be empty"); - } - int index = name.indexOf('.'); - if (index <= 0 && packageName != null && !packageName.isEmpty()) { - name = packageName + (index == -1 ? "." : "") + name; - } - mName = name; - - // Get activity icon. - String value = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON); - if (value != null && value.length() > 0) { - mIcon = value; - } else { - mIcon = null; - } - - // Get activity label. - value = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL); - if (value != null && value.length() > 0) { - mLabel = value; - } else { - mLabel = null; - } - - // Get activity parent. Also search the meta-data for parent info. - value = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_PARENT_ACTIVITY_NAME); - if (value == null || value.length() == 0) { - // TODO: Not sure if meta data can be used for API Level > 16 - NodeList metaData = activity.getElementsByTagName(NODE_METADATA); - for (int j = 0, m = metaData.getLength(); j < m; j++) { - Element data = (Element) metaData.item(j); - String metadataName = data.getAttributeNS(NS_RESOURCES, ATTRIBUTE_NAME); - if (VALUE_PARENT_ACTIVITY.equals(metadataName)) { - value = data.getAttributeNS(NS_RESOURCES, ATTRIBUTE_VALUE); - if (value != null) { - index = value.indexOf('.'); - if (index <= 0 && packageName != null && !packageName.isEmpty()) { - value = packageName + (index == -1 ? "." : "") + value; - break; - } - } - } - } - } - if (value != null && value.length() > 0) { - mParentActivity = value; - } else { - mParentActivity = null; - } - - // Get activity theme. - value = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME); - if (value != null && value.length() > 0) { - mTheme = value; - } else { - mTheme = null; - } - - // Get UI options. - value = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_UI_OPTIONS); - if (value != null && value.length() > 0) { - mUiOptions = value; - } else { - mUiOptions = null; - } - } - - @Nullable - public String getIcon() { - return mIcon; - } - - @Nullable - public String getLabel() { - return mLabel; - } - - public String getName() { - return mName; - } - - @Nullable - public String getParentActivity() { - return mParentActivity; - } - - @Nullable - public String getTheme() { - return mTheme; - } - - @Nullable - public String getUiOptions() { - return mUiOptions; - } - } - - /** - * The maximum number of milliseconds to search for an activity in the codebase when - * attempting to associate layouts with activities in - * {@link #guessActivity(IFile, String)} - */ - private static final int SEARCH_TIMEOUT_MS = 3000; - - private final IProject mProject; - private String mPackage; - private String mManifestTheme; - private Map<String, ActivityAttributes> mActivityAttributes; - private IAbstractFile mManifestFile; - private long mLastModified; - private long mLastChecked; - private String mMinSdkName; - private int mMinSdk; - private int mTargetSdk; - private String mApplicationIcon; - private String mApplicationLabel; - private boolean mApplicationSupportsRtl; - - /** - * Qualified name for the per-project non-persistent property storing the - * {@link ManifestInfo} for this project - */ - final static QualifiedName MANIFEST_FINDER = new QualifiedName(AdtPlugin.PLUGIN_ID, - "manifest"); //$NON-NLS-1$ - - /** - * Constructs an {@link ManifestInfo} for the given project. Don't use this method; - * use the {@link #get} factory method instead. - * - * @param project project to create an {@link ManifestInfo} for - */ - private ManifestInfo(IProject project) { - mProject = project; - } - - /** - * Clears the cached manifest information. The next get call on one of the - * properties will cause the information to be refreshed. - */ - public void clear() { - mLastChecked = 0; - } - - /** - * Returns the {@link ManifestInfo} for the given project - * - * @param project the project the finder is associated with - * @return a {@ManifestInfo} for the given project, never null - */ - @NonNull - public static ManifestInfo get(IProject project) { - ManifestInfo finder = null; - try { - finder = (ManifestInfo) project.getSessionProperty(MANIFEST_FINDER); - } catch (CoreException e) { - // Not a problem; we will just create a new one - } - - if (finder == null) { - finder = new ManifestInfo(project); - try { - project.setSessionProperty(MANIFEST_FINDER, finder); - } catch (CoreException e) { - AdtPlugin.log(e, "Can't store ManifestInfo"); - } - } - - return finder; - } - - /** - * Ensure that the package, theme and activity maps are initialized and up to date - * with respect to the manifest file - */ - private void sync() { - // Since each of the accessors call sync(), allow a bunch of immediate - // accessors to all bypass the file stat() below - long now = System.currentTimeMillis(); - if (now - mLastChecked < 50 && mManifestFile != null) { - return; - } - mLastChecked = now; - - if (mManifestFile == null) { - IFolderWrapper projectFolder = new IFolderWrapper(mProject); - mManifestFile = AndroidManifest.getManifest(projectFolder); - if (mManifestFile == null) { - return; - } - } - - // Check to see if our data is up to date - long fileModified = mManifestFile.getModificationStamp(); - if (fileModified == mLastModified) { - // Already have up to date data - return; - } - mLastModified = fileModified; - - mActivityAttributes = new HashMap<String, ActivityAttributes>(); - mManifestTheme = null; - mTargetSdk = 1; // Default when not specified - mMinSdk = 1; // Default when not specified - mMinSdkName = "1"; // Default when not specified - mPackage = ""; //$NON-NLS-1$ - mApplicationIcon = null; - mApplicationLabel = null; - mApplicationSupportsRtl = false; - - Document document = null; - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - InputSource is = new InputSource(mManifestFile.getContents()); - - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder builder = factory.newDocumentBuilder(); - document = builder.parse(is); - - Element root = document.getDocumentElement(); - mPackage = root.getAttribute(ATTRIBUTE_PACKAGE); - NodeList activities = document.getElementsByTagName(NODE_ACTIVITY); - for (int i = 0, n = activities.getLength(); i < n; i++) { - Element activity = (Element) activities.item(i); - ActivityAttributes info = new ActivityAttributes(activity, mPackage); - mActivityAttributes.put(info.getName(), info); - } - - NodeList applications = root.getElementsByTagName(AndroidManifest.NODE_APPLICATION); - if (applications.getLength() > 0) { - assert applications.getLength() == 1; - Element application = (Element) applications.item(0); - if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON)) { - mApplicationIcon = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON); - } - if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL)) { - mApplicationLabel = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL); - } - if (SdkConstants.VALUE_TRUE.equals(application.getAttributeNS(NS_RESOURCES, - ATTRIBUTE_SUPPORTS_RTL))) { - mApplicationSupportsRtl = true; - } - - String defaultTheme = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME); - if (defaultTheme != null && !defaultTheme.isEmpty()) { - // From manifest theme documentation: - // "If that attribute is also not set, the default system theme is used." - mManifestTheme = defaultTheme; - } - } - - // Look up target SDK - NodeList usesSdks = root.getElementsByTagName(NODE_USES_SDK); - if (usesSdks.getLength() > 0) { - Element usesSdk = (Element) usesSdks.item(0); - mMinSdk = getApiVersion(usesSdk, ATTRIBUTE_MIN_SDK_VERSION, 1); - mTargetSdk = getApiVersion(usesSdk, ATTRIBUTE_TARGET_SDK_VERSION, mMinSdk); - } - - } catch (SAXException e) { - AdtPlugin.log(e, "Malformed manifest"); - } catch (Exception e) { - AdtPlugin.log(e, "Could not read Manifest data"); - } - } - - private int getApiVersion(Element usesSdk, String attribute, int defaultApiLevel) { - String valueString = null; - if (usesSdk.hasAttributeNS(NS_RESOURCES, attribute)) { - valueString = usesSdk.getAttributeNS(NS_RESOURCES, attribute); - if (attribute.equals(ATTRIBUTE_MIN_SDK_VERSION)) { - mMinSdkName = valueString; - } - } - - if (valueString != null) { - int apiLevel = -1; - try { - apiLevel = Integer.valueOf(valueString); - } catch (NumberFormatException e) { - // Handle codename - if (Sdk.getCurrent() != null) { - IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString( - "android-" + valueString); //$NON-NLS-1$ - if (target != null) { - // codename future API level is current api + 1 - apiLevel = target.getVersion().getApiLevel() + 1; - } - } - } - - return apiLevel; - } - - return defaultApiLevel; - } - - /** - * Returns the default package registered in the Android manifest - * - * @return the default package registered in the manifest - */ - @NonNull - public String getPackage() { - sync(); - return mPackage; - } - - /** - * Returns a map from activity full class names to the corresponding {@link ActivityAttributes}. - * - * @return a map from activity fqcn to ActivityAttributes - */ - @NonNull - public Map<String, ActivityAttributes> getActivityAttributesMap() { - sync(); - return mActivityAttributes; - } - - /** - * Returns the attributes of an activity given its full class name. - */ - @Nullable - public ActivityAttributes getActivityAttributes(String activity) { - return getActivityAttributesMap().get(activity); - } - - /** - * Returns the manifest theme registered on the application, if any - * - * @return a manifest theme, or null if none was registered - */ - @Nullable - public String getManifestTheme() { - sync(); - return mManifestTheme; - } - - /** - * Returns the default theme for this project, by looking at the manifest default - * theme registration, target SDK, rendering target, etc. - * - * @param renderingTarget the rendering target use to render the theme, or null - * @param screenSize the screen size to obtain a default theme for, or null if unknown - * @return the theme to use for this project, never null - */ - @NonNull - public String getDefaultTheme(IAndroidTarget renderingTarget, ScreenSize screenSize) { - sync(); - - if (mManifestTheme != null) { - return mManifestTheme; - } - - int renderingTargetSdk = mTargetSdk; - if (renderingTarget != null) { - renderingTargetSdk = renderingTarget.getVersion().getApiLevel(); - } - - int apiLevel = Math.min(mTargetSdk, renderingTargetSdk); - // For now this theme works only on XLARGE screens. When it works for all sizes, - // add that new apiLevel to this check. - if (apiLevel >= 11 && screenSize == ScreenSize.XLARGE || apiLevel >= 14) { - return ANDROID_STYLE_RESOURCE_PREFIX + "Theme.Holo"; //$NON-NLS-1$ - } else { - return ANDROID_STYLE_RESOURCE_PREFIX + "Theme"; //$NON-NLS-1$ - } - } - - /** - * Returns the application icon, or null - * - * @return the application icon, or null - */ - @Nullable - public String getApplicationIcon() { - sync(); - return mApplicationIcon; - } - - /** - * Returns the application label, or null - * - * @return the application label, or null - */ - @Nullable - public String getApplicationLabel() { - sync(); - return mApplicationLabel; - } - - /** - * Returns true if the application has RTL support. - * - * @return true if the application has RTL support. - */ - public boolean isRtlSupported() { - sync(); - return mApplicationSupportsRtl; - } - - /** - * Returns the target SDK version - * - * @return the target SDK version - */ - public int getTargetSdkVersion() { - sync(); - return mTargetSdk; - } - - /** - * Returns the minimum SDK version - * - * @return the minimum SDK version - */ - public int getMinSdkVersion() { - sync(); - return mMinSdk; - } - - /** - * Returns the minimum SDK version name (which may not be a numeric string, e.g. - * it could be a codename). It will never be null or empty; if no min sdk version - * was specified in the manifest, the return value will be "1". Use - * {@link #getMinSdkCodeName()} instead if you want to look up whether there is a code name. - * - * @return the minimum SDK version - */ - @NonNull - public String getMinSdkName() { - sync(); - if (mMinSdkName == null || mMinSdkName.isEmpty()) { - mMinSdkName = "1"; //$NON-NLS-1$ - } - - return mMinSdkName; - } - - /** - * Returns the code name used for the minimum SDK version, if any. - * - * @return the minSdkVersion codename or null - */ - @Nullable - public String getMinSdkCodeName() { - String minSdkName = getMinSdkName(); - if (!Character.isDigit(minSdkName.charAt(0))) { - return minSdkName; - } - - return null; - } - - /** - * 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. 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 - */ - @Nullable - public static String guessActivity(IProject project, String layoutName, String pkg) { - List<String> activities = guessActivities(project, layoutName, pkg); - if (activities.size() > 0) { - return activities.get(0); - } else { - 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 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(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; - } - - - /** - * 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(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; - } - - /** - * Performs a search using the given pattern, scope and handler. The search will abort - * if it takes longer than {@link #SEARCH_TIMEOUT_MS} milliseconds. - */ - private static void search(SearchRequestor requestor, IJavaProject javaProject, - SearchPattern pattern) throws CoreException { - // Find the package fragment specified in the manifest; the activities should - // live there. - IJavaSearchScope scope = createPackageScope(javaProject); - - SearchParticipant[] participants = new SearchParticipant[] { - SearchEngine.getDefaultSearchParticipant() - }; - SearchEngine engine = new SearchEngine(); - - final long searchStart = System.currentTimeMillis(); - NullProgressMonitor monitor = new NullProgressMonitor() { - private boolean mCancelled; - @Override - public void internalWorked(double work) { - long searchEnd = System.currentTimeMillis(); - if (searchEnd - searchStart > SEARCH_TIMEOUT_MS) { - mCancelled = true; - } - } - - @Override - public boolean isCanceled() { - return mCancelled; - } - }; - engine.search(pattern, participants, scope, requestor, monitor); - } - - /** Creates a package search scope for the first package root in the given java project */ - private static IJavaSearchScope createPackageScope(IJavaProject javaProject) { - IPackageFragmentRoot packageRoot = getSourcePackageRoot(javaProject); - - IJavaSearchScope scope; - if (packageRoot != null) { - IJavaElement[] scopeElements = new IJavaElement[] { packageRoot }; - scope = SearchEngine.createJavaSearchScope(scopeElements); - } else { - scope = SearchEngine.createWorkspaceScope(); - } - return scope; - } - - /** - * 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; - } - - /** - * Computes the minimum SDK and target SDK versions for the project - * - * @param project the project to look up the versions for - * @return a pair of (minimum SDK, target SDK) versions, never null - */ - @NonNull - public static Pair<Integer, Integer> computeSdkVersions(IProject project) { - int mMinSdkVersion = 1; - int mTargetSdkVersion = 1; - - IAbstractFile manifestFile = AndroidManifest.getManifest(new IFolderWrapper(project)); - if (manifestFile != null) { - try { - Object value = AndroidManifest.getMinSdkVersion(manifestFile); - mMinSdkVersion = 1; // Default case if missing - if (value instanceof Integer) { - mMinSdkVersion = ((Integer) value).intValue(); - } else if (value instanceof String) { - // handle codename, only if we can resolve it. - if (Sdk.getCurrent() != null) { - IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString( - "android-" + value); //$NON-NLS-1$ - if (target != null) { - // codename future API level is current api + 1 - mMinSdkVersion = target.getVersion().getApiLevel() + 1; - } - } - } - - value = AndroidManifest.getTargetSdkVersion(manifestFile); - if (value == null) { - mTargetSdkVersion = mMinSdkVersion; - } else if (value instanceof String) { - // handle codename, only if we can resolve it. - if (Sdk.getCurrent() != null) { - IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString( - "android-" + value); //$NON-NLS-1$ - if (target != null) { - // codename future API level is current api + 1 - mTargetSdkVersion = target.getVersion().getApiLevel() + 1; - } - } - } - } catch (XPathExpressionException e) { - // do nothing we'll use 1 below. - } catch (StreamException e) { - // do nothing we'll use 1 below. - } - } - - return Pair.of(mMinSdkVersion, mTargetSdkVersion); - } -} |