2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.sdklib;
19 import java.util.Properties;
22 * Represents the version of a target or device.
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>
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.
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()}.
37 * For generic UI display of the API version, {@link #getApiString()} is to be used.
40 public final class AndroidVersion implements Comparable<AndroidVersion> {
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$
45 private final int mApiLevel;
46 private final String mCodename;
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.
52 public AndroidVersion(int apiLevel, String codename) {
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)}.
63 public AndroidVersion(Properties properties, int defaultApiLevel, String defaultCodeName) {
64 if (properties == null) {
65 mApiLevel = defaultApiLevel;
66 mCodename = defaultCodeName;
68 mApiLevel = Integer.parseInt(properties.getProperty(PROP_API_LEVEL,
69 Integer.toString(defaultApiLevel)));
70 mCodename = properties.getProperty(PROP_CODENAME, defaultCodeName);
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);
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.
88 * @see #getApiString()
90 public int getApiLevel() {
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.
99 public String getCodename() {
104 * Returns a string representing the API level and/or the code name.
106 public String getApiString() {
107 if (mCodename != null) {
111 return Integer.toString(mApiLevel);
115 * Returns whether or not the version is a preview version.
117 public boolean isPreview() {
118 return mCodename != null;
122 * Checks whether a device running a version similar to the receiver can run a project compiled
123 * for the given <var>version</var>.
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)}.
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.
133 public boolean canRun(AndroidVersion appVersion) {
134 // if the application is compiled for a preview version, the device must be running exactly
136 if (appVersion.mCodename != null) {
137 return appVersion.mCodename.equals(mCodename);
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;
146 * Returns <code>true</code> if the AndroidVersion is an API level equals to
147 * <var>apiLevel</var>.
149 public boolean equals(int apiLevel) {
150 return mCodename == null && apiLevel == mApiLevel;
154 * Compares the receiver with either an {@link AndroidVersion} object or a {@link String}
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>.
163 public boolean equals(Object obj) {
164 if (obj instanceof AndroidVersion) {
165 AndroidVersion version = (AndroidVersion)obj;
167 if (mCodename == null) {
168 return version.mCodename == null &&
169 mApiLevel == version.mApiLevel;
171 return mCodename.equals(version.mCodename) &&
172 mApiLevel == version.mApiLevel;
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);
181 // else we try to convert to a int and compare to the api level
183 int value = Integer.parseInt((String)obj);
184 return value == mApiLevel;
185 } catch (NumberFormatException e) {
186 // not a number? we'll return false below.
194 public int hashCode() {
195 if (mCodename != null) {
196 return mCodename.hashCode();
199 // there may be some collisions between the hashcode of the codename and the api level
200 // but it's acceptable.
205 * Compares this object with the specified object for order. Returns a
206 * negative integer, zero, or a positive integer as this object is less
207 * than, equal to, or greater than the specified object.
209 * @param o the Object to be compared.
210 * @return a negative integer, zero, or a positive integer as this object is
211 * less than, equal to, or greater than the specified object.
213 public int compareTo(AndroidVersion o) {
214 if (mCodename == null) {
215 if (o.mCodename == null) {
216 return mApiLevel - o.mApiLevel;
218 if (mApiLevel == o.mApiLevel) {
219 return -1; // same api level but o is a preview for next version
222 return mApiLevel - o.mApiLevel;
225 // 'this' is a preview
226 if (mApiLevel == o.mApiLevel) {
227 if (o.mCodename == null) {
230 return mCodename.compareTo(o.mCodename); // strange case where the 2 previews
231 // have different codename?
234 return mApiLevel - o.mApiLevel;