• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ide.common.xml;
18 
19 import com.android.resources.Keyboard;
20 import com.android.resources.Navigation;
21 import com.android.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 
Instrumentation(String name, String targetPackage)81         Instrumentation(String name, String targetPackage) {
82             mName = name;
83             mTargetPackage = targetPackage;
84         }
85 
86         /**
87          * Returns the fully qualified instrumentation class name
88          */
getName()89         public String getName() {
90             return mName;
91         }
92 
93         /**
94          * Returns the Android app package that is the target of this instrumentation
95          */
getTargetPackage()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 
Activity(String name, boolean exported)111         public Activity(String name, boolean exported) {
112             mName = name;
113             mIsExported = exported;
114         }
115 
getName()116         public String getName() {
117             return mName;
118         }
119 
isExported()120         public boolean isExported() {
121             return mIsExported;
122         }
123 
hasAction()124         public boolean hasAction() {
125             return mHasAction;
126         }
127 
isHomeActivity()128         public boolean isHomeActivity() {
129             return mHasMainAction && mHasLauncherCategory;
130         }
131 
setHasAction(boolean hasAction)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          */
resetIntentFilter()140         void resetIntentFilter() {
141             if (isHomeActivity() == false) {
142                 mHasMainAction = mHasLauncherCategory = false;
143             }
144         }
145 
setHasMainAction(boolean hasMainAction)146         void setHasMainAction(boolean hasMainAction) {
147             mHasMainAction = hasMainAction;
148         }
149 
setHasLauncherCategory(boolean hasLauncherCategory)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 
SupportsScreens()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          */
SupportsScreens(String value)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          */
getDefaultValues(int targetSdkVersion)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          */
resolveSupportsScreensValues(int targetSdkVersion)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          */
getResizeable()226         public Boolean getResizeable() {
227             return mResizeable;
228         }
229 
setResizeable(Boolean resizeable)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          */
getAnyDensity()237         public Boolean getAnyDensity() {
238             return mAnyDensity;
239         }
240 
setAnyDensity(Boolean anyDensity)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          */
getSmallScreens()248         public Boolean getSmallScreens() {
249             return mSmallScreens;
250         }
251 
setSmallScreens(Boolean smallScreens)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          */
getNormalScreens()259         public Boolean getNormalScreens() {
260             return mNormalScreens;
261         }
262 
setNormalScreens(Boolean normalScreens)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          */
getLargeScreens()270         public Boolean getLargeScreens() {
271             return mLargeScreens;
272         }
273 
setLargeScreens(Boolean largeScreens)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          */
getConstantBoolean(Boolean v)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
equals(Object obj)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 &&
303                        mAnyDensity    == support.mAnyDensity &&
304                        mSmallScreens  == support.mSmallScreens &&
305                        mNormalScreens == support.mNormalScreens &&
306                        mLargeScreens  == support.mLargeScreens;
307             }
308 
309             return false;
310         }
311 
312         /* Override hashCode, mostly to make Eclipse happy and not warn about it.
313          * And if you ever put this in a Map or Set, it will avoid surprises. */
314         @Override
hashCode()315         public int hashCode() {
316             final int prime = 31;
317             int result = 1;
318             result = prime * result + ((mAnyDensity    == null) ? 0 : mAnyDensity.hashCode());
319             result = prime * result + ((mLargeScreens  == null) ? 0 : mLargeScreens.hashCode());
320             result = prime * result + ((mNormalScreens == null) ? 0 : mNormalScreens.hashCode());
321             result = prime * result + ((mResizeable    == null) ? 0 : mResizeable.hashCode());
322             result = prime * result + ((mSmallScreens  == null) ? 0 : mSmallScreens.hashCode());
323             return result;
324         }
325 
326         /**
327          * Returns true if the two instances support the same screen sizes.
328          * This is similar to {@link #equals(Object)} except that it ignores the values of
329          * {@link #getAnyDensity()} and {@link #getResizeable()}.
330          * @param support the other instance to compare to.
331          * @return true if the two instances support the same screen sizes.
332          */
hasSameScreenSupportAs(SupportsScreens support)333         public boolean hasSameScreenSupportAs(SupportsScreens support) {
334             // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
335             // (or null), we can simply check they are identical and not bother with
336             // calling equals (which would require to check != null.
337             // see #getConstanntBoolean(Boolean)
338 
339             // This only checks that matter here are the screen sizes. resizeable and anyDensity
340             // are not checked.
341             return  mSmallScreens == support.mSmallScreens &&
342                     mNormalScreens == support.mNormalScreens &&
343                     mLargeScreens == support.mLargeScreens;
344         }
345 
346         /**
347          * Returns true if the two instances have strictly different screen size support.
348          * This means that there is no screen size that they both support.
349          * @param support the other instance to compare to.
350          * @return true if they are stricly different.
351          */
hasStrictlyDifferentScreenSupportAs(SupportsScreens support)352         public boolean hasStrictlyDifferentScreenSupportAs(SupportsScreens support) {
353             // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
354             // (or null), we can simply check they are identical and not bother with
355             // calling equals (which would require to check != null.
356             // see #getConstanntBoolean(Boolean)
357 
358             // This only checks that matter here are the screen sizes. resizeable and anyDensity
359             // are not checked.
360             return (mSmallScreens != Boolean.TRUE || support.mSmallScreens != Boolean.TRUE) &&
361                     (mNormalScreens != Boolean.TRUE || support.mNormalScreens != Boolean.TRUE) &&
362                     (mLargeScreens != Boolean.TRUE || support.mLargeScreens != Boolean.TRUE);
363         }
364 
365         /**
366          * Comparison of 2 Supports-screens. This only uses screen sizes (ignores resizeable and
367          * anyDensity), and considers that
368          * {@link #hasStrictlyDifferentScreenSupportAs(SupportsScreens)} returns true and
369          * {@link #overlapWith(SupportsScreens)} returns false.
370          * @throws IllegalArgumentException if the two instanced are not strictly different or
371          * overlap each other
372          * @see #hasStrictlyDifferentScreenSupportAs(SupportsScreens)
373          * @see #overlapWith(SupportsScreens)
374          */
compareScreenSizesWith(SupportsScreens o)375         public int compareScreenSizesWith(SupportsScreens o) {
376             if (hasStrictlyDifferentScreenSupportAs(o) == false) {
377                 throw new IllegalArgumentException("The two instances are not strictly different.");
378             }
379             if (overlapWith(o)) {
380                 throw new IllegalArgumentException("The two instances overlap each other.");
381             }
382 
383             int comp = mLargeScreens.compareTo(o.mLargeScreens);
384             if (comp != 0) return comp;
385 
386             comp = mNormalScreens.compareTo(o.mNormalScreens);
387             if (comp != 0) return comp;
388 
389             comp = mSmallScreens.compareTo(o.mSmallScreens);
390             if (comp != 0) return comp;
391 
392             return 0;
393         }
394 
395         /**
396          * Returns a string encoding of the content of the instance. This string can be used to
397          * instantiate a {@link SupportsScreens} object through
398          * {@link #SupportsScreens(String)}.
399          */
getEncodedValues()400         public String getEncodedValues() {
401             return String.format("%1$s|%2$s|%3$s|%4$s|%5$s",
402                     mAnyDensity, mResizeable, mSmallScreens, mNormalScreens, mLargeScreens);
403         }
404 
405         @Override
toString()406         public String toString() {
407             StringBuilder sb = new StringBuilder();
408 
409             boolean alreadyOutputSomething = false;
410 
411             if (Boolean.TRUE.equals(mSmallScreens)) {
412                 alreadyOutputSomething = true;
413                 sb.append("small");
414             }
415 
416             if (Boolean.TRUE.equals(mNormalScreens)) {
417                 if (alreadyOutputSomething) {
418                     sb.append(", ");
419                 }
420                 alreadyOutputSomething = true;
421                 sb.append("normal");
422             }
423 
424             if (Boolean.TRUE.equals(mLargeScreens)) {
425                 if (alreadyOutputSomething) {
426                     sb.append(", ");
427                 }
428                 alreadyOutputSomething = true;
429                 sb.append("large");
430             }
431 
432             if (alreadyOutputSomething == false) {
433                 sb.append("<none>");
434             }
435 
436             return sb.toString();
437         }
438 
439         /**
440          * Returns true if the two instance overlap with each other.
441          * This can happen if one instances supports a size, when the other instance doesn't while
442          * supporting a size above and a size below.
443          * @param otherSS the other supports-screens to compare to.
444          */
overlapWith(SupportsScreens otherSS)445         public boolean overlapWith(SupportsScreens otherSS) {
446             if (mSmallScreens == null || mNormalScreens == null || mLargeScreens == null ||
447                     otherSS.mSmallScreens == null || otherSS.mNormalScreens == null ||
448                     otherSS.mLargeScreens == null) {
449                 throw new IllegalArgumentException("Some screen sizes Boolean are not initialized");
450             }
451 
452             if (mSmallScreens == Boolean.TRUE && mNormalScreens == Boolean.FALSE &&
453                     mLargeScreens == Boolean.TRUE) {
454                 return otherSS.mNormalScreens == Boolean.TRUE;
455             }
456 
457             if (otherSS.mSmallScreens == Boolean.TRUE && otherSS.mNormalScreens == Boolean.FALSE &&
458                     otherSS.mLargeScreens == Boolean.TRUE) {
459                 return mNormalScreens == Boolean.TRUE;
460             }
461 
462             return false;
463         }
464     }
465 
466     /**
467      * Class representing a <code>uses-library</code> node in the manifest.
468      */
469     public final static class UsesLibrary {
470         String mName;
471         Boolean mRequired = Boolean.TRUE; // default is true even if missing
472 
getName()473         public String getName() {
474             return mName;
475         }
476 
getRequired()477         public Boolean getRequired() {
478             return mRequired;
479         }
480     }
481 
482     /**
483      * Class representing a <code>uses-feature</code> node in the manifest.
484      */
485     public final static class UsesFeature {
486         String mName;
487         int mGlEsVersion = 0;
488         Boolean mRequired = Boolean.TRUE;  // default is true even if missing
489 
getName()490         public String getName() {
491             return mName;
492         }
493 
494         /**
495          * Returns the value of the glEsVersion attribute, or 0 if the attribute was not present.
496          */
getGlEsVersion()497         public int getGlEsVersion() {
498             return mGlEsVersion;
499         }
500 
getRequired()501         public Boolean getRequired() {
502             return mRequired;
503         }
504     }
505 
506     /**
507      * Class representing the <code>uses-configuration</code> node in the manifest.
508      */
509     public final static class UsesConfiguration {
510         Boolean mReqFiveWayNav;
511         Boolean mReqHardKeyboard;
512         Keyboard mReqKeyboardType;
513         TouchScreen mReqTouchScreen;
514         Navigation mReqNavigation;
515 
516         /**
517          * returns the value of the <code>reqFiveWayNav</code> attribute or null if not present.
518          */
getReqFiveWayNav()519         public Boolean getReqFiveWayNav() {
520             return mReqFiveWayNav;
521         }
522 
523         /**
524          * returns the value of the <code>reqNavigation</code> attribute or null if not present.
525          */
getReqNavigation()526         public Navigation getReqNavigation() {
527             return mReqNavigation;
528         }
529 
530         /**
531          * returns the value of the <code>reqHardKeyboard</code> attribute or null if not present.
532          */
getReqHardKeyboard()533         public Boolean getReqHardKeyboard() {
534             return mReqHardKeyboard;
535         }
536 
537         /**
538          * returns the value of the <code>reqKeyboardType</code> attribute or null if not present.
539          */
getReqKeyboardType()540         public Keyboard getReqKeyboardType() {
541             return mReqKeyboardType;
542         }
543 
544         /**
545          * returns the value of the <code>reqTouchScreen</code> attribute or null if not present.
546          */
getReqTouchScreen()547         public TouchScreen getReqTouchScreen() {
548             return mReqTouchScreen;
549         }
550     }
551 
552     /**
553      * Returns the package defined in the manifest, if found.
554      * @return The package name or null if not found.
555      */
getPackage()556     public String getPackage() {
557         return mPackage;
558     }
559 
560     /**
561      * Returns the versionCode value defined in the manifest, if found, null otherwise.
562      * @return the versionCode or null if not found.
563      */
getVersionCode()564     public Integer getVersionCode() {
565         return mVersionCode;
566     }
567 
568     /**
569      * Returns the list of activities found in the manifest.
570      * @return An array of fully qualified class names, or empty if no activity were found.
571      */
getActivities()572     public Activity[] getActivities() {
573         return mActivities.toArray(new Activity[mActivities.size()]);
574     }
575 
576     /**
577      * Returns the name of one activity found in the manifest, that is configured to show
578      * up in the HOME screen.
579      * @return the fully qualified name of a HOME activity or null if none were found.
580      */
getLauncherActivity()581     public Activity getLauncherActivity() {
582         return mLauncherActivity;
583     }
584 
585     /**
586      * Returns the list of process names declared by the manifest.
587      */
getProcesses()588     public String[] getProcesses() {
589         if (mProcesses != null) {
590             return mProcesses.toArray(new String[mProcesses.size()]);
591         }
592 
593         return new String[0];
594     }
595 
596     /**
597      * Returns the <code>debuggable</code> attribute value or null if it is not set.
598      */
getDebuggable()599     public Boolean getDebuggable() {
600         return mDebuggable;
601     }
602 
603     /**
604      * Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
605      */
getMinSdkVersionString()606     public String getMinSdkVersionString() {
607         return mMinSdkVersionString;
608     }
609 
610     /**
611      * Sets the value of the <code>minSdkVersion</code> attribute.
612      * @param minSdkVersion the string value of the attribute in the manifest.
613      */
setMinSdkVersionString(String minSdkVersion)614     public void setMinSdkVersionString(String minSdkVersion) {
615         mMinSdkVersionString = minSdkVersion;
616         if (mMinSdkVersionString != null) {
617             try {
618                 mMinSdkVersion = Integer.parseInt(mMinSdkVersionString);
619             } catch (NumberFormatException e) {
620                 mMinSdkVersion = MIN_SDK_CODENAME;
621             }
622         }
623     }
624 
625     /**
626      * Returns the <code>minSdkVersion</code> attribute, or 0 if it's not set or is a codename.
627      * @see #getMinSdkVersionString()
628      */
getMinSdkVersion()629     public int getMinSdkVersion() {
630         return mMinSdkVersion;
631     }
632 
633 
634     /**
635      * Sets the value of the <code>minSdkVersion</code> attribute.
636      * @param targetSdkVersion the string value of the attribute in the manifest.
637      */
setTargetSdkVersionString(String targetSdkVersion)638     public void setTargetSdkVersionString(String targetSdkVersion) {
639         if (targetSdkVersion != null) {
640             try {
641                 mTargetSdkVersion = Integer.parseInt(targetSdkVersion);
642             } catch (NumberFormatException e) {
643                 // keep the value at 0.
644             }
645         }
646     }
647 
648     /**
649      * Returns the <code>targetSdkVersion</code> attribute, or the same value as
650      * {@link #getMinSdkVersion()} if it was not set in the manifest.
651      */
getTargetSdkVersion()652     public int getTargetSdkVersion() {
653         if (mTargetSdkVersion == 0) {
654             return getMinSdkVersion();
655         }
656 
657         return mTargetSdkVersion;
658     }
659 
660     /**
661      * Returns the list of instrumentations found in the manifest.
662      * @return An array of {@link Instrumentation}, or empty if no instrumentations were
663      * found.
664      */
getInstrumentations()665     public Instrumentation[] getInstrumentations() {
666         return mInstrumentations.toArray(new Instrumentation[mInstrumentations.size()]);
667     }
668 
669     /**
670      * Returns the list of libraries in use found in the manifest.
671      * @return An array of {@link UsesLibrary} objects, or empty if no libraries were found.
672      */
getUsesLibraries()673     public UsesLibrary[] getUsesLibraries() {
674         return mLibraries.toArray(new UsesLibrary[mLibraries.size()]);
675     }
676 
677     /**
678      * Returns the list of features in use found in the manifest.
679      * @return An array of {@link UsesFeature} objects, or empty if no libraries were found.
680      */
getUsesFeatures()681     public UsesFeature[] getUsesFeatures() {
682         return mFeatures.toArray(new UsesFeature[mFeatures.size()]);
683     }
684 
685     /**
686      * Returns the glEsVersion from a <uses-feature> or {@link #GL_ES_VERSION_NOT_SET} if not set.
687      */
getGlEsVersion()688     public int getGlEsVersion() {
689         for (UsesFeature feature : mFeatures) {
690             if (feature.mGlEsVersion > 0) {
691                 return feature.mGlEsVersion;
692             }
693         }
694         return GL_ES_VERSION_NOT_SET;
695     }
696 
697     /**
698      * Returns the {@link SupportsScreens} object representing the <code>supports-screens</code>
699      * node, or null if the node doesn't exist at all.
700      * Some values in the {@link SupportsScreens} instance maybe null, indicating that they
701      * were not present in the manifest. To get an instance that contains the values, as seen
702      * by the Android platform when the app is running, use {@link #getSupportsScreensValues()}.
703      */
getSupportsScreensFromManifest()704     public SupportsScreens getSupportsScreensFromManifest() {
705         return mSupportsScreensFromManifest;
706     }
707 
708     /**
709      * Returns an always non-null instance of {@link SupportsScreens} that's been initialized with
710      * the default values, and the values from the manifest.
711      * The default values depends on the manifest values for minSdkVersion and targetSdkVersion.
712      */
getSupportsScreensValues()713     public synchronized SupportsScreens getSupportsScreensValues() {
714         if (mSupportsScreensValues == null) {
715             if (mSupportsScreensFromManifest == null) {
716                 mSupportsScreensValues = SupportsScreens.getDefaultValues(getTargetSdkVersion());
717             } else {
718                 // get a SupportsScreen that replace the missing values with default values.
719                 mSupportsScreensValues = mSupportsScreensFromManifest.resolveSupportsScreensValues(
720                         getTargetSdkVersion());
721             }
722         }
723 
724         return mSupportsScreensValues;
725     }
726 
727     /**
728      * Returns the {@link UsesConfiguration} object representing the <code>uses-configuration</code>
729      * node, or null if the node doesn't exist at all.
730      */
getUsesConfiguration()731     public UsesConfiguration getUsesConfiguration() {
732         return mUsesConfiguration;
733     }
734 
addProcessName(String processName)735     void addProcessName(String processName) {
736         if (mProcesses == null) {
737             mProcesses = new TreeSet<String>();
738         }
739 
740         if (processName.startsWith(":")) {
741             mProcesses.add(mPackage + processName);
742         } else {
743             mProcesses.add(processName);
744         }
745     }
746 
747 }
748