• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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;
18 
19 import java.util.Properties;
20 
21 /**
22  * Represents the version of a target or device.
23  * <p/>
24  * A version is defined by an API level and an optional code name.
25  * <ul><li>Release versions of the Android platform are identified by their API level (integer),
26  * (technically the code name for release version is "REL" but this class will return
27  * <code>null<code> instead.)</li>
28  * <li>Preview versions of the platform are identified by a code name. Their API level
29  * is usually set to the value of the previous platform.</li></ul>
30  * <p/>
31  * While this class contains both values, its goal is to abstract them, so that code comparing 2+
32  * versions doesn't have to deal with the logic of handle both values.
33  * <p/>
34  * There are some cases where ones may want to access the values directly. This can be done
35  * with {@link #getApiLevel()} and {@link #getCodename()}.
36  * <p/>
37  * For generic UI display of the API version, {@link #getApiString()} is to be used.
38  *
39  */
40 public class AndroidVersion {
41 
42     private static final String PROP_API_LEVEL = "AndroidVersion.ApiLevel";  //$NON-NLS-1$
43     private static final String PROP_CODENAME = "AndroidVersion.CodeName";   //$NON-NLS-1$
44 
45     private final int mApiLevel;
46     private final String mCodename;
47 
48     /**
49      * Creates an {@link AndroidVersion} with the given api level and codename.
50      * Codename should be null for a release version, otherwise it's a preview codename.
51      */
AndroidVersion(int apiLevel, String codename)52     public AndroidVersion(int apiLevel, String codename) {
53         mApiLevel = apiLevel;
54         mCodename = codename;
55     }
56 
57     /**
58      * Creates an {@link AndroidVersion} from {@link Properties}, with default values if the
59      * {@link Properties} object doesn't contain the expected values.
60      * <p/>The {@link Properties} is expected to have been filled with
61      * {@link #saveProperties(Properties)}.
62      */
AndroidVersion(Properties properties, int defaultApiLevel, String defaultCodeName)63     public AndroidVersion(Properties properties, int defaultApiLevel, String defaultCodeName) {
64         if (properties == null) {
65             mApiLevel = defaultApiLevel;
66             mCodename = defaultCodeName;
67         } else {
68             mApiLevel = Integer.parseInt(properties.getProperty(PROP_API_LEVEL,
69                     Integer.toString(defaultApiLevel)));
70             mCodename = properties.getProperty(PROP_CODENAME, defaultCodeName);
71         }
72     }
73 
saveProperties(Properties props)74     public void saveProperties(Properties props) {
75         props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
76         if (mCodename != null) {
77             props.setProperty(PROP_CODENAME, mCodename);
78         }
79     }
80 
81     /**
82      * Returns the api level as an integer.
83      * <p/>For target that are in preview mode, this can be superseded by
84      * {@link #getCodename()}.
85      * <p/>To display the API level in the UI, use {@link #getApiString()}, which will use the
86      * codename if applicable.
87      * @see #getCodename()
88      * @see #getApiString()
89      */
getApiLevel()90     public int getApiLevel() {
91         return mApiLevel;
92     }
93 
94     /**
95      * Returns the version code name if applicable, null otherwise.
96      * <p/>If the codename is non null, then the API level should be ignored, and this should be
97      * used as a unique identifier of the target instead.
98      */
getCodename()99     public String getCodename() {
100         return mCodename;
101     }
102 
103     /**
104      * Returns a string representing the API level and/or the code name.
105      */
getApiString()106     public String getApiString() {
107         if (mCodename != null) {
108             return mCodename;
109         }
110 
111         return Integer.toString(mApiLevel);
112     }
113 
114     /**
115      * Returns whether or not the version is a preview version.
116      */
isPreview()117     public boolean isPreview() {
118         return mCodename != null;
119     }
120 
121     /**
122      * Checks whether a device running a version similar to the receiver can run a project compiled
123      * for the given <var>version</var>.
124      * <p/>
125      * Be aware that this is not a perfect test, as other properties could break compatibility
126      * despite this method returning true. For a more comprehensive test, see
127      * {@link IAndroidTarget#isCompatibleBaseFor(IAndroidTarget)}.
128      * <p/>
129      * Nevertheless, when testing if an application can run on a device (where there is no
130      * access to the list of optional libraries), this method can give a good indication of whether
131      * there is a chance the application could run, or if there's a direct incompatibility.
132      */
canRun(AndroidVersion appVersion)133     public boolean canRun(AndroidVersion appVersion) {
134         // if the application is compiled for a preview version, the device must be running exactly
135         // the same.
136         if (appVersion.mCodename != null) {
137             return appVersion.mCodename.equals(mCodename);
138         }
139 
140         // otherwise, we check the api level (note that a device running a preview version
141         // will have the api level of the previous platform).
142         return mApiLevel >= appVersion.mApiLevel;
143     }
144 
145     /**
146      * Returns <code>true</code> if the AndroidVersion is an API level equals to
147      * <var>apiLevel</var>.
148      */
equals(int apiLevel)149     public boolean equals(int apiLevel) {
150         return mCodename == null && apiLevel == mApiLevel;
151     }
152 
153     /**
154      * Compares the receiver with either an {@link AndroidVersion} object or a {@link String}
155      * object.
156      * <p/>If <var>obj</var> is a {@link String}, then the method will first check if it's a string
157      * representation of a number, in which case it'll compare it to the api level. Otherwise, it'll
158      * compare it against the code name.
159      * <p/>For all other type of object give as parameter, this method will return
160      * <code>false</code>.
161      */
162     @Override
equals(Object obj)163     public boolean equals(Object obj) {
164         if (obj instanceof AndroidVersion) {
165             AndroidVersion version = (AndroidVersion)obj;
166 
167             if (mCodename == null) {
168                 return version.mCodename == null &&
169                         mApiLevel == version.mApiLevel;
170             } else {
171                 return mCodename.equals(version.mCodename) &&
172                         mApiLevel == version.mApiLevel;
173             }
174 
175         } else if (obj instanceof String) {
176             // if we have a code name, this must match.
177             if (mCodename != null) {
178                 return mCodename.equals(obj);
179             }
180 
181             // else we try to convert to a int and compare to the api level
182             try {
183                 int value = Integer.parseInt((String)obj);
184                 return value == mApiLevel;
185             } catch (NumberFormatException e) {
186                 // not a number? we'll return false below.
187             }
188         }
189 
190         return false;
191     }
192 
193     @Override
hashCode()194     public int hashCode() {
195         if (mCodename != null) {
196             return mCodename.hashCode();
197         }
198 
199         // there may be some collisions between the hashcode of the codename and the api level
200         // but it's acceptable.
201         return mApiLevel;
202     }
203 }
204