/*
 * 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.TestApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
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.
/** * 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
/** * 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_GLO_L1CA, TYPE_BDS_D1, TYPE_BDS_D2, TYPE_GAL_I, TYPE_GAL_F}) public @interface GnssNavigationMessageType {} // The following enumerations must be in sync with the values declared in gps.h
Message type unknown
/** Message type unknown */
public static final int TYPE_UNKNOWN = 0;
GPS L1 C/A message contained in the structure.
/** 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.
/** GPS L2-CNAV message contained in the structure. */
public static final int TYPE_GPS_L2CNAV = 0x0102;
GPS L5-CNAV message contained in the structure.
/** GPS L5-CNAV message contained in the structure. */
public static final int TYPE_GPS_L5CNAV = 0x0103;
GPS CNAV-2 message contained in the structure.
/** GPS CNAV-2 message contained in the structure. */
public static final int TYPE_GPS_CNAV2 = 0x0104;
Glonass L1 CA message contained in the structure.
/** Glonass L1 CA message contained in the structure. */
public static final int TYPE_GLO_L1CA = 0x0301;
Beidou D1 message contained in the structure.
/** Beidou D1 message contained in the structure. */
public static final int TYPE_BDS_D1 = 0x0501;
Beidou D2 message contained in the structure.
/** Beidou D2 message contained in the structure. */
public static final int TYPE_BDS_D2 = 0x0502;
Galileo I/NAV message contained in the structure.
/** Galileo I/NAV message contained in the structure. */
public static final int TYPE_GAL_I = 0x0601;
Galileo F/NAV message contained in the structure.
/** Galileo F/NAV message contained in the structure. */
public static final int TYPE_GAL_F = 0x0602;
The Navigation Message Status is 'unknown'.
/** * 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.
/** * 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.
/** * 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.

You can implement this interface and call LocationManager.registerGnssNavigationMessageCallback.

/** * 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.
@hide
/** * The status of GNSS Navigation Message event. * @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.
/** * The system does not support tracking of GNSS Navigation Messages. * * This status will not change in the future. */
public static final int STATUS_NOT_SUPPORTED = 0;
GNSS Navigation Messages are successfully being tracked, it will receive updates once they are available.
/** * GNSS Navigation Messages are successfully being tracked, it will receive updates once * they are available. */
public static final int STATUS_READY = 1;
GNSS provider or Location is disabled, updated will not be received until they are enabled.
/** * GNSS provider or Location is disabled, updated will not be received until they are * enabled. */
public static final int STATUS_LOCATION_DISABLED = 2;
Returns the latest collected GNSS Navigation Message.
/** * Returns the latest collected GNSS Navigation Message. */
public void onGnssNavigationMessageReceived(GnssNavigationMessage event) {}
Returns the latest status of the GNSS Navigation Messages sub-system.
/** * Returns the latest status of the GNSS Navigation Messages sub-system. */
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
/** * @hide */
@TestApi public GnssNavigationMessage() { initialize(); }
Sets all contents to the values stored in the provided object.
@hide
/** * 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
/** * 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.
/** * 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
/** * 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.
/** * 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_GLO_L1CA: return "Glonass L1 C/A"; case TYPE_BDS_D1: return "Beidou D1"; case TYPE_BDS_D2: return "Beidou D2"; case TYPE_GAL_I: return "Galileo I"; case TYPE_GAL_F: return "Galileo F"; default: return "<Invalid:" + mType + ">"; } }
Gets the satellite ID.

Range varies by constellation. See definition at GnssStatus#getSvid(int)

/** * Gets the satellite ID. * * <p>Range varies by constellation. See definition at {@code GnssStatus#getSvid(int)} */
public int getSvid() { return mSvid; }
Sets the satellite ID.
@hide
/** * Sets the satellite ID. * @hide */
@TestApi public void setSvid(int value) { mSvid = value; }
Gets the Message identifier.

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.

  • 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.)
  • For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5.
  • For BeiDou D1, this refers to the frame number in the range of 1-24
  • For Beidou D2, this refers to the frame number, in the range of 1-120
  • For Galileo F/NAV nominal frame structure, this refers to the subframe number, in the range of 1-12
  • For Galileo I/NAV nominal frame structure, this refers to the subframe number in the range of 1-24
/** * 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> * </ul> */
public int getMessageId() { return mMessageId; }
Sets the Message Identifier.
@hide
/** * Sets the Message Identifier. * @hide */
@TestApi public void setMessageId(int value) { mMessageId = value; }
Gets the sub-message identifier, relevant to the getType() of the message.
  • 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.
  • For Glonass L1 C/A, this refers to the String number, in the range from 1-15
  • For Galileo F/NAV, this refers to the page type in the range 1-6
  • For Galileo I/NAV, this refers to the word type in the range 1-10+
  • 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.
/** * Gets the sub-message identifier, relevant to the {@link #getType()} of the message. * * <ul> * <li> For GPS L1 C/A, BeiDou D1 &amp; 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> * </ul> */
public int getSubmessageId() { return mSubmessageId; }
Sets the Sub-message identifier.
@hide
/** * Sets the Sub-message identifier. * @hide */
@TestApi public void setSubmessageId(int value) { mSubmessageId = value; }
Gets the data of the reported GPS message.

The bytes (or words) specified using big endian format (MSB first).

  • For GPS L1 C/A, 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.
  • 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.
  • 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.
  • 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).
/** * Gets the data of the reported GPS message. * * <p>The bytes (or words) specified using big endian format (MSB first). * * <ul> * <li>For GPS L1 C/A, Beidou D1 &amp; 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 &amp; 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 &amp; tail excluded) that should be fit into 29 bytes, with MSB first (skip * B229-B232).</li> * </ul> */
@NonNull public byte[] getData() { return mData; }
Sets the data associated with the Navigation Message.
@hide
/** * 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.
/** * Gets the Status of the navigation message contained in the object. */
public int getStatus() { return mStatus; }
Sets the status of the navigation message.
@hide
/** * Sets the status of the navigation message. * @hide */
@TestApi public void setStatus(int value) { mStatus = value; }
Gets a string representation of the 'status'. For internal and logging use only.
/** * 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 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; } }