blob: 7a667ae4ef6cd2a90a58a5453be711a9394efec2 [file] [log] [blame]
/*
* 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 &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>
* <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 &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>
* <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;
}
}