Home | History | Annotate | Download | only in xml
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.sdklib.xml;
     18 
     19 import com.android.sdklib.resources.Keyboard;
     20 import com.android.sdklib.resources.Navigation;
     21 import com.android.sdklib.resources.TouchScreen;
     22 
     23 import java.util.ArrayList;
     24 import java.util.Set;
     25 import java.util.TreeSet;
     26 
     27 /**
     28  * Class containing the manifest info obtained during the parsing.
     29  */
     30 public final class ManifestData {
     31 
     32     /**
     33      * Value returned by {@link #getMinSdkVersion()} when the value of the minSdkVersion attribute
     34      * in the manifest is a codename and not an integer value.
     35      */
     36     public final static int MIN_SDK_CODENAME = 0;
     37 
     38     /**
     39      * Value returned by {@link #getGlEsVersion()} when there are no <uses-feature> node with the
     40      * attribute glEsVersion set.
     41      */
     42     public final static int GL_ES_VERSION_NOT_SET = -1;
     43 
     44     /** Application package */
     45     String mPackage;
     46     /** Application version Code, null if the attribute is not present. */
     47     Integer mVersionCode = null;
     48     /** List of all activities */
     49     final ArrayList<Activity> mActivities = new ArrayList<Activity>();
     50     /** Launcher activity */
     51     Activity mLauncherActivity = null;
     52     /** list of process names declared by the manifest */
     53     Set<String> mProcesses = null;
     54     /** debuggable attribute value. If null, the attribute is not present. */
     55     Boolean mDebuggable = null;
     56     /** API level requirement. if null the attribute was not present. */
     57     private String mMinSdkVersionString = null;
     58     /** API level requirement. Default is 1 even if missing. If value is a codename, then it'll be
     59      * 0 instead. */
     60     private int mMinSdkVersion = 1;
     61     private int mTargetSdkVersion = 0;
     62     /** List of all instrumentations declared by the manifest */
     63     final ArrayList<Instrumentation> mInstrumentations =
     64         new ArrayList<Instrumentation>();
     65     /** List of all libraries in use declared by the manifest */
     66     final ArrayList<UsesLibrary> mLibraries = new ArrayList<UsesLibrary>();
     67     /** List of all feature in use declared by the manifest */
     68     final ArrayList<UsesFeature> mFeatures = new ArrayList<UsesFeature>();
     69 
     70     SupportsScreens mSupportsScreensFromManifest;
     71     SupportsScreens mSupportsScreensValues;
     72     UsesConfiguration mUsesConfiguration;
     73 
     74     /**
     75      * Instrumentation info obtained from manifest
     76      */
     77     public final static class Instrumentation {
     78         private final String mName;
     79         private final String mTargetPackage;
     80 
     81         Instrumentation(String name, String targetPackage) {
     82             mName = name;
     83             mTargetPackage = targetPackage;
     84         }
     85 
     86         /**
     87          * Returns the fully qualified instrumentation class name
     88          */
     89         public String getName() {
     90             return mName;
     91         }
     92 
     93         /**
     94          * Returns the Android app package that is the target of this instrumentation
     95          */
     96         public String getTargetPackage() {
     97             return mTargetPackage;
     98         }
     99     }
    100 
    101     /**
    102      * Activity info obtained from the manifest.
    103      */
    104     public final static class Activity {
    105         private final String mName;
    106         private final boolean mIsExported;
    107         private boolean mHasAction = false;
    108         private boolean mHasMainAction = false;
    109         private boolean mHasLauncherCategory = false;
    110 
    111         public Activity(String name, boolean exported) {
    112             mName = name;
    113             mIsExported = exported;
    114         }
    115 
    116         public String getName() {
    117             return mName;
    118         }
    119 
    120         public boolean isExported() {
    121             return mIsExported;
    122         }
    123 
    124         public boolean hasAction() {
    125             return mHasAction;
    126         }
    127 
    128         public boolean isHomeActivity() {
    129             return mHasMainAction && mHasLauncherCategory;
    130         }
    131 
    132         void setHasAction(boolean hasAction) {
    133             mHasAction = hasAction;
    134         }
    135 
    136         /** If the activity doesn't yet have a filter set for the launcher, this resets both
    137          * flags. This is to handle multiple intent-filters where one could have the valid
    138          * action, and another one of the valid category.
    139          */
    140         void resetIntentFilter() {
    141             if (isHomeActivity() == false) {
    142                 mHasMainAction = mHasLauncherCategory = false;
    143             }
    144         }
    145 
    146         void setHasMainAction(boolean hasMainAction) {
    147             mHasMainAction = hasMainAction;
    148         }
    149 
    150         void setHasLauncherCategory(boolean hasLauncherCategory) {
    151             mHasLauncherCategory = hasLauncherCategory;
    152         }
    153     }
    154 
    155     /**
    156      * Class representing the <code>supports-screens</code> node in the manifest.
    157      * By default, all the getters will return null if there was no value defined in the manifest.
    158      *
    159      * To get an instance with all the actual values, use {@link #resolveSupportsScreensValues(int)}
    160      */
    161     public final static class SupportsScreens {
    162         private Boolean mResizeable;
    163         private Boolean mAnyDensity;
    164         private Boolean mSmallScreens;
    165         private Boolean mNormalScreens;
    166         private Boolean mLargeScreens;
    167 
    168         public SupportsScreens() {
    169         }
    170 
    171         /**
    172          * Instantiate an instance from a string. The string must have been created with
    173          * {@link #getEncodedValues()}.
    174          * @param value the string.
    175          */
    176         public SupportsScreens(String value) {
    177             String[] values = value.split("\\|");
    178 
    179             mAnyDensity = Boolean.valueOf(values[0]);
    180             mResizeable = Boolean.valueOf(values[1]);
    181             mSmallScreens = Boolean.valueOf(values[2]);
    182             mNormalScreens = Boolean.valueOf(values[3]);
    183             mLargeScreens = Boolean.valueOf(values[4]);
    184         }
    185 
    186         /**
    187          * Returns an instance of {@link SupportsScreens} initialized with the default values
    188          * based on the given targetSdkVersion.
    189          * @param targetSdkVersion
    190          */
    191         public static SupportsScreens getDefaultValues(int targetSdkVersion) {
    192             SupportsScreens result = new SupportsScreens();
    193 
    194             result.mNormalScreens = Boolean.TRUE;
    195             // Screen size and density became available in Android 1.5/API3, so before that
    196             // non normal screens were not supported by default. After they are considered
    197             // supported.
    198             result.mResizeable = result.mAnyDensity = result.mSmallScreens = result.mLargeScreens =
    199                 targetSdkVersion <= 3 ? Boolean.FALSE : Boolean.TRUE;
    200 
    201             return result;
    202         }
    203 
    204         /**
    205          * Returns a version of the receiver for which all values have been set, even if they
    206          * were not present in the manifest.
    207          * @param targetSdkVersion the target api level of the app, since this has an effect
    208          * on default values.
    209          */
    210         public SupportsScreens resolveSupportsScreensValues(int targetSdkVersion) {
    211             SupportsScreens result = getDefaultValues(targetSdkVersion);
    212 
    213             // Override the default with the existing values:
    214             if (mResizeable != null) result.mResizeable = mResizeable;
    215             if (mAnyDensity != null) result.mAnyDensity = mAnyDensity;
    216             if (mSmallScreens != null) result.mSmallScreens = mSmallScreens;
    217             if (mNormalScreens != null) result.mNormalScreens = mNormalScreens;
    218             if (mLargeScreens != null) result.mLargeScreens = mLargeScreens;
    219 
    220             return result;
    221         }
    222 
    223         /**
    224          * returns the value of the <code>resizeable</code> attribute or null if not present.
    225          */
    226         public Boolean getResizeable() {
    227             return mResizeable;
    228         }
    229 
    230         void setResizeable(Boolean resizeable) {
    231             mResizeable = getConstantBoolean(resizeable);
    232         }
    233 
    234         /**
    235          * returns the value of the <code>anyDensity</code> attribute or null if not present.
    236          */
    237         public Boolean getAnyDensity() {
    238             return mAnyDensity;
    239         }
    240 
    241         void setAnyDensity(Boolean anyDensity) {
    242             mAnyDensity = getConstantBoolean(anyDensity);
    243         }
    244 
    245         /**
    246          * returns the value of the <code>smallScreens</code> attribute or null if not present.
    247          */
    248         public Boolean getSmallScreens() {
    249             return mSmallScreens;
    250         }
    251 
    252         void setSmallScreens(Boolean smallScreens) {
    253             mSmallScreens = getConstantBoolean(smallScreens);
    254         }
    255 
    256         /**
    257          * returns the value of the <code>normalScreens</code> attribute or null if not present.
    258          */
    259         public Boolean getNormalScreens() {
    260             return mNormalScreens;
    261         }
    262 
    263         void setNormalScreens(Boolean normalScreens) {
    264             mNormalScreens = getConstantBoolean(normalScreens);
    265         }
    266 
    267         /**
    268          * returns the value of the <code>largeScreens</code> attribute or null if not present.
    269          */
    270         public Boolean getLargeScreens() {
    271             return mLargeScreens;
    272         }
    273 
    274         void setLargeScreens(Boolean largeScreens) {
    275             mLargeScreens = getConstantBoolean(largeScreens);
    276         }
    277 
    278         /**
    279          * Returns either {@link Boolean#TRUE} or {@link Boolean#FALSE} based on the value of
    280          * the given Boolean object.
    281          */
    282         private Boolean getConstantBoolean(Boolean v) {
    283             if (v != null) {
    284                 if (v.equals(Boolean.TRUE)) {
    285                     return Boolean.TRUE;
    286                 } else {
    287                     return Boolean.FALSE;
    288                 }
    289             }
    290 
    291             return null;
    292         }
    293 
    294         @Override
    295         public boolean equals(Object obj) {
    296             if (obj instanceof SupportsScreens) {
    297                 SupportsScreens support = (SupportsScreens)obj;
    298                 // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
    299                 // (or null), we can simply check they are identical and not bother with
    300                 // calling equals (which would require to check != null.
    301                 // see #getConstanntBoolean(Boolean)
    302                 return mResizeable == support.mResizeable && mAnyDensity == support.mAnyDensity &&
    303                         mSmallScreens == support.mSmallScreens &&
    304                         mNormalScreens == support.mNormalScreens &&
    305                         mLargeScreens == support.mLargeScreens;
    306             }
    307 
    308             return false;
    309         }
    310 
    311         /**
    312          * Returns true if the two instances support the same screen sizes.
    313          * This is similar to {@link #equals(Object)} except that it ignores the values of
    314          * {@link #getAnyDensity()} and {@link #getResizeable()}.
    315          * @param support the other instance to compare to.
    316          * @return true if the two instances support the same screen sizes.
    317          */
    318         public boolean hasSameScreenSupportAs(SupportsScreens support) {
    319             // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
    320             // (or null), we can simply check they are identical and not bother with
    321             // calling equals (which would require to check != null.
    322             // see #getConstanntBoolean(Boolean)
    323 
    324             // This only checks that matter here are the screen sizes. resizeable and anyDensity
    325             // are not checked.
    326             return  mSmallScreens == support.mSmallScreens &&
    327                     mNormalScreens == support.mNormalScreens &&
    328                     mLargeScreens == support.mLargeScreens;
    329         }
    330 
    331         /**
    332          * Returns true if the two instances have strictly different screen size support.
    333          * This means that there is no screen size that they both support.
    334          * @param support the other instance to compare to.
    335          * @return true if they are stricly different.
    336          */
    337         public boolean hasStrictlyDifferentScreenSupportAs(SupportsScreens support) {
    338             // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
    339             // (or null), we can simply check they are identical and not bother with
    340             // calling equals (which would require to check != null.
    341             // see #getConstanntBoolean(Boolean)
    342 
    343             // This only checks that matter here are the screen sizes. resizeable and anyDensity
    344             // are not checked.
    345             return (mSmallScreens != Boolean.TRUE || support.mSmallScreens != Boolean.TRUE) &&
    346                     (mNormalScreens != Boolean.TRUE || support.mNormalScreens != Boolean.TRUE) &&
    347                     (mLargeScreens != Boolean.TRUE || support.mLargeScreens != Boolean.TRUE);
    348         }
    349 
    350         /**
    351          * Comparison of 2 Supports-screens. This only uses screen sizes (ignores resizeable and
    352          * anyDensity), and considers that
    353          * {@link #hasStrictlyDifferentScreenSupportAs(SupportsScreens)} returns true and
    354          * {@link #overlapWith(SupportsScreens)} returns false.
    355          * @throws IllegalArgumentException if the two instanced are not strictly different or
    356          * overlap each other
    357          * @see #hasStrictlyDifferentScreenSupportAs(SupportsScreens)
    358          * @see #overlapWith(SupportsScreens)
    359          */
    360         public int compareScreenSizesWith(SupportsScreens o) {
    361             if (hasStrictlyDifferentScreenSupportAs(o) == false) {
    362                 throw new IllegalArgumentException("The two instances are not strictly different.");
    363             }
    364             if (overlapWith(o)) {
    365                 throw new IllegalArgumentException("The two instances overlap each other.");
    366             }
    367 
    368             int comp = mLargeScreens.compareTo(o.mLargeScreens);
    369             if (comp != 0) return comp;
    370 
    371             comp = mNormalScreens.compareTo(o.mNormalScreens);
    372             if (comp != 0) return comp;
    373 
    374             comp = mSmallScreens.compareTo(o.mSmallScreens);
    375             if (comp != 0) return comp;
    376 
    377             return 0;
    378         }
    379 
    380         /**
    381          * Returns a string encoding of the content of the instance. This string can be used to
    382          * instantiate a {@link SupportsScreens} object through
    383          * {@link #SupportsScreens(String)}.
    384          */
    385         public String getEncodedValues() {
    386             return String.format("%1$s|%2$s|%3$s|%4$s|%5$s",
    387                     mAnyDensity, mResizeable, mSmallScreens, mNormalScreens, mLargeScreens);
    388         }
    389 
    390         @Override
    391         public String toString() {
    392             StringBuilder sb = new StringBuilder();
    393 
    394             boolean alreadyOutputSomething = false;
    395 
    396             if (Boolean.TRUE.equals(mSmallScreens)) {
    397                 alreadyOutputSomething = true;
    398                 sb.append("small");
    399             }
    400 
    401             if (Boolean.TRUE.equals(mNormalScreens)) {
    402                 if (alreadyOutputSomething) {
    403                     sb.append(", ");
    404                 }
    405                 alreadyOutputSomething = true;
    406                 sb.append("normal");
    407             }
    408 
    409             if (Boolean.TRUE.equals(mLargeScreens)) {
    410                 if (alreadyOutputSomething) {
    411                     sb.append(", ");
    412                 }
    413                 alreadyOutputSomething = true;
    414                 sb.append("large");
    415             }
    416 
    417             if (alreadyOutputSomething == false) {
    418                 sb.append("<none>");
    419             }
    420 
    421             return sb.toString();
    422         }
    423 
    424         /**
    425          * Returns true if the two instance overlap with each other.
    426          * This can happen if one instances supports a size, when the other instance doesn't while
    427          * supporting a size above and a size below.
    428          * @param otherSS the other supports-screens to compare to.
    429          */
    430         public boolean overlapWith(SupportsScreens otherSS) {
    431             if (mSmallScreens == null || mNormalScreens == null || mLargeScreens == null ||
    432                     otherSS.mSmallScreens == null || otherSS.mNormalScreens == null ||
    433                     otherSS.mLargeScreens == null) {
    434                 throw new IllegalArgumentException("Some screen sizes Boolean are not initialized");
    435             }
    436 
    437             if (mSmallScreens == Boolean.TRUE && mNormalScreens == Boolean.FALSE &&
    438                     mLargeScreens == Boolean.TRUE) {
    439                 return otherSS.mNormalScreens == Boolean.TRUE;
    440             }
    441 
    442             if (otherSS.mSmallScreens == Boolean.TRUE && otherSS.mNormalScreens == Boolean.FALSE &&
    443                     otherSS.mLargeScreens == Boolean.TRUE) {
    444                 return mNormalScreens == Boolean.TRUE;
    445             }
    446 
    447             return false;
    448         }
    449     }
    450 
    451     /**
    452      * Class representing a <code>uses-library</code> node in the manifest.
    453      */
    454     public final static class UsesLibrary {
    455         String mName;
    456         Boolean mRequired = Boolean.TRUE; // default is true even if missing
    457 
    458         public String getName() {
    459             return mName;
    460         }
    461 
    462         public Boolean getRequired() {
    463             return mRequired;
    464         }
    465     }
    466 
    467     /**
    468      * Class representing a <code>uses-feature</code> node in the manifest.
    469      */
    470     public final static class UsesFeature {
    471         String mName;
    472         int mGlEsVersion = 0;
    473         Boolean mRequired = Boolean.TRUE;  // default is true even if missing
    474 
    475         public String getName() {
    476             return mName;
    477         }
    478 
    479         /**
    480          * Returns the value of the glEsVersion attribute, or 0 if the attribute was not present.
    481          */
    482         public int getGlEsVersion() {
    483             return mGlEsVersion;
    484         }
    485 
    486         public Boolean getRequired() {
    487             return mRequired;
    488         }
    489     }
    490 
    491     /**
    492      * Class representing the <code>uses-configuration</code> node in the manifest.
    493      */
    494     public final static class UsesConfiguration {
    495         Boolean mReqFiveWayNav;
    496         Boolean mReqHardKeyboard;
    497         Keyboard mReqKeyboardType;
    498         TouchScreen mReqTouchScreen;
    499         Navigation mReqNavigation;
    500 
    501         /**
    502          * returns the value of the <code>reqFiveWayNav</code> attribute or null if not present.
    503          */
    504         public Boolean getReqFiveWayNav() {
    505             return mReqFiveWayNav;
    506         }
    507 
    508         /**
    509          * returns the value of the <code>reqNavigation</code> attribute or null if not present.
    510          */
    511         public Navigation getReqNavigation() {
    512             return mReqNavigation;
    513         }
    514 
    515         /**
    516          * returns the value of the <code>reqHardKeyboard</code> attribute or null if not present.
    517          */
    518         public Boolean getReqHardKeyboard() {
    519             return mReqHardKeyboard;
    520         }
    521 
    522         /**
    523          * returns the value of the <code>reqKeyboardType</code> attribute or null if not present.
    524          */
    525         public Keyboard getReqKeyboardType() {
    526             return mReqKeyboardType;
    527         }
    528 
    529         /**
    530          * returns the value of the <code>reqTouchScreen</code> attribute or null if not present.
    531          */
    532         public TouchScreen getReqTouchScreen() {
    533             return mReqTouchScreen;
    534         }
    535     }
    536 
    537     /**
    538      * Returns the package defined in the manifest, if found.
    539      * @return The package name or null if not found.
    540      */
    541     public String getPackage() {
    542         return mPackage;
    543     }
    544 
    545     /**
    546      * Returns the versionCode value defined in the manifest, if found, null otherwise.
    547      * @return the versionCode or null if not found.
    548      */
    549     public Integer getVersionCode() {
    550         return mVersionCode;
    551     }
    552 
    553     /**
    554      * Returns the list of activities found in the manifest.
    555      * @return An array of fully qualified class names, or empty if no activity were found.
    556      */
    557     public Activity[] getActivities() {
    558         return mActivities.toArray(new Activity[mActivities.size()]);
    559     }
    560 
    561     /**
    562      * Returns the name of one activity found in the manifest, that is configured to show
    563      * up in the HOME screen.
    564      * @return the fully qualified name of a HOME activity or null if none were found.
    565      */
    566     public Activity getLauncherActivity() {
    567         return mLauncherActivity;
    568     }
    569 
    570     /**
    571      * Returns the list of process names declared by the manifest.
    572      */
    573     public String[] getProcesses() {
    574         if (mProcesses != null) {
    575             return mProcesses.toArray(new String[mProcesses.size()]);
    576         }
    577 
    578         return new String[0];
    579     }
    580 
    581     /**
    582      * Returns the <code>debuggable</code> attribute value or null if it is not set.
    583      */
    584     public Boolean getDebuggable() {
    585         return mDebuggable;
    586     }
    587 
    588     /**
    589      * Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
    590      */
    591     public String getMinSdkVersionString() {
    592         return mMinSdkVersionString;
    593     }
    594 
    595     /**
    596      * Sets the value of the <code>minSdkVersion</code> attribute.
    597      * @param minSdkVersion the string value of the attribute in the manifest.
    598      */
    599     public void setMinSdkVersionString(String minSdkVersion) {
    600         mMinSdkVersionString = minSdkVersion;
    601         if (mMinSdkVersionString != null) {
    602             try {
    603                 mMinSdkVersion = Integer.parseInt(mMinSdkVersionString);
    604             } catch (NumberFormatException e) {
    605                 mMinSdkVersion = MIN_SDK_CODENAME;
    606             }
    607         }
    608     }
    609 
    610     /**
    611      * Returns the <code>minSdkVersion</code> attribute, or 0 if it's not set or is a codename.
    612      * @see #getMinSdkVersionString()
    613      */
    614     public int getMinSdkVersion() {
    615         return mMinSdkVersion;
    616     }
    617 
    618 
    619     /**
    620      * Sets the value of the <code>minSdkVersion</code> attribute.
    621      * @param targetSdkVersion the string value of the attribute in the manifest.
    622      */
    623     public void setTargetSdkVersionString(String targetSdkVersion) {
    624         if (targetSdkVersion != null) {
    625             try {
    626                 mTargetSdkVersion = Integer.parseInt(targetSdkVersion);
    627             } catch (NumberFormatException e) {
    628                 // keep the value at 0.
    629             }
    630         }
    631     }
    632 
    633     /**
    634      * Returns the <code>targetSdkVersion</code> attribute, or the same value as
    635      * {@link #getMinSdkVersion()} if it was not set in the manifest.
    636      */
    637     public int getTargetSdkVersion() {
    638         if (mTargetSdkVersion == 0) {
    639             return getMinSdkVersion();
    640         }
    641 
    642         return mTargetSdkVersion;
    643     }
    644 
    645     /**
    646      * Returns the list of instrumentations found in the manifest.
    647      * @return An array of {@link Instrumentation}, or empty if no instrumentations were
    648      * found.
    649      */
    650     public Instrumentation[] getInstrumentations() {
    651         return mInstrumentations.toArray(new Instrumentation[mInstrumentations.size()]);
    652     }
    653 
    654     /**
    655      * Returns the list of libraries in use found in the manifest.
    656      * @return An array of {@link UsesLibrary} objects, or empty if no libraries were found.
    657      */
    658     public UsesLibrary[] getUsesLibraries() {
    659         return mLibraries.toArray(new UsesLibrary[mLibraries.size()]);
    660     }
    661 
    662     /**
    663      * Returns the list of features in use found in the manifest.
    664      * @return An array of {@link UsesFeature} objects, or empty if no libraries were found.
    665      */
    666     public UsesFeature[] getUsesFeatures() {
    667         return mFeatures.toArray(new UsesFeature[mFeatures.size()]);
    668     }
    669 
    670     /**
    671      * Returns the glEsVersion from a <uses-feature> or {@link #GL_ES_VERSION_NOT_SET} if not set.
    672      */
    673     public int getGlEsVersion() {
    674         for (UsesFeature feature : mFeatures) {
    675             if (feature.mGlEsVersion > 0) {
    676                 return feature.mGlEsVersion;
    677             }
    678         }
    679         return GL_ES_VERSION_NOT_SET;
    680     }
    681 
    682     /**
    683      * Returns the {@link SupportsScreens} object representing the <code>supports-screens</code>
    684      * node, or null if the node doesn't exist at all.
    685      * Some values in the {@link SupportsScreens} instance maybe null, indicating that they
    686      * were not present in the manifest. To get an instance that contains the values, as seen
    687      * by the Android platform when the app is running, use {@link #getSupportsScreensValues()}.
    688      */
    689     public SupportsScreens getSupportsScreensFromManifest() {
    690         return mSupportsScreensFromManifest;
    691     }
    692 
    693     /**
    694      * Returns an always non-null instance of {@link SupportsScreens} that's been initialized with
    695      * the default values, and the values from the manifest.
    696      * The default values depends on the manifest values for minSdkVersion and targetSdkVersion.
    697      */
    698     public synchronized SupportsScreens getSupportsScreensValues() {
    699         if (mSupportsScreensValues == null) {
    700             if (mSupportsScreensFromManifest == null) {
    701                 mSupportsScreensValues = SupportsScreens.getDefaultValues(getTargetSdkVersion());
    702             } else {
    703                 // get a SupportsScreen that replace the missing values with default values.
    704                 mSupportsScreensValues = mSupportsScreensFromManifest.resolveSupportsScreensValues(
    705                         getTargetSdkVersion());
    706             }
    707         }
    708 
    709         return mSupportsScreensValues;
    710     }
    711 
    712     /**
    713      * Returns the {@link UsesConfiguration} object representing the <code>uses-configuration</code>
    714      * node, or null if the node doesn't exist at all.
    715      */
    716     public UsesConfiguration getUsesConfiguration() {
    717         return mUsesConfiguration;
    718     }
    719 
    720     void addProcessName(String processName) {
    721         if (mProcesses == null) {
    722             mProcesses = new TreeSet<String>();
    723         }
    724 
    725         mProcesses.add(processName);
    726     }
    727 
    728 }
    729