| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package android.location; |
| |
| import android.annotation.FlaggedApi; |
| import android.annotation.IntDef; |
| import android.annotation.IntRange; |
| import android.annotation.NonNull; |
| import android.annotation.TestApi; |
| import android.location.flags.Flags; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.security.InvalidParameterException; |
| |
| /** |
| * A class containing a GNSS satellite Navigation Message. |
| */ |
| public final class GnssNavigationMessage implements Parcelable { |
| |
| private static final byte[] EMPTY_ARRAY = new byte[0]; |
| |
| /** |
| * The type of the GNSS Navigation Message |
| * @hide |
| */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({TYPE_UNKNOWN, TYPE_GPS_L1CA, TYPE_GPS_L2CNAV, TYPE_GPS_L5CNAV, TYPE_GPS_CNAV2, |
| TYPE_SBS, TYPE_GLO_L1CA, TYPE_QZS_L1CA, TYPE_BDS_D1, TYPE_BDS_D2, TYPE_BDS_CNAV1, |
| TYPE_BDS_CNAV2, TYPE_GAL_I, TYPE_GAL_F, TYPE_IRN_L5CA, TYPE_IRN_L5, TYPE_IRN_L1}) |
| public @interface GnssNavigationMessageType {} |
| |
| // The following enumerations must be in sync with the values declared in gps.h |
| |
| /** Message type unknown */ |
| public static final int TYPE_UNKNOWN = 0; |
| /** GPS L1 C/A message contained in the structure. */ |
| public static final int TYPE_GPS_L1CA = 0x0101; |
| /** GPS L2-CNAV message contained in the structure. */ |
| public static final int TYPE_GPS_L2CNAV = 0x0102; |
| /** GPS L5-CNAV message contained in the structure. */ |
| public static final int TYPE_GPS_L5CNAV = 0x0103; |
| /** GPS CNAV-2 message contained in the structure. */ |
| public static final int TYPE_GPS_CNAV2 = 0x0104; |
| /** SBAS message contained in the structure. */ |
| public static final int TYPE_SBS = 0x0201; |
| /** Glonass L1 CA message contained in the structure. */ |
| public static final int TYPE_GLO_L1CA = 0x0301; |
| /** QZSS L1 C/A message contained in the structure. */ |
| public static final int TYPE_QZS_L1CA = 0x0401; |
| /** Beidou D1 message contained in the structure. */ |
| public static final int TYPE_BDS_D1 = 0x0501; |
| /** Beidou D2 message contained in the structure. */ |
| public static final int TYPE_BDS_D2 = 0x0502; |
| /** Beidou CNAV1 message contained in the structure. */ |
| public static final int TYPE_BDS_CNAV1 = 0x0503; |
| /** Beidou CNAV2 message contained in the structure. */ |
| public static final int TYPE_BDS_CNAV2 = 0x0504; |
| /** Galileo I/NAV message contained in the structure. */ |
| public static final int TYPE_GAL_I = 0x0601; |
| /** Galileo F/NAV message contained in the structure. */ |
| public static final int TYPE_GAL_F = 0x0602; |
| /** |
| * NavIC L5 C/A message contained in the structure. |
| */ |
| public static final int TYPE_IRN_L5CA = 0x0701; |
| /** NavIC L5 message contained in the structure. */ |
| @FlaggedApi(Flags.FLAG_GNSS_API_NAVIC_L1) |
| public static final int TYPE_IRN_L5 = 0x0702; |
| /** NavIC L1 message contained in the structure. */ |
| @FlaggedApi(Flags.FLAG_GNSS_API_NAVIC_L1) |
| public static final int TYPE_IRN_L1 = 0x0703; |
| |
| /** |
| * The status of the GNSS Navigation Message |
| * @hide |
| */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({STATUS_UNKNOWN, STATUS_PARITY_PASSED, STATUS_PARITY_REBUILT}) |
| public @interface GnssNavigationMessageStatus {} |
| |
| /** |
| * The Navigation Message Status is 'unknown'. |
| */ |
| public static final int STATUS_UNKNOWN = 0; |
| |
| /** |
| * The Navigation Message was received without any parity error in its navigation words. |
| */ |
| public static final int STATUS_PARITY_PASSED = (1<<0); |
| |
| /** |
| * The Navigation Message was received with words that failed parity check, but the receiver was |
| * able to correct those words. |
| */ |
| public static final int STATUS_PARITY_REBUILT = (1<<1); |
| |
| /** |
| * Used for receiving GNSS satellite Navigation Messages from the GNSS engine. |
| * |
| * <p>You can implement this interface and call |
| * {@link LocationManager#registerGnssNavigationMessageCallback}. |
| */ |
| public static abstract class Callback { |
| /** |
| * The status of GNSS Navigation Message event. |
| * @deprecated Do not use. |
| * @hide |
| */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED}) |
| public @interface GnssNavigationMessageStatus {} |
| |
| /** |
| * The system does not support tracking of GNSS Navigation Messages. |
| * |
| * This status will not change in the future. |
| * |
| * @deprecated Do not use. |
| */ |
| @Deprecated |
| public static final int STATUS_NOT_SUPPORTED = 0; |
| |
| /** |
| * GNSS Navigation Messages are successfully being tracked, it will receive updates once |
| * they are available. |
| * |
| * @deprecated Do not use. |
| */ |
| @Deprecated |
| public static final int STATUS_READY = 1; |
| |
| /** |
| * GNSS provider or Location is disabled, updated will not be received until they are |
| * enabled. |
| * |
| * @deprecated Do not use. |
| */ |
| @Deprecated |
| public static final int STATUS_LOCATION_DISABLED = 2; |
| |
| /** |
| * Returns the latest collected GNSS Navigation Message. |
| */ |
| public void onGnssNavigationMessageReceived(GnssNavigationMessage event) {} |
| |
| /** |
| * Returns the latest status of the GNSS Navigation Messages sub-system. |
| * |
| * @deprecated Do not rely on this callback. From Android S onwards this callback will be |
| * invoked once with {@link #STATUS_READY} in all cases for backwards compatibility, and |
| * then never invoked again. Use LocationManager APIs if you need to determine if |
| * GNSS navigation messages are supported or if location is off, etc... |
| */ |
| @Deprecated |
| public void onStatusChanged(@GnssNavigationMessageStatus int status) {} |
| } |
| |
| // End enumerations in sync with gps.h |
| |
| private int mType; |
| private int mSvid; |
| private int mMessageId; |
| private int mSubmessageId; |
| private byte[] mData; |
| private int mStatus; |
| |
| /** |
| * @hide |
| */ |
| @TestApi |
| public GnssNavigationMessage() { |
| initialize(); |
| } |
| |
| /** |
| * Sets all contents to the values stored in the provided object. |
| * @hide |
| */ |
| @TestApi |
| public void set(GnssNavigationMessage navigationMessage) { |
| mType = navigationMessage.mType; |
| mSvid = navigationMessage.mSvid; |
| mMessageId = navigationMessage.mMessageId; |
| mSubmessageId = navigationMessage.mSubmessageId; |
| mData = navigationMessage.mData; |
| mStatus = navigationMessage.mStatus; |
| } |
| |
| /** |
| * Resets all the contents to its original state. |
| * @hide |
| */ |
| @TestApi |
| public void reset() { |
| initialize(); |
| } |
| |
| /** |
| * Gets the type of the navigation message contained in the object. |
| */ |
| @GnssNavigationMessageType |
| public int getType() { |
| return mType; |
| } |
| |
| /** |
| * Sets the type of the navigation message. |
| * @hide |
| */ |
| @TestApi |
| public void setType(@GnssNavigationMessageType int value) { |
| mType = value; |
| } |
| |
| /** |
| * Gets a string representation of the 'type'. |
| * For internal and logging use only. |
| */ |
| private String getTypeString() { |
| switch (mType) { |
| case TYPE_UNKNOWN: |
| return "Unknown"; |
| case TYPE_GPS_L1CA: |
| return "GPS L1 C/A"; |
| case TYPE_GPS_L2CNAV: |
| return "GPS L2-CNAV"; |
| case TYPE_GPS_L5CNAV: |
| return "GPS L5-CNAV"; |
| case TYPE_GPS_CNAV2: |
| return "GPS CNAV2"; |
| case TYPE_SBS: |
| return "SBS"; |
| case TYPE_GLO_L1CA: |
| return "Glonass L1 C/A"; |
| case TYPE_QZS_L1CA: |
| return "QZSS L1 C/A"; |
| case TYPE_BDS_D1: |
| return "Beidou D1"; |
| case TYPE_BDS_D2: |
| return "Beidou D2"; |
| case TYPE_BDS_CNAV1: |
| return "Beidou CNAV1"; |
| case TYPE_BDS_CNAV2: |
| return "Beidou CNAV2"; |
| case TYPE_GAL_I: |
| return "Galileo I"; |
| case TYPE_GAL_F: |
| return "Galileo F"; |
| case TYPE_IRN_L5CA: |
| return "NavIC L5 C/A"; |
| default: |
| if (Flags.gnssApiNavicL1()) { |
| if (mType == TYPE_IRN_L5) { |
| return "NavIC L5"; |
| } else if (mType == TYPE_IRN_L1) { |
| return "NavIC L1"; |
| } |
| } |
| return "<Invalid:" + mType + ">"; |
| } |
| } |
| |
| /** |
| * Gets the satellite ID. |
| * |
| * <p>Range varies by constellation. See definition at {@code GnssStatus#getSvid(int)} |
| */ |
| @IntRange(from = 1, to = 200) |
| public int getSvid() { |
| return mSvid; |
| } |
| |
| /** |
| * Sets the satellite ID. |
| * @hide |
| */ |
| @TestApi |
| public void setSvid(@IntRange(from = 1, to = 200) int value) { |
| mSvid = value; |
| } |
| |
| /** |
| * Gets the Message identifier. |
| * |
| * <p>This provides an index to help with complete Navigation Message assembly. Similar |
| * identifiers within the data bits themselves often supplement this information, in ways even |
| * more specific to each message type; see the relevant satellite constellation ICDs for |
| * details. |
| * |
| * <ul> |
| * <li> For GPS L1 C/A subframe 4 and 5, this value corresponds to the 'frame id' of the |
| * navigation message, in the range of 1-25 (Subframe 1, 2, 3 does not contain a 'frame id' and |
| * this value can be set to -1.)</li> |
| * <li> For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5.</li> |
| * <li> For BeiDou D1, this refers to the frame number in the range of 1-24</li> |
| * <li> For Beidou D2, this refers to the frame number, in the range of 1-120</li> |
| * <li> For Galileo F/NAV nominal frame structure, this refers to the subframe number, in the |
| * range of 1-12</li> |
| * <li> For Galileo I/NAV nominal frame structure, this refers to the subframe number in the |
| * range of 1-24</li> |
| * <li> For SBAS and Beidou CNAV2, this is unused and can be set to -1.</li> |
| * <li> For QZSS L1 C/A subframe 4 and 5, this value corresponds to the 'frame id' of the |
| * navigation message, in the range of 1-25 (Subframe 1, 2, 3 does not contain a 'frame id' and |
| * this value can be set to -1.)</li> |
| * <li> For Beidou CNAV1 this refers to the page type number in the range of 1-63.</li> |
| * <li> For NavIC L5 subframe 3 and 4, this value corresponds to the Message Id of the |
| * navigation message, in the range of 1-63. (Subframe 1 and 2 does not contain a message type |
| * id and this value can be set to -1.)</li> |
| * <li> For NavIC L1 subframe 3, this value corresponds to the Message Id of the navigation |
| * message, in the range of 1-63. (Subframe 1 and 2 does not contain a message type id and this |
| * value can be set to -1.)</li> |
| * </ul> |
| */ |
| @IntRange(from = -1, to = 120) |
| public int getMessageId() { |
| return mMessageId; |
| } |
| |
| /** |
| * Sets the Message Identifier. |
| * @hide |
| */ |
| @TestApi |
| public void setMessageId(@IntRange(from = -1, to = 120) int value) { |
| mMessageId = value; |
| } |
| |
| /** |
| * Gets the sub-message identifier, relevant to the {@link #getType()} of the message. |
| * |
| * <ul> |
| * <li> For GPS L1 C/A, BeiDou D1 & BeiDou D2, the submessage id corresponds to the subframe |
| * number of the navigation message, in the range of 1-5.</li> |
| * <li>For Glonass L1 C/A, this refers to the String number, in the range from 1-15</li> |
| * <li>For Galileo F/NAV, this refers to the page type in the range 1-6</li> |
| * <li>For Galileo I/NAV, this refers to the word type in the range 1-10+</li> |
| * <li>For Galileo in particular, the type information embedded within the data bits may be even |
| * more useful in interpretation, than the nominal page and word types provided in this |
| * field.</li> |
| * <li> For SBAS, the submessage id corresponds to the message type, in the range 1-63.</li> |
| * <li> For Beidou CNAV1, the submessage id corresponds to the subframe number of the |
| * navigation message, in the range of 1-3.</li> |
| * <li> For Beidou CNAV2, the submessage id corresponds to the message type, in the range |
| * 1-63.</li> |
| * <li> For NavIC L5, the submessage id corresponds to the subframe number of the navigation |
| * message, in the range of 1-4.</li> |
| * <li> For NavIC L1, the submessage id corresponds to the subframe number of the navigation |
| * message, in the range of 1-3.</li> |
| * </ul> |
| */ |
| @IntRange(from = 1) |
| public int getSubmessageId() { |
| return mSubmessageId; |
| } |
| |
| /** |
| * Sets the Sub-message identifier. |
| * @hide |
| */ |
| @TestApi |
| public void setSubmessageId(@IntRange(from = 1) int value) { |
| mSubmessageId = value; |
| } |
| |
| /** |
| * Gets the data of the reported GNSS message. |
| * |
| * <p>The bytes (or words) specified using big endian format (MSB first). |
| * |
| * <ul> |
| * <li>For GPS L1 C/A, NavIC L5, Beidou D1 & Beidou D2, each subframe contains 10 |
| * 30-bit words. Each word (30 bits) should be fit into the last 30 bits in a 4-byte word (skip |
| * B31 and B32), with MSB first, for a total of 40 bytes, covering a time period of 6, 6, and |
| * 0.6 seconds, respectively.</li> |
| * <li>For Glonass L1 C/A, each string contains 85 data bits, including the checksum. These |
| * bits should be fit into 11 bytes, with MSB first (skip B86-B88), covering a time period of 2 |
| * seconds.</li> |
| * <li>For Galileo F/NAV, each word consists of 238-bit (sync & tail symbols excluded). Each |
| * word should be fit into 30-bytes, with MSB first (skip B239, B240), covering a time period of |
| * 10 seconds.</li> |
| * <li>For Galileo I/NAV, each page contains 2 page parts, even and odd, with a total of 2x114 = |
| * 228 bits, (sync & tail excluded) that should be fit into 29 bytes, with MSB first (skip |
| * B229-B232).</li> |
| * <li>For SBAS, each block consists of 250 data bits, that should be fit into 32 bytes. MSB |
| * first (skip B251-B256).</li> |
| * <li>For Beidou CNAV1, subframe #1 consists of 14 data bits, that should be fit into 2 |
| * bytes. MSB first (skip B15-B16). subframe #2 consists of 600 bits that should be fit into |
| * 75 bytes. subframe #3 consists of 264 data bits that should be fit into 33 bytes.</li> |
| * <li>For Beidou CNAV2, each subframe consists of 288 data bits, that should be fit into 36 |
| * bytes.</li> |
| * <li> For NavIC L1, subframe #1 consists of 9 data bits that should be fit into 2 bytes (skip |
| * B10-B16). subframe #2 consists of 600 bits that should be fit into 75 bytes. subframe #3 |
| * consists of 274 data bits that should be fit into 35 bytes (skip B275-B280).</li> |
| * </ul> |
| */ |
| @NonNull |
| public byte[] getData() { |
| return mData; |
| } |
| |
| /** |
| * Sets the data associated with the Navigation Message. |
| * @hide |
| */ |
| @TestApi |
| public void setData(byte[] value) { |
| if (value == null) { |
| throw new InvalidParameterException("Data must be a non-null array"); |
| } |
| |
| mData = value; |
| } |
| |
| /** |
| * Gets the Status of the navigation message contained in the object. |
| */ |
| @GnssNavigationMessageStatus |
| public int getStatus() { |
| return mStatus; |
| } |
| |
| /** |
| * Sets the status of the navigation message. |
| * @hide |
| */ |
| @TestApi |
| public void setStatus(@GnssNavigationMessageStatus int value) { |
| mStatus = value; |
| } |
| |
| /** |
| * Gets a string representation of the 'status'. |
| * For internal and logging use only. |
| */ |
| private String getStatusString() { |
| switch (mStatus) { |
| case STATUS_UNKNOWN: |
| return "Unknown"; |
| case STATUS_PARITY_PASSED: |
| return "ParityPassed"; |
| case STATUS_PARITY_REBUILT: |
| return "ParityRebuilt"; |
| default: |
| return "<Invalid:" + mStatus + ">"; |
| } |
| } |
| |
| public static final @android.annotation.NonNull Creator<GnssNavigationMessage> CREATOR = |
| new Creator<GnssNavigationMessage>() { |
| @Override |
| public GnssNavigationMessage createFromParcel(Parcel parcel) { |
| GnssNavigationMessage navigationMessage = new GnssNavigationMessage(); |
| |
| navigationMessage.setType(parcel.readInt()); |
| navigationMessage.setSvid(parcel.readInt()); |
| navigationMessage.setMessageId(parcel.readInt()); |
| navigationMessage.setSubmessageId(parcel.readInt()); |
| int dataLength = parcel.readInt(); |
| byte[] data = new byte[dataLength]; |
| parcel.readByteArray(data); |
| navigationMessage.setData(data); |
| navigationMessage.setStatus(parcel.readInt()); |
| |
| return navigationMessage; |
| } |
| |
| @Override |
| public GnssNavigationMessage[] newArray(int size) { |
| return new GnssNavigationMessage[size]; |
| } |
| }; |
| |
| @Override |
| public void writeToParcel(Parcel parcel, int flags) { |
| parcel.writeInt(mType); |
| parcel.writeInt(mSvid); |
| parcel.writeInt(mMessageId); |
| parcel.writeInt(mSubmessageId); |
| parcel.writeInt(mData.length); |
| parcel.writeByteArray(mData); |
| parcel.writeInt(mStatus); |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public String toString() { |
| final String format = " %-15s = %s\n"; |
| StringBuilder builder = new StringBuilder("GnssNavigationMessage:\n"); |
| |
| builder.append(String.format(format, "Type", getTypeString())); |
| builder.append(String.format(format, "Svid", mSvid)); |
| builder.append(String.format(format, "Status", getStatusString())); |
| builder.append(String.format(format, "MessageId", mMessageId)); |
| builder.append(String.format(format, "SubmessageId", mSubmessageId)); |
| |
| builder.append(String.format(format, "Data", "{")); |
| String prefix = " "; |
| for(byte value : mData) { |
| builder.append(prefix); |
| builder.append(value); |
| prefix = ", "; |
| } |
| builder.append(" }"); |
| |
| return builder.toString(); |
| } |
| |
| private void initialize() { |
| mType = TYPE_UNKNOWN; |
| mSvid = 0; |
| mMessageId = -1; |
| mSubmessageId = -1; |
| mData = EMPTY_ARRAY; |
| mStatus = STATUS_UNKNOWN; |
| } |
| } |