19bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye/*
29bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * Copyright (C) 2011 The Android Open Source Project
39bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye *
49bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License");
59bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * you may not use this file except in compliance with the License.
69bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * You may obtain a copy of the License at
79bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye *
89bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye *      http://www.eclipse.org/org/documents/epl-v10.php
99bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye *
109bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * Unless required by applicable law or agreed to in writing, software
119bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * distributed under the License is distributed on an "AS IS" BASIS,
129bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * See the License for the specific language governing permissions and
149bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * limitations under the License.
159bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye */
169bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
179bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyepackage com.android.ide.eclipse.adt.internal.editors.manifest;
189bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX;
2012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.CLASS_ACTIVITY;
2181cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.SdkConstants.NS_RESOURCES;
2281cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.ATTRIBUTE_ICON;
2381cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.ATTRIBUTE_LABEL;
2481cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION;
2581cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.ATTRIBUTE_NAME;
2681cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.ATTRIBUTE_PACKAGE;
2781cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.ATTRIBUTE_TARGET_SDK_VERSION;
2881cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.ATTRIBUTE_THEME;
2981cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.NODE_ACTIVITY;
3081cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport static com.android.xml.AndroidManifest.NODE_USES_SDK;
319bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport static org.eclipse.jdt.core.search.IJavaSearchConstants.REFERENCES;
329bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
339bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbyeimport com.android.annotations.NonNull;
349bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbyeimport com.android.annotations.Nullable;
359bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport com.android.ide.eclipse.adt.AdtPlugin;
369bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
379bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport com.android.ide.eclipse.adt.internal.sdk.Sdk;
389bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport com.android.ide.eclipse.adt.io.IFolderWrapper;
399bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport com.android.io.IAbstractFile;
4071ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbyeimport com.android.io.StreamException;
4147e918dd86afa699e017f498de3349a296e7a20fXavier Ducrohetimport com.android.resources.ScreenSize;
429bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport com.android.sdklib.IAndroidTarget;
4385e4a1a9dd133abb879ec211ce8dd385004edf22Xavier Ducrohetimport com.android.utils.Pair;
4481cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport com.android.xml.AndroidManifest;
459bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
469bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.resources.IFile;
479bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.resources.IProject;
489bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.resources.IResource;
499bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.resources.IWorkspace;
509bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.resources.ResourcesPlugin;
519bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.runtime.CoreException;
529bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.runtime.IPath;
539bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.runtime.NullProgressMonitor;
5457f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbyeimport org.eclipse.core.runtime.OperationCanceledException;
559bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.core.runtime.QualifiedName;
569bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.IField;
579bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.IJavaElement;
589bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.IJavaProject;
599bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.IMethod;
60d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbyeimport org.eclipse.jdt.core.IPackageFragment;
619bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.IPackageFragmentRoot;
629bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.IType;
63bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbyeimport org.eclipse.jdt.core.ITypeHierarchy;
649bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.search.IJavaSearchScope;
659bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.search.SearchEngine;
669bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.search.SearchMatch;
679bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.search.SearchParticipant;
689bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.search.SearchPattern;
699bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jdt.core.search.SearchRequestor;
70bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbyeimport org.eclipse.jdt.internal.core.BinaryType;
719bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.jface.text.IDocument;
729bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.ui.editors.text.TextFileDocumentProvider;
739bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.eclipse.ui.texteditor.IDocumentProvider;
749bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.w3c.dom.Document;
759bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.w3c.dom.Element;
769bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.w3c.dom.NodeList;
779bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.xml.sax.InputSource;
789bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport org.xml.sax.SAXException;
799bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
80bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbyeimport java.util.ArrayList;
817e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbyeimport java.util.Collections;
829bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport java.util.HashMap;
83bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbyeimport java.util.LinkedList;
849bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport java.util.List;
859bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport java.util.Map;
869bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport java.util.regex.Matcher;
879bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport java.util.regex.Pattern;
889bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
899bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport javax.xml.parsers.DocumentBuilder;
909bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyeimport javax.xml.parsers.DocumentBuilderFactory;
9171ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbyeimport javax.xml.xpath.XPathExpressionException;
929bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
939bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye/**
949bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * Retrieves and caches manifest information such as the themes to be used for
959bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * a given activity.
969bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye *
979bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * @see AndroidManifest
989bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye */
999bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbyepublic class ManifestInfo {
1009bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
1019bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * The maximum number of milliseconds to search for an activity in the codebase when
1029bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * attempting to associate layouts with activities in
1039bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * {@link #guessActivity(IFile, String)}
1049bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
1059bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private static final int SEARCH_TIMEOUT_MS = 3000;
1069bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1079bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private final IProject mProject;
1089bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private String mPackage;
1091032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye    private String mManifestTheme;
1109bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private Map<String, String> mActivityThemes;
1119bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private IAbstractFile mManifestFile;
1129bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private long mLastModified;
1137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye    private long mLastChecked;
1147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye    private String mMinSdkName;
1159bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    private int mMinSdk;
1161032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye    private int mTargetSdk;
117ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    private String mApplicationIcon;
118ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    private String mApplicationLabel;
1199bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1209bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
1219bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Qualified name for the per-project non-persistent property storing the
1229bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * {@link ManifestInfo} for this project
1239bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
1249bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    final static QualifiedName MANIFEST_FINDER = new QualifiedName(AdtPlugin.PLUGIN_ID,
1259bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            "manifest"); //$NON-NLS-1$
1269bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1279bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
1289bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Constructs an {@link ManifestInfo} for the given project. Don't use this method;
1299bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * use the {@link #get} factory method instead.
1309bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     *
1319bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @param project project to create an {@link ManifestInfo} for
1329bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
1339bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private ManifestInfo(IProject project) {
1349bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        mProject = project;
1359bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
1369bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1379bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
138140a4978947acc893356cbf06807e912588b3bdfTor Norbye     * Clears the cached manifest information. The next get call on one of the
139140a4978947acc893356cbf06807e912588b3bdfTor Norbye     * properties will cause the information to be refreshed.
140140a4978947acc893356cbf06807e912588b3bdfTor Norbye     */
141140a4978947acc893356cbf06807e912588b3bdfTor Norbye    public void clear() {
142140a4978947acc893356cbf06807e912588b3bdfTor Norbye        mLastChecked = 0;
143140a4978947acc893356cbf06807e912588b3bdfTor Norbye    }
144140a4978947acc893356cbf06807e912588b3bdfTor Norbye
145140a4978947acc893356cbf06807e912588b3bdfTor Norbye    /**
1469bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Returns the {@link ManifestInfo} for the given project
1479bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     *
1489bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @param project the project the finder is associated with
1499bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @return a {@ManifestInfo} for the given project, never null
1509bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
1519bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @NonNull
1529bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    public static ManifestInfo get(IProject project) {
1539bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        ManifestInfo finder = null;
1549bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        try {
1559bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            finder = (ManifestInfo) project.getSessionProperty(MANIFEST_FINDER);
1569bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        } catch (CoreException e) {
1579bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            // Not a problem; we will just create a new one
1589bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
1599bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1609bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        if (finder == null) {
1619bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            finder = new ManifestInfo(project);
1629bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            try {
1639bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                project.setSessionProperty(MANIFEST_FINDER, finder);
1649bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            } catch (CoreException e) {
1659bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                AdtPlugin.log(e, "Can't store ManifestInfo");
1669bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
1679bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
1689bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1699bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        return finder;
1709bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
1719bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1729bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
1739bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Ensure that the package, theme and activity maps are initialized and up to date
1749bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * with respect to the manifest file
1759bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
1769bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private void sync() {
1777dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        // Since each of the accessors call sync(), allow a bunch of immediate
1787dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        // accessors to all bypass the file stat() below
1797dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        long now = System.currentTimeMillis();
1807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        if (now - mLastChecked < 50 && mManifestFile != null) {
1817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye            return;
1827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        }
1837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        mLastChecked = now;
184bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye
1859bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        if (mManifestFile == null) {
1869bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            IFolderWrapper projectFolder = new IFolderWrapper(mProject);
1879bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            mManifestFile = AndroidManifest.getManifest(projectFolder);
1889bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            if (mManifestFile == null) {
1899bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                return;
1909bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
1919bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
1929bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
1939bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        // Check to see if our data is up to date
1949bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        long fileModified = mManifestFile.getModificationStamp();
1959bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        if (fileModified == mLastModified) {
1969bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            // Already have up to date data
1979bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            return;
1989bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
1999bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        mLastModified = fileModified;
2009bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
2019bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        mActivityThemes = new HashMap<String, String>();
2021032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        mManifestTheme = null;
2031032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        mTargetSdk = 1; // Default when not specified
2049bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        mMinSdk = 1; // Default when not specified
205140a4978947acc893356cbf06807e912588b3bdfTor Norbye        mMinSdkName = "1"; // Default when not specified
2069bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        mPackage = ""; //$NON-NLS-1$
207ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye        mApplicationIcon = null;
208ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye        mApplicationLabel = null;
2091032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye
2109bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        Document document = null;
2119bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        try {
2129bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
2139bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            InputSource is = new InputSource(mManifestFile.getContents());
2149bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
2159bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            factory.setNamespaceAware(true);
2169bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            factory.setValidating(false);
2179bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            DocumentBuilder builder = factory.newDocumentBuilder();
2189bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            document = builder.parse(is);
2199bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
2209bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            Element root = document.getDocumentElement();
2219bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            mPackage = root.getAttribute(ATTRIBUTE_PACKAGE);
2229bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            NodeList activities = document.getElementsByTagName(NODE_ACTIVITY);
2239bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            for (int i = 0, n = activities.getLength(); i < n; i++) {
2249bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                Element activity = (Element) activities.item(i);
2259bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                String theme = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME);
2269bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                if (theme != null && theme.length() > 0) {
2279bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    String name = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_NAME);
2289bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    if (name.startsWith(".")  //$NON-NLS-1$
2299bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            && mPackage != null && mPackage.length() > 0) {
2309bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        name = mPackage + name;
2319bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    }
2329bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    mActivityThemes.put(name, theme);
2339bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                }
2349bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
2359bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
236ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye            NodeList applications = root.getElementsByTagName(AndroidManifest.NODE_APPLICATION);
237ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye            if (applications.getLength() > 0) {
238ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                assert applications.getLength() == 1;
239ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                Element application = (Element) applications.item(0);
240ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON)) {
241ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                    mApplicationIcon = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON);
242ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                }
243ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL)) {
244ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                    mApplicationLabel = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL);
245ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye                }
2464a5bddd1c70b6a6a8197d1868d0159f80a0fde77Tor Norbye
24734230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                String defaultTheme = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME);
24834230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                if (defaultTheme != null && !defaultTheme.isEmpty()) {
24934230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                    // From manifest theme documentation:
25034230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                    // "If that attribute is also not set, the default system theme is used."
25134230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                    mManifestTheme = defaultTheme;
25234230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                }
253ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye            }
254ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye
2559bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            // Look up target SDK
25634230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye            NodeList usesSdks = root.getElementsByTagName(NODE_USES_SDK);
25734230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye            if (usesSdks.getLength() > 0) {
25834230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                Element usesSdk = (Element) usesSdks.item(0);
25934230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                mMinSdk = getApiVersion(usesSdk, ATTRIBUTE_MIN_SDK_VERSION, 1);
26034230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye                mTargetSdk = getApiVersion(usesSdk, ATTRIBUTE_TARGET_SDK_VERSION, mMinSdk);
2619bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
26234230d8dd05143b85d520f5e34a5ea4f055e0e96Tor Norbye
2639bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        } catch (SAXException e) {
2649bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            AdtPlugin.log(e, "Malformed manifest");
2659bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        } catch (Exception e) {
2669bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            AdtPlugin.log(e, "Could not read Manifest data");
2679bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
2689bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
2699bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
2707dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye    private int getApiVersion(Element usesSdk, String attribute, int defaultApiLevel) {
2719bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        String valueString = null;
2729bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        if (usesSdk.hasAttributeNS(NS_RESOURCES, attribute)) {
2739bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye            valueString = usesSdk.getAttributeNS(NS_RESOURCES, attribute);
274140a4978947acc893356cbf06807e912588b3bdfTor Norbye            if (attribute.equals(ATTRIBUTE_MIN_SDK_VERSION)) {
275140a4978947acc893356cbf06807e912588b3bdfTor Norbye                mMinSdkName = valueString;
276140a4978947acc893356cbf06807e912588b3bdfTor Norbye            }
2779bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        }
2789bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye
2799bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        if (valueString != null) {
2809bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye            int apiLevel = -1;
2819bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye            try {
2829bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                apiLevel = Integer.valueOf(valueString);
2839bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye            } catch (NumberFormatException e) {
2849bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                // Handle codename
2859bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                if (Sdk.getCurrent() != null) {
2869bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                    IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(
2879bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                            "android-" + valueString); //$NON-NLS-1$
2889bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                    if (target != null) {
2899bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                        // codename future API level is current api + 1
2909bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                        apiLevel = target.getVersion().getApiLevel() + 1;
2919bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                    }
2929bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye                }
2939bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye            }
2949bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye
2959bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye            return apiLevel;
2969bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        }
2979bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye
2989bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        return defaultApiLevel;
2999bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    }
3009bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye
3019bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
3029bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Returns the default package registered in the Android manifest
3039bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     *
3049bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @return the default package registered in the manifest
3059bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
3069bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @NonNull
3079bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    public String getPackage() {
3089bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        sync();
3099bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        return mPackage;
3109bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
3119bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
3129bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
3139bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Returns a map from activity full class names to the corresponding theme style to be
3149bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * used
3159bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     *
3169bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @return a map from activity fqcn to theme style
3179bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
3189bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @NonNull
3199bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    public Map<String, String> getActivityThemes() {
3209bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        sync();
3219bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        return mActivityThemes;
3229bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
3239bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
3249bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
325bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * Returns the manifest theme registered on the application, if any
326bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     *
327bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * @return a manifest theme, or null if none was registered
328bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     */
329bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    @Nullable
3307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye    public String getManifestTheme() {
331bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        sync();
332bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        return mManifestTheme;
333bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    }
334bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye
335bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    /**
3369bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Returns the default theme for this project, by looking at the manifest default
3371032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye     * theme registration, target SDK, rendering target, etc.
3389bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     *
3391032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye     * @param renderingTarget the rendering target use to render the theme, or null
3409bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @param screenSize the screen size to obtain a default theme for, or null if unknown
3419bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @return the theme to use for this project, never null
3429bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
3439bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @NonNull
34447e918dd86afa699e017f498de3349a296e7a20fXavier Ducrohet    public String getDefaultTheme(IAndroidTarget renderingTarget, ScreenSize screenSize) {
3459bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        sync();
3469bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
3471032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        if (mManifestTheme != null) {
3481032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye            return mManifestTheme;
3491032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        }
3501032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye
3511032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        int renderingTargetSdk = mTargetSdk;
3521032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        if (renderingTarget != null) {
3531032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye            renderingTargetSdk = renderingTarget.getVersion().getApiLevel();
3541032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        }
3551032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye
3561032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        int apiLevel = Math.min(mTargetSdk, renderingTargetSdk);
3571032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        // For now this theme works only on XLARGE screens. When it works for all sizes,
3581032d1fc8b5fbc3f8b472505d6b2d9f82741c3e1Tor Norbye        // add that new apiLevel to this check.
3594a5bddd1c70b6a6a8197d1868d0159f80a0fde77Tor Norbye        if (apiLevel >= 11 && screenSize == ScreenSize.XLARGE || apiLevel >= 14) {
36012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye            return ANDROID_STYLE_RESOURCE_PREFIX + "Theme.Holo"; //$NON-NLS-1$
3619bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        } else {
36212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye            return ANDROID_STYLE_RESOURCE_PREFIX + "Theme"; //$NON-NLS-1$
3639bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
3649bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
3659bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
3669bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
367ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     * Returns the application icon, or null
368ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     *
369ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     * @return the application icon, or null
370ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     */
3719bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @Nullable
372ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    public String getApplicationIcon() {
373ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye        sync();
374ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye        return mApplicationIcon;
375ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    }
376ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye
377ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    /**
378ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     * Returns the application label, or null
379ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     *
380ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     * @return the application label, or null
381ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye     */
3829bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @Nullable
383ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    public String getApplicationLabel() {
384ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye        sync();
385ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye        return mApplicationLabel;
386ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    }
387ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye
388ab02e0845abebb9dd36e6e3cf9a2b5ecfb34bdaaTor Norbye    /**
3899bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * Returns the target SDK version
3909bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     *
3919bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * @return the target SDK version
3929bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     */
3939bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    public int getTargetSdkVersion() {
3949bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        sync();
3959bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        return mTargetSdk;
3969bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    }
3979bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye
3989bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    /**
3999bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * Returns the minimum SDK version
4009bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     *
4019bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * @return the minimum SDK version
4029bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     */
4039bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    public int getMinSdkVersion() {
4049bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        sync();
4059bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye        return mMinSdk;
4069bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    }
4079bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye
4089bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    /**
4097dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye     * Returns the minimum SDK version name (which may not be a numeric string, e.g.
410140a4978947acc893356cbf06807e912588b3bdfTor Norbye     * it could be a codename). It will never be null or empty; if no min sdk version
411140a4978947acc893356cbf06807e912588b3bdfTor Norbye     * was specified in the manifest, the return value will be "1". Use
4122e3527410003859ee6bcb3a2971d72bcfdbcc829Tor Norbye     * {@link #getMinSdkCodeName()} instead if you want to look up whether there is a code name.
4137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye     *
4147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye     * @return the minimum SDK version
4157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye     */
416140a4978947acc893356cbf06807e912588b3bdfTor Norbye    @NonNull
4177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye    public String getMinSdkName() {
4187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        sync();
419140a4978947acc893356cbf06807e912588b3bdfTor Norbye        if (mMinSdkName == null || mMinSdkName.isEmpty()) {
420140a4978947acc893356cbf06807e912588b3bdfTor Norbye            mMinSdkName = "1"; //$NON-NLS-1$
421140a4978947acc893356cbf06807e912588b3bdfTor Norbye        }
422140a4978947acc893356cbf06807e912588b3bdfTor Norbye
4237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye        return mMinSdkName;
4247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye    }
4257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye
4267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye    /**
427140a4978947acc893356cbf06807e912588b3bdfTor Norbye     * Returns the code name used for the minimum SDK version, if any.
428140a4978947acc893356cbf06807e912588b3bdfTor Norbye     *
429140a4978947acc893356cbf06807e912588b3bdfTor Norbye     * @return the minSdkVersion codename or null
430140a4978947acc893356cbf06807e912588b3bdfTor Norbye     */
431140a4978947acc893356cbf06807e912588b3bdfTor Norbye    @Nullable
432140a4978947acc893356cbf06807e912588b3bdfTor Norbye    public String getMinSdkCodeName() {
433140a4978947acc893356cbf06807e912588b3bdfTor Norbye        String minSdkName = getMinSdkName();
434140a4978947acc893356cbf06807e912588b3bdfTor Norbye        if (!Character.isDigit(minSdkName.charAt(0))) {
435140a4978947acc893356cbf06807e912588b3bdfTor Norbye            return minSdkName;
436140a4978947acc893356cbf06807e912588b3bdfTor Norbye        }
437140a4978947acc893356cbf06807e912588b3bdfTor Norbye
438140a4978947acc893356cbf06807e912588b3bdfTor Norbye        return null;
439140a4978947acc893356cbf06807e912588b3bdfTor Norbye    }
440140a4978947acc893356cbf06807e912588b3bdfTor Norbye
441140a4978947acc893356cbf06807e912588b3bdfTor Norbye    /**
442d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye     * Returns the {@link IPackageFragment} for the package registered in the manifest
443d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye     *
444d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye     * @return the {@link IPackageFragment} for the package registered in the manifest
445d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye     */
4469bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @Nullable
447d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye    public IPackageFragment getPackageFragment() {
448d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye        sync();
449d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye        try {
450d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye            IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject);
451d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye            if (javaProject != null) {
452d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye                IPackageFragmentRoot root = ManifestInfo.getSourcePackageRoot(javaProject);
453d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye                if (root != null) {
454d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye                    return root.getPackageFragment(mPackage);
455d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye                }
456d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye            }
457d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye        } catch (CoreException e) {
458d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye            AdtPlugin.log(e, null);
459d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye        }
460d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye
461d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye        return null;
462d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye    }
463d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye
464d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye    /**
4659bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Returns the activity associated with the given layout file. Makes an educated guess
4669bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * by peeking at the usages of the R.layout.name field corresponding to the layout and
4679bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * if it finds a usage.
4689bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     *
4699bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @param project the project containing the layout
4709bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @param layoutName the layout whose activity we want to look up
4719bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @param pkg the package containing activities
4729bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @return the activity name
4739bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
4749bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @Nullable
4759bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    public static String guessActivity(IProject project, String layoutName, String pkg) {
476bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        List<String> activities = guessActivities(project, layoutName, pkg);
477bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        if (activities.size() > 0) {
478bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye            return activities.get(0);
479bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        } else {
480bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye            return null;
481bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        }
482bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    }
483bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye
484bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    /**
485bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * Returns the activities associated with the given layout file. Makes an educated guess
486bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * by peeking at the usages of the R.layout.name field corresponding to the layout and
487bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * if it finds a usage.
488bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     *
489bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * @param project the project containing the layout
490bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * @param layoutName the layout whose activity we want to look up
491bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * @param pkg the package containing activities
492bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * @return the activity name
493bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     */
494bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    @NonNull
495bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    public static List<String> guessActivities(IProject project, String layoutName, String pkg) {
496bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        final LinkedList<String> activities = new LinkedList<String>();
4979bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        SearchRequestor requestor = new SearchRequestor() {
4989bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            @Override
4999bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            public void acceptSearchMatch(SearchMatch match) throws CoreException {
5009bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                Object element = match.getElement();
5019bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                if (element instanceof IMethod) {
5029bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    IMethod method = (IMethod) element;
5039bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    IType declaringType = method.getDeclaringType();
5049bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    String fqcn = declaringType.getFullyQualifiedName();
505bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye
506bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                    if ((declaringType.getSuperclassName() != null &&
507bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                            declaringType.getSuperclassName().endsWith("Activity")) //$NON-NLS-1$
508bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                        || method.getElementName().equals("onCreate")) { //$NON-NLS-1$
509bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                        activities.addFirst(fqcn);
510bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                    } else {
511bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                        activities.addLast(fqcn);
5129bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    }
5139bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                }
5149bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
5159bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        };
5169bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        try {
5179bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
5189bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            if (javaProject == null) {
5197e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye                return Collections.emptyList();
5209bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
5219bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            // TODO - look around a bit more and see if we can figure out whether the
5229bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            // call if from within a setContentView call!
5239bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
5249bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            // Search for which java classes call setContentView(R.layout.layoutname);
5259bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            String typeFqcn = "R.layout"; //$NON-NLS-1$
5269bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            if (pkg != null) {
5279bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                typeFqcn = pkg + '.' + typeFqcn;
5289bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
5299bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
5309bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            IType type = javaProject.findType(typeFqcn);
5319bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            if (type != null) {
5329bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                IField field = type.getField(layoutName);
5339bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                if (field.exists()) {
5349bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    SearchPattern pattern = SearchPattern.createPattern(field, REFERENCES);
53557f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye                    try {
53657f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye                        search(requestor, javaProject, pattern);
53757f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye                    } catch (OperationCanceledException canceled) {
53857f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye                        // pass
53957f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye                    }
5409bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                }
5419bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
5429bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        } catch (CoreException e) {
5439bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            AdtPlugin.log(e, null);
5449bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
5459bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
546bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        return activities;
5479bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
5489bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
5499bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
550bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * Returns all activities found in the given project (including those in libraries,
551bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * except for android.jar itself)
552bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     *
553bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * @param project the project
554bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     * @return a list of activity classes as fully qualified class names
555bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye     */
556bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    @SuppressWarnings("restriction") // BinaryType
557bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    @NonNull
558bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    public static List<String> getProjectActivities(IProject project) {
559bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        final List<String> activities = new ArrayList<String>();
560bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        try {
561bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye            final IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
562bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye            if (javaProject != null) {
563bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                IType[] activityTypes = new IType[0];
56412d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye                IType activityType = javaProject.findType(CLASS_ACTIVITY);
565bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                if (activityType != null) {
566bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                    ITypeHierarchy hierarchy =
567bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                        activityType.newTypeHierarchy(javaProject, new NullProgressMonitor());
568bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                    activityTypes = hierarchy.getAllSubtypes(activityType);
569bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                    for (IType type : activityTypes) {
570bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                        if (type instanceof BinaryType && (type.getClassFile() == null
571bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                                    || type.getClassFile().getResource() == null)) {
572bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                            continue;
573bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                        }
574bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                        activities.add(type.getFullyQualifiedName());
575bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                    }
576bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye                }
577bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye            }
578bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        } catch (CoreException e) {
579bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye            AdtPlugin.log(e, null);
580bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        }
581bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye
582bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye        return activities;
583bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    }
584bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye
585bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye
586bc5879056fba2eb616dea06e6191bdc218b594c0Tor Norbye    /**
5879bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Returns the activity associated with the given layout file.
5889bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * <p>
5899bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * This is an alternative to {@link #guessActivity(IFile, String)}. Whereas
5909bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * guessActivity simply looks for references to "R.layout.foo", this method searches
5919bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * for all usages of Activity#setContentView(int), and for each match it looks up the
5929bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * corresponding call text (such as "setContentView(R.layout.foo)"). From this it uses
5939bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * a regexp to pull out "foo" from this, and stores the association that layout "foo"
5949bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * is associated with the activity class that contained the setContentView call.
5959bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * <p>
5969bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * This has two potential advantages:
5979bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * <ol>
5989bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * <li>It can be faster. We do the reference search -once-, and we've built a map of
5999bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * all the layout-to-activity mappings which we can then immediately look up other
6009bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * layouts for, which is particularly useful at startup when we have to compute the
6019bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * layout activity associations to populate the theme choosers.
6029bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * <li>It can be more accurate. Just because an activity references an "R.layout.foo"
6039bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * field doesn't mean it's setting it as a content view.
6049bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * </ol>
6059bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * However, this second advantage is also its chief problem. There are some common
6069bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * code constructs which means that the associated layout is not explicitly referenced
6079bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * in a direct setContentView call; on a couple of sample projects I tested I found
6089bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * patterns like for example "setContentView(v)" where "v" had been computed earlier.
6099bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Therefore, for now we're going to stick with the more general approach of just
6109bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * looking up each field when needed. We're keeping the code around, though statically
6119bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * compiled out with the "if (false)" construct below in case we revisit this.
6129bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     *
6139bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @param layoutFile the layout whose activity we want to look up
6149bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * @return the activity name
6159bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
6169bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    @SuppressWarnings("all")
6179bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @Nullable
6189bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    public String guessActivityBySetContentView(String layoutName) {
6199bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        if (false) {
6209bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            // These should be fields
6219bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            final Pattern LAYOUT_FIELD_PATTERN =
6229bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                Pattern.compile("R\\.layout\\.([a-z0-9_]+)"); //$NON-NLS-1$
6239bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            Map<String, String> mUsages = null;
6249bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
6259bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            sync();
6269bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            if (mUsages == null) {
6279bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                final Map<String, String> usages = new HashMap<String, String>();
6289bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                mUsages = usages;
6299bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                SearchRequestor requestor = new SearchRequestor() {
6309bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    @Override
6319bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    public void acceptSearchMatch(SearchMatch match) throws CoreException {
6329bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        Object element = match.getElement();
6339bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        if (element instanceof IMethod) {
6349bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            IMethod method = (IMethod) element;
6359bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            IType declaringType = method.getDeclaringType();
6369bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            String fqcn = declaringType.getFullyQualifiedName();
6379bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            IDocumentProvider provider = new TextFileDocumentProvider();
6389bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            IResource resource = match.getResource();
6399bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            try {
6409bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                provider.connect(resource);
6419bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                IDocument document = provider.getDocument(resource);
6429bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                if (document != null) {
6439bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                    String matchText = document.get(match.getOffset(),
6449bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                            match.getLength());
6459bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                    Matcher matcher = LAYOUT_FIELD_PATTERN.matcher(matchText);
6469bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                    if (matcher.find()) {
6479bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                        usages.put(matcher.group(1), fqcn);
6489bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                    }
6499bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                }
6509bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            } catch (Exception e) {
6519bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                AdtPlugin.log(e, "Can't find range information for %1$s",
6529bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                        resource.getName());
6539bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            } finally {
6549bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                provider.disconnect(resource);
6559bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            }
6569bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        }
6579bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    }
6589bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                };
6599bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                try {
6609bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject);
6619bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    if (javaProject == null) {
6629bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        return null;
6639bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    }
6649bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
6659bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    // Search for which java classes call setContentView(R.layout.layoutname);
6669bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    String typeFqcn = "R.layout"; //$NON-NLS-1$
6679bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    if (mPackage != null) {
6689bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        typeFqcn = mPackage + '.' + typeFqcn;
6699bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    }
6709bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
67112d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye                    IType activityType = javaProject.findType(CLASS_ACTIVITY);
6729bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    if (activityType != null) {
6739bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        IMethod method = activityType.getMethod(
6749bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                "setContentView", new String[] {"I"}); //$NON-NLS-1$ //$NON-NLS-2$
6759bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        if (method.exists()) {
6769bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            SearchPattern pattern = SearchPattern.createPattern(method,
6779bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                                    REFERENCES);
6789bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                            search(requestor, javaProject, pattern);
6799bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                        }
6809bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    }
6819bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                } catch (CoreException e) {
6829bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    AdtPlugin.log(e, null);
6839bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                }
6849bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
6859bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
6869bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            return mUsages.get(layoutName);
6879bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
6889bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
6899bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        return null;
6909bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
6919bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
6929bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /**
6939bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * Performs a search using the given pattern, scope and handler. The search will abort
6949bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     * if it takes longer than {@link #SEARCH_TIMEOUT_MS} milliseconds.
6959bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye     */
6969bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private static void search(SearchRequestor requestor, IJavaProject javaProject,
6979bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            SearchPattern pattern) throws CoreException {
6989bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        // Find the package fragment specified in the manifest; the activities should
6999bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        // live there.
7009bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        IJavaSearchScope scope = createPackageScope(javaProject);
7019bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
7029bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        SearchParticipant[] participants = new SearchParticipant[] {
7039bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            SearchEngine.getDefaultSearchParticipant()
7049bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        };
7059bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        SearchEngine engine = new SearchEngine();
7069bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
7079bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        final long searchStart = System.currentTimeMillis();
7089bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        NullProgressMonitor monitor = new NullProgressMonitor() {
7099bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            private boolean mCancelled;
7109bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            @Override
7119bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            public void internalWorked(double work) {
7129bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                long searchEnd = System.currentTimeMillis();
7139bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                if (searchEnd - searchStart > SEARCH_TIMEOUT_MS) {
7149bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    mCancelled = true;
7159bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                }
7169bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
7179bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
7189bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            @Override
7199bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            public boolean isCanceled() {
7209bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                return mCancelled;
7219bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
7229bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        };
7239bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        engine.search(pattern, participants, scope, requestor, monitor);
7249bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
7259bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
7269bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    /** Creates a package search scope for the first package root in the given java project */
7279bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    private static IJavaSearchScope createPackageScope(IJavaProject javaProject) {
7289bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        IPackageFragmentRoot packageRoot = getSourcePackageRoot(javaProject);
7299bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
7309bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        IJavaSearchScope scope;
7319bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        if (packageRoot != null) {
7329bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            IJavaElement[] scopeElements = new IJavaElement[] { packageRoot };
7339bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            scope = SearchEngine.createJavaSearchScope(scopeElements);
7349bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        } else {
735b3ab7ef8a24a64bcd6f347e8e03bc647c12eb24bTor Norbye            scope = SearchEngine.createWorkspaceScope();
7369bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
7379bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        return scope;
7389bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
7399bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
7409bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    /**
7419bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * Returns the first package root for the given java project
7429bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     *
7439bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * @param javaProject the project to search in
7449bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * @return the first package root, or null
7459bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     */
7469bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @Nullable
747d9cceddf012ef3284cf939773edc7b6e291fba21Tor Norbye    public static IPackageFragmentRoot getSourcePackageRoot(IJavaProject javaProject) {
7489bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        IPackageFragmentRoot packageRoot = null;
7499bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        List<IPath> sources = BaseProjectHelper.getSourceClasspaths(javaProject);
7509bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye
7519bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        IWorkspace workspace = ResourcesPlugin.getWorkspace();
7529bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        for (IPath path : sources) {
7539bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            IResource firstSource = workspace.getRoot().findMember(path);
7549bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            if (firstSource != null) {
7559bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                packageRoot = javaProject.getPackageFragmentRoot(firstSource);
7569bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                if (packageRoot != null) {
7579bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                    break;
7589bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye                }
7599bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye            }
7609bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        }
7619bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye        return packageRoot;
7629bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye    }
76371ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye
76471ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye    /**
76571ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye     * Computes the minimum SDK and target SDK versions for the project
76671ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye     *
7679bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye     * @param project the project to look up the versions for
76871ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye     * @return a pair of (minimum SDK, target SDK) versions, never null
76971ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye     */
7709bfb05e9d9ea4b2b969e50c3096e2fdb95653648Tor Norbye    @NonNull
77171ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye    public static Pair<Integer, Integer> computeSdkVersions(IProject project) {
77271ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye        int mMinSdkVersion = 1;
77371ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye        int mTargetSdkVersion = 1;
77471ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye
77571ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye        IAbstractFile manifestFile = AndroidManifest.getManifest(new IFolderWrapper(project));
77671ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye        if (manifestFile != null) {
77771ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye            try {
77871ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                Object value = AndroidManifest.getMinSdkVersion(manifestFile);
77971ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                mMinSdkVersion = 1; // Default case if missing
78071ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                if (value instanceof Integer) {
78171ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                    mMinSdkVersion = ((Integer) value).intValue();
78271ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                } else if (value instanceof String) {
78371ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                    // handle codename, only if we can resolve it.
78471ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                    if (Sdk.getCurrent() != null) {
78571ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                        IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(
78671ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                                "android-" + value); //$NON-NLS-1$
78771ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                        if (target != null) {
78871ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                            // codename future API level is current api + 1
78971ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                            mMinSdkVersion = target.getVersion().getApiLevel() + 1;
79071ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                        }
79171ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                    }
79271ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                }
79371ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye
79471ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                Integer i = AndroidManifest.getTargetSdkVersion(manifestFile);
79571ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                if (i == null) {
79671ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                    mTargetSdkVersion = mMinSdkVersion;
79771ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                } else {
79871ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                    mTargetSdkVersion = i.intValue();
79971ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                }
80071ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye            } catch (XPathExpressionException e) {
80171ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                // do nothing we'll use 1 below.
80271ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye            } catch (StreamException e) {
80371ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye                // do nothing we'll use 1 below.
80471ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye            }
80571ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye        }
80671ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye
80771ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye        return Pair.of(mMinSdkVersion, mTargetSdkVersion);
80871ca2b70f4c4d463be013ebf643d363b92ebd5f7Tor Norbye    }
8099bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye}
810