1 /* 2 * Copyright (C) 2014 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.TestApi; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.security.InvalidParameterException; 28 29 /** 30 * A class containing a GNSS satellite Navigation Message. 31 */ 32 public final class GnssNavigationMessage implements Parcelable { 33 34 private static final byte[] EMPTY_ARRAY = new byte[0]; 35 36 /** 37 * The type of the GNSS Navigation Message 38 * @hide 39 */ 40 @Retention(RetentionPolicy.SOURCE) 41 @IntDef({TYPE_UNKNOWN, TYPE_GPS_L1CA, TYPE_GPS_L2CNAV, TYPE_GPS_L5CNAV, TYPE_GPS_CNAV2, 42 TYPE_GLO_L1CA, TYPE_BDS_D1, TYPE_BDS_D2, TYPE_GAL_I, TYPE_GAL_F}) 43 public @interface GnssNavigationMessageType {} 44 45 // The following enumerations must be in sync with the values declared in gps.h 46 47 /** Message type unknown */ 48 public static final int TYPE_UNKNOWN = 0; 49 /** GPS L1 C/A message contained in the structure. */ 50 public static final int TYPE_GPS_L1CA = 0x0101; 51 /** GPS L2-CNAV message contained in the structure. */ 52 public static final int TYPE_GPS_L2CNAV = 0x0102; 53 /** GPS L5-CNAV message contained in the structure. */ 54 public static final int TYPE_GPS_L5CNAV = 0x0103; 55 /** GPS CNAV-2 message contained in the structure. */ 56 public static final int TYPE_GPS_CNAV2 = 0x0104; 57 /** Glonass L1 CA message contained in the structure. */ 58 public static final int TYPE_GLO_L1CA = 0x0301; 59 /** Beidou D1 message contained in the structure. */ 60 public static final int TYPE_BDS_D1 = 0x0501; 61 /** Beidou D2 message contained in the structure. */ 62 public static final int TYPE_BDS_D2 = 0x0502; 63 /** Galileo I/NAV message contained in the structure. */ 64 public static final int TYPE_GAL_I = 0x0601; 65 /** Galileo F/NAV message contained in the structure. */ 66 public static final int TYPE_GAL_F = 0x0602; 67 68 /** 69 * The Navigation Message Status is 'unknown'. 70 */ 71 public static final int STATUS_UNKNOWN = 0; 72 73 /** 74 * The Navigation Message was received without any parity error in its navigation words. 75 */ 76 public static final int STATUS_PARITY_PASSED = (1<<0); 77 78 /** 79 * The Navigation Message was received with words that failed parity check, but the receiver was 80 * able to correct those words. 81 */ 82 public static final int STATUS_PARITY_REBUILT = (1<<1); 83 84 /** 85 * Used for receiving GNSS satellite Navigation Messages from the GNSS engine. 86 * 87 * <p>You can implement this interface and call 88 * {@link LocationManager#registerGnssNavigationMessageCallback}. 89 */ 90 public static abstract class Callback { 91 /** 92 * The status of GNSS Navigation Message event. 93 * @hide 94 */ 95 @Retention(RetentionPolicy.SOURCE) 96 @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED}) 97 public @interface GnssNavigationMessageStatus {} 98 99 /** 100 * The system does not support tracking of GNSS Navigation Messages. 101 * 102 * This status will not change in the future. 103 */ 104 public static final int STATUS_NOT_SUPPORTED = 0; 105 106 /** 107 * GNSS Navigation Messages are successfully being tracked, it will receive updates once 108 * they are available. 109 */ 110 public static final int STATUS_READY = 1; 111 112 /** 113 * GNSS provider or Location is disabled, updated will not be received until they are 114 * enabled. 115 */ 116 public static final int STATUS_LOCATION_DISABLED = 2; 117 118 /** 119 * Returns the latest collected GNSS Navigation Message. 120 */ onGnssNavigationMessageReceived(GnssNavigationMessage event)121 public void onGnssNavigationMessageReceived(GnssNavigationMessage event) {} 122 123 /** 124 * Returns the latest status of the GNSS Navigation Messages sub-system. 125 */ onStatusChanged(@nssNavigationMessageStatus int status)126 public void onStatusChanged(@GnssNavigationMessageStatus int status) {} 127 } 128 129 // End enumerations in sync with gps.h 130 131 private int mType; 132 private int mSvid; 133 private int mMessageId; 134 private int mSubmessageId; 135 private byte[] mData; 136 private int mStatus; 137 138 /** 139 * @hide 140 */ 141 @TestApi GnssNavigationMessage()142 public GnssNavigationMessage() { 143 initialize(); 144 } 145 146 /** 147 * Sets all contents to the values stored in the provided object. 148 * @hide 149 */ 150 @TestApi set(GnssNavigationMessage navigationMessage)151 public void set(GnssNavigationMessage navigationMessage) { 152 mType = navigationMessage.mType; 153 mSvid = navigationMessage.mSvid; 154 mMessageId = navigationMessage.mMessageId; 155 mSubmessageId = navigationMessage.mSubmessageId; 156 mData = navigationMessage.mData; 157 mStatus = navigationMessage.mStatus; 158 } 159 160 /** 161 * Resets all the contents to its original state. 162 * @hide 163 */ 164 @TestApi reset()165 public void reset() { 166 initialize(); 167 } 168 169 /** 170 * Gets the type of the navigation message contained in the object. 171 */ 172 @GnssNavigationMessageType getType()173 public int getType() { 174 return mType; 175 } 176 177 /** 178 * Sets the type of the navigation message. 179 * @hide 180 */ 181 @TestApi setType(@nssNavigationMessageType int value)182 public void setType(@GnssNavigationMessageType int value) { 183 mType = value; 184 } 185 186 /** 187 * Gets a string representation of the 'type'. 188 * For internal and logging use only. 189 */ getTypeString()190 private String getTypeString() { 191 switch (mType) { 192 case TYPE_UNKNOWN: 193 return "Unknown"; 194 case TYPE_GPS_L1CA: 195 return "GPS L1 C/A"; 196 case TYPE_GPS_L2CNAV: 197 return "GPS L2-CNAV"; 198 case TYPE_GPS_L5CNAV: 199 return "GPS L5-CNAV"; 200 case TYPE_GPS_CNAV2: 201 return "GPS CNAV2"; 202 case TYPE_GLO_L1CA: 203 return "Glonass L1 C/A"; 204 case TYPE_BDS_D1: 205 return "Beidou D1"; 206 case TYPE_BDS_D2: 207 return "Beidou D2"; 208 case TYPE_GAL_I: 209 return "Galileo I"; 210 case TYPE_GAL_F: 211 return "Galileo F"; 212 default: 213 return "<Invalid:" + mType + ">"; 214 } 215 } 216 217 /** 218 * Gets the satellite ID. 219 * 220 * <p>Range varies by constellation. See definition at {@code GnssStatus#getSvid(int)} 221 */ getSvid()222 public int getSvid() { 223 return mSvid; 224 } 225 226 /** 227 * Sets the satellite ID. 228 * @hide 229 */ 230 @TestApi setSvid(int value)231 public void setSvid(int value) { 232 mSvid = value; 233 } 234 235 /** 236 * Gets the Message identifier. 237 * 238 * <p>This provides an index to help with complete Navigation Message assembly. Similar 239 * identifiers within the data bits themselves often supplement this information, in ways even 240 * more specific to each message type; see the relevant satellite constellation ICDs for 241 * details. 242 * 243 * <ul> 244 * <li> For GPS L1 C/A subframe 4 and 5, this value corresponds to the 'frame id' of the 245 * navigation message, in the range of 1-25 (Subframe 1, 2, 3 does not contain a 'frame id' and 246 * this value can be set to -1.)</li> 247 * <li> For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5.</li> 248 * <li> For BeiDou D1, this refers to the frame number in the range of 1-24</li> 249 * <li> For Beidou D2, this refers to the frame number, in the range of 1-120</li> 250 * <li> For Galileo F/NAV nominal frame structure, this refers to the subframe number, in the 251 * range of 1-12</li> 252 * <li> For Galileo I/NAV nominal frame structure, this refers to the subframe number in the 253 * range of 1-24</li> 254 * </ul> 255 */ getMessageId()256 public int getMessageId() { 257 return mMessageId; 258 } 259 260 /** 261 * Sets the Message Identifier. 262 * @hide 263 */ 264 @TestApi setMessageId(int value)265 public void setMessageId(int value) { 266 mMessageId = value; 267 } 268 269 /** 270 * Gets the sub-message identifier, relevant to the {@link #getType()} of the message. 271 * 272 * <ul> 273 * <li> For GPS L1 C/A, BeiDou D1 & BeiDou D2, the submessage id corresponds to the subframe 274 * number of the navigation message, in the range of 1-5.</li> 275 * <li>For Glonass L1 C/A, this refers to the String number, in the range from 1-15</li> 276 * <li>For Galileo F/NAV, this refers to the page type in the range 1-6</li> 277 * <li>For Galileo I/NAV, this refers to the word type in the range 1-10+</li> 278 * <li>For Galileo in particular, the type information embedded within the data bits may be even 279 * more useful in interpretation, than the nominal page and word types provided in this 280 * field.</li> 281 * </ul> 282 */ getSubmessageId()283 public int getSubmessageId() { 284 return mSubmessageId; 285 } 286 287 /** 288 * Sets the Sub-message identifier. 289 * @hide 290 */ 291 @TestApi setSubmessageId(int value)292 public void setSubmessageId(int value) { 293 mSubmessageId = value; 294 } 295 296 /** 297 * Gets the data of the reported GPS message. 298 * 299 * <p>The bytes (or words) specified using big endian format (MSB first). 300 * 301 * <ul> 302 * <li>For GPS L1 C/A, Beidou D1 & Beidou D2, each subframe contains 10 30-bit words. Each 303 * word (30 bits) should be fit into the last 30 bits in a 4-byte word (skip B31 and B32), with 304 * MSB first, for a total of 40 bytes, covering a time period of 6, 6, and 0.6 seconds, 305 * respectively.</li> 306 * <li>For Glonass L1 C/A, each string contains 85 data bits, including the checksum. These 307 * bits should be fit into 11 bytes, with MSB first (skip B86-B88), covering a time period of 2 308 * seconds.</li> 309 * <li>For Galileo F/NAV, each word consists of 238-bit (sync & tail symbols excluded). Each 310 * word should be fit into 30-bytes, with MSB first (skip B239, B240), covering a time period of 311 * 10 seconds.</li> 312 * <li>For Galileo I/NAV, each page contains 2 page parts, even and odd, with a total of 2x114 = 313 * 228 bits, (sync & tail excluded) that should be fit into 29 bytes, with MSB first (skip 314 * B229-B232).</li> 315 * </ul> 316 */ 317 @NonNull getData()318 public byte[] getData() { 319 return mData; 320 } 321 322 /** 323 * Sets the data associated with the Navigation Message. 324 * @hide 325 */ 326 @TestApi setData(byte[] value)327 public void setData(byte[] value) { 328 if (value == null) { 329 throw new InvalidParameterException("Data must be a non-null array"); 330 } 331 332 mData = value; 333 } 334 335 /** 336 * Gets the Status of the navigation message contained in the object. 337 */ getStatus()338 public int getStatus() { 339 return mStatus; 340 } 341 342 /** 343 * Sets the status of the navigation message. 344 * @hide 345 */ 346 @TestApi setStatus(int value)347 public void setStatus(int value) { 348 mStatus = value; 349 } 350 351 /** 352 * Gets a string representation of the 'status'. 353 * For internal and logging use only. 354 */ getStatusString()355 private String getStatusString() { 356 switch (mStatus) { 357 case STATUS_UNKNOWN: 358 return "Unknown"; 359 case STATUS_PARITY_PASSED: 360 return "ParityPassed"; 361 case STATUS_PARITY_REBUILT: 362 return "ParityRebuilt"; 363 default: 364 return "<Invalid:" + mStatus + ">"; 365 } 366 } 367 368 public static final @android.annotation.NonNull Creator<GnssNavigationMessage> CREATOR = 369 new Creator<GnssNavigationMessage>() { 370 @Override 371 public GnssNavigationMessage createFromParcel(Parcel parcel) { 372 GnssNavigationMessage navigationMessage = new GnssNavigationMessage(); 373 374 navigationMessage.setType(parcel.readInt()); 375 navigationMessage.setSvid(parcel.readInt()); 376 navigationMessage.setMessageId(parcel.readInt()); 377 navigationMessage.setSubmessageId(parcel.readInt()); 378 int dataLength = parcel.readInt(); 379 byte[] data = new byte[dataLength]; 380 parcel.readByteArray(data); 381 navigationMessage.setData(data); 382 navigationMessage.setStatus(parcel.readInt()); 383 384 return navigationMessage; 385 } 386 387 @Override 388 public GnssNavigationMessage[] newArray(int size) { 389 return new GnssNavigationMessage[size]; 390 } 391 }; 392 393 @Override writeToParcel(Parcel parcel, int flags)394 public void writeToParcel(Parcel parcel, int flags) { 395 parcel.writeInt(mType); 396 parcel.writeInt(mSvid); 397 parcel.writeInt(mMessageId); 398 parcel.writeInt(mSubmessageId); 399 parcel.writeInt(mData.length); 400 parcel.writeByteArray(mData); 401 parcel.writeInt(mStatus); 402 } 403 404 @Override describeContents()405 public int describeContents() { 406 return 0; 407 } 408 409 @Override toString()410 public String toString() { 411 final String format = " %-15s = %s\n"; 412 StringBuilder builder = new StringBuilder("GnssNavigationMessage:\n"); 413 414 builder.append(String.format(format, "Type", getTypeString())); 415 builder.append(String.format(format, "Svid", mSvid)); 416 builder.append(String.format(format, "Status", getStatusString())); 417 builder.append(String.format(format, "MessageId", mMessageId)); 418 builder.append(String.format(format, "SubmessageId", mSubmessageId)); 419 420 builder.append(String.format(format, "Data", "{")); 421 String prefix = " "; 422 for(byte value : mData) { 423 builder.append(prefix); 424 builder.append(value); 425 prefix = ", "; 426 } 427 builder.append(" }"); 428 429 return builder.toString(); 430 } 431 initialize()432 private void initialize() { 433 mType = TYPE_UNKNOWN; 434 mSvid = 0; 435 mMessageId = -1; 436 mSubmessageId = -1; 437 mData = EMPTY_ARRAY; 438 mStatus = STATUS_UNKNOWN; 439 } 440 } 441