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 android.location; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.os.SystemClock; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.util.Locale; 31 32 /** 33 * This class wraps the country information. 34 * 35 * @hide 36 */ 37 @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) 38 public final class Country implements Parcelable { 39 /** 40 * The country code came from the mobile network 41 */ 42 public static final int COUNTRY_SOURCE_NETWORK = 0; 43 44 /** 45 * The country code came from the location service 46 */ 47 public static final int COUNTRY_SOURCE_LOCATION = 1; 48 49 /** 50 * The country code was read from the SIM card 51 */ 52 public static final int COUNTRY_SOURCE_SIM = 2; 53 54 /** 55 * The country code came from the system locale setting 56 */ 57 public static final int COUNTRY_SOURCE_LOCALE = 3; 58 59 /** 60 * Country source type 61 * 62 * @hide 63 */ 64 @IntDef( 65 prefix = {"COUNTRY_SOURCE_"}, 66 value = { 67 COUNTRY_SOURCE_NETWORK, 68 COUNTRY_SOURCE_LOCATION, 69 COUNTRY_SOURCE_SIM, 70 COUNTRY_SOURCE_LOCALE 71 }) 72 @Retention(RetentionPolicy.SOURCE) 73 public @interface CountrySource {} 74 75 /** The ISO 3166-1 two letters country code. */ 76 private final String mCountryIso; 77 78 /** 79 * Where the country code came from. 80 */ 81 private final int mSource; 82 83 private int mHashCode; 84 85 /** 86 * Time that this object was created (which we assume to be the time that the source was 87 * consulted). This time is in milliseconds since boot up. 88 */ 89 private final long mTimestamp; 90 91 /** 92 * @param countryIso the ISO 3166-1 two letters country code. 93 * @param source where the countryIso came from, could be one of below values 94 * <p> 95 * <ul> 96 * <li>{@link #COUNTRY_SOURCE_NETWORK} 97 * <li>{@link #COUNTRY_SOURCE_LOCATION} 98 * <li>{@link #COUNTRY_SOURCE_SIM} 99 * <li>{@link #COUNTRY_SOURCE_LOCALE} 100 * </ul> 101 */ Country(@onNull final String countryIso, @CountrySource final int source)102 public Country(@NonNull final String countryIso, @CountrySource final int source) { 103 if (countryIso == null 104 || source < COUNTRY_SOURCE_NETWORK 105 || source > COUNTRY_SOURCE_LOCALE) { 106 throw new IllegalArgumentException(); 107 } 108 mCountryIso = countryIso.toUpperCase(Locale.US); 109 mSource = source; 110 mTimestamp = SystemClock.elapsedRealtime(); 111 } 112 Country(final String countryIso, final int source, long timestamp)113 private Country(final String countryIso, final int source, long timestamp) { 114 if (countryIso == null || source < COUNTRY_SOURCE_NETWORK 115 || source > COUNTRY_SOURCE_LOCALE) { 116 throw new IllegalArgumentException(); 117 } 118 mCountryIso = countryIso.toUpperCase(Locale.US); 119 mSource = source; 120 mTimestamp = timestamp; 121 } 122 123 /** @hide */ Country(Country country)124 public Country(Country country) { 125 mCountryIso = country.mCountryIso; 126 mSource = country.mSource; 127 mTimestamp = country.mTimestamp; 128 } 129 130 /** 131 * @return the ISO 3166-1 two letters country code 132 * 133 * @hide 134 * 135 * @deprecated clients using getCountryIso should use the {@link #getCountryCode()} API instead. 136 */ 137 @UnsupportedAppUsage 138 @Deprecated getCountryIso()139 public String getCountryIso() { 140 return mCountryIso; 141 } 142 143 /** 144 * Retrieves country code. 145 * 146 * @return country code in ISO 3166-1:alpha2 147 */ 148 @NonNull getCountryCode()149 public String getCountryCode() { 150 return mCountryIso; 151 } 152 153 /** 154 * @return where the country code came from, could be one of below values 155 * <p> 156 * <ul> 157 * <li>{@link #COUNTRY_SOURCE_NETWORK}</li> 158 * <li>{@link #COUNTRY_SOURCE_LOCATION}</li> 159 * <li>{@link #COUNTRY_SOURCE_SIM}</li> 160 * <li>{@link #COUNTRY_SOURCE_LOCALE}</li> 161 * </ul> 162 */ 163 @CountrySource getSource()164 public int getSource() { 165 return mSource; 166 } 167 168 /** 169 * Returns the time that this object was created (which we assume to be the time that the source 170 * was consulted). 171 * 172 * @hide 173 */ getTimestamp()174 public long getTimestamp() { 175 return mTimestamp; 176 } 177 178 @android.annotation.NonNull 179 public static final Parcelable.Creator<Country> CREATOR = new Parcelable.Creator<Country>() { 180 public Country createFromParcel(Parcel in) { 181 return new Country(in.readString(), in.readInt(), in.readLong()); 182 } 183 184 public Country[] newArray(int size) { 185 return new Country[size]; 186 } 187 }; 188 189 @Override describeContents()190 public int describeContents() { 191 return 0; 192 } 193 194 @Override writeToParcel(@onNull Parcel parcel, int flags)195 public void writeToParcel(@NonNull Parcel parcel, int flags) { 196 parcel.writeString(mCountryIso); 197 parcel.writeInt(mSource); 198 parcel.writeLong(mTimestamp); 199 } 200 201 /** 202 * Returns true if this {@link Country} is equivalent to the given object. This ignores 203 * the timestamp value and just checks for equivalence of countryIso and source values. 204 * Returns false otherwise. 205 * 206 */ 207 @Override equals(@ullable Object object)208 public boolean equals(@Nullable Object object) { 209 if (object == this) { 210 return true; 211 } 212 if (object instanceof Country) { 213 Country c = (Country) object; 214 // No need to check the equivalence of the timestamp 215 return mCountryIso.equals(c.getCountryIso()) && mSource == c.getSource(); 216 } 217 return false; 218 } 219 220 @Override hashCode()221 public int hashCode() { 222 int hash = mHashCode; 223 if (hash == 0) { 224 hash = 17; 225 hash = hash * 13 + mCountryIso.hashCode(); 226 hash = hash * 13 + mSource; 227 mHashCode = hash; 228 } 229 return mHashCode; 230 } 231 232 /** 233 * Compare the specified country to this country object ignoring the source 234 * and timestamp fields, return true if the countryIso fields are equal 235 * 236 * @param country the country to compare 237 * @return true if the specified country's countryIso field is equal to this 238 * country's, false otherwise. 239 * 240 * @hide 241 */ equalsIgnoreSource(Country country)242 public boolean equalsIgnoreSource(Country country) { 243 return country != null && mCountryIso.equals(country.getCountryIso()); 244 } 245 246 @Override 247 @NonNull toString()248 public String toString() { 249 return "Country {ISO=" + mCountryIso + ", source=" + mSource + ", time=" + mTimestamp + "}"; 250 } 251 } 252