OSDN Git Service

android-2.1_r1 snapshot
[android-x86/sdk.git] / sdkmanager / libs / sdklib / src / com / android / sdklib / AndroidVersion.java
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 final class AndroidVersion implements Comparable<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      */
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      */
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
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      */
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      */
99     public String getCodename() {
100         return mCodename;
101     }
102
103     /**
104      * Returns a string representing the API level and/or the code name.
105      */
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      */
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      */
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      */
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
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
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     /**
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.
208      *
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.
212      */
213     public int compareTo(AndroidVersion o) {
214         if (mCodename == null) {
215             if (o.mCodename == null) {
216                 return mApiLevel - o.mApiLevel;
217             } else {
218                 if (mApiLevel == o.mApiLevel) {
219                     return -1; // same api level but o is a preview for next version
220                 }
221
222                 return mApiLevel - o.mApiLevel;
223             }
224         } else {
225             // 'this' is a preview
226             if (mApiLevel == o.mApiLevel) {
227                 if (o.mCodename == null) {
228                     return +1;
229                 } else {
230                     return mCodename.compareTo(o.mCodename); // strange case where the 2 previews
231                                                              // have different codename?
232                 }
233             } else {
234                 return mApiLevel - o.mApiLevel;
235             }
236         }
237     }
238 }