diff --git a/core/api/current.txt b/core/api/current.txt index 3ac71c53b1787..5c954e491aa97 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18966,8 +18966,23 @@ package android.location { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } - public final class GnssCapabilities { - method public boolean hasGnssAntennaInfo(); + public final class GnssCapabilities implements android.os.Parcelable { + method public int describeContents(); + method public boolean hasAntennaInfo(); + method @Deprecated public boolean hasGnssAntennaInfo(); + method public boolean hasMeasurements(); + method public boolean hasNavigationMessages(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class GnssCapabilities.Builder { + ctor public GnssCapabilities.Builder(); + ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities); + method @NonNull public android.location.GnssCapabilities build(); + method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurements(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasNavigationMessages(boolean); } public final class GnssClock implements android.os.Parcelable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 567676f9caf89..5f97da928b14d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3938,19 +3938,29 @@ package android.location { method public void onLocationBatch(java.util.List); } - public final class GnssCapabilities { + public final class GnssCapabilities implements android.os.Parcelable { method public boolean hasGeofencing(); method public boolean hasLowPowerMode(); method public boolean hasMeasurementCorrections(); method public boolean hasMeasurementCorrectionsExcessPathLength(); method public boolean hasMeasurementCorrectionsLosSats(); - method public boolean hasMeasurementCorrectionsReflectingPane(); - method public boolean hasMeasurements(); - method public boolean hasNavMessages(); + method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane(); + method public boolean hasMeasurementCorrectionsReflectingPlane(); + method @Deprecated public boolean hasNavMessages(); method @Deprecated public boolean hasSatelliteBlacklist(); method public boolean hasSatelliteBlocklist(); } + public static final class GnssCapabilities.Builder { + method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrections(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean); + } + public final class GnssMeasurementCorrections implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters(); diff --git a/location/java/android/location/GnssCapabilities.aidl b/location/java/android/location/GnssCapabilities.aidl new file mode 100644 index 0000000000000..bdf301483a5f2 --- /dev/null +++ b/location/java/android/location/GnssCapabilities.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020, 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; + +parcelable GnssCapabilities; \ No newline at end of file diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java index bbb5bb8fa3a76..89a3bd57519ef 100644 --- a/location/java/android/location/GnssCapabilities.java +++ b/location/java/android/location/GnssCapabilities.java @@ -16,121 +16,207 @@ package android.location; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; +import java.util.concurrent.Executor; /** - * A container of supported GNSS chipset capabilities. + * GNSS chipset capabilities. */ -public final class GnssCapabilities { - /** - * Bit mask indicating GNSS chipset supports low power mode. - * @hide - */ - public static final long LOW_POWER_MODE = 1L << 0; +public final class GnssCapabilities implements Parcelable { - /** - * Bit mask indicating GNSS chipset supports blocklisting satellites. - * @hide - */ - public static final long SATELLITE_BLOCKLIST = 1L << 1; - - /** - * Bit mask indicating GNSS chipset supports geofencing. - * @hide - */ - public static final long GEOFENCING = 1L << 2; - - /** - * Bit mask indicating GNSS chipset supports measurements. - * @hide - */ - public static final long MEASUREMENTS = 1L << 3; - - /** - * Bit mask indicating GNSS chipset supports navigation messages. - * @hide - */ - public static final long NAV_MESSAGES = 1L << 4; - - /** - * Bit mask indicating GNSS chipset supports measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS = 1L << 5; - - /** - * Bit mask indicating GNSS chipset supports line-of-sight satellite identification - * measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS_LOS_SATS = 1L << 6; - - /** - * Bit mask indicating GNSS chipset supports per satellite excess-path-length - * measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 1L << 7; - - /** - * Bit mask indicating GNSS chipset supports reflecting planes measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 1L << 8; - - /** - * Bit mask indicating GNSS chipset supports GNSS antenna info. - * @hide - */ - public static final long ANTENNA_INFO = 1L << 9; + // IMPORTANT - must match the Capabilities enum in IGnssCallback.hal + /** @hide */ + public static final int TOP_HAL_CAPABILITY_SCHEDULING = 1; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MSB = 2; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MSA = 4; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_SINGLE_SHOT = 8; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_ON_DEMAND_TIME = 16; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_GEOFENCING = 32; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MEASUREMENTS = 64; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_NAV_MESSAGES = 128; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_LOW_POWER_MODE = 256; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST = 512; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS = 1024; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_ANTENNA_INFO = 2048; /** @hide */ - public static final long INVALID_CAPABILITIES = -1; + @IntDef(flag = true, prefix = {"TOP_HAL_CAPABILITY_"}, value = {TOP_HAL_CAPABILITY_SCHEDULING, + TOP_HAL_CAPABILITY_MSB, TOP_HAL_CAPABILITY_MSA, TOP_HAL_CAPABILITY_SINGLE_SHOT, + TOP_HAL_CAPABILITY_ON_DEMAND_TIME, TOP_HAL_CAPABILITY_GEOFENCING, + TOP_HAL_CAPABILITY_MEASUREMENTS, TOP_HAL_CAPABILITY_NAV_MESSAGES, + TOP_HAL_CAPABILITY_LOW_POWER_MODE, TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST, + TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS, TOP_HAL_CAPABILITY_ANTENNA_INFO}) + @Retention(RetentionPolicy.SOURCE) + public @interface TopHalCapabilityFlags {} - /** A bitmask of supported GNSS capabilities. */ - private final long mGnssCapabilities; + // IMPORTANT - must match the Capabilities enum in IMeasurementCorrectionsCallback.hal + /** @hide */ + public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS = 1; + /** @hide */ + public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH = 2; + /** @hide */ + public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE = 4; /** @hide */ - public static GnssCapabilities of(long gnssCapabilities) { - return new GnssCapabilities(gnssCapabilities); - } + @IntDef(flag = true, prefix = {"SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_"}, value = { + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE}) + @Retention(RetentionPolicy.SOURCE) + public @interface SubHalMeasurementCorrectionsCapabilityFlags {} - private GnssCapabilities(long gnssCapabilities) { - mGnssCapabilities = gnssCapabilities; - } + // IMPORATANT - must match values in IGnssPowerIndicationCallback.aidl + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_TOTAL = 1; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING = 2; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING = 4; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION = 8; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION = 16; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_OTHER_MODES = 32; + + /** @hide */ + @IntDef(flag = true, prefix = {"SUB_HAL_POWER_CAPABILITY_"}, value = { + SUB_HAL_POWER_CAPABILITY_TOTAL, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING, + SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING, + SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION, + SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION, + SUB_HAL_POWER_CAPABILITY_OTHER_MODES}) + @Retention(RetentionPolicy.SOURCE) + public @interface SubHalPowerCapabilityFlags {} /** - * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise. + * Returns an empty GnssCapabilities object. * * @hide */ - @SystemApi - public boolean hasLowPowerMode() { - return hasCapability(LOW_POWER_MODE); + public static GnssCapabilities empty() { + return new GnssCapabilities(0, 0, 0); + } + + private final @TopHalCapabilityFlags int mTopFlags; + private final @SubHalMeasurementCorrectionsCapabilityFlags int mMeasurementCorrectionsFlags; + private final @SubHalPowerCapabilityFlags int mPowerFlags; + + private GnssCapabilities( + @TopHalCapabilityFlags int topFlags, + @SubHalMeasurementCorrectionsCapabilityFlags int measurementCorrectionsFlags, + @SubHalPowerCapabilityFlags int powerFlags) { + mTopFlags = topFlags; + mMeasurementCorrectionsFlags = measurementCorrectionsFlags; + mPowerFlags = powerFlags; } /** - * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false} - * otherwise. + * Returns a new GnssCapabilities object with top hal values set from the given flags. * * @hide - * @deprecated use {@link #hasSatelliteBlocklist} instead. */ - @SystemApi - @Deprecated - public boolean hasSatelliteBlacklist() { - return hasCapability(SATELLITE_BLOCKLIST); + public GnssCapabilities withTopHalFlags(@TopHalCapabilityFlags int flags) { + if (mTopFlags == flags) { + return this; + } else { + return new GnssCapabilities(flags, mMeasurementCorrectionsFlags, mPowerFlags); + } } /** - * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false} + * Returns a new GnssCapabilities object with gnss measurement corrections sub hal values set + * from the given flags. + * + * @hide + */ + public GnssCapabilities withSubHalMeasurementCorrectionsFlags( + @SubHalMeasurementCorrectionsCapabilityFlags int flags) { + if (mMeasurementCorrectionsFlags == flags) { + return this; + } else { + return new GnssCapabilities(mTopFlags, flags, mPowerFlags); + } + } + + /** + * Returns a new GnssCapabilities object with gnss measurement corrections sub hal values set + * from the given flags. + * + * @hide + */ + public GnssCapabilities withSubHalPowerFlags(@SubHalPowerCapabilityFlags int flags) { + if (mPowerFlags == flags) { + return this; + } else { + return new GnssCapabilities(mTopFlags, mMeasurementCorrectionsFlags, flags); + } + } + + /** + * Returns {@code true} if GNSS chipset supports scheduling, {@code false} otherwise. + * + * @hide + */ + public boolean hasScheduling() { + return (mTopFlags & TOP_HAL_CAPABILITY_SCHEDULING) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports Mobile Station Based assistance, {@code false} * otherwise. * * @hide */ - @SystemApi - public boolean hasSatelliteBlocklist() { - return hasCapability(SATELLITE_BLOCKLIST); + public boolean hasMsb() { + return (mTopFlags & TOP_HAL_CAPABILITY_MSB) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports Mobile Station Assisted assitance, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasMsa() { + return (mTopFlags & TOP_HAL_CAPABILITY_MSA) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports single shot locating, {@code false} otherwise. + * + * @hide + */ + public boolean hasSingleShot() { + return (mTopFlags & TOP_HAL_CAPABILITY_SINGLE_SHOT) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports on demand time, {@code false} otherwise. + * + * @hide + */ + public boolean hasOnDemandTime() { + return (mTopFlags & TOP_HAL_CAPABILITY_ON_DEMAND_TIME) != 0; } /** @@ -140,27 +226,71 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasGeofencing() { - return hasCapability(GEOFENCING); + return (mTopFlags & TOP_HAL_CAPABILITY_GEOFENCING) != 0; } /** * Returns {@code true} if GNSS chipset supports measurements, {@code false} otherwise. * - * @hide + * @see LocationManager#registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback) */ - @SystemApi public boolean hasMeasurements() { - return hasCapability(MEASUREMENTS); + return (mTopFlags & TOP_HAL_CAPABILITY_MEASUREMENTS) != 0; } /** * Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise. * + * @deprecated Use {@link #hasNavigationMessages()} instead. + * + * @hide + */ + @Deprecated + @SystemApi + public boolean hasNavMessages() { + return hasNavigationMessages(); + } + + /** + * Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise. + * + * @see LocationManager#registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback) + */ + public boolean hasNavigationMessages() { + return (mTopFlags & TOP_HAL_CAPABILITY_NAV_MESSAGES) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise. + * * @hide */ @SystemApi - public boolean hasNavMessages() { - return hasCapability(NAV_MESSAGES); + public boolean hasLowPowerMode() { + return (mTopFlags & TOP_HAL_CAPABILITY_LOW_POWER_MODE) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports satellite blocklists, {@code false} otherwise. + * + * @deprecated Use {@link #hasSatelliteBlocklist} instead. + * + * @hide + */ + @SystemApi + @Deprecated + public boolean hasSatelliteBlacklist() { + return (mTopFlags & TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports satellite blocklists, {@code false} otherwise. + * + * @hide + */ + @SystemApi + public boolean hasSatelliteBlocklist() { + return (mTopFlags & TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST) != 0; } /** @@ -171,7 +301,26 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasMeasurementCorrections() { - return hasCapability(MEASUREMENT_CORRECTIONS); + return (mTopFlags & TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise. + * + * @deprecated Use {@link #hasAntennaInfo()} instead. + */ + @Deprecated + public boolean hasGnssAntennaInfo() { + return hasAntennaInfo(); + } + + /** + * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise. + * + * @see LocationManager#registerAntennaInfoListener(Executor, GnssAntennaInfo.Listener) + */ + public boolean hasAntennaInfo() { + return (mTopFlags & TOP_HAL_CAPABILITY_ANTENNA_INFO) != 0; } /** @@ -182,7 +331,8 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasMeasurementCorrectionsLosSats() { - return hasCapability(MEASUREMENT_CORRECTIONS_LOS_SATS); + return (mMeasurementCorrectionsFlags & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS) + != 0; } /** @@ -193,28 +343,468 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasMeasurementCorrectionsExcessPathLength() { - return hasCapability(MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH); + return (mMeasurementCorrectionsFlags + & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH) != 0; } /** - * Returns {@code true} if GNSS chipset supports reflecting planes measurement corrections, + * Returns {@code true} if GNSS chipset supports reflecting plane measurement corrections, * {@code false} otherwise. * + * @deprecated Use {@link #hasMeasurementCorrectionsReflectingPlane()} instead. + * * @hide */ @SystemApi public boolean hasMeasurementCorrectionsReflectingPane() { - return hasCapability(MEASUREMENT_CORRECTIONS_REFLECTING_PLANE); + return hasMeasurementCorrectionsReflectingPlane(); } /** - * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise. + * Returns {@code true} if GNSS chipset supports reflecting plane measurement corrections, + * {@code false} otherwise. + * + * @hide */ - public boolean hasGnssAntennaInfo() { - return hasCapability(ANTENNA_INFO); + @SystemApi + public boolean hasMeasurementCorrectionsReflectingPlane() { + return (mMeasurementCorrectionsFlags + & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE) != 0; } - private boolean hasCapability(long capability) { - return (mGnssCapabilities & capability) == capability; + /** + * Returns {@code true} if GNSS chipset supports measuring power totals, {@code false} + * otherwise. + * + * @hide + */ + public boolean hasPowerTotal() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_TOTAL) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring single-band tracking power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerSinglebandTracking() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring multi-band tracking power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerMultibandTracking() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring single-band acquisition power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerSinglebandAcquisition() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring multi-band acquisition power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerMultibandAcquisition() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring OEM defined mode power, {@code false} + * otherwise. + * + * @hide + */ + public boolean hasPowerOtherModes() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_OTHER_MODES) != 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof GnssCapabilities)) { + return false; + } + + GnssCapabilities that = (GnssCapabilities) o; + return mTopFlags == that.mTopFlags + && mMeasurementCorrectionsFlags == that.mMeasurementCorrectionsFlags + && mPowerFlags == that.mPowerFlags; + } + + @Override + public int hashCode() { + return Objects.hash(mTopFlags, mMeasurementCorrectionsFlags, mPowerFlags); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public GnssCapabilities createFromParcel(Parcel in) { + return new GnssCapabilities(in.readInt(), in.readInt(), in.readInt()); + } + + @Override + public GnssCapabilities[] newArray(int size) { + return new GnssCapabilities[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mTopFlags); + parcel.writeInt(mMeasurementCorrectionsFlags); + parcel.writeInt(mPowerFlags); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + if (hasScheduling()) { + builder.append("SCHEDULING "); + } + if (hasMsb()) { + builder.append("MSB "); + } + if (hasMsa()) { + builder.append("MSA "); + } + if (hasSingleShot()) { + builder.append("SINGLE_SHOT "); + } + if (hasOnDemandTime()) { + builder.append("ON_DEMAND_TIME "); + } + if (hasGeofencing()) { + builder.append("GEOFENCING "); + } + if (hasMeasurementCorrections()) { + builder.append("MEASUREMENTS "); + } + if (hasNavigationMessages()) { + builder.append("NAVIGATION_MESSAGES "); + } + if (hasLowPowerMode()) { + builder.append("LOW_POWER_MODE "); + } + if (hasSatelliteBlocklist()) { + builder.append("SATELLITE_BLOCKLIST "); + } + if (hasMeasurementCorrections()) { + builder.append("MEASUREMENT_CORRECTIONS "); + } + if (hasAntennaInfo()) { + builder.append("ANTENNA_INFO "); + } + if (hasMeasurementCorrectionsLosSats()) { + builder.append("LOS_SATS "); + } + if (hasMeasurementCorrectionsExcessPathLength()) { + builder.append("EXCESS_PATH_LENGTH "); + } + if (hasMeasurementCorrectionsReflectingPlane()) { + builder.append("REFLECTING_PLANE "); + } + if (hasPowerTotal()) { + builder.append("TOTAL_POWER "); + } + if (hasPowerSinglebandTracking()) { + builder.append("SINGLEBAND_TRACKING_POWER "); + } + if (hasPowerMultibandTracking()) { + builder.append("MULTIBAND_TRACKING_POWER "); + } + if (hasPowerSinglebandAcquisition()) { + builder.append("SINGLEBAND_ACQUISITION_POWER "); + } + if (hasPowerMultibandAcquisition()) { + builder.append("MULTIBAND_ACQUISITION_POWER "); + } + if (hasPowerOtherModes()) { + builder.append("OTHER_MODES_POWER "); + } + if (builder.length() > 1) { + builder.setLength(builder.length() - 1); + } else { + builder.append("NONE"); + } + builder.append("]"); + return builder.toString(); + } + + /** + * Builder for GnssCapabilities. + */ + public static final class Builder { + + private @TopHalCapabilityFlags int mTopFlags; + private @SubHalMeasurementCorrectionsCapabilityFlags int mMeasurementCorrectionsFlags; + private @SubHalPowerCapabilityFlags int mPowerFlags; + + public Builder() { + mTopFlags = 0; + mMeasurementCorrectionsFlags = 0; + mPowerFlags = 0; + } + + public Builder(@NonNull GnssCapabilities capabilities) { + mTopFlags = capabilities.mTopFlags; + mMeasurementCorrectionsFlags = capabilities.mMeasurementCorrectionsFlags; + mPowerFlags = capabilities.mPowerFlags; + } + + /** + * Sets scheduling capability. + * + * @hide + */ + public @NonNull Builder setHasScheduling(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SCHEDULING, capable); + return this; + } + + /** + * Sets Mobile Station Based capability. + * + * @hide + */ + public @NonNull Builder setHasMsb(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MSB, capable); + return this; + } + + /** + * Sets Mobile Station Assisted capability. + * + * @hide + */ + public @NonNull Builder setHasMsa(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MSA, capable); + return this; + } + + /** + * Sets single shot locating capability. + * + * @hide + */ + public @NonNull Builder setHasSingleShot(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SINGLE_SHOT, capable); + return this; + } + + /** + * Sets on demand time capability. + * + * @hide + */ + public @NonNull Builder setHasOnDemandTime(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ON_DEMAND_TIME, capable); + return this; + } + + /** + * Sets geofencing capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasGeofencing(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_GEOFENCING, capable); + return this; + } + + /** + * Sets measurements capability. + */ + public @NonNull Builder setHasMeasurements(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MEASUREMENTS, capable); + return this; + } + + /** + * Sets navigation messages capability. + */ + public @NonNull Builder setHasNavigationMessages(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_NAV_MESSAGES, capable); + return this; + } + + /** + * Sets low power mode capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasLowPowerMode(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_LOW_POWER_MODE, capable); + return this; + } + + /** + * Sets satellite blocklist capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasSatelliteBlocklist(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST, capable); + return this; + } + + /** + * Sets measurement corrections capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrections(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS, capable); + return this; + } + + /** + * Sets antenna info capability. + */ + public @NonNull Builder setHasAntennaInfo(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ANTENNA_INFO, capable); + return this; + } + + /** + * Sets measurement corrections line-of-sight satellites capabilitity. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrectionsLosSats(boolean capable) { + mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS, capable); + return this; + } + + /** + * Sets measurement corrections excess path length capabilitity. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrectionsExcessPathLength(boolean capable) { + mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH, capable); + return this; + } + + /** + * Sets measurement corrections reflecting plane capabilitity. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrectionsReflectingPlane(boolean capable) { + mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE, capable); + return this; + } + + /** + * Sets power totals capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerTotal(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_TOTAL, capable); + return this; + } + + /** + * Sets power single-band tracking capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerSinglebandTracking(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING, + capable); + return this; + } + + /** + * Sets power multi-band tracking capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerMultibandTracking(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING, + capable); + return this; + } + + /** + * Sets power single-band acquisition capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerSinglebandAcquisition(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION, + capable); + return this; + } + + /** + * Sets power multi-band acquisition capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerMultibandAcquisition(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION, + capable); + return this; + } + + /** + * Sets power other modes capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerOtherModes(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_OTHER_MODES, capable); + return this; + } + + /** + * Builds a new GnssCapabilities. + */ + public @NonNull GnssCapabilities build() { + return new GnssCapabilities(mTopFlags, mMeasurementCorrectionsFlags, mPowerFlags); + } + + private static int setFlag(int value, int flag, boolean set) { + if (set) { + return value | flag; + } else { + return value & ~flag; + } + } } } diff --git a/location/java/android/location/IGnssNmeaListener.aidl b/location/java/android/location/IGnssNmeaListener.aidl new file mode 100644 index 0000000000000..c67cc897ea870 --- /dev/null +++ b/location/java/android/location/IGnssNmeaListener.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020, 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; + +/** + * {@hide} + */ +oneway interface IGnssNmeaListener +{ + void onNmeaReceived(long timestamp, String nmea); +} \ No newline at end of file diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl index 57b1268f8aafb..c25046e3def82 100644 --- a/location/java/android/location/IGnssStatusListener.aidl +++ b/location/java/android/location/IGnssStatusListener.aidl @@ -27,5 +27,4 @@ oneway interface IGnssStatusListener void onGnssStopped(); void onFirstFix(int ttff); void onSvStatusChanged(in GnssStatus gnssStatus); - void onNmeaReceived(long timestamp, String nmea); } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 1dbc98d6c996f..621fe1ba14324 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -21,6 +21,7 @@ import android.location.Address; import android.location.Criteria; import android.location.GeocoderParams; import android.location.Geofence; +import android.location.GnssCapabilities; import android.location.GnssMeasurementCorrections; import android.location.GnssMeasurementRequest; import android.location.IGeocodeListener; @@ -28,6 +29,7 @@ import android.location.IGnssAntennaInfoListener; import android.location.IGnssMeasurementsListener; import android.location.IGnssStatusListener; import android.location.IGnssNavigationMessageListener; +import android.location.IGnssNmeaListener; import android.location.ILocationCallback; import android.location.ILocationListener; import android.location.LastLocationRequest; @@ -70,13 +72,16 @@ interface ILocationManager double upperRightLatitude, double upperRightLongitude, int maxResults, in GeocoderParams params, in IGeocodeListener listener); - long getGnssCapabilities(); + GnssCapabilities getGnssCapabilities(); int getGnssYearOfHardware(); String getGnssHardwareModelName(); void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, String attributionTag); void unregisterGnssStatusCallback(in IGnssStatusListener callback); + void registerGnssNmeaCallback(in IGnssNmeaListener callback, String packageName, String attributionTag); + void unregisterGnssNmeaCallback(in IGnssNmeaListener callback); + void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, String attributionTag); void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener); void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index b0ee3246bcd86..00381a68a2a22 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -380,6 +380,8 @@ public class LocationManager { @GuardedBy("mLock") @Nullable private GnssStatusTransportMultiplexer mGnssStatusTransportMultiplexer; @GuardedBy("mLock") + @Nullable private GnssNmeaTransportMultiplexer mGnssNmeaTransportMultiplexer; + @GuardedBy("mLock") @Nullable private GnssMeasurementsTransportMultiplexer mGnssMeasurementsTransportMultiplexer; @GuardedBy("mLock") @Nullable private GnssNavigationTransportMultiplexer mGnssNavigationTransportMultiplexer; @@ -403,6 +405,15 @@ public class LocationManager { } } + private GnssNmeaTransportMultiplexer getGnssNmeaTransportMultiplexer() { + synchronized (mLock) { + if (mGnssNmeaTransportMultiplexer == null) { + mGnssNmeaTransportMultiplexer = new GnssNmeaTransportMultiplexer(); + } + return mGnssNmeaTransportMultiplexer; + } + } + private GnssMeasurementsTransportMultiplexer getGnssMeasurementsTransportMultiplexer() { synchronized (mLock) { if (mGnssMeasurementsTransportMultiplexer == null) { @@ -2092,20 +2103,15 @@ public class LocationManager { */ public @NonNull GnssCapabilities getGnssCapabilities() { try { - long gnssCapabilities = mService.getGnssCapabilities(); - if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) { - gnssCapabilities = 0L; - } - return GnssCapabilities.of(gnssCapabilities); + return mService.getGnssCapabilities(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Returns the model year of the GNSS hardware and software build. More details, such as build - * date, may be available in {@link #getGnssHardwareModelName()}. May return 0 if the model year - * is less than 2016. + * Returns the model year of the GNSS hardware and software build, or 0 if the model year + * is before 2016. */ public int getGnssYearOfHardware() { try { @@ -2116,13 +2122,10 @@ public class LocationManager { } /** - * Returns the Model Name (including Vendor and Hardware/Software Version) of the GNSS hardware - * driver. + * Returns the model name (including vendor and hardware/software version) of the GNSS hardware + * driver, or null if this information is not available. * - *

No device-specific serial number or ID is returned from this API. - * - *

Will return null when the GNSS hardware abstraction layer does not support providing - * this value. + *

No device-specific serial number or ID is returned from this API. */ @Nullable public String getGnssHardwareModelName() { @@ -2217,8 +2220,11 @@ public class LocationManager { * Registers a GNSS status callback. This method must be called from a {@link Looper} thread, * and callbacks will occur on that looper. * - * @param callback GNSS status callback object to register - * @return true if the listener was successfully added + *

See {@link #registerGnssStatusCallback(Executor, GnssStatus.Callback)} for more detail on + * how this method works. + * + * @param callback the callback to register + * @return {@code true} always * * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present * @@ -2234,9 +2240,12 @@ public class LocationManager { /** * Registers a GNSS status callback. * - * @param callback GNSS status callback object to register - * @param handler a handler with a looper that the callback runs on - * @return true if the listener was successfully added + *

See {@link #registerGnssStatusCallback(Executor, GnssStatus.Callback)} for more detail on + * how this method works. + * + * @param callback the callback to register + * @param handler the handler the callback runs on + * @return {@code true} always * * @throws IllegalArgumentException if callback is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2252,11 +2261,12 @@ public class LocationManager { } /** - * Registers a GNSS status callback. + * Registers a GNSS status callback. GNSS status information will only be received while the + * {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * * @param executor the executor that the callback runs on - * @param callback GNSS status callback object to register - * @return true if the listener was successfully added + * @param callback the callback to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2301,8 +2311,12 @@ public class LocationManager { /** * Adds an NMEA listener. * - * @param listener a {@link OnNmeaMessageListener} object to register - * @return true if the listener was successfully added + *

See {@link #addNmeaListener(Executor, OnNmeaMessageListener)} for more detail on how this + * method works. + * + * @param listener the listener to register + * @return {@code true} always + * * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present * @deprecated Use {@link #addNmeaListener(OnNmeaMessageListener, Handler)} or {@link * #addNmeaListener(Executor, OnNmeaMessageListener)} instead. @@ -2316,9 +2330,12 @@ public class LocationManager { /** * Adds an NMEA listener. * - * @param listener a {@link OnNmeaMessageListener} object to register - * @param handler a handler with the looper that the listener runs on. - * @return true if the listener was successfully added + *

See {@link #addNmeaListener(Executor, OnNmeaMessageListener)} for more detail on how this + * method works. + * + * @param listener the listener to register + * @param handler the handler that the listener runs on + * @return {@code true} always * * @throws IllegalArgumentException if listener is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2334,11 +2351,12 @@ public class LocationManager { } /** - * Adds an NMEA listener. + * Adds an NMEA listener. GNSS NMEA information will only be received while the + * {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param listener a {@link OnNmeaMessageListener} object to register - * @param executor the {@link Executor} that the listener runs on. - * @return true if the listener was successfully added + * @param listener the listener to register + * @param executor the executor that the listener runs on + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if listener is null @@ -2348,7 +2366,7 @@ public class LocationManager { public boolean addNmeaListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnNmeaMessageListener listener) { - getGnssStatusTransportMultiplexer().addListener(listener, executor); + getGnssNmeaTransportMultiplexer().addListener(listener, executor); return true; } @@ -2358,7 +2376,7 @@ public class LocationManager { * @param listener a {@link OnNmeaMessageListener} object to remove */ public void removeNmeaListener(@NonNull OnNmeaMessageListener listener) { - getGnssStatusTransportMultiplexer().removeListener(listener); + getGnssNmeaTransportMultiplexer().removeListener(listener); } /** @@ -2386,10 +2404,14 @@ public class LocationManager { public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {} /** - * Registers a GPS Measurement callback which will run on a binder thread. + * Registers a GNSS measurements callback which will run on a binder thread. + * + *

See {@link #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback) + * for more detail on how this method works. + * + * @param callback a {@link GnssMeasurementsEvent.Callback} object to register + * @return {@code true} always * - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. * @deprecated Use {@link * #registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback, Handler)} or {@link * #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback)} instead. @@ -2402,11 +2424,14 @@ public class LocationManager { } /** - * Registers a GPS Measurement callback. + * Registers a GNSS measurements callback. * - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @param handler the handler that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

See {@link #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback) + * for more detail on how this method works. + * + * @param callback a {@link GnssMeasurementsEvent.Callback} object to register + * @param handler the handler that the callback runs on + * @return {@code true} always * * @throws IllegalArgumentException if callback is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2423,11 +2448,14 @@ public class LocationManager { } /** - * Registers a GPS Measurement callback. + * Registers a GNSS measurements callback. GNSS measurements information will only be received + * while the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @param executor the executor that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

Not all GNSS chipsets support measurements updates, see {@link #getGnssCapabilities()}. + * + * @param executor the executor that the callback runs on + * @param callback the callback to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2444,12 +2472,11 @@ public class LocationManager { /** * Registers a GNSS Measurement callback. * - * @param request extra parameters to pass to GNSS measurement provider. For example, if {@link - * GnssRequest#isFullTracking()} is true, GNSS chipset switches off duty - * cycling. - * @param executor the executor that the callback runs on. - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + * @param request the gnss measurement request containgin measurement parameters + * @param executor the executor that the callback runs on + * @param callback the callack to register + * @return {@code true} always + * * @throws IllegalArgumentException if request is null * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2498,8 +2525,7 @@ public class LocationManager { /** * Injects GNSS measurement corrections into the GNSS chipset. * - * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS - * measurement corrections to be injected into the GNSS chipset. + * @param measurementCorrections measurement corrections to be injected into the chipset * * @throws IllegalArgumentException if measurementCorrections is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2528,12 +2554,14 @@ public class LocationManager { } /** - * Registers a Gnss Antenna Info listener. Only expect results if - * {@link GnssCapabilities#hasGnssAntennaInfo()} shows that antenna info is supported. + * Registers a GNSS antenna info listener. GNSS antenna info updates will only be received while + * the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param executor the executor that the listener runs on. - * @param listener a {@link GnssAntennaInfo.Listener} object to register. - * @return {@code true} if the listener was added successfully, {@code false} otherwise. + *

Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}. + * + * @param executor the executor that the listener runs on + * @param listener the listener to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if listener is null @@ -2550,7 +2578,7 @@ public class LocationManager { /** * Unregisters a GNSS Antenna Info listener. * - * @param listener a {@link GnssAntennaInfo.Listener} object to remove. + * @param listener a {@link GnssAntennaInfo.Listener} object to remove */ public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) { getGnssAntennaInfoTransportMultiplexer().removeListener(listener); @@ -2581,10 +2609,15 @@ public class LocationManager { public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {} /** - * Registers a GNSS Navigation Message callback which will run on a binder thread. + * Registers a GNSS navigation message callback which will run on a binder thread. + * + *

See + * {@link #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} for + * more detail on how this method works. + * + * @param callback the callback to register + * @return {@code true} always * - * @param callback a {@link GnssNavigationMessage.Callback} object to register. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. * @deprecated Use {@link * #registerGnssNavigationMessageCallback(GnssNavigationMessage.Callback, Handler)} or {@link * #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} instead. @@ -2596,11 +2629,15 @@ public class LocationManager { } /** - * Registers a GNSS Navigation Message callback. + * Registers a GNSS navigation message callback. * - * @param callback a {@link GnssNavigationMessage.Callback} object to register. - * @param handler the handler that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

See + * {@link #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} for + * more detail on how this method works. + * + * @param callback the callback to register + * @param handler the handler that the callback runs on + * @return {@code true} always * * @throws IllegalArgumentException if callback is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2616,11 +2653,15 @@ public class LocationManager { } /** - * Registers a GNSS Navigation Message callback. + * Registers a GNSS navigation message callback. GNSS navigation messages will only be received + * while the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param callback a {@link GnssNavigationMessage.Callback} object to register. - * @param executor the looper that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

Not all GNSS chipsets support navigation message updates, see + * {@link #getGnssCapabilities()}. + * + * @param executor the executor that the callback runs on + * @param callback the callback to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2854,20 +2895,6 @@ public class LocationManager { } } - private static class NmeaAdapter extends GnssStatus.Callback implements OnNmeaMessageListener { - - private final OnNmeaMessageListener mListener; - - NmeaAdapter(OnNmeaMessageListener listener) { - mListener = listener; - } - - @Override - public void onNmeaMessage(String message, long timestamp) { - mListener.onNmeaMessage(message, timestamp); - } - } - private static class GpsAdapter extends GnssStatus.Callback { private final GpsStatus.Listener mGpsListener; @@ -2915,11 +2942,6 @@ public class LocationManager { return mTtff; } - public void addListener(@NonNull OnNmeaMessageListener listener, - @NonNull Executor executor) { - addListener(listener, null, new NmeaAdapter(listener), executor); - } - public void addListener(@NonNull GpsStatus.Listener listener, @NonNull Executor executor) { addListener(listener, null, new GpsAdapter(listener), executor); } @@ -2972,14 +2994,51 @@ public class LocationManager { mGnssStatus = gnssStatus; deliverToListeners(callback -> callback.onSatelliteStatusChanged(gnssStatus)); } + } + } + + private class GnssNmeaTransportMultiplexer extends + ListenerTransportMultiplexer { + + private @Nullable IGnssNmeaListener mListenerTransport; + + GnssNmeaTransportMultiplexer() {} + + public void addListener(@NonNull OnNmeaMessageListener listener, + @NonNull Executor executor) { + addListener(listener, null, listener, executor); + } + + @Override + protected void registerWithServer(Void ignored) throws RemoteException { + IGnssNmeaListener transport = mListenerTransport; + if (transport == null) { + transport = new GnssNmeaListener(); + } + + // if a remote exception is thrown the transport should not be set + mListenerTransport = null; + mService.registerGnssNmeaCallback(transport, mContext.getPackageName(), + mContext.getAttributionTag()); + mListenerTransport = transport; + } + + @Override + protected void unregisterWithServer() throws RemoteException { + if (mListenerTransport != null) { + IGnssNmeaListener transport = mListenerTransport; + mListenerTransport = null; + mService.unregisterGnssNmeaCallback(transport); + } + } + + private class GnssNmeaListener extends IGnssNmeaListener.Stub { + + GnssNmeaListener() {} @Override public void onNmeaReceived(long timestamp, String nmea) { - deliverToListeners((callback) -> { - if (callback instanceof NmeaAdapter) { - ((NmeaAdapter) callback).onNmeaMessage(nmea, timestamp); - } - }); + deliverToListeners(callback -> callback.onNmeaMessage(nmea, timestamp)); } } } diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 0de2ae24bad76..372bceeea3c48 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -52,8 +52,8 @@ import android.location.IGeocodeListener; import android.location.IGnssAntennaInfoListener; import android.location.IGnssMeasurementsListener; import android.location.IGnssNavigationMessageListener; +import android.location.IGnssNmeaListener; import android.location.IGnssStatusListener; -import android.location.IGpsGeofenceHardware; import android.location.ILocationCallback; import android.location.ILocationListener; import android.location.ILocationManager; @@ -87,10 +87,13 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.location.geofence.GeofenceManager; import com.android.server.location.geofence.GeofenceProxy; +import com.android.server.location.gnss.GnssConfiguration; import com.android.server.location.gnss.GnssManagerService; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AlarmHelper; import com.android.server.location.injector.AppForegroundHelper; import com.android.server.location.injector.AppOpsHelper; +import com.android.server.location.injector.EmergencyHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationAttributionHelper; import com.android.server.location.injector.LocationEventLog; @@ -102,6 +105,7 @@ import com.android.server.location.injector.SettingsHelper; import com.android.server.location.injector.SystemAlarmHelper; import com.android.server.location.injector.SystemAppForegroundHelper; import com.android.server.location.injector.SystemAppOpsHelper; +import com.android.server.location.injector.SystemEmergencyHelper; import com.android.server.location.injector.SystemLocationPermissionsHelper; import com.android.server.location.injector.SystemLocationPowerSaveModeHelper; import com.android.server.location.injector.SystemScreenInteractiveHelper; @@ -367,8 +371,10 @@ public class LocationManagerService extends ILocationManager.Stub { // initialize gnss last because it has no awareness of boot phases and blindly assumes that // all other location providers are loaded at initialization - if (GnssManagerService.isGnssSupported()) { - mGnssManagerService = new GnssManagerService(mContext, mInjector); + if (GnssNative.isSupported()) { + GnssConfiguration gnssConfiguration = new GnssConfiguration(mContext); + GnssNative gnssNative = GnssNative.create(mInjector, gnssConfiguration); + mGnssManagerService = new GnssManagerService(mContext, mInjector, gnssNative); mGnssManagerService.onSystemReady(); LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector, @@ -390,13 +396,11 @@ public class LocationManagerService extends ILocationManager.Stub { } // bind to gnss geofence proxy - if (GnssManagerService.isGnssSupported()) { - IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy(); - if (gpsGeofenceHardware != null) { - GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware); - if (provider == null) { - Log.e(TAG, "unable to bind to GeofenceProxy"); - } + if (mGnssManagerService != null) { + GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, + mGnssManagerService.getGnssGeofenceProxy()); + if (provider == null) { + Log.e(TAG, "unable to bind to GeofenceProxy"); } } @@ -863,6 +867,21 @@ public class LocationManagerService extends ILocationManager.Stub { } } + @Override + public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, + String attributionTag) { + if (mGnssManagerService != null) { + mGnssManagerService.registerGnssNmeaCallback(listener, packageName, attributionTag); + } + } + + @Override + public void unregisterGnssNmeaCallback(IGnssNmeaListener listener) { + if (mGnssManagerService != null) { + mGnssManagerService.unregisterGnssNmeaCallback(listener); + } + } + @Override public void addGnssMeasurementsListener(@Nullable GnssMeasurementRequest request, IGnssMeasurementsListener listener, String packageName, String attributionTag) { @@ -888,8 +907,8 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public long getGnssCapabilities() { - return mGnssManagerService == null ? GnssCapabilities.INVALID_CAPABILITIES + public GnssCapabilities getGnssCapabilities() { + return mGnssManagerService == null ? new GnssCapabilities.Builder().build() : mGnssManagerService.getGnssCapabilities(); } @@ -1289,8 +1308,10 @@ public class LocationManagerService extends ILocationManager.Stub { private static class SystemInjector implements Injector { - private final LocationEventLog mLocationEventLog; + private final Context mContext; + private final UserInfoHelper mUserInfoHelper; + private final LocationEventLog mLocationEventLog; private final AlarmHelper mAlarmHelper; private final SystemAppOpsHelper mAppOpsHelper; private final SystemLocationPermissionsHelper mLocationPermissionsHelper; @@ -1301,9 +1322,19 @@ public class LocationManagerService extends ILocationManager.Stub { private final LocationAttributionHelper mLocationAttributionHelper; private final LocationUsageLogger mLocationUsageLogger; + // lazily instantiated since they may not always be used + + @GuardedBy("this") + private @Nullable SystemEmergencyHelper mEmergencyCallHelper; + + @GuardedBy("this") + private boolean mSystemReady; + SystemInjector(Context context, UserInfoHelper userInfoHelper) { - mLocationEventLog = new LocationEventLog(); + mContext = context; + mUserInfoHelper = userInfoHelper; + mLocationEventLog = new LocationEventLog(); mAlarmHelper = new SystemAlarmHelper(context); mAppOpsHelper = new SystemAppOpsHelper(context); mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context, @@ -1317,13 +1348,19 @@ public class LocationManagerService extends ILocationManager.Stub { mLocationUsageLogger = new LocationUsageLogger(); } - void onSystemReady() { + synchronized void onSystemReady() { mAppOpsHelper.onSystemReady(); mLocationPermissionsHelper.onSystemReady(); mSettingsHelper.onSystemReady(); mAppForegroundHelper.onSystemReady(); mLocationPowerSaveModeHelper.onSystemReady(); mScreenInteractiveHelper.onSystemReady(); + + if (mEmergencyCallHelper != null) { + mEmergencyCallHelper.onSystemReady(); + } + + mSystemReady = true; } @Override @@ -1356,11 +1393,6 @@ public class LocationManagerService extends ILocationManager.Stub { return mAppForegroundHelper; } - @Override - public LocationUsageLogger getLocationUsageLogger() { - return mLocationUsageLogger; - } - @Override public LocationPowerSaveModeHelper getLocationPowerSaveModeHelper() { return mLocationPowerSaveModeHelper; @@ -1376,9 +1408,26 @@ public class LocationManagerService extends ILocationManager.Stub { return mLocationAttributionHelper; } + @Override + public synchronized EmergencyHelper getEmergencyHelper() { + if (mEmergencyCallHelper == null) { + mEmergencyCallHelper = new SystemEmergencyHelper(mContext); + if (mSystemReady) { + mEmergencyCallHelper.onSystemReady(); + } + } + + return mEmergencyCallHelper; + } + @Override public LocationEventLog getLocationEventLog() { return mLocationEventLog; } + + @Override + public LocationUsageLogger getLocationUsageLogger() { + return mLocationUsageLogger; + } } } diff --git a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java index 9961d274ea9c4..e9f79efb05130 100644 --- a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java @@ -20,12 +20,12 @@ import static com.android.server.location.gnss.GnssManagerService.D; import static com.android.server.location.gnss.GnssManagerService.TAG; import android.location.GnssAntennaInfo; +import android.location.GnssCapabilities; import android.location.IGnssAntennaInfoListener; import android.location.util.identity.CallerIdentity; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import java.util.Collection; @@ -35,23 +35,22 @@ import java.util.List; * Provides GNSS antenna information to clients. */ public class GnssAntennaInfoProvider extends - GnssListenerMultiplexer { + GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.AntennaInfoCallbacks { - private final GnssAntennaInfoProviderNative mNative; + private final GnssNative mGnssNative; - public GnssAntennaInfoProvider(Injector injector) { - this(injector, new GnssAntennaInfoProviderNative()); - } - - @VisibleForTesting - public GnssAntennaInfoProvider(Injector injector, GnssAntennaInfoProviderNative aNative) { + public GnssAntennaInfoProvider(Injector injector, GnssNative gnssNative) { super(injector); - mNative = aNative; + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addAntennaInfoCallbacks(this); } @Override protected boolean isServiceSupported() { - return mNative.isAntennaInfoSupported(); + return mGnssNative.isAntennaInfoListeningSupported(); } @Override @@ -62,9 +61,7 @@ public class GnssAntennaInfoProvider extends @Override protected boolean registerWithService(Void ignored, Collection registrations) { - Preconditions.checkState(mNative.isAntennaInfoSupported()); - - if (mNative.startAntennaInfoListening()) { + if (mGnssNative.startAntennaInfoListening()) { if (D) { Log.d(TAG, "starting gnss antenna info"); } @@ -77,7 +74,7 @@ public class GnssAntennaInfoProvider extends @Override protected void unregisterWithService() { - if (mNative.stopAntennaInfoListening()) { + if (mGnssNative.stopAntennaInfoListening()) { if (D) { Log.d(TAG, "stopping gnss antenna info"); } @@ -86,39 +83,19 @@ public class GnssAntennaInfoProvider extends } } - /** - * Called by GnssLocationProvider. - */ - public void onGnssAntennaInfoAvailable(List gnssAntennaInfos) { - deliverToListeners((listener) -> { - listener.onGnssAntennaInfoReceived(gnssAntennaInfos); + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportAntennaInfo(List antennaInfos) { + deliverToListeners(listener -> { + listener.onGnssAntennaInfoReceived(antennaInfos); }); } - - /** - * Wrapper class for native methods. This is mocked for testing. - */ - @VisibleForTesting - public static class GnssAntennaInfoProviderNative { - - public boolean isAntennaInfoSupported() { - return native_is_antenna_info_supported(); - } - - /** Start antenna info listening. */ - public boolean startAntennaInfoListening() { - return native_start_antenna_info_listening(); - } - - /** Stop antenna info listening. */ - public boolean stopAntennaInfoListening() { - return native_stop_antenna_info_listening(); - } - } - - static native boolean native_is_antenna_info_supported(); - - static native boolean native_start_antenna_info_listening(); - - static native boolean native_stop_antenna_info_listening(); } diff --git a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java deleted file mode 100644 index 1c4fb10b8d0ee..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.server.location.gnss; - -import android.location.GnssCapabilities; -import android.util.Log; - -import com.android.internal.annotations.GuardedBy; - -/** - * Provides GNSS capabilities supported by the GNSS HAL implementation. - */ -public class GnssCapabilitiesProvider { - private static final String TAG = "GnssCapabilitiesProvider"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private static final long GNSS_CAPABILITIES_TOP_HAL = - GnssCapabilities.LOW_POWER_MODE | GnssCapabilities.SATELLITE_BLOCKLIST - | GnssCapabilities.GEOFENCING | GnssCapabilities.MEASUREMENTS - | GnssCapabilities.NAV_MESSAGES; - - private static final long GNSS_CAPABILITIES_SUB_HAL_MEASUREMENT_CORRECTIONS = - GnssCapabilities.MEASUREMENT_CORRECTIONS - | GnssCapabilities.MEASUREMENT_CORRECTIONS_LOS_SATS - | GnssCapabilities.MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH - | GnssCapabilities.MEASUREMENT_CORRECTIONS_REFLECTING_PLANE; - - // Capabilities in {@link android.location.GnssCapabilities} supported by GNSS chipset. - @GuardedBy("this") - private long mGnssCapabilities; - - /** - * Returns the capabilities supported by the GNSS chipset. - * - *

The capabilities are described in {@link android.location.GnssCapabilities} and - * their integer values correspond to the bit positions in the returned {@code long} value. - */ - public long getGnssCapabilities() { - synchronized (this) { - return mGnssCapabilities; - } - } - - /** - * Updates the general capabilities exposed through {@link android.location.GnssCapabilities}. - */ - void setTopHalCapabilities(int topHalCapabilities) { - long gnssCapabilities = 0; - if (hasCapability(topHalCapabilities, - GnssLocationProvider.GPS_CAPABILITY_LOW_POWER_MODE)) { - gnssCapabilities |= GnssCapabilities.LOW_POWER_MODE; - } - if (hasCapability(topHalCapabilities, - GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLOCKLIST)) { - gnssCapabilities |= GnssCapabilities.SATELLITE_BLOCKLIST; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_GEOFENCING)) { - gnssCapabilities |= GnssCapabilities.GEOFENCING; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENTS; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES)) { - gnssCapabilities |= GnssCapabilities.NAV_MESSAGES; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_ANTENNA_INFO)) { - gnssCapabilities |= GnssCapabilities.ANTENNA_INFO; - } - - synchronized (this) { - mGnssCapabilities &= ~GNSS_CAPABILITIES_TOP_HAL; - mGnssCapabilities |= gnssCapabilities; - if (DEBUG) { - Log.d(TAG, "setTopHalCapabilities, mGnssCapabilities=0x" + Long.toHexString( - mGnssCapabilities) + ", " + GnssCapabilities.of(mGnssCapabilities)); - } - } - } - - /** - * Updates the measurement corrections related capabilities exposed through - * {@link android.location.GnssCapabilities}. - */ - void setSubHalMeasurementCorrectionsCapabilities(int measurementCorrectionsCapabilities) { - long gnssCapabilities = GnssCapabilities.MEASUREMENT_CORRECTIONS; - if (hasCapability(measurementCorrectionsCapabilities, - GnssMeasurementCorrectionsProvider.CAPABILITY_LOS_SATS)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_LOS_SATS; - } - if (hasCapability(measurementCorrectionsCapabilities, - GnssMeasurementCorrectionsProvider.CAPABILITY_EXCESS_PATH_LENGTH)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH; - } - if (hasCapability(measurementCorrectionsCapabilities, - GnssMeasurementCorrectionsProvider.CAPABILITY_REFLECTING_PLANE)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_REFLECTING_PLANE; - } - - synchronized (this) { - mGnssCapabilities &= ~GNSS_CAPABILITIES_SUB_HAL_MEASUREMENT_CORRECTIONS; - mGnssCapabilities |= gnssCapabilities; - if (DEBUG) { - Log.d(TAG, "setSubHalMeasurementCorrectionsCapabilities, mGnssCapabilities=0x" - + Long.toHexString(mGnssCapabilities) + ", " + GnssCapabilities.of( - mGnssCapabilities)); - } - } - } - - private static boolean hasCapability(int halCapabilities, int capability) { - return (halCapabilities & capability) != 0; - } -} diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java index 26283729f4e97..60b7447e9f6c8 100644 --- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java @@ -31,7 +31,7 @@ import libcore.io.IoUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -48,7 +48,7 @@ import java.util.Properties; * Instances of this class are not thread-safe and should either be used from a single thread * or with external synchronization when used by multiple threads. */ -class GnssConfiguration { +public class GnssConfiguration { private static final String TAG = "GnssConfiguration"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -98,13 +98,13 @@ class GnssConfiguration { /** * Properties loaded from PROPERTIES_FILE. */ - private Properties mProperties; + private final Properties mProperties; private int mEsExtensionSec = 0; private final Context mContext; - GnssConfiguration(Context context) { + public GnssConfiguration(Context context) { mContext = context; mProperties = new Properties(); } @@ -120,7 +120,7 @@ class GnssConfiguration { * Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked * and constrained to min/max limits. */ - int getEsExtensionSec() { + public int getEsExtensionSec() { return mEsExtensionSec; } @@ -168,8 +168,8 @@ class GnssConfiguration { * Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is * provided or if there is an error parsing the configured value. */ - int getSuplEs(int defaulSuplEs) { - return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs); + public int getSuplEs(int defaultSuplEs) { + return getIntConfig(CONFIG_SUPL_ES, defaultSuplEs); } /** @@ -181,27 +181,21 @@ class GnssConfiguration { } /** - * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or - * {@Collections.EMPTY_LIST} if no value is provided. + * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS. */ List getProxyApps() { // Space separated list of Android proxy app package names. String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS); if (TextUtils.isEmpty(proxyAppsStr)) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+"); if (proxyAppsArray.length == 0) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } - ArrayList proxyApps = new ArrayList(proxyAppsArray.length); - for (String proxyApp : proxyAppsArray) { - proxyApps.add(proxyApp); - } - - return proxyApps; + return Arrays.asList(proxyAppsArray); } /** diff --git a/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java b/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java similarity index 59% rename from services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java rename to services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java index 53883b91c36de..32a7952b14d1d 100644 --- a/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java @@ -16,20 +16,17 @@ package com.android.server.location.gnss; +import android.location.GnssCapabilities; import android.location.IGpsGeofenceHardware; -import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.gnss.hal.GnssNative; /** * Manages GNSS Geofence operations. */ -class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { - - private static final String TAG = "GnssGeofenceProvider"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); +class GnssGeofenceProxy extends IGpsGeofenceHardware.Stub implements GnssNative.BaseCallbacks { /** Holds the parameters of a geofence. */ private static class GeofenceEntry { @@ -45,43 +42,22 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { } private final Object mLock = new Object(); - @GuardedBy("mLock") - private final GnssGeofenceProviderNative mNative; + + private final GnssNative mGnssNative; + @GuardedBy("mLock") private final SparseArray mGeofenceEntries = new SparseArray<>(); - GnssGeofenceProvider() { - this(new GnssGeofenceProviderNative()); - } + GnssGeofenceProxy(GnssNative gnssNative) { + mGnssNative = gnssNative; - @VisibleForTesting - GnssGeofenceProvider(GnssGeofenceProviderNative gnssGeofenceProviderNative) { - mNative = gnssGeofenceProviderNative; - } - - void resumeIfStarted() { - if (DEBUG) { - Log.d(TAG, "resumeIfStarted"); - } - synchronized (mLock) { - for (int i = 0; i < mGeofenceEntries.size(); i++) { - GeofenceEntry entry = mGeofenceEntries.valueAt(i); - boolean added = mNative.addGeofence(entry.geofenceId, entry.latitude, - entry.longitude, - entry.radius, - entry.lastTransition, entry.monitorTransitions, - entry.notificationResponsiveness, entry.unknownTimer); - if (added && entry.paused) { - mNative.pauseGeofence(entry.geofenceId); - } - } - } + mGnssNative.addBaseCallbacks(this); } @Override public boolean isHardwareGeofenceSupported() { synchronized (mLock) { - return mNative.isGeofenceSupported(); + return mGnssNative.isGeofencingSupported(); } } @@ -90,7 +66,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { double longitude, double radius, int lastTransition, int monitorTransitions, int notificationResponsiveness, int unknownTimer) { synchronized (mLock) { - boolean added = mNative.addGeofence(geofenceId, latitude, longitude, radius, + boolean added = mGnssNative.addGeofence(geofenceId, latitude, longitude, radius, lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer); if (added) { @@ -112,7 +88,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { @Override public boolean removeHardwareGeofence(int geofenceId) { synchronized (mLock) { - boolean removed = mNative.removeGeofence(geofenceId); + boolean removed = mGnssNative.removeGeofence(geofenceId); if (removed) { mGeofenceEntries.remove(geofenceId); } @@ -123,7 +99,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { @Override public boolean pauseHardwareGeofence(int geofenceId) { synchronized (mLock) { - boolean paused = mNative.pauseGeofence(geofenceId); + boolean paused = mGnssNative.pauseGeofence(geofenceId); if (paused) { GeofenceEntry entry = mGeofenceEntries.get(geofenceId); if (entry != null) { @@ -137,7 +113,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { @Override public boolean resumeHardwareGeofence(int geofenceId, int monitorTransitions) { synchronized (mLock) { - boolean resumed = mNative.resumeGeofence(geofenceId, monitorTransitions); + boolean resumed = mGnssNative.resumeGeofence(geofenceId, monitorTransitions); if (resumed) { GeofenceEntry entry = mGeofenceEntries.get(geofenceId); if (entry != null) { @@ -149,41 +125,24 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { } } - @VisibleForTesting - static class GnssGeofenceProviderNative { - public boolean isGeofenceSupported() { - return native_is_geofence_supported(); - } - - public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius, - int lastTransition, int monitorTransitions, int notificationResponsiveness, - int unknownTimer) { - return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition, - monitorTransitions, notificationResponsiveness, unknownTimer); - } - - public boolean removeGeofence(int geofenceId) { - return native_remove_geofence(geofenceId); - } - - public boolean resumeGeofence(int geofenceId, int transitions) { - return native_resume_geofence(geofenceId, transitions); - } - - public boolean pauseGeofence(int geofenceId) { - return native_pause_geofence(geofenceId); + @Override + public void onHalRestarted() { + synchronized (mLock) { + for (int i = 0; i < mGeofenceEntries.size(); i++) { + GeofenceEntry entry = mGeofenceEntries.valueAt(i); + boolean added = mGnssNative.addGeofence(entry.geofenceId, entry.latitude, + entry.longitude, + entry.radius, + entry.lastTransition, entry.monitorTransitions, + entry.notificationResponsiveness, entry.unknownTimer); + if (added && entry.paused) { + mGnssNative.pauseGeofence(entry.geofenceId); + } + } } } - private static native boolean native_is_geofence_supported(); - - private static native boolean native_add_geofence(int geofenceId, double latitude, - double longitude, double radius, int lastTransition, int monitorTransitions, - int notificationResponsivenes, int unknownTimer); - - private static native boolean native_remove_geofence(int geofenceId); - - private static native boolean native_resume_geofence(int geofenceId, int transitions); - - private static native boolean native_pause_geofence(int geofenceId); + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} } diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index 691b85af62d3d..afe75674647fc 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -17,6 +17,28 @@ package com.android.server.location.gnss; import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_GSM_CELLID; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_UMTS_CELLID; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_IMSI; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_MSISDN; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_NONE; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALL; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALMANAC; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_CELLDB_INFO; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_EPHEMERIS; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_HEALTH; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_IONO; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_POSITION; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_RTI; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SADATA; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVDIR; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVSTEER; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_TIME; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_UTC; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_ASSISTED; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_BASED; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_STANDALONE; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_RECURRENCE_PERIODIC; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -28,14 +50,9 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; -import android.hardware.location.GeofenceHardware; -import android.hardware.location.GeofenceHardwareImpl; -import android.location.FusedBatchOptions; -import android.location.GnssAntennaInfo; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; +import android.location.Criteria; +import android.location.GnssCapabilities; import android.location.GnssStatus; -import android.location.IGpsGeofenceHardware; import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationListener; @@ -73,11 +90,11 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; import com.android.internal.location.ProviderRequest; -import com.android.internal.location.gnssmetrics.GnssMetrics; import com.android.internal.util.FrameworkStatsLog; import com.android.server.FgThread; import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback; import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import com.android.server.location.provider.AbstractLocationProvider; @@ -96,8 +113,10 @@ import java.util.Set; * {@hide} */ public class GnssLocationProvider extends AbstractLocationProvider implements - InjectNtpTimeCallback, - GnssSatelliteBlocklistCallback { + InjectNtpTimeCallback, GnssSatelliteBlocklistCallback, GnssNative.BaseCallbacks, + GnssNative.LocationCallbacks, GnssNative.SvStatusCallbacks, GnssNative.AGpsCallbacks, + GnssNative.PsdsCallbacks, GnssNative.NotificationCallbacks, + GnssNative.LocationRequestCallbacks, GnssNative.TimeCallbacks { private static final String TAG = "GnssLocationProvider"; @@ -115,101 +134,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements ProviderProperties.POWER_USAGE_HIGH, ProviderProperties.ACCURACY_FINE); - // these need to match GnssPositionMode enum in IGnss.hal - private static final int GPS_POSITION_MODE_STANDALONE = 0; - private static final int GPS_POSITION_MODE_MS_BASED = 1; - private static final int GPS_POSITION_MODE_MS_ASSISTED = 2; - - // these need to match GnssPositionRecurrence enum in IGnss.hal - private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0; - private static final int GPS_POSITION_RECURRENCE_SINGLE = 1; - - // these need to match GnssStatusValue enum in IGnssCallback.hal - private static final int GPS_STATUS_NONE = 0; - private static final int GPS_STATUS_SESSION_BEGIN = 1; - private static final int GPS_STATUS_SESSION_END = 2; - private static final int GPS_STATUS_ENGINE_ON = 3; - private static final int GPS_STATUS_ENGINE_OFF = 4; - - // these need to match GnssLocationFlags enum in types.hal - private static final int LOCATION_INVALID = 0; - private static final int LOCATION_HAS_LAT_LONG = 1; - private static final int LOCATION_HAS_ALTITUDE = 2; - private static final int LOCATION_HAS_SPEED = 4; - private static final int LOCATION_HAS_BEARING = 8; - private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16; - private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32; - private static final int LOCATION_HAS_SPEED_ACCURACY = 64; - private static final int LOCATION_HAS_BEARING_ACCURACY = 128; - - // these need to match ElapsedRealtimeFlags enum in types.hal - private static final int ELAPSED_REALTIME_HAS_TIMESTAMP_NS = 1; - private static final int ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2; - - // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal - private static final int GPS_DELETE_EPHEMERIS = 0x0001; - private static final int GPS_DELETE_ALMANAC = 0x0002; - private static final int GPS_DELETE_POSITION = 0x0004; - private static final int GPS_DELETE_TIME = 0x0008; - private static final int GPS_DELETE_IONO = 0x0010; - private static final int GPS_DELETE_UTC = 0x0020; - private static final int GPS_DELETE_HEALTH = 0x0040; - private static final int GPS_DELETE_SVDIR = 0x0080; - private static final int GPS_DELETE_SVSTEER = 0x0100; - private static final int GPS_DELETE_SADATA = 0x0200; - private static final int GPS_DELETE_RTI = 0x0400; - private static final int GPS_DELETE_CELLDB_INFO = 0x8000; - private static final int GPS_DELETE_ALL = 0xFFFF; - - // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal - private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001; - private static final int GPS_CAPABILITY_MSB = 0x0000002; - private static final int GPS_CAPABILITY_MSA = 0x0000004; - private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008; - private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010; - public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020; - public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040; - public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080; - public static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100; - public static final int GPS_CAPABILITY_SATELLITE_BLOCKLIST = 0x0000200; - public static final int GPS_CAPABILITY_MEASUREMENT_CORRECTIONS = 0x0000400; - public static final int GPS_CAPABILITY_ANTENNA_INFO = 0x0000800; - // The AGPS SUPL mode private static final int AGPS_SUPL_MODE_MSA = 0x02; private static final int AGPS_SUPL_MODE_MSB = 0x01; + // handler messages private static final int INJECT_NTP_TIME = 5; - // PSDS stands for Predicted Satellite Data Service private static final int DOWNLOAD_PSDS_DATA = 6; private static final int REQUEST_LOCATION = 16; private static final int REPORT_LOCATION = 17; // HAL reports location private static final int REPORT_SV_STATUS = 18; // HAL reports SV status - // Request setid - private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; - private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; - - // ref. location info - private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; - private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; - - // set id info - private static final int AGPS_SETID_TYPE_NONE = 0; - private static final int AGPS_SETID_TYPE_IMSI = 1; - private static final int AGPS_SETID_TYPE_MSISDN = 2; - - private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L; - private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L; - - // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal. - private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0; - private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100; - private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101; - private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102; - private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103; - private static final int GPS_GEOFENCE_ERROR_GENERIC = -149; - // TCP/IP constants. // Valid TCP/UDP port range is (0, 65535]. private static final int TCP_MIN_PORT = 0; @@ -289,19 +224,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000; private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000; - private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderPsdsDownload"; - - // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL - // stops output right at 600m/s, depriving this of the information of a device that reaches - // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases. - private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F; - - private final Object mLock = new Object(); private final Context mContext; private final Handler mHandler; + private final GnssNative mGnssNative; + @GuardedBy("mLock") private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); @@ -314,7 +243,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private boolean mBatchingEnabled; private boolean mShutdown; - private boolean mNavigating; private boolean mStarted; private boolean mBatchingStarted; private long mStartedChangedElapsedRealtime; @@ -334,9 +262,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final WorkSource mClientSource = new WorkSource(); - // capabilities reported through the top level IGnssCallback.hal - private volatile int mTopHalCapabilities; - // true if PSDS is supported private boolean mSupportsPsds; @GuardedBy("mLock") @@ -357,15 +282,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private boolean mSuplEsEnabled = false; private final LocationExtras mLocationExtras = new LocationExtras(); - private final GnssStatusProvider mGnssStatusListenerHelper; - private final GnssMeasurementsProvider mGnssMeasurementsProvider; - private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider; - private final GnssAntennaInfoProvider mGnssAntennaInfoProvider; - private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; - private final GnssPowerIndicationProvider mGnssPowerIndicationProvider; private final NtpTimeHelper mNtpTimeHelper; - private final GnssGeofenceProvider mGnssGeofenceProvider; - private final GnssCapabilitiesProvider mGnssCapabilitiesProvider; private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper; // Available only on GNSS HAL 2.0 implementations and later. @@ -384,44 +301,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final AppOpsManager mAppOps; private final IBatteryStats mBatteryStats; - private GeofenceHardwareImpl mGeofenceHardwareImpl; - - // Volatile for simple inter-thread sync on these values. - private volatile int mHardwareYear = 0; - private volatile String mHardwareModelName; - - private volatile boolean mItarSpeedLimitExceeded = false; - @GuardedBy("mLock") private final ArrayList mFlushListeners = new ArrayList<>(0); // GNSS Metrics private final GnssMetrics mGnssMetrics; - public GnssStatusProvider getGnssStatusProvider() { - return mGnssStatusListenerHelper; - } - - public IGpsGeofenceHardware getGpsGeofenceProxy() { - return mGnssGeofenceProvider; - } - - public GnssMeasurementsProvider getGnssMeasurementsProvider() { - return mGnssMeasurementsProvider; - } - - public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() { - return mGnssMeasurementCorrectionsProvider; - } - - public GnssAntennaInfoProvider getGnssAntennaInfoProvider() { - return mGnssAntennaInfoProvider; - } - - public GnssNavigationMessageProvider getGnssNavigationMessageProvider() { - return mGnssNavigationMessageProvider; - } - /** * Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}. */ @@ -485,20 +370,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - public GnssLocationProvider(Context context, Injector injector) { + public GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative, + GnssMetrics gnssMetrics) { super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES); mContext = context; + mGnssNative = gnssNative; + mGnssMetrics = gnssMetrics; // Create a wake lock PowerManager powerManager = Objects.requireNonNull( mContext.getSystemService(PowerManager.class)); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*location*:" + TAG); mWakeLock.setReferenceCounted(true); // Create a separate wake lock for psds downloader as it may be released due to timeout. mDownloadPsdsWakeLock = powerManager.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY); + PowerManager.PARTIAL_WAKE_LOCK, "*location*:PsdsDownload"); mDownloadPsdsWakeLock.setReferenceCounted(true); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); @@ -518,8 +406,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // relative long time, so the ctor() is kept to create objects needed by this instance, // while IO initialization and registration is delegated to our internal handler // this approach is just fine because events are posted to our handler anyway - mGnssConfiguration = new GnssConfiguration(mContext); - mGnssCapabilitiesProvider = new GnssCapabilitiesProvider(); + mGnssConfiguration = mGnssNative.getConfiguration(); // Create a GPS net-initiated handler (also needed by handleInitialize) mNIHandler = new GpsNetInitiatedHandler(context, mNetInitiatedListener, @@ -529,21 +416,21 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context, GnssLocationProvider.this::onNetworkAvailable, mHandler.getLooper(), mNIHandler); - mGnssStatusListenerHelper = new GnssStatusProvider(injector); - mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector); - mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler); - mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(injector); - mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector); - mGnssPowerIndicationProvider = new GnssPowerIndicationProvider(); - - mGnssMetrics = new GnssMetrics(mContext, mBatteryStats); mNtpTimeHelper = new NtpTimeHelper(mContext, mHandler.getLooper(), this); mGnssSatelliteBlocklistHelper = new GnssSatelliteBlocklistHelper(mContext, mHandler.getLooper(), this); - mGnssGeofenceProvider = new GnssGeofenceProvider(); setAllowed(true); + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addLocationCallbacks(this); + mGnssNative.addSvStatusCallbacks(this); + mGnssNative.setAGpsCallbacks(this); + mGnssNative.setPsdsCallbacks(this); + mGnssNative.setNotificationCallbacks(this); + mGnssNative.setLocationRequestCallbacks(this); + mGnssNative.setTimeCallbacks(this); } /** Called when system is ready. */ @@ -573,12 +460,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } private void handleInitialize() { - // it *appears* that native_init() needs to be called at least once before invoking any - // other gnss methods, so we cycle once on initialization. - native_init(); - native_cleanup(); - - if (native_is_gnss_visibility_control_supported()) { + if (mGnssNative.isGnssVisibilityControlSupported()) { mGnssVisibilityControl = new GnssVisibilityControl(mContext, mHandler.getLooper(), mNIHandler); } @@ -633,7 +515,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements */ @Override public void injectTime(long time, long timeReference, int uncertainty) { - native_inject_time(time, timeReference, uncertainty); + mGnssNative.injectTime(time, timeReference, uncertainty); } /** @@ -645,7 +527,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (mSupportsPsds) { synchronized (mLock) { for (int psdsType : mPendingDownloadPsdsTypes) { - downloadPsdsData(psdsType); + sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null); } mPendingDownloadPsdsTypes.clear(); } @@ -722,38 +604,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return; } - int gnssLocationFlags = LOCATION_HAS_LAT_LONG - | (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) - | (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) - | (location.hasBearing() ? LOCATION_HAS_BEARING : 0) - | (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) - | (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) - | (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) - | (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0); - - double latitudeDegrees = location.getLatitude(); - double longitudeDegrees = location.getLongitude(); - double altitudeMeters = location.getAltitude(); - float speedMetersPerSec = location.getSpeed(); - float bearingDegrees = location.getBearing(); - float horizontalAccuracyMeters = location.getAccuracy(); - float verticalAccuracyMeters = location.getVerticalAccuracyMeters(); - float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond(); - float bearingAccuracyDegrees = location.getBearingAccuracyDegrees(); - long timestamp = location.getTime(); - - int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS - | (location.hasElapsedRealtimeUncertaintyNanos() - ? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0); - long elapsedRealtimeNanos = location.getElapsedRealtimeNanos(); - double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos(); - - native_inject_best_location( - gnssLocationFlags, latitudeDegrees, longitudeDegrees, - altitudeMeters, speedMetersPerSec, bearingDegrees, - horizontalAccuracyMeters, verticalAccuracyMeters, - speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp, - elapsedRealtimeFlags, elapsedRealtimeNanos, elapsedRealtimeUncertaintyNanos); + mGnssNative.injectBestLocation(location); } /** Returns true if the location request is too frequent. */ @@ -787,7 +638,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (data != null) { mHandler.post(() -> { if (DEBUG) Log.d(TAG, "calling native_inject_psds_data"); - native_inject_psds_data(data, data.length, psdsType); + mGnssNative.injectPsdsData(data, data.length, psdsType); synchronized (mLock) { mPsdsBackOff.reset(); } @@ -822,9 +673,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } private void injectLocation(Location location) { - if (location.hasAccuracy() && !location.isFromMockProvider()) { - native_inject_location(location.getLatitude(), location.getLongitude(), - location.getAccuracy()); + if (!location.isFromMockProvider()) { + mGnssNative.injectLocation(location); } } @@ -834,7 +684,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (mSuplServerHost != null && mSuplServerPort > TCP_MIN_PORT && mSuplServerPort <= TCP_MAX_PORT) { - native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, + mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); } } @@ -850,16 +700,16 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (agpsEnabled) { int suplMode = mGnssConfiguration.getSuplMode(0); if (suplMode == 0) { - return GPS_POSITION_MODE_STANDALONE; + return GNSS_POSITION_MODE_STANDALONE; } // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor // such mode when it is available - if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { - return GPS_POSITION_MODE_MS_BASED; + if (mGnssNative.getCapabilities().hasMsb() && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { + return GNSS_POSITION_MODE_MS_BASED; } } - return GPS_POSITION_MODE_STANDALONE; + return GNSS_POSITION_MODE_STANDALONE; } private void setGpsEnabled(boolean enabled) { @@ -871,23 +721,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private void handleEnable() { if (DEBUG) Log.d(TAG, "handleEnable"); - boolean inited = native_init(); + boolean inited = mGnssNative.init(); if (inited) { setGpsEnabled(true); - mSupportsPsds = native_supports_psds(); + mSupportsPsds = mGnssNative.isPsdsSupported(); // TODO: remove the following native calls if we can make sure they are redundant. if (mSuplServerHost != null) { - native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, + mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); } if (mC2KServerHost != null) { - native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K, + mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); } - mBatchingEnabled = native_init_batching() && native_get_batch_size() > 1; + mBatchingEnabled = mGnssNative.initBatching() && mGnssNative.getBatchSize() > 1; if (mGnssVisibilityControl != null) { mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true); } @@ -909,8 +759,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false); } // do this before releasing wakelock - native_cleanup_batching(); - native_cleanup(); + mGnssNative.cleanupBatching(); + mGnssNative.cleanup(); } private void updateEnabled() { @@ -949,7 +799,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements * minimum size guaranteed to be available for batching operations. */ public int getBatchSize() { - return native_get_batch_size(); + return mGnssNative.getBatchSize(); } @Override @@ -963,7 +813,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (!added) { listener.run(); } else { - native_flush_batch(); + mGnssNative.flushBatch(); } } @@ -1007,9 +857,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } else { stopBatching(); - if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { + if (mStarted && mGnssNative.getCapabilities().hasScheduling()) { // change period and/or lowPowerMode - if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, + if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval, mProviderRequest.isLowPower())) { Log.e(TAG, "set_position_mode failed in updateRequirements"); } @@ -1043,8 +893,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return true; } - boolean result = native_set_position_mode(mode, recurrence, minInterval, - 0, 0, lowPowerMode); + boolean result = mGnssNative.setPositionMode(mode, recurrence, minInterval, 0, 0, + lowPowerMode); if (result) { mLastPositionMode = positionMode; } else { @@ -1123,11 +973,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements requestUtcTime(); } else if ("force_psds_injection".equals(command)) { if (mSupportsPsds) { - downloadPsdsData(/* psdsType= */ - GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX); + sendMessage(DOWNLOAD_PSDS_DATA, GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX, + null); } } else if ("request_power_stats".equals(command)) { - GnssPowerIndicationProvider.requestPowerStats(); + mGnssNative.requestPowerStats(); } else { Log.w(TAG, "sendExtraCommand: unknown command " + command); } @@ -1137,26 +987,26 @@ public class GnssLocationProvider extends AbstractLocationProvider implements int flags; if (extras == null) { - flags = GPS_DELETE_ALL; + flags = GNSS_AIDING_TYPE_ALL; } else { flags = 0; - if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; - if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; - if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; - if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; - if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; - if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; - if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; - if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; - if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; - if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; - if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; - if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; - if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; + if (extras.getBoolean("ephemeris")) flags |= GNSS_AIDING_TYPE_EPHEMERIS; + if (extras.getBoolean("almanac")) flags |= GNSS_AIDING_TYPE_ALMANAC; + if (extras.getBoolean("position")) flags |= GNSS_AIDING_TYPE_POSITION; + if (extras.getBoolean("time")) flags |= GNSS_AIDING_TYPE_TIME; + if (extras.getBoolean("iono")) flags |= GNSS_AIDING_TYPE_IONO; + if (extras.getBoolean("utc")) flags |= GNSS_AIDING_TYPE_UTC; + if (extras.getBoolean("health")) flags |= GNSS_AIDING_TYPE_HEALTH; + if (extras.getBoolean("svdir")) flags |= GNSS_AIDING_TYPE_SVDIR; + if (extras.getBoolean("svsteer")) flags |= GNSS_AIDING_TYPE_SVSTEER; + if (extras.getBoolean("sadata")) flags |= GNSS_AIDING_TYPE_SADATA; + if (extras.getBoolean("rti")) flags |= GNSS_AIDING_TYPE_RTI; + if (extras.getBoolean("celldb-info")) flags |= GNSS_AIDING_TYPE_CELLDB_INFO; + if (extras.getBoolean("all")) flags |= GNSS_AIDING_TYPE_ALL; } if (flags != 0) { - native_delete_aiding_data(flags); + mGnssNative.deleteAidingData(flags); } } @@ -1166,13 +1016,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mTimeToFirstFix = 0; mLastFixTime = 0; setStarted(true); - mPositionMode = GPS_POSITION_MODE_STANDALONE; - // Notify about suppressed output, if speed limit was previously exceeded. - // Elsewhere, we check again with every speed output reported. - if (mItarSpeedLimitExceeded) { - Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " - + "until slow enough speed reported."); - } + mPositionMode = GNSS_POSITION_MODE_STANDALONE; boolean agpsEnabled = (Settings.Global.getInt(mContext.getContentResolver(), @@ -1183,13 +1027,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements String mode; switch (mPositionMode) { - case GPS_POSITION_MODE_STANDALONE: + case GNSS_POSITION_MODE_STANDALONE: mode = "standalone"; break; - case GPS_POSITION_MODE_MS_ASSISTED: + case GNSS_POSITION_MODE_MS_ASSISTED: mode = "MS_ASSISTED"; break; - case GPS_POSITION_MODE_MS_BASED: + case GNSS_POSITION_MODE_MS_BASED: mode = "MS_BASED"; break; default: @@ -1199,14 +1043,14 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.d(TAG, "setting position_mode to " + mode); } - int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); - if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, + int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000; + if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, mProviderRequest.isLowPower())) { setStarted(false); Log.e(TAG, "set_position_mode failed in startNavigating()"); return; } - if (!native_start()) { + if (!mGnssNative.start()) { setStarted(false); Log.e(TAG, "native_start failed in startNavigating()"); return; @@ -1215,7 +1059,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // reset SV count to zero mLocationExtras.reset(); mFixRequestTime = SystemClock.elapsedRealtime(); - if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { + if (!mGnssNative.getCapabilities().hasScheduling()) { // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT // and our fix interval is not short if (mFixInterval >= NO_FIX_TIMEOUT) { @@ -1231,7 +1075,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (DEBUG) Log.d(TAG, "stopNavigating"); if (mStarted) { setStarted(false); - native_stop(); + mGnssNative.stop(); mLastFixTime = 0; // native_stop() may reset the position mode in hardware. mLastPositionMode = null; @@ -1247,7 +1091,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (DEBUG) { Log.d(TAG, "startBatching " + mFixInterval); } - if (native_start_batch(MILLISECONDS.toNanos(mFixInterval), true)) { + if (mGnssNative.startBatch(MILLISECONDS.toNanos(mFixInterval), true)) { mBatchingStarted = true; } else { Log.e(TAG, "native_start_batch failed in startBatching()"); @@ -1257,7 +1101,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private void stopBatching() { if (DEBUG) Log.d(TAG, "stopBatching"); if (mBatchingStarted) { - native_stop_batch(); + mGnssNative.stopBatch(); mBatchingStarted = false; } } @@ -1277,28 +1121,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mWakeupListener, mHandler); } - private boolean hasCapability(int capability) { - return (mTopHalCapabilities & capability) != 0; - } - - void reportLocation(boolean hasLatLong, Location location) { - sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); - } - private void handleReportLocation(boolean hasLatLong, Location location) { - if (location.hasSpeed()) { - mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND; - } - - if (mItarSpeedLimitExceeded) { - Log.i(TAG, "Hal reported a speed in excess of ITAR limit." - + " GPS/GNSS Navigation output blocked."); - if (mStarted) { - mGnssMetrics.logReceivedLocationStatus(false); - } - return; // No output of location allowed - } - if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString()); location.setExtras(mLocationExtras.getBundle()); @@ -1341,9 +1164,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (mStarted) { mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); } - - // notify status listeners - mGnssStatusListenerHelper.onFirstFix(mTimeToFirstFix); } if (mStarted) { @@ -1351,51 +1171,19 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // spend too much power searching for a location, when the requested update rate is // slow. // As we just recievied a location, we'll cancel that timer. - if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { + if (!mGnssNative.getCapabilities().hasScheduling() && mFixInterval < NO_FIX_TIMEOUT) { mAlarmManager.cancel(mTimeoutListener); } } - if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted + if (!mGnssNative.getCapabilities().hasScheduling() && mStarted && mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { if (DEBUG) Log.d(TAG, "got fix, hibernating"); hibernate(); } } - void reportStatus(int status) { - if (DEBUG) Log.v(TAG, "reportStatus status: " + status); - - boolean wasNavigating = mNavigating; - switch (status) { - case GPS_STATUS_SESSION_BEGIN: - mNavigating = true; - break; - case GPS_STATUS_ENGINE_ON: - break; - case GPS_STATUS_SESSION_END: - // fall through - case GPS_STATUS_ENGINE_OFF: - mNavigating = false; - break; - } - - if (wasNavigating != mNavigating) { - mGnssStatusListenerHelper.onStatusChanged(mNavigating); - } - } - - void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs) { - sendMessage(REPORT_SV_STATUS, 0, - GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, - carrierFrequencies, basebandCn0DbHzs)); - } - private void handleReportSvStatus(GnssStatus gnssStatus) { - mGnssStatusListenerHelper.onSvStatusChanged(gnssStatus); - // Log CN0 as part of GNSS metrics mGnssMetrics.logCn0(gnssStatus); @@ -1425,289 +1213,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssMetrics.logSvStatus(gnssStatus); } - void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { - mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); - } - - void reportNmea(long timestamp) { - if (!mItarSpeedLimitExceeded) { - int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); - String nmea = new String(mNmeaBuffer, 0 /* offset */, length); - mGnssStatusListenerHelper.onNmeaReceived(timestamp, nmea); - } - } - - void reportMeasurementData(GnssMeasurementsEvent event) { - if (!mItarSpeedLimitExceeded) { - // send to handler to allow native to return quickly - mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event)); - } - } - - void reportAntennaInfo(List antennaInfos) { - mHandler.post(() -> mGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(antennaInfos)); - } - - void reportNavigationMessage(GnssNavigationMessage event) { - if (!mItarSpeedLimitExceeded) { - // send to handler to allow native to return quickly - mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event)); - } - } - - void reportGnssPowerStats(GnssPowerStats powerStats) { - mHandler.post(() -> mGnssPowerIndicationProvider.onGnssPowerStatsAvailable(powerStats)); - } - - void setTopHalCapabilities(int topHalCapabilities) { - mHandler.post(() -> { - mTopHalCapabilities = topHalCapabilities; - - if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { - mNtpTimeHelper.enablePeriodicTimeInjection(); - requestUtcTime(); - } - - restartRequests(); - - mGnssCapabilitiesProvider.setTopHalCapabilities(mTopHalCapabilities); - }); - } - - void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { - mHandler.post(() -> { - if (!mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(subHalCapabilities)) { - return; - } - - mGnssCapabilitiesProvider.setSubHalMeasurementCorrectionsCapabilities( - subHalCapabilities); - }); - } - - /** - * Sets the capabilities bits for IGnssPowerIndication HAL. - * - * These capabilities are defined in IGnssPowerIndicationCallback.aidl. - */ - void setSubHalPowerIndicationCapabilities(int subHalCapabilities) { - mHandler.post(() -> mGnssPowerIndicationProvider.onCapabilitiesUpdated(subHalCapabilities)); - } - - private void restartRequests() { - Log.i(TAG, "restartRequests"); - - restartLocationRequest(); - mGnssGeofenceProvider.resumeIfStarted(); - } - private void restartLocationRequest() { if (DEBUG) Log.d(TAG, "restartLocationRequest"); setStarted(false); updateRequirements(); } - void setGnssYearOfHardware(final int yearOfHardware) { - // mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync - if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware); - mHardwareYear = yearOfHardware; - } - - void setGnssHardwareModelName(final String modelName) { - // mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync - if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName); - mHardwareModelName = modelName; - } - - void reportGnssServiceRestarted() { - if (DEBUG) Log.d(TAG, "reportGnssServiceDied"); - - // it *appears* that native_init() needs to be called at least once before invoking any - // other gnss methods, so we cycle once on initialization. - native_init(); - native_cleanup(); - - // resend configuration into the restarted HAL service. - reloadGpsProperties(); - if (isGpsEnabled()) { - setGpsEnabled(false); - updateEnabled(); - } - } - - /** - * Interface for GnssSystemInfo methods. - */ - public interface GnssSystemInfoProvider { - /** - * Returns the year of underlying GPS hardware. - */ - int getGnssYearOfHardware(); - - /** - * Returns the model name of underlying GPS hardware. - */ - String getGnssHardwareModelName(); - } - - /** - * @hide - */ - public GnssSystemInfoProvider getGnssSystemInfoProvider() { - return new GnssSystemInfoProvider() { - @Override - public int getGnssYearOfHardware() { - return mHardwareYear; - } - - @Override - public String getGnssHardwareModelName() { - return mHardwareModelName; - } - }; - } - - /** - * Interface for GnssMetrics methods. - */ - public interface GnssMetricsProvider { - /** - * Returns GNSS metrics as proto string - */ - String getGnssMetricsAsProtoString(); - } - - /** - * @hide - */ - public GnssMetricsProvider getGnssMetricsProvider() { - return mGnssMetrics::dumpGnssMetricsAsProtoString; - } - - /** - * @hide - */ - public GnssCapabilitiesProvider getGnssCapabilitiesProvider() { - return mGnssCapabilitiesProvider; - } - - void reportLocationBatch(Location[] locations) { - if (DEBUG) { - Log.d(TAG, "Location batch of size " + locations.length + " reported"); - } - - Runnable[] listeners; - synchronized (mLock) { - listeners = mFlushListeners.toArray(new Runnable[0]); - mFlushListeners.clear(); - } - - if (locations.length > 0) { - reportLocation(LocationResult.create(Arrays.asList(locations)).validate()); - } - - for (Runnable listener : listeners) { - listener.run(); - } - } - - void downloadPsdsData(int psdsType) { - if (DEBUG) Log.d(TAG, "downloadPsdsData. psdsType: " + psdsType); - sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null); - } - - /** - * Converts the GPS HAL status to the internal Geofence Hardware status. - */ - private static int getGeofenceStatus(int status) { - switch (status) { - case GPS_GEOFENCE_OPERATION_SUCCESS: - return GeofenceHardware.GEOFENCE_SUCCESS; - case GPS_GEOFENCE_ERROR_GENERIC: - return GeofenceHardware.GEOFENCE_FAILURE; - case GPS_GEOFENCE_ERROR_ID_EXISTS: - return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; - case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: - return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; - case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: - return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; - case GPS_GEOFENCE_ERROR_ID_UNKNOWN: - return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; - default: - return -1; - } - } - - void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - - mGeofenceHardwareImpl.reportGeofenceTransition( - geofenceId, - location, - transition, - transitionTimestamp, - GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, - FusedBatchOptions.SourceTechnologies.GNSS); - }); - } - - void reportGeofenceStatus(int status, Location location) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; - if (status == GPS_GEOFENCE_AVAILABLE) { - monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; - } - mGeofenceHardwareImpl.reportGeofenceMonitorStatus( - GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, - monitorStatus, - location, - FusedBatchOptions.SourceTechnologies.GNSS); - }); - } - - void reportGeofenceAddStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); - }); - } - - void reportGeofenceRemoveStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); - }); - } - - void reportGeofencePauseStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); - }); - } - - void reportGeofenceResumeStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); - }); - } - //============================================================= // NI Client support //============================================================= @@ -1721,7 +1232,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.d(TAG, "sendNiResponse, notifId: " + notificationId + ", response: " + userResponse); } - native_send_ni_response(notificationId, userResponse); + mGnssNative.sendNiResponse(notificationId, userResponse); FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE, @@ -1749,7 +1260,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } /** Reports a NI notification. */ - void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, + private void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, int defaultResponse, String requestorId, String text, int requestorIdEncoding, int textEncoding) { Log.i(TAG, "reportNiNotification: entered"); @@ -1798,52 +1309,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements /* userResponse= */ 0); } - /** - * We should be careful about receiving null string from the TelephonyManager, - * because sending null String to JNI function would cause a crash. - */ - void requestSetID(int flags) { - TelephonyManager phone = (TelephonyManager) - mContext.getSystemService(Context.TELEPHONY_SERVICE); - int type = AGPS_SETID_TYPE_NONE; - String setId = null; - - int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); - if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { - phone = phone.createForSubscriptionId(ddSubId); - } - if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { - setId = phone.getSubscriberId(); - if (setId != null) { - // This means the framework has the SIM card. - type = AGPS_SETID_TYPE_IMSI; - } - } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { - setId = phone.getLine1Number(); - if (setId != null) { - // This means the framework has the SIM card. - type = AGPS_SETID_TYPE_MSISDN; - } - } - - native_agps_set_id(type, (setId == null) ? "" : setId); - } - - void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { - if (DEBUG) { - Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss - + ", isUserEmergency: " - + isUserEmergency); - } - sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency); - } - - void requestUtcTime() { + private void requestUtcTime() { if (DEBUG) Log.d(TAG, "utcTimeRequest"); sendMessage(INJECT_NTP_TIME, 0, null); } - void requestRefLocation() { + private void requestRefLocation() { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); final int phoneType = phone.getPhoneType(); @@ -1864,8 +1335,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } else { type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; } - native_agps_set_ref_location_cellid(type, mcc, mnc, - gsm_cell.getLac(), gsm_cell.getCid()); + mGnssNative.setAgpsReferenceLocationCellId(type, mcc, mnc, gsm_cell.getLac(), + gsm_cell.getCid()); } else { Log.e(TAG, "Error getting cell location info."); } @@ -1874,21 +1345,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal. - void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, byte responseType, - boolean inEmergencyMode, boolean isCachedLocation) { - if (mGnssVisibilityControl == null) { - Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl is not initialized."); - return; - } - - mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack, - otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, - isCachedLocation); - } - - // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal. boolean isInEmergencySession() { return mNIHandler.getInEmergency(); } @@ -1986,97 +1442,143 @@ public class GnssLocationProvider extends AbstractLocationProvider implements pw.println("mBatchingStarted=" + mBatchingStarted); pw.println("mBatchSize=" + getBatchSize()); pw.println("mFixInterval=" + mFixInterval); - mGnssPowerIndicationProvider.dump(fd, pw, args); - pw.print("mTopHalCapabilities=0x" + Integer.toHexString(mTopHalCapabilities) + " ( "); - if (hasCapability(GPS_CAPABILITY_SCHEDULING)) pw.print("SCHEDULING "); - if (hasCapability(GPS_CAPABILITY_MSB)) pw.print("MSB "); - if (hasCapability(GPS_CAPABILITY_MSA)) pw.print("MSA "); - if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) pw.print("SINGLE_SHOT "); - if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) pw.print("ON_DEMAND_TIME "); - if (hasCapability(GPS_CAPABILITY_GEOFENCING)) pw.print("GEOFENCING "); - if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) pw.print("MEASUREMENTS "); - if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) pw.print("NAV_MESSAGES "); - if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) pw.print("LOW_POWER_MODE "); - if (hasCapability(GPS_CAPABILITY_SATELLITE_BLOCKLIST)) pw.print("SATELLITE_BLOCKLIST "); - if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) { - pw.print("MEASUREMENT_CORRECTIONS "); - } - if (hasCapability(GPS_CAPABILITY_ANTENNA_INFO)) pw.print("ANTENNA_INFO "); - pw.println(")"); - if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) { - pw.println("SubHal=MEASUREMENT_CORRECTIONS[" - + mGnssMeasurementCorrectionsProvider.toStringCapabilities() + "]"); - } pw.print(mGnssMetrics.dumpGnssMetricsAsText()); if (dumpAll) { pw.println("native internal state: "); - pw.println(" " + native_get_internal_state()); + pw.println(" " + mGnssNative.getInternalState()); } } - // preallocated to avoid memory allocation in reportNmea() - private final byte[] mNmeaBuffer = new byte[120]; + @Override + public void onHalRestarted() { + reloadGpsProperties(); + if (isGpsEnabled()) { + setGpsEnabled(false); + updateEnabled(); + } + } - private static native boolean native_is_gnss_visibility_control_supported(); + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) { + mHandler.post(() -> { + if (mGnssNative.getCapabilities().hasOnDemandTime()) { + mNtpTimeHelper.enablePeriodicTimeInjection(); + requestUtcTime(); + } - private native boolean native_init(); + restartLocationRequest(); + }); + } - private native void native_cleanup(); + @Override + public void onReportLocation(boolean hasLatLong, Location location) { + sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); + } - private native boolean native_set_position_mode(int mode, int recurrence, int minInterval, - int preferredAccuracy, int preferredTime, boolean lowPowerMode); + @Override + public void onReportLocations(Location[] locations) { + if (DEBUG) { + Log.d(TAG, "Location batch of size " + locations.length + " reported"); + } - private native boolean native_start(); + Runnable[] listeners; + synchronized (mLock) { + listeners = mFlushListeners.toArray(new Runnable[0]); + mFlushListeners.clear(); + } - private native boolean native_stop(); + if (locations.length > 0) { + reportLocation(LocationResult.create(Arrays.asList(locations)).validate()); + } - private native void native_delete_aiding_data(int flags); + for (Runnable listener : listeners) { + listener.run(); + } + } - private native int native_read_nmea(byte[] buffer, int bufferSize); + @Override + public void onReportSvStatus(GnssStatus gnssStatus) { + sendMessage(REPORT_SV_STATUS, 0, gnssStatus); + } - private native void native_inject_best_location( - int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees, - double altitudeMeters, float speedMetersPerSec, float bearingDegrees, - float horizontalAccuracyMeters, float verticalAccuracyMeters, - float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees, - long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos, - double elapsedRealtimeUncertaintyNanos); + @Override + public void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { + mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); + } - private native void native_inject_location(double latitude, double longitude, float accuracy); + @Override + public void onRequestPsdsDownload(int psdsType) { + sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null); + } - // PSDS Support - private native void native_inject_time(long time, long timeReference, int uncertainty); + @Override + public void onReportNiNotification(int notificationId, int niType, int notifyFlags, + int timeout, int defaultResponse, String requestorId, String text, + int requestorIdEncoding, int textEncoding) { + reportNiNotification(notificationId, niType, notifyFlags, timeout, + defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); + } - private native boolean native_supports_psds(); + @Override + public void onRequestSetID(@GnssNative.AGpsCallbacks.AgpsSetIdFlags int flags) { + TelephonyManager phone = (TelephonyManager) + mContext.getSystemService(Context.TELEPHONY_SERVICE); + int type = AGPS_SETID_TYPE_NONE; + String setId = null; - private native void native_inject_psds_data(byte[] data, int length, int psdsType); + int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { + phone = phone.createForSubscriptionId(ddSubId); + } + if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) { + setId = phone.getSubscriberId(); + if (setId != null) { + // This means the framework has the SIM card. + type = AGPS_SETID_TYPE_IMSI; + } + } else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) { + setId = phone.getLine1Number(); + if (setId != null) { + // This means the framework has the SIM card. + type = AGPS_SETID_TYPE_MSISDN; + } + } - // DEBUG Support - private native String native_get_internal_state(); + mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId); + } - // AGPS Support - private native void native_agps_ni_message(byte[] msg, int length); + @Override + public void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency) { + if (DEBUG) { + Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss + + ", isUserEmergency: " + + isUserEmergency); + } + sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency); + } - private native void native_set_agps_server(int type, String hostname, int port); + @Override + public void onRequestUtcTime() { + requestUtcTime(); + } - // Network-initiated (NI) Support - private native void native_send_ni_response(int notificationId, int userResponse); + @Override + public void onRequestRefLocation() { + requestRefLocation(); + } - // AGPS ril support - private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, - int lac, int cid); + @Override + public void onReportNfwNotification(String proxyAppPackageName, byte protocolStack, + String otherProtocolStackName, byte requestor, String requestorId, + byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { + if (mGnssVisibilityControl == null) { + Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl uninitialized."); + return; + } - private native void native_agps_set_id(int type, String setid); - - private static native boolean native_init_batching(); - - private static native void native_cleanup_batching(); - - private static native int native_get_batch_size(); - - private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull); - - private static native void native_flush_batch(); - - private static native boolean native_stop_batch(); + mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack, + otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, + isCachedLocation); + } } diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index fa137aa43eb2e..ff92444640691 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -19,99 +19,78 @@ package com.android.server.location.gnss; import android.Manifest; import android.annotation.Nullable; import android.content.Context; -import android.location.GnssAntennaInfo; +import android.hardware.location.GeofenceHardware; +import android.hardware.location.GeofenceHardwareImpl; +import android.location.FusedBatchOptions; +import android.location.GnssCapabilities; import android.location.GnssMeasurementCorrections; import android.location.GnssMeasurementRequest; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; import android.location.IGnssAntennaInfoListener; import android.location.IGnssMeasurementsListener; import android.location.IGnssNavigationMessageListener; +import android.location.IGnssNmeaListener; import android.location.IGnssStatusListener; import android.location.IGpsGeofenceHardware; -import android.location.INetInitiatedListener; import android.location.Location; -import android.location.LocationManagerInternal; import android.location.util.identity.CallerIdentity; +import android.os.BatteryStats; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.IndentingPrintWriter; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; -import com.android.server.LocalServices; -import com.android.server.location.injector.AppOpsHelper; +import com.android.internal.app.IBatteryStats; +import com.android.server.FgThread; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import java.io.FileDescriptor; -import java.util.List; /** Manages Gnss providers and related Gnss functions for LocationManagerService. */ -public class GnssManagerService implements GnssNative.Callbacks { +public class GnssManagerService { public static final String TAG = "GnssManager"; public static final boolean D = Log.isLoggable(TAG, Log.DEBUG); private static final String ATTRIBUTION_ID = "GnssService"; - public static boolean isGnssSupported() { - return GnssNative.isSupported(); - } - private final Context mContext; - private final AppOpsHelper mAppOpsHelper; - private final LocationManagerInternal mLocationManagerInternal; + private final GnssNative mGnssNative; private final GnssLocationProvider mGnssLocationProvider; private final GnssStatusProvider mGnssStatusProvider; + private final GnssNmeaProvider mGnssNmeaProvider; private final GnssMeasurementsProvider mGnssMeasurementsProvider; - private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider; private final GnssAntennaInfoProvider mGnssAntennaInfoProvider; private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; - private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider; - private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider; - private final GnssCapabilitiesProvider mGnssCapabilitiesProvider; - private final INetInitiatedListener mNetInitiatedListener; - private final IGpsGeofenceHardware mGpsGeofenceProxy; + private final IGpsGeofenceHardware mGnssGeofenceProxy; - public GnssManagerService(Context context, Injector injector) { - this(context, injector, null); - } - - @VisibleForTesting - GnssManagerService(Context context, Injector injector, - GnssLocationProvider gnssLocationProvider) { - Preconditions.checkState(isGnssSupported()); - - GnssNative.initialize(); + private final GnssMetrics mGnssMetrics; + public GnssManagerService(Context context, Injector injector, GnssNative gnssNative) { mContext = context.createAttributionContext(ATTRIBUTION_ID); - mAppOpsHelper = injector.getAppOpsHelper(); - mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class); + mGnssNative = gnssNative; - if (gnssLocationProvider == null) { - gnssLocationProvider = new GnssLocationProvider(mContext, injector); - } + mGnssMetrics = new GnssMetrics(mContext, IBatteryStats.Stub.asInterface( + ServiceManager.getService(BatteryStats.SERVICE_NAME))); - mGnssLocationProvider = gnssLocationProvider; - mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider(); - mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider(); - mGnssAntennaInfoProvider = mGnssLocationProvider.getGnssAntennaInfoProvider(); - mGnssMeasurementCorrectionsProvider = - mGnssLocationProvider.getGnssMeasurementCorrectionsProvider(); - mGnssNavigationMessageProvider = mGnssLocationProvider.getGnssNavigationMessageProvider(); - mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider(); - mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider(); - mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider(); - mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener(); - mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy(); + mGnssLocationProvider = new GnssLocationProvider(mContext, injector, mGnssNative, + mGnssMetrics); + mGnssStatusProvider = new GnssStatusProvider(injector, mGnssNative); + mGnssNmeaProvider = new GnssNmeaProvider(injector, mGnssNative); + mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector, mGnssNative); + mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(injector, mGnssNative); + mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector, mGnssNative); + mGnssGeofenceProxy = new GnssGeofenceProxy(mGnssNative); + + mGnssNative.setGeofenceCallbacks(new GnssGeofenceHalModule()); // allow gnss access to begin - we must assume that callbacks can start immediately - GnssNative.register(this); + mGnssNative.register(); } /** Called when system is ready. */ - public synchronized void onSystemReady() { + public void onSystemReady() { mGnssLocationProvider.onSystemReady(); } @@ -121,15 +100,15 @@ public class GnssManagerService implements GnssNative.Callbacks { } /** Retrieve the IGpsGeofenceHardware. */ - public IGpsGeofenceHardware getGpsGeofenceProxy() { - return mGpsGeofenceProxy; + public IGpsGeofenceHardware getGnssGeofenceProxy() { + return mGnssGeofenceProxy; } /** * Get year of GNSS hardware. */ public int getGnssYearOfHardware() { - return mGnssSystemInfoProvider.getGnssYearOfHardware(); + return mGnssNative.getHardwareYear(); } /** @@ -137,15 +116,15 @@ public class GnssManagerService implements GnssNative.Callbacks { */ @Nullable public String getGnssHardwareModelName() { - return mGnssSystemInfoProvider.getGnssHardwareModelName(); + return mGnssNative.getHardwareModelName(); } /** * Get GNSS hardware capabilities. The capabilities returned are a bitfield as described in * {@link android.location.GnssCapabilities}. */ - public long getGnssCapabilities() { - return mGnssCapabilitiesProvider.getGnssCapabilities(); + public GnssCapabilities getGnssCapabilities() { + return mGnssNative.getCapabilities(); } /** @@ -173,6 +152,24 @@ public class GnssManagerService implements GnssNative.Callbacks { mGnssStatusProvider.removeListener(listener); } + /** + * Registers listener for GNSS NMEA messages. + */ + public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, + @Nullable String attributionTag) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); + + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); + mGnssNmeaProvider.addListener(identity, listener); + } + + /** + * Unregisters listener for GNSS NMEA messages. + */ + public void unregisterGnssNmeaCallback(IGnssNmeaListener listener) { + mGnssNmeaProvider.removeListener(listener); + } + /** * Adds a GNSS measurements listener. */ @@ -192,7 +189,9 @@ public class GnssManagerService implements GnssNative.Callbacks { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(corrections); + if (!mGnssNative.injectMeasurementCorrections(corrections)) { + Log.w(TAG, "failed to inject GNSS measurement corrections"); + } } /** @@ -248,9 +247,9 @@ public class GnssManagerService implements GnssNative.Callbacks { */ public void sendNiResponse(int notifId, int userResponse) { try { - mNetInitiatedListener.sendNiResponse(notifId, userResponse); + mGnssLocationProvider.getNetInitiatedListener().sendNiResponse(notifId, userResponse); } catch (RemoteException e) { - Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); + throw e.rethrowFromSystemServer(); } } @@ -259,12 +258,12 @@ public class GnssManagerService implements GnssNative.Callbacks { */ public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { if (args.length > 0 && args[0].equals("--gnssmetrics")) { - if (mGnssMetricsProvider != null) { - ipw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString()); - } + ipw.append(mGnssMetrics.dumpGnssMetricsAsProtoString()); return; } + ipw.println("Capabilities: " + mGnssNative.getCapabilities()); + ipw.println("Antenna Info Provider:"); ipw.increaseIndent(); mGnssAntennaInfoProvider.dump(fd, ipw, args); @@ -284,169 +283,92 @@ public class GnssManagerService implements GnssNative.Callbacks { ipw.increaseIndent(); mGnssStatusProvider.dump(fd, ipw, args); ipw.decreaseIndent(); + + GnssPowerStats powerStats = mGnssNative.getPowerStats(); + if (powerStats != null) { + ipw.println("Last Power Stats:"); + ipw.increaseIndent(); + powerStats.dump(fd, ipw, args, mGnssNative.getCapabilities()); + ipw.decreaseIndent(); + } } - // all native callbacks - to be funneled to various locations as appropriate + private class GnssGeofenceHalModule implements GnssNative.GeofenceCallbacks { - @Override - public void reportLocation(boolean hasLatLong, Location location) { - mGnssLocationProvider.reportLocation(hasLatLong, location); - } + private GeofenceHardwareImpl mGeofenceHardwareImpl; - @Override - public void reportStatus(int status) { - mGnssLocationProvider.reportStatus(status); - } + private synchronized GeofenceHardwareImpl getGeofenceHardware() { + if (mGeofenceHardwareImpl == null) { + mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); + } + return mGeofenceHardwareImpl; + } - @Override - public void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs) { - mGnssLocationProvider.reportSvStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, - carrierFrequencies, basebandCn0DbHzs); - } + @Override + public void onReportGeofenceTransition(int geofenceId, Location location, + @GeofenceTransition int transition, long timestamp) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceTransition( + geofenceId, location, transition, timestamp, + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + FusedBatchOptions.SourceTechnologies.GNSS)); + } - @Override - public void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { - mGnssLocationProvider.reportAGpsStatus(agpsType, agpsStatus, suplIpAddr); - } + @Override + public void onReportGeofenceStatus(@GeofenceAvailability int status, Location location) { + FgThread.getHandler().post(() -> { + int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; + if (status == GEOFENCE_AVAILABILITY_AVAILABLE) { + monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; + } + getGeofenceHardware().reportGeofenceMonitorStatus( + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + monitorStatus, + location, + FusedBatchOptions.SourceTechnologies.GNSS); + }); + } - @Override - public void reportNmea(long timestamp) { - mGnssLocationProvider.reportNmea(timestamp); - } + @Override + public void onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceAddStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportMeasurementData(GnssMeasurementsEvent event) { - mGnssLocationProvider.reportMeasurementData(event); - } + @Override + public void onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceRemoveStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportAntennaInfo(List antennaInfos) { - mGnssLocationProvider.reportAntennaInfo(antennaInfos); - } + @Override + public void onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofencePauseStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportNavigationMessage(GnssNavigationMessage event) { - mGnssLocationProvider.reportNavigationMessage(event); - } + @Override + public void onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceResumeStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportGnssPowerStats(GnssPowerStats powerStats) { - mGnssLocationProvider.reportGnssPowerStats(powerStats); - } - - @Override - public void setTopHalCapabilities(int topHalCapabilities) { - mGnssLocationProvider.setTopHalCapabilities(topHalCapabilities); - } - - @Override - public void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { - mGnssLocationProvider.setSubHalMeasurementCorrectionsCapabilities(subHalCapabilities); - } - - @Override - public void setSubHalPowerIndicationCapabilities(int subHalCapabilities) { - mGnssLocationProvider.setSubHalPowerIndicationCapabilities(subHalCapabilities); - } - - @Override - public void setGnssYearOfHardware(int yearOfHardware) { - mGnssLocationProvider.setGnssYearOfHardware(yearOfHardware); - } - - @Override - public void setGnssHardwareModelName(String modelName) { - mGnssLocationProvider.setGnssHardwareModelName(modelName); - } - - @Override - public void reportGnssServiceRestarted() { - mGnssLocationProvider.reportGnssServiceRestarted(); - } - - @Override - public void reportLocationBatch(Location[] locationArray) { - mGnssLocationProvider.reportLocationBatch(locationArray); - } - - @Override - public void psdsDownloadRequest(int psdsType) { - mGnssLocationProvider.downloadPsdsData(psdsType); - } - - @Override - public void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp) { - mGnssLocationProvider.reportGeofenceTransition(geofenceId, location, transition, - transitionTimestamp); - } - - @Override - public void reportGeofenceStatus(int status, Location location) { - mGnssLocationProvider.reportGeofenceStatus(status, location); - } - - @Override - public void reportGeofenceAddStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofenceAddStatus(geofenceId, status); - } - - @Override - public void reportGeofenceRemoveStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofenceRemoveStatus(geofenceId, status); - } - - @Override - public void reportGeofencePauseStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofencePauseStatus(geofenceId, status); - } - - @Override - public void reportGeofenceResumeStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofenceResumeStatus(geofenceId, status); - } - - @Override - public void reportNiNotification(int notificationId, int niType, int notifyFlags, - int timeout, int defaultResponse, String requestorId, String text, - int requestorIdEncoding, int textEncoding) { - mGnssLocationProvider.reportNiNotification(notificationId, niType, notifyFlags, timeout, - defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); - } - - @Override - public void requestSetID(int flags) { - mGnssLocationProvider.requestSetID(flags); - } - - @Override - public void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { - mGnssLocationProvider.requestLocation(independentFromGnss, isUserEmergency); - } - - @Override - public void requestUtcTime() { - mGnssLocationProvider.requestUtcTime(); - } - - @Override - public void requestRefLocation() { - mGnssLocationProvider.requestRefLocation(); - } - - @Override - public void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, - byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { - mGnssLocationProvider.reportNfwNotification(proxyAppPackageName, protocolStack, - otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, - isCachedLocation); - } - - @Override - public boolean isInEmergencySession() { - return mGnssLocationProvider.isInEmergencySession(); + private int translateGeofenceStatus(@GeofenceStatus int status) { + switch (status) { + case GEOFENCE_STATUS_OPERATION_SUCCESS: + return GeofenceHardware.GEOFENCE_SUCCESS; + case GEOFENCE_STATUS_ERROR_GENERIC: + return GeofenceHardware.GEOFENCE_FAILURE; + case GEOFENCE_STATUS_ERROR_ID_EXISTS: + return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; + case GEOFENCE_STATUS_ERROR_INVALID_TRANSITION: + return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; + case GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES: + return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; + case GEOFENCE_STATUS_ERROR_ID_UNKNOWN: + return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; + default: + return -1; + } + } } } diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java deleted file mode 100644 index 4401f29b4e57a..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.server.location.gnss; - -import android.location.GnssMeasurementCorrections; -import android.os.Handler; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * Manages GNSS measurement corrections. - * - *

Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal} - * and {@code IMeasurementCorrectionsCallback.hal). - * - * @hide - */ -public class GnssMeasurementCorrectionsProvider { - private static final String TAG = "GnssMeasurementCorrectionsProvider"; - - // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal. - static final int CAPABILITY_LOS_SATS = 0x0000001; - static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002; - static final int CAPABILITY_REFLECTING_PLANE = 0x0000004; - - private static final int INVALID_CAPABILITIES = 1 << 31; - - private final Handler mHandler; - private final GnssMeasurementCorrectionsProviderNative mNative; - private volatile int mCapabilities = INVALID_CAPABILITIES; - - GnssMeasurementCorrectionsProvider(Handler handler) { - this(handler, new GnssMeasurementCorrectionsProviderNative()); - } - - @VisibleForTesting - GnssMeasurementCorrectionsProvider(Handler handler, - GnssMeasurementCorrectionsProviderNative aNative) { - mHandler = handler; - mNative = aNative; - } - - /** - * Returns {@code true} if the GNSS HAL implementation supports measurement corrections. - */ - public boolean isAvailableInPlatform() { - return mNative.isMeasurementCorrectionsSupported(); - } - - /** - * Injects GNSS measurement corrections into the GNSS chipset. - * - * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS - * measurement corrections to be injected into the GNSS chipset. - */ - public void injectGnssMeasurementCorrections( - GnssMeasurementCorrections measurementCorrections) { - if (!isCapabilitiesReceived()) { - Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities " - + "not received yet."); - return; - } - mHandler.post(() -> { - if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) { - Log.e(TAG, "Failure in injecting GNSS corrections."); - } - }); - } - - /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */ - boolean onCapabilitiesUpdated(int capabilities) { - if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities, - CAPABILITY_EXCESS_PATH_LENGTH)) { - mCapabilities = capabilities; - return true; - } else { - Log.e(TAG, "Failed to set capabilities. Received capabilities 0x" - + Integer.toHexString(capabilities) + " does not contain the mandatory " - + "LOS_SATS or the EXCESS_PATH_LENGTH capability."); - return false; - } - } - - /** - * Returns the measurement corrections specific capabilities of the GNSS HAL implementation. - */ - int getCapabilities() { - return mCapabilities; - } - - /** - * Returns the string representation of the GNSS measurement capabilities. - */ - String toStringCapabilities() { - final int capabilities = getCapabilities(); - StringBuilder s = new StringBuilder(); - s.append("mCapabilities=0x").append(Integer.toHexString(capabilities)); - s.append(" ( "); - if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) { - s.append("LOS_SATS "); - } - if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) { - s.append("EXCESS_PATH_LENGTH "); - } - if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) { - s.append("REFLECTING_PLANE "); - } - s.append(")"); - return s.toString(); - } - - private static boolean hasCapability(int halCapabilities, int capability) { - return (halCapabilities & capability) != 0; - } - - private boolean isCapabilitiesReceived() { - return mCapabilities != INVALID_CAPABILITIES; - } - - @VisibleForTesting - static class GnssMeasurementCorrectionsProviderNative { - public boolean isMeasurementCorrectionsSupported() { - return native_is_measurement_corrections_supported(); - } - - public boolean injectGnssMeasurementCorrections( - GnssMeasurementCorrections measurementCorrections) { - return native_inject_gnss_measurement_corrections(measurementCorrections); - } - } - - static native boolean native_is_measurement_corrections_supported(); - - static native boolean native_inject_gnss_measurement_corrections( - GnssMeasurementCorrections measurementCorrections); -} diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java index fa8e2a6f34b3e..b7cc9f51bfec6 100644 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java @@ -21,6 +21,7 @@ import static com.android.server.location.gnss.GnssManagerService.TAG; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.location.GnssCapabilities; import android.location.GnssMeasurementRequest; import android.location.GnssMeasurementsEvent; import android.location.IGnssMeasurementsListener; @@ -29,8 +30,7 @@ import android.os.IBinder; import android.stats.location.LocationStatsEnums; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationAttributionHelper; @@ -38,7 +38,6 @@ import com.android.server.location.injector.LocationUsageLogger; import com.android.server.location.injector.SettingsHelper; import java.util.Collection; -import java.util.Objects; /** * An base implementation for GNSS measurements provider. It abstracts out the responsibility of @@ -47,8 +46,10 @@ import java.util.Objects; * @hide */ public final class GnssMeasurementsProvider extends - GnssListenerMultiplexer - implements SettingsHelper.GlobalSettingChangedListener { + GnssListenerMultiplexer implements + SettingsHelper.GlobalSettingChangedListener, GnssNative.BaseCallbacks, + GnssNative.MeasurementCallbacks { private class GnssMeasurementListenerRegistration extends GnssListenerRegistration { @@ -79,24 +80,22 @@ public final class GnssMeasurementsProvider extends private final AppOpsHelper mAppOpsHelper; private final LocationAttributionHelper mLocationAttributionHelper; private final LocationUsageLogger mLogger; - private final GnssMeasurementProviderNative mNative; + private final GnssNative mGnssNative; - public GnssMeasurementsProvider(Injector injector) { - this(injector, new GnssMeasurementProviderNative()); - } - - @VisibleForTesting - public GnssMeasurementsProvider(Injector injector, GnssMeasurementProviderNative aNative) { + public GnssMeasurementsProvider(Injector injector, GnssNative gnssNative) { super(injector); mAppOpsHelper = injector.getAppOpsHelper(); mLocationAttributionHelper = injector.getLocationAttributionHelper(); mLogger = injector.getLocationUsageLogger(); - mNative = aNative; + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addMeasurementCallbacks(this); } @Override protected boolean isServiceSupported() { - return mNative.isMeasurementSupported(); + return mGnssNative.isMeasurementSupported(); } @Override @@ -112,17 +111,14 @@ public final class GnssMeasurementsProvider extends } @Override - protected boolean registerWithService(Boolean fullTrackingRequest, + protected boolean registerWithService(GnssMeasurementRequest request, Collection registrations) { - Preconditions.checkState(mNative.isMeasurementSupported()); - - if (mNative.startMeasurementCollection(fullTrackingRequest)) { + if (mGnssNative.startMeasurementCollection(request.isFullTracking())) { if (D) { - Log.d(TAG, "starting gnss measurements (" + fullTrackingRequest + ")"); + Log.d(TAG, "starting gnss measurements (" + request + ")"); } return true; } else { - Log.e(TAG, "error starting gnss measurements"); return false; } @@ -130,14 +126,12 @@ public final class GnssMeasurementsProvider extends @Override protected void unregisterWithService() { - if (mNative.isMeasurementSupported()) { - if (mNative.stopMeasurementCollection()) { - if (D) { - Log.d(TAG, "stopping gnss measurements"); - } - } else { - Log.e(TAG, "error stopping gnss measurements"); + if (mGnssNative.stopMeasurementCollection()) { + if (D) { + Log.d(TAG, "stopping gnss measurements"); } + } else { + Log.e(TAG, "error stopping gnss measurements"); } } @@ -158,18 +152,21 @@ public final class GnssMeasurementsProvider extends } @Override - protected Boolean mergeRegistrations(Collection registrations) { + protected GnssMeasurementRequest mergeRegistrations( + Collection registrations) { + boolean fullTracking = false; if (mSettingsHelper.isGnssMeasurementsFullTrackingEnabled()) { - return true; - } - - for (GnssListenerRegistration registration : registrations) { - if (Objects.requireNonNull(registration.getRequest()).isFullTracking()) { - return true; + fullTracking = true; + } else { + for (GnssListenerRegistration registration : registrations) { + if (registration.getRequest().isFullTracking()) { + fullTracking = true; + break; + } } } - return false; + return new GnssMeasurementRequest.Builder().setFullTracking(fullTracking).build(); } @Override @@ -198,10 +195,17 @@ public final class GnssMeasurementsProvider extends null, registration.isForeground()); } - /** - * Called by GnssLocationProvider. - */ - public void onMeasurementsAvailable(GnssMeasurementsEvent event) { + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportMeasurements(GnssMeasurementsEvent event) { deliverToListeners(registration -> { if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, registration.getIdentity())) { @@ -211,25 +215,4 @@ public final class GnssMeasurementsProvider extends } }); } - - @VisibleForTesting - static class GnssMeasurementProviderNative { - boolean isMeasurementSupported() { - return native_is_measurement_supported(); - } - - boolean startMeasurementCollection(boolean enableFullTracking) { - return native_start_measurement_collection(enableFullTracking); - } - - boolean stopMeasurementCollection() { - return native_stop_measurement_collection(); - } - } - - static native boolean native_is_measurement_supported(); - - static native boolean native_start_measurement_collection(boolean enableFullTracking); - - static native boolean native_stop_measurement_collection(); } diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/services/core/java/com/android/server/location/gnss/GnssMetrics.java similarity index 96% rename from location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java rename to services/core/java/com/android/server/location/gnss/GnssMetrics.java index dd8a8c3bd1d5b..c7d8144342ab7 100644 --- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java +++ b/services/core/java/com/android/server/location/gnss/GnssMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,15 +14,11 @@ * limitations under the License. */ -package com.android.internal.location.gnssmetrics; - -import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD; -import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR; -import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN; -import static android.location.GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; +package com.android.server.location.gnss; import android.app.StatsManager; import android.content.Context; +import android.location.GnssSignalQuality; import android.location.GnssStatus; import android.os.RemoteException; import android.os.SystemClock; @@ -67,11 +63,11 @@ public class GnssMetrics { // A boolean array indicating whether the constellation types have been used in fix. private boolean[] mConstellationTypes; - private Statistics mLocationFailureStatistics; - private Statistics mTimeToFirstFixSecStatistics; - private Statistics mPositionAccuracyMeterStatistics; - private Statistics mTopFourAverageCn0Statistics; - private Statistics mTopFourAverageCn0StatisticsL5; + private final Statistics mLocationFailureStatistics; + private final Statistics mTimeToFirstFixSecStatistics; + private final Statistics mPositionAccuracyMeterStatistics; + private final Statistics mTopFourAverageCn0Statistics; + private final Statistics mTopFourAverageCn0StatisticsL5; // Total number of sv status messages processed private int mNumSvStatus; // Total number of L5 sv status messages processed @@ -91,7 +87,7 @@ public class GnssMetrics { long mSvStatusReportsUsedInFix; long mL5SvStatusReportsUsedInFix; - private StatsManager mStatsManager; + private final StatsManager mStatsManager; public GnssMetrics(Context context, IBatteryStats stats) { mGnssPowerMetrics = new GnssPowerMetrics(stats); @@ -390,7 +386,7 @@ public class GnssMetrics { stats.getLoggingDurationMs() / ((double) DateUtils.MINUTE_IN_MILLIS)).append( "\n"); long[] t = stats.getTimeInGpsSignalQualityLevel(); - if (t != null && t.length == NUM_GNSS_SIGNAL_QUALITY_LEVELS) { + if (t != null && t.length == GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS) { s.append(" Amount of time (while on battery) Top 4 Avg CN0 > " + GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ + " dB-Hz (min): ").append( @@ -505,7 +501,7 @@ public class GnssMetrics { // so that // the first CNO report will trigger an update to BatteryStats mLastAverageCn0 = -100.0; - mLastSignalLevel = GNSS_SIGNAL_QUALITY_UNKNOWN; + mLastSignalLevel = GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN; } /** @@ -577,9 +573,9 @@ public class GnssMetrics { */ private int getSignalLevel(double cn0) { if (cn0 > POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) { - return GNSS_SIGNAL_QUALITY_GOOD; + return GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD; } - return GNSS_SIGNAL_QUALITY_POOR; + return GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR; } } diff --git a/services/core/java/com/android/server/location/gnss/GnssNative.java b/services/core/java/com/android/server/location/gnss/GnssNative.java deleted file mode 100644 index 4494c191a16bf..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssNative.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.server.location.gnss; - -import android.location.GnssAntennaInfo; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; -import android.location.Location; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; -import com.android.server.FgThread; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.List; - -/** - * Entry point for all GNSS native callbacks, and responsible for initializing the GNSS HAL. - */ -class GnssNative { - - interface Callbacks { - void reportLocation(boolean hasLatLong, Location location); - void reportStatus(int status); - void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs); - void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr); - void reportNmea(long timestamp); - void reportMeasurementData(GnssMeasurementsEvent event); - void reportAntennaInfo(List antennaInfos); - void reportNavigationMessage(GnssNavigationMessage event); - void reportGnssPowerStats(GnssPowerStats powerStats); - void setTopHalCapabilities(int topHalCapabilities); - void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities); - void setSubHalPowerIndicationCapabilities(int subHalCapabilities); - void setGnssYearOfHardware(int yearOfHardware); - void setGnssHardwareModelName(String modelName); - void reportGnssServiceRestarted(); - void reportLocationBatch(Location[] locationArray); - void psdsDownloadRequest(int psdsType); - void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp); - void reportGeofenceStatus(int status, Location location); - void reportGeofenceAddStatus(int geofenceId, int status); - void reportGeofenceRemoveStatus(int geofenceId, int status); - void reportGeofencePauseStatus(int geofenceId, int status); - void reportGeofenceResumeStatus(int geofenceId, int status); - void reportNiNotification( - int notificationId, - int niType, - int notifyFlags, - int timeout, - int defaultResponse, - String requestorId, - String text, - int requestorIdEncoding, - int textEncoding - ); - void requestSetID(int flags); - void requestLocation(boolean independentFromGnss, boolean isUserEmergency); - void requestUtcTime(); - void requestRefLocation(); - void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, - byte responseType, boolean inEmergencyMode, boolean isCachedLocation); - boolean isInEmergencySession(); - } - - /** - * Indicates that this method is a native entry point. Useful purely for IDEs which can - * understand entry points, and thus eliminate incorrect warnings about methods not used. - */ - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.SOURCE) - private @interface NativeEntryPoint {} - - @GuardedBy("GnssNative.class") - private static boolean sInitialized; - - @GuardedBy("GnssNative.class") - private static GnssNativeInitNative sInitNative = new GnssNativeInitNative(); - - @GuardedBy("GnssNative.class") - private static GnssNative sInstance; - - @VisibleForTesting - public static synchronized void setInitNativeForTest(GnssNativeInitNative initNative) { - sInitNative = initNative; - } - - public static synchronized boolean isSupported() { - initialize(); - return sInitNative.isSupported(); - } - - static synchronized void initialize() { - if (!sInitialized) { - sInitNative.classInitOnce(); - sInitialized = true; - } - } - - @VisibleForTesting - public static synchronized void resetCallbacksForTest() { - sInstance = null; - } - - static synchronized void register(Callbacks callbacks) { - Preconditions.checkState(sInstance == null); - initialize(); - sInstance = new GnssNative(callbacks); - } - - private final Callbacks mCallbacks; - - private GnssNative(Callbacks callbacks) { - mCallbacks = callbacks; - sInitNative.initOnce(this, false); - } - - @NativeEntryPoint - private void reportLocation(boolean hasLatLong, Location location) { - mCallbacks.reportLocation(hasLatLong, location); - } - - @NativeEntryPoint - private void reportStatus(int status) { - mCallbacks.reportStatus(status); - } - - @NativeEntryPoint - private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs) { - mCallbacks.reportSvStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, - carrierFrequencies, basebandCn0DbHzs); - } - - @NativeEntryPoint - private void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { - mCallbacks.reportAGpsStatus(agpsType, agpsStatus, suplIpAddr); - } - - @NativeEntryPoint - private void reportNmea(long timestamp) { - mCallbacks.reportNmea(timestamp); - } - - @NativeEntryPoint - private void reportMeasurementData(GnssMeasurementsEvent event) { - mCallbacks.reportMeasurementData(event); - } - - @NativeEntryPoint - private void reportAntennaInfo(List antennaInfos) { - mCallbacks.reportAntennaInfo(antennaInfos); - } - - @NativeEntryPoint - private void reportNavigationMessage(GnssNavigationMessage event) { - mCallbacks.reportNavigationMessage(event); - } - - @NativeEntryPoint - private void reportGnssPowerStats(GnssPowerStats powerStats) { - mCallbacks.reportGnssPowerStats(powerStats); - } - - @NativeEntryPoint - private void setTopHalCapabilities(int topHalCapabilities) { - mCallbacks.setTopHalCapabilities(topHalCapabilities); - } - - @NativeEntryPoint - private void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { - mCallbacks.setSubHalMeasurementCorrectionsCapabilities(subHalCapabilities); - } - - @NativeEntryPoint - private void setSubHalPowerIndicationCapabilities(int subHalCapabilities) { - mCallbacks.setSubHalPowerIndicationCapabilities(subHalCapabilities); - } - - @NativeEntryPoint - private void setGnssYearOfHardware(int yearOfHardware) { - mCallbacks.setGnssYearOfHardware(yearOfHardware); - } - - @NativeEntryPoint - private void setGnssHardwareModelName(String modelName) { - mCallbacks.setGnssHardwareModelName(modelName); - } - - @NativeEntryPoint - private void reportGnssServiceDied() { - FgThread.getExecutor().execute(() -> { - sInitNative.initOnce(GnssNative.this, true); - mCallbacks.reportGnssServiceRestarted(); - }); - } - - @NativeEntryPoint - private void reportLocationBatch(Location[] locationArray) { - mCallbacks.reportLocationBatch(locationArray); - } - - @NativeEntryPoint - private void psdsDownloadRequest(int psdsType) { - mCallbacks.psdsDownloadRequest(psdsType); - } - - @NativeEntryPoint - private void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp) { - mCallbacks.reportGeofenceTransition(geofenceId, location, transition, transitionTimestamp); - } - - @NativeEntryPoint - private void reportGeofenceStatus(int status, Location location) { - mCallbacks.reportGeofenceStatus(status, location); - } - - @NativeEntryPoint - private void reportGeofenceAddStatus(int geofenceId, int status) { - mCallbacks.reportGeofenceAddStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportGeofenceRemoveStatus(int geofenceId, int status) { - mCallbacks.reportGeofenceRemoveStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportGeofencePauseStatus(int geofenceId, int status) { - mCallbacks.reportGeofencePauseStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportGeofenceResumeStatus(int geofenceId, int status) { - mCallbacks.reportGeofenceResumeStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportNiNotification(int notificationId, int niType, int notifyFlags, - int timeout, int defaultResponse, String requestorId, String text, - int requestorIdEncoding, int textEncoding) { - mCallbacks.reportNiNotification(notificationId, niType, notifyFlags, timeout, - defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); - } - - @NativeEntryPoint - private void requestSetID(int flags) { - mCallbacks.requestSetID(flags); - } - - @NativeEntryPoint - private void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { - mCallbacks.requestLocation(independentFromGnss, isUserEmergency); - } - - @NativeEntryPoint - private void requestUtcTime() { - mCallbacks.requestUtcTime(); - } - - @NativeEntryPoint - private void requestRefLocation() { - mCallbacks.requestRefLocation(); - } - - @NativeEntryPoint - private void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, - byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { - mCallbacks.reportNfwNotification(proxyAppPackageName, protocolStack, otherProtocolStackName, - requestor, requestorId, responseType, inEmergencyMode, isCachedLocation); - } - - @NativeEntryPoint - private boolean isInEmergencySession() { - return mCallbacks.isInEmergencySession(); - } - - @VisibleForTesting - public static class GnssNativeInitNative { - - public void classInitOnce() { - native_class_init_once(); - } - - public boolean isSupported() { - return native_is_supported(); - } - - public void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) { - gnssNative.native_init_once(reinitializeGnssServiceHandle); - } - } - - static native void native_class_init_once(); - - static native boolean native_is_supported(); - - native void native_init_once(boolean reinitializeGnssServiceHandle); -} diff --git a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java index 92491f7ecd5a4..9b1cde0d967c7 100644 --- a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java @@ -20,13 +20,13 @@ import static com.android.server.location.gnss.GnssManagerService.D; import static com.android.server.location.gnss.GnssManagerService.TAG; import android.app.AppOpsManager; +import android.location.GnssCapabilities; import android.location.GnssNavigationMessage; import android.location.IGnssNavigationMessageListener; import android.location.util.identity.CallerIdentity; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.Injector; @@ -40,21 +40,24 @@ import java.util.Collection; * @hide */ public class GnssNavigationMessageProvider extends - GnssListenerMultiplexer { + GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.NavigationMessageCallbacks { private final AppOpsHelper mAppOpsHelper; - private final GnssNavigationMessageProviderNative mNative; + private final GnssNative mGnssNative; - public GnssNavigationMessageProvider(Injector injector) { - this(injector, new GnssNavigationMessageProviderNative()); - } - - @VisibleForTesting - public GnssNavigationMessageProvider(Injector injector, - GnssNavigationMessageProviderNative aNative) { + public GnssNavigationMessageProvider(Injector injector, GnssNative gnssNative) { super(injector); mAppOpsHelper = injector.getAppOpsHelper(); - mNative = aNative; + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addNavigationMessageCallbacks(this); + } + + @Override + protected boolean isServiceSupported() { + return mGnssNative.isNavigationMessageCollectionSupported(); } @Override @@ -65,9 +68,7 @@ public class GnssNavigationMessageProvider extends @Override protected boolean registerWithService(Void ignored, Collection registrations) { - Preconditions.checkState(mNative.isNavigationMessageSupported()); - - if (mNative.startNavigationMessageCollection()) { + if (mGnssNative.startNavigationMessageCollection()) { if (D) { Log.d(TAG, "starting gnss navigation messages"); } @@ -80,21 +81,26 @@ public class GnssNavigationMessageProvider extends @Override protected void unregisterWithService() { - if (mNative.isNavigationMessageSupported()) { - if (mNative.stopNavigationMessageCollection()) { - if (D) { - Log.d(TAG, "stopping gnss navigation messages"); - } - } else { - Log.e(TAG, "error stopping gnss navigation messages"); + if (mGnssNative.stopNavigationMessageCollection()) { + if (D) { + Log.d(TAG, "stopping gnss navigation messages"); } + } else { + Log.e(TAG, "error stopping gnss navigation messages"); } } - /** - * Called by GnssLocationProvider. - */ - public void onNavigationMessageAvailable(GnssNavigationMessage event) { + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportNavigationMessage(GnssNavigationMessage event) { deliverToListeners(registration -> { if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, registration.getIdentity())) { @@ -104,30 +110,4 @@ public class GnssNavigationMessageProvider extends } }); } - - @Override - protected boolean isServiceSupported() { - return mNative.isNavigationMessageSupported(); - } - - @VisibleForTesting - static class GnssNavigationMessageProviderNative { - boolean isNavigationMessageSupported() { - return native_is_navigation_message_supported(); - } - - boolean startNavigationMessageCollection() { - return native_start_navigation_message_collection(); - } - - boolean stopNavigationMessageCollection() { - return native_stop_navigation_message_collection(); - } - } - - static native boolean native_is_navigation_message_supported(); - - static native boolean native_start_navigation_message_collection(); - - static native boolean native_stop_navigation_message_collection(); } diff --git a/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java new file mode 100644 index 0000000000000..bad1b79e3568e --- /dev/null +++ b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 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 com.android.server.location.gnss; + +import static com.android.server.location.gnss.GnssManagerService.D; +import static com.android.server.location.gnss.GnssManagerService.TAG; + +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.location.GnssCapabilities; +import android.location.IGnssNmeaListener; +import android.location.util.identity.CallerIdentity; +import android.util.Log; + +import com.android.internal.listeners.ListenerExecutor; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.AppOpsHelper; +import com.android.server.location.injector.Injector; + +import java.util.Collection; +import java.util.function.Function; + +/** + * Implementation of a handler for {@link IGnssNmeaListener}. + */ +class GnssNmeaProvider extends GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.NmeaCallbacks { + + private final AppOpsHelper mAppOpsHelper; + private final GnssNative mGnssNative; + + // preallocated to avoid memory allocation in onReportNmea() + private final byte[] mNmeaBuffer = new byte[120]; + + GnssNmeaProvider(Injector injector, GnssNative gnssNative) { + super(injector); + + mAppOpsHelper = injector.getAppOpsHelper(); + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addNmeaCallbacks(this); + } + + @Override + public void addListener(CallerIdentity identity, IGnssNmeaListener listener) { + super.addListener(identity, listener); + } + + @Override + protected boolean registerWithService(Void ignored, + Collection registrations) { + if (D) { + Log.d(TAG, "starting gnss nmea messages"); + } + return true; + } + + @Override + protected void unregisterWithService() { + if (D) { + Log.d(TAG, "stopping gnss nmea messages"); + } + } + + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportNmea(long timestamp) { + deliverToListeners( + new Function>() { + + // only read in the nmea string if we need to + private @Nullable String mNmea; + + @Override + public ListenerExecutor.ListenerOperation apply( + GnssListenerRegistration registration) { + if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, + registration.getIdentity())) { + if (mNmea == null) { + int length = mGnssNative.readNmea(mNmeaBuffer, + mNmeaBuffer.length); + mNmea = new String(mNmeaBuffer, 0, length); + } + return listener -> listener.onNmeaReceived(timestamp, mNmea); + } else { + return null; + } + } + }); + } +} diff --git a/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java b/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java deleted file mode 100644 index 5941a33298dd3..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.server.location.gnss; - -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_MULTIBAND_ACQUISITION; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_MULTIBAND_TRACKING; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_OTHER_MODES; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_SINGLEBAND_ACQUISITION; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_SINGLEBAND_TRACKING; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_TOTAL; - -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Manages GNSS Power Indication operations. - */ -class GnssPowerIndicationProvider { - private static final String TAG = "GnssPowerIndPdr"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private volatile int mCapabilities; - private GnssPowerStats mGnssPowerStats; - - /** - * Handles GNSS Power Indication capabilities update from the GNSS HAL callback. - */ - public void onCapabilitiesUpdated(int capabilities) { - mCapabilities = capabilities; - } - - public void onGnssPowerStatsAvailable(GnssPowerStats powerStats) { - if (DEBUG) { - Log.d(TAG, "onGnssPowerStatsAvailable: " + powerStats.toString()); - } - powerStats.validate(); - mGnssPowerStats = powerStats; - } - - /** - * Returns the GNSS Power Indication specific capabilities. - */ - public int getCapabilities() { - return mCapabilities; - } - - /** - * Requests the GNSS HAL to report {@link GnssPowerStats}. - */ - public static void requestPowerStats() { - native_request_power_stats(); - } - - private boolean hasCapability(int capability) { - return (mCapabilities & capability) != 0; - } - - /** - * Dump info for debugging. - */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mGnssPowerStats == null) { - return; - } - pw.print("GnssPowerStats["); - if (mGnssPowerStats.hasElapsedRealtimeNanos()) { - pw.print("ElapsedRealtime=" + mGnssPowerStats.getElapsedRealtimeNanos()); - } - if (mGnssPowerStats.hasElapsedRealtimeUncertaintyNanos()) { - pw.print(", ElapsedRealtimeUncertaintyNanos=" - + mGnssPowerStats.getElapsedRealtimeUncertaintyNanos()); - } - if (hasCapability(CAPABILITY_TOTAL)) { - pw.print(", TotalEnergyMilliJoule=" + mGnssPowerStats.getTotalEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_SINGLEBAND_TRACKING)) { - pw.print(", SinglebandTrackingModeEnergyMilliJoule=" - + mGnssPowerStats.getSinglebandTrackingModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_MULTIBAND_TRACKING)) { - pw.print(", MultibandTrackingModeEnergyMilliJoule=" - + mGnssPowerStats.getMultibandTrackingModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_SINGLEBAND_ACQUISITION)) { - pw.print(", SinglebandAcquisitionModeEnergyMilliJoule=" - + mGnssPowerStats.getSinglebandAcquisitionModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_MULTIBAND_ACQUISITION)) { - pw.print(", MultibandAcquisitionModeEnergyMilliJoule=" - + mGnssPowerStats.getMultibandAcquisitionModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_OTHER_MODES)) { - pw.print(", OtherModesEnergyMilliJoule=["); - double[] otherModes = mGnssPowerStats.getOtherModesEnergyMilliJoule(); - for (int i = 0; i < otherModes.length; i++) { - pw.print(otherModes[i]); - if (i < otherModes.length - 1) { - pw.print(", "); - } - } - pw.print("] "); - } - pw.println(']'); - } - - private static native void native_request_power_stats(); -} diff --git a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java index b924d1fd98b28..924ffe10be7b0 100644 --- a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java +++ b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java @@ -19,13 +19,23 @@ package com.android.server.location.gnss; import static android.hardware.gnss.ElapsedRealtime.HAS_TIMESTAMP_NS; import static android.hardware.gnss.ElapsedRealtime.HAS_TIME_UNCERTAINTY_NS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import android.location.GnssCapabilities; +import android.util.IndentingPrintWriter; +import android.util.TimeUtils; + import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative.GnssRealtimeFlags; + +import java.io.FileDescriptor; /** * Represents Cumulative GNSS power statistics since boot. */ -class GnssPowerStats { - private final int mElapsedRealtimeFlags; +public class GnssPowerStats { + + private final @GnssRealtimeFlags int mElapsedRealtimeFlags; private final long mElapsedRealtimeNanos; private final double mElapsedRealtimeUncertaintyNanos; private final double mTotalEnergyMilliJoule; @@ -35,7 +45,7 @@ class GnssPowerStats { private final double mMultibandAcquisitionModeEnergyMilliJoule; private final double[] mOtherModesEnergyMilliJoule; - GnssPowerStats(int elapsedRealtimeFlags, + public GnssPowerStats(@GnssRealtimeFlags int elapsedRealtimeFlags, long elapsedRealtimeNanos, double elapsedRealtimeUncertaintyNanos, double totalEnergyMilliJoule, @@ -131,4 +141,51 @@ class GnssPowerStats { public void validate() { Preconditions.checkArgument(hasElapsedRealtimeNanos()); } + + /** + * Dumps power stat information filtered by the given capabilities. + */ + public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args, + GnssCapabilities capabilities) { + if (hasElapsedRealtimeNanos()) { + ipw.print("time: "); + ipw.print(TimeUtils.formatRealtime(NANOSECONDS.toMillis(mElapsedRealtimeNanos))); + if (hasElapsedRealtimeUncertaintyNanos() && mElapsedRealtimeUncertaintyNanos != 0) { + ipw.print(" +/- "); + ipw.print(NANOSECONDS.toMillis((long) mElapsedRealtimeUncertaintyNanos)); + } + } + if (capabilities.hasPowerTotal()) { + ipw.print("total power: "); + ipw.print(mTotalEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerSinglebandTracking()) { + ipw.print("single-band tracking power: "); + ipw.print(mSinglebandTrackingModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerMultibandTracking()) { + ipw.print("multi-band tracking power: "); + ipw.print(mMultibandTrackingModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerSinglebandAcquisition()) { + ipw.print("single-band acquisition power: "); + ipw.print(mSinglebandAcquisitionModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerMultibandAcquisition()) { + ipw.print("multi-band acquisition power: "); + ipw.print(mMultibandAcquisitionModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerOtherModes()) { + for (int i = 1; i <= mOtherModesEnergyMilliJoule.length; i++) { + ipw.print("other mode [" + i + "] power: "); + ipw.print(mOtherModesEnergyMilliJoule[i]); + ipw.println("mJ"); + } + } + } } diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java index 49aa235926e94..e0673db274e57 100644 --- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java @@ -20,6 +20,7 @@ import static com.android.server.location.gnss.GnssManagerService.D; import static com.android.server.location.gnss.GnssManagerService.TAG; import android.app.AppOpsManager; +import android.location.GnssCapabilities; import android.location.GnssStatus; import android.location.IGnssStatusListener; import android.location.util.identity.CallerIdentity; @@ -27,6 +28,7 @@ import android.os.IBinder; import android.stats.location.LocationStatsEnums; import android.util.Log; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationUsageLogger; @@ -36,15 +38,23 @@ import java.util.Collection; /** * Implementation of a handler for {@link IGnssStatusListener}. */ -public class GnssStatusProvider extends GnssListenerMultiplexer { +public class GnssStatusProvider extends + GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.StatusCallbacks, GnssNative.SvStatusCallbacks { private final AppOpsHelper mAppOpsHelper; private final LocationUsageLogger mLogger; - public GnssStatusProvider(Injector injector) { + private boolean mIsNavigating = false; + + public GnssStatusProvider(Injector injector, GnssNative gnssNative) { super(injector); mAppOpsHelper = injector.getAppOpsHelper(); mLogger = injector.getLocationUsageLogger(); + + gnssNative.addBaseCallbacks(this); + gnssNative.addStatusCallbacks(this); + gnssNative.addSvStatusCallbacks(this); } @Override @@ -95,30 +105,50 @@ public class GnssStatusProvider extends GnssListenerMultiplexer { listener.onFirstFix(ttff); }); } - /** - * Called by GnssLocationProvider. - */ - public void onSvStatusChanged(GnssStatus gnssStatus) { + @Override + public void onReportSvStatus(GnssStatus gnssStatus) { deliverToListeners(registration -> { if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, registration.getIdentity())) { @@ -128,18 +158,4 @@ public class GnssStatusProvider extends GnssListenerMultiplexer { - if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, - registration.getIdentity())) { - return listener -> listener.onNmeaReceived(timestamp, nmea); - } else { - return null; - } - }); - } } diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java new file mode 100644 index 0000000000000..89d82495dca30 --- /dev/null +++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java @@ -0,0 +1,1490 @@ +/* + * Copyright (C) 2020 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 com.android.server.location.gnss.hal; + +import static com.android.server.location.gnss.GnssManagerService.TAG; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.location.GnssAntennaInfo; +import android.location.GnssCapabilities; +import android.location.GnssMeasurementCorrections; +import android.location.GnssMeasurementsEvent; +import android.location.GnssNavigationMessage; +import android.location.GnssStatus; +import android.location.Location; +import android.os.SystemClock; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Preconditions; +import com.android.server.FgThread; +import com.android.server.location.gnss.GnssConfiguration; +import com.android.server.location.gnss.GnssPowerStats; +import com.android.server.location.injector.EmergencyHelper; +import com.android.server.location.injector.Injector; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +import java.util.Objects; + +/** + * Entry point for most GNSS HAL commands and callbacks. + */ +public class GnssNative { + + // IMPORTANT - must match GnssPositionMode enum in IGnss.hal + public static final int GNSS_POSITION_MODE_STANDALONE = 0; + public static final int GNSS_POSITION_MODE_MS_BASED = 1; + public static final int GNSS_POSITION_MODE_MS_ASSISTED = 2; + + @IntDef(prefix = "GNSS_POSITION_MODE_", value = {GNSS_POSITION_MODE_STANDALONE, + GNSS_POSITION_MODE_MS_BASED, GNSS_POSITION_MODE_MS_ASSISTED}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssPositionMode {} + + // IMPORTANT - must match GnssPositionRecurrence enum in IGnss.hal + public static final int GNSS_POSITION_RECURRENCE_PERIODIC = 0; + public static final int GNSS_POSITION_RECURRENCE_SINGLE = 1; + + @IntDef(prefix = "GNSS_POSITION_RECURRENCE_", value = {GNSS_POSITION_RECURRENCE_PERIODIC, + GNSS_POSITION_RECURRENCE_SINGLE}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssPositionRecurrence {} + + // IMPORTANT - must match the GnssLocationFlags enum in types.hal + public static final int GNSS_LOCATION_HAS_LAT_LONG = 1; + public static final int GNSS_LOCATION_HAS_ALTITUDE = 2; + public static final int GNSS_LOCATION_HAS_SPEED = 4; + public static final int GNSS_LOCATION_HAS_BEARING = 8; + public static final int GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY = 16; + public static final int GNSS_LOCATION_HAS_VERTICAL_ACCURACY = 32; + public static final int GNSS_LOCATION_HAS_SPEED_ACCURACY = 64; + public static final int GNSS_LOCATION_HAS_BEARING_ACCURACY = 128; + + @IntDef(flag = true, prefix = "GNSS_LOCATION_", value = {GNSS_LOCATION_HAS_LAT_LONG, + GNSS_LOCATION_HAS_ALTITUDE, GNSS_LOCATION_HAS_SPEED, GNSS_LOCATION_HAS_BEARING, + GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY, GNSS_LOCATION_HAS_VERTICAL_ACCURACY, + GNSS_LOCATION_HAS_SPEED_ACCURACY, GNSS_LOCATION_HAS_BEARING_ACCURACY}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssLocationFlags {} + + // IMPORTANT - must match the ElapsedRealtimeFlags enum in types.hal + public static final int GNSS_REALTIME_HAS_TIMESTAMP_NS = 1; + public static final int GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2; + + @IntDef(flag = true, value = {GNSS_REALTIME_HAS_TIMESTAMP_NS, + GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssRealtimeFlags {} + + // IMPORTANT - must match the GnssAidingData enum in IGnss.hal + public static final int GNSS_AIDING_TYPE_EPHEMERIS = 0x0001; + public static final int GNSS_AIDING_TYPE_ALMANAC = 0x0002; + public static final int GNSS_AIDING_TYPE_POSITION = 0x0004; + public static final int GNSS_AIDING_TYPE_TIME = 0x0008; + public static final int GNSS_AIDING_TYPE_IONO = 0x0010; + public static final int GNSS_AIDING_TYPE_UTC = 0x0020; + public static final int GNSS_AIDING_TYPE_HEALTH = 0x0040; + public static final int GNSS_AIDING_TYPE_SVDIR = 0x0080; + public static final int GNSS_AIDING_TYPE_SVSTEER = 0x0100; + public static final int GNSS_AIDING_TYPE_SADATA = 0x0200; + public static final int GNSS_AIDING_TYPE_RTI = 0x0400; + public static final int GNSS_AIDING_TYPE_CELLDB_INFO = 0x8000; + public static final int GNSS_AIDING_TYPE_ALL = 0xFFFF; + + @IntDef(flag = true, prefix = "GNSS_AIDING_", value = {GNSS_AIDING_TYPE_EPHEMERIS, + GNSS_AIDING_TYPE_ALMANAC, GNSS_AIDING_TYPE_POSITION, GNSS_AIDING_TYPE_TIME, + GNSS_AIDING_TYPE_IONO, GNSS_AIDING_TYPE_UTC, GNSS_AIDING_TYPE_HEALTH, + GNSS_AIDING_TYPE_SVDIR, GNSS_AIDING_TYPE_SVSTEER, GNSS_AIDING_TYPE_SADATA, + GNSS_AIDING_TYPE_RTI, GNSS_AIDING_TYPE_CELLDB_INFO, GNSS_AIDING_TYPE_ALL}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssAidingTypeFlags {} + + // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason + public static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; + public static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; + + @IntDef(prefix = "AGPS_REF_LOCATION_TYPE_", value = {AGPS_REF_LOCATION_TYPE_GSM_CELLID, + AGPS_REF_LOCATION_TYPE_UMTS_CELLID}) + @Retention(RetentionPolicy.SOURCE) + public @interface AgpsReferenceLocationType {} + + // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason + public static final int AGPS_SETID_TYPE_NONE = 0; + public static final int AGPS_SETID_TYPE_IMSI = 1; + public static final int AGPS_SETID_TYPE_MSISDN = 2; + + @IntDef(prefix = "AGPS_SETID_TYPE_", value = {AGPS_SETID_TYPE_NONE, AGPS_SETID_TYPE_IMSI, + AGPS_SETID_TYPE_MSISDN}) + @Retention(RetentionPolicy.SOURCE) + public @interface AgpsSetIdType {} + + /** Callbacks relevant to the entire HAL. */ + public interface BaseCallbacks { + void onHalRestarted(); + void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities); + } + + /** Callbacks for status events. */ + public interface StatusCallbacks { + + // IMPORTANT - must match GnssStatusValue enum in IGnssCallback.hal + int GNSS_STATUS_NONE = 0; + int GNSS_STATUS_SESSION_BEGIN = 1; + int GNSS_STATUS_SESSION_END = 2; + int GNSS_STATUS_ENGINE_ON = 3; + int GNSS_STATUS_ENGINE_OFF = 4; + + @IntDef(prefix = "GNSS_STATUS_", value = {GNSS_STATUS_NONE, GNSS_STATUS_SESSION_BEGIN, + GNSS_STATUS_SESSION_END, GNSS_STATUS_ENGINE_ON, GNSS_STATUS_ENGINE_OFF}) + @Retention(RetentionPolicy.SOURCE) + @interface GnssStatusValue {} + + void onReportStatus(@GnssStatusValue int status); + void onReportFirstFix(int ttff); + } + + /** Callbacks for SV status events. */ + public interface SvStatusCallbacks { + void onReportSvStatus(GnssStatus gnssStatus); + } + + /** Callbacks for NMEA events. */ + public interface NmeaCallbacks { + void onReportNmea(long timestamp); + } + + /** Callbacks for location events. */ + public interface LocationCallbacks { + void onReportLocation(boolean hasLatLong, Location location); + void onReportLocations(Location[] locations); + } + + /** Callbacks for measurement events. */ + public interface MeasurementCallbacks { + void onReportMeasurements(GnssMeasurementsEvent event); + } + + /** Callbacks for antenna info events. */ + public interface AntennaInfoCallbacks { + void onReportAntennaInfo(List antennaInfos); + } + + /** Callbacks for navigation message events. */ + public interface NavigationMessageCallbacks { + void onReportNavigationMessage(GnssNavigationMessage event); + } + + /** Callbacks for geofence events. */ + public interface GeofenceCallbacks { + + // IMPORTANT - must match GeofenceTransition enum in IGnssGeofenceCallback.hal + int GEOFENCE_TRANSITION_ENTERED = 1 << 0L; + int GEOFENCE_TRANSITION_EXITED = 1 << 1L; + int GEOFENCE_TRANSITION_UNCERTAIN = 1 << 2L; + + @IntDef(prefix = "GEOFENCE_TRANSITION_", value = {GEOFENCE_TRANSITION_ENTERED, + GEOFENCE_TRANSITION_EXITED, GEOFENCE_TRANSITION_UNCERTAIN}) + @Retention(RetentionPolicy.SOURCE) + @interface GeofenceTransition {} + + // IMPORTANT - must match GeofenceAvailability enum in IGnssGeofenceCallback.hal + int GEOFENCE_AVAILABILITY_UNAVAILABLE = 1 << 0L; + int GEOFENCE_AVAILABILITY_AVAILABLE = 1 << 1L; + + @IntDef(prefix = "GEOFENCE_AVAILABILITY_", value = {GEOFENCE_AVAILABILITY_UNAVAILABLE, + GEOFENCE_AVAILABILITY_AVAILABLE}) + @Retention(RetentionPolicy.SOURCE) + @interface GeofenceAvailability {} + + // IMPORTANT - must match GeofenceStatus enum in IGnssGeofenceCallback.hal + int GEOFENCE_STATUS_OPERATION_SUCCESS = 0; + int GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES = 100; + int GEOFENCE_STATUS_ERROR_ID_EXISTS = -101; + int GEOFENCE_STATUS_ERROR_ID_UNKNOWN = -102; + int GEOFENCE_STATUS_ERROR_INVALID_TRANSITION = -103; + int GEOFENCE_STATUS_ERROR_GENERIC = -149; + + @IntDef(prefix = "GEOFENCE_STATUS_", value = {GEOFENCE_STATUS_OPERATION_SUCCESS, + GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES, GEOFENCE_STATUS_ERROR_ID_EXISTS, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN, GEOFENCE_STATUS_ERROR_INVALID_TRANSITION, + GEOFENCE_STATUS_ERROR_GENERIC}) + @Retention(RetentionPolicy.SOURCE) + @interface GeofenceStatus {} + + void onReportGeofenceTransition(int geofenceId, Location location, + @GeofenceTransition int transition, long timestamp); + void onReportGeofenceStatus(@GeofenceAvailability int availabilityStatus, + Location location); + void onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status); + void onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status); + void onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status); + void onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status); + } + + /** Callbacks for the HAL requesting time. */ + public interface TimeCallbacks { + void onRequestUtcTime(); + } + + /** Callbacks for the HAL requesting locations. */ + public interface LocationRequestCallbacks { + void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency); + void onRequestRefLocation(); + } + + /** Callbacks for HAL requesting PSDS download. */ + public interface PsdsCallbacks { + void onRequestPsdsDownload(int psdsType); + } + + /** Callbacks for AGPS functionality. */ + public interface AGpsCallbacks { + + // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason + int AGPS_REQUEST_SETID_IMSI = 1 << 0L; + int AGPS_REQUEST_SETID_MSISDN = 1 << 1L; + + @IntDef(flag = true, prefix = "AGPS_REQUEST_SETID_", value = {AGPS_REQUEST_SETID_IMSI, + AGPS_REQUEST_SETID_MSISDN}) + @Retention(RetentionPolicy.SOURCE) + @interface AgpsSetIdFlags {} + + void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr); + void onRequestSetID(@AgpsSetIdFlags int flags); + } + + /** Callbacks for notifications. */ + public interface NotificationCallbacks { + void onReportNiNotification(int notificationId, int niType, int notifyFlags, + int timeout, int defaultResponse, String requestorId, String text, + int requestorIdEncoding, int textEncoding); + void onReportNfwNotification(String proxyAppPackageName, byte protocolStack, + String otherProtocolStackName, byte requestor, String requestorId, + byte responseType, boolean inEmergencyMode, boolean isCachedLocation); + } + + // set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL + // stops output right at 600m/s, depriving this of the information of a device that reaches + // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases. + private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0f; + + /** + * Indicates that this method is a native entry point. Useful purely for IDEs which can + * understand entry points, and thus eliminate incorrect warnings about methods not used. + */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.SOURCE) + private @interface NativeEntryPoint {} + + @GuardedBy("GnssNative.class") + private static GnssHal sGnssHal; + + @GuardedBy("GnssNative.class") + private static boolean sGnssHalInitialized; + + @GuardedBy("GnssNative.class") + private static GnssNative sInstance; + + /** + * Sets GnssHal instance to use for testing. + */ + @VisibleForTesting + public static synchronized void setGnssHalForTest(GnssHal gnssHal) { + sGnssHal = Objects.requireNonNull(gnssHal); + sGnssHalInitialized = false; + sInstance = null; + } + + private static synchronized void initializeHal() { + if (!sGnssHalInitialized) { + if (sGnssHal == null) { + sGnssHal = new GnssHal(); + } + sGnssHal.classInitOnce(); + sGnssHalInitialized = true; + } + } + + /** + * Returns true if GNSS is supported on this device. If true, then + * {@link #create(Injector, GnssConfiguration)} may be invoked. + */ + public static synchronized boolean isSupported() { + initializeHal(); + return sGnssHal.isSupported(); + } + + /** + * Creates a new instance of GnssNative. Should only be invoked if {@link #isSupported()} is + * true. May only be invoked once. + */ + public static synchronized GnssNative create(Injector injector, + GnssConfiguration configuration) { + // side effect - ensures initialization + Preconditions.checkState(isSupported()); + Preconditions.checkState(sInstance == null); + return (sInstance = new GnssNative(sGnssHal, injector, configuration)); + } + + private final GnssHal mGnssHal; + private final EmergencyHelper mEmergencyHelper; + private final GnssConfiguration mConfiguration; + + // these callbacks may have multiple implementations + private BaseCallbacks[] mBaseCallbacks = new BaseCallbacks[0]; + private StatusCallbacks[] mStatusCallbacks = new StatusCallbacks[0]; + private SvStatusCallbacks[] mSvStatusCallbacks = new SvStatusCallbacks[0]; + private NmeaCallbacks[] mNmeaCallbacks = new NmeaCallbacks[0]; + private LocationCallbacks[] mLocationCallbacks = new LocationCallbacks[0]; + private MeasurementCallbacks[] mMeasurementCallbacks = new MeasurementCallbacks[0]; + private AntennaInfoCallbacks[] mAntennaInfoCallbacks = new AntennaInfoCallbacks[0]; + private NavigationMessageCallbacks[] mNavigationMessageCallbacks = + new NavigationMessageCallbacks[0]; + + // these callbacks may only have a single implementation + private GeofenceCallbacks mGeofenceCallbacks; + private TimeCallbacks mTimeCallbacks; + private LocationRequestCallbacks mLocationRequestCallbacks; + private PsdsCallbacks mPsdsCallbacks; + private AGpsCallbacks mAGpsCallbacks; + private NotificationCallbacks mNotificationCallbacks; + + private boolean mRegistered; + + private volatile boolean mItarSpeedLimitExceeded; + + private GnssCapabilities mCapabilities = new GnssCapabilities.Builder().build(); + private @Nullable GnssPowerStats mPowerStats = null; + private int mHardwareYear = 0; + private @Nullable String mHardwareModelName = null; + private long mStartRealtimeMs = 0; + private boolean mHasFirstFix = false; + + private GnssNative(GnssHal gnssHal, Injector injector, GnssConfiguration configuration) { + mGnssHal = Objects.requireNonNull(gnssHal); + mEmergencyHelper = injector.getEmergencyHelper(); + mConfiguration = configuration; + } + + public void addBaseCallbacks(BaseCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mBaseCallbacks = ArrayUtils.appendElement(BaseCallbacks.class, mBaseCallbacks, callbacks); + } + + public void addStatusCallbacks(StatusCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mStatusCallbacks = ArrayUtils.appendElement(StatusCallbacks.class, mStatusCallbacks, + callbacks); + } + + public void addSvStatusCallbacks(SvStatusCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mSvStatusCallbacks = ArrayUtils.appendElement(SvStatusCallbacks.class, mSvStatusCallbacks, + callbacks); + } + + public void addNmeaCallbacks(NmeaCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mNmeaCallbacks = ArrayUtils.appendElement(NmeaCallbacks.class, mNmeaCallbacks, + callbacks); + } + + public void addLocationCallbacks(LocationCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mLocationCallbacks = ArrayUtils.appendElement(LocationCallbacks.class, mLocationCallbacks, + callbacks); + } + + public void addMeasurementCallbacks(MeasurementCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mMeasurementCallbacks = ArrayUtils.appendElement(MeasurementCallbacks.class, + mMeasurementCallbacks, callbacks); + } + + public void addAntennaInfoCallbacks(AntennaInfoCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mAntennaInfoCallbacks = ArrayUtils.appendElement(AntennaInfoCallbacks.class, + mAntennaInfoCallbacks, callbacks); + } + + public void addNavigationMessageCallbacks(NavigationMessageCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mNavigationMessageCallbacks = ArrayUtils.appendElement(NavigationMessageCallbacks.class, + mNavigationMessageCallbacks, callbacks); + } + + public void setGeofenceCallbacks(GeofenceCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mGeofenceCallbacks == null); + mGeofenceCallbacks = Objects.requireNonNull(callbacks); + } + + public void setTimeCallbacks(TimeCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mTimeCallbacks == null); + mTimeCallbacks = Objects.requireNonNull(callbacks); + } + + public void setLocationRequestCallbacks(LocationRequestCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mLocationRequestCallbacks == null); + mLocationRequestCallbacks = Objects.requireNonNull(callbacks); + } + + public void setPsdsCallbacks(PsdsCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mPsdsCallbacks == null); + mPsdsCallbacks = Objects.requireNonNull(callbacks); + } + + public void setAGpsCallbacks(AGpsCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mAGpsCallbacks == null); + mAGpsCallbacks = Objects.requireNonNull(callbacks); + } + + public void setNotificationCallbacks(NotificationCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mNotificationCallbacks == null); + mNotificationCallbacks = Objects.requireNonNull(callbacks); + } + + /** + * Registers with the HAL and allows callbacks to begin. Once registered with the native HAL, + * no more callbacks can be added or set. Must only be called once. + */ + public void register() { + Preconditions.checkState(!mRegistered); + mRegistered = true; + + initializeGnss(false); + } + + private void initializeGnss(boolean restart) { + Preconditions.checkState(mRegistered); + mGnssHal.initOnce(GnssNative.this, restart); + + // gnss chipset appears to require an init/cleanup cycle on startup in order to properly + // initialize - undocumented and no idea why this is the case + if (mGnssHal.init()) { + mGnssHal.cleanup(); + Log.i(TAG, "gnss hal initialized"); + } else { + Log.e(TAG, "gnss hal initialization failed"); + } + } + + public GnssConfiguration getConfiguration() { + return mConfiguration; + } + + /** + * Starts up GNSS HAL, and has undocumented side effect of informing HAL that location is + * allowed by settings. + */ + public boolean init() { + Preconditions.checkState(mRegistered); + return mGnssHal.init(); + } + + /** + * Shuts down GNSS HAL, and has undocumented side effect of informing HAL that location is not + * allowed by settings. + */ + public void cleanup() { + Preconditions.checkState(mRegistered); + mGnssHal.cleanup(); + } + + /** + * Returns the latest power stats from the GNSS HAL. + */ + public @Nullable GnssPowerStats getPowerStats() { + return mPowerStats; + } + + /** + * Returns current capabilities of the GNSS HAL. + */ + public GnssCapabilities getCapabilities() { + return mCapabilities; + } + + /** + * Returns hardware year of GNSS chipset. + */ + public int getHardwareYear() { + return mHardwareYear; + } + + /** + * Returns hardware model name of GNSS chipset. + */ + public @Nullable String getHardwareModelName() { + return mHardwareModelName; + } + + /** + * Returns true if the ITAR speed limit is currently being exceeded, and thus location + * information may be blocked. + */ + public boolean isItarSpeedLimitExceeded() { + return mItarSpeedLimitExceeded; + } + + /** + * Starts the GNSS HAL. + */ + public boolean start() { + Preconditions.checkState(mRegistered); + mStartRealtimeMs = SystemClock.elapsedRealtime(); + mHasFirstFix = false; + return mGnssHal.start(); + } + + /** + * Stops the GNSS HAL. + */ + public boolean stop() { + Preconditions.checkState(mRegistered); + return mGnssHal.stop(); + } + + /** + * Sets the position mode. + */ + public boolean setPositionMode(@GnssPositionMode int mode, + @GnssPositionRecurrence int recurrence, int minInterval, int preferredAccuracy, + int preferredTime, boolean lowPowerMode) { + Preconditions.checkState(mRegistered); + return mGnssHal.setPositionMode(mode, recurrence, minInterval, preferredAccuracy, + preferredTime, lowPowerMode); + } + + /** + * Returns a debug string from the GNSS HAL. + */ + public String getInternalState() { + Preconditions.checkState(mRegistered); + return mGnssHal.getInternalState(); + } + + /** + * Deletes any aiding data specified by the given flags. + */ + public void deleteAidingData(@GnssAidingTypeFlags int flags) { + Preconditions.checkState(mRegistered); + mGnssHal.deleteAidingData(flags); + } + + /** + * Reads an NMEA message into the given buffer, returning the number of bytes loaded into the + * buffer. + */ + public int readNmea(byte[] buffer, int bufferSize) { + Preconditions.checkState(mRegistered); + return mGnssHal.readNmea(buffer, bufferSize); + } + + /** + * Injects location information into the GNSS HAL. + */ + public void injectLocation(Location location) { + Preconditions.checkState(mRegistered); + if (location.hasAccuracy()) { + mGnssHal.injectLocation(location.getLatitude(), location.getLongitude(), + location.getAccuracy()); + } + } + + /** + * Injects a location into the GNSS HAL in response to a HAL request for location. + */ + public void injectBestLocation(Location location) { + Preconditions.checkState(mRegistered); + + int gnssLocationFlags = GNSS_LOCATION_HAS_LAT_LONG + | (location.hasAltitude() ? GNSS_LOCATION_HAS_ALTITUDE : 0) + | (location.hasSpeed() ? GNSS_LOCATION_HAS_SPEED : 0) + | (location.hasBearing() ? GNSS_LOCATION_HAS_BEARING : 0) + | (location.hasAccuracy() ? GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY : 0) + | (location.hasVerticalAccuracy() ? GNSS_LOCATION_HAS_VERTICAL_ACCURACY : 0) + | (location.hasSpeedAccuracy() ? GNSS_LOCATION_HAS_SPEED_ACCURACY : 0) + | (location.hasBearingAccuracy() ? GNSS_LOCATION_HAS_BEARING_ACCURACY : 0); + + double latitudeDegrees = location.getLatitude(); + double longitudeDegrees = location.getLongitude(); + double altitudeMeters = location.getAltitude(); + float speedMetersPerSec = location.getSpeed(); + float bearingDegrees = location.getBearing(); + float horizontalAccuracyMeters = location.getAccuracy(); + float verticalAccuracyMeters = location.getVerticalAccuracyMeters(); + float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond(); + float bearingAccuracyDegrees = location.getBearingAccuracyDegrees(); + long timestamp = location.getTime(); + + int elapsedRealtimeFlags = GNSS_REALTIME_HAS_TIMESTAMP_NS + | (location.hasElapsedRealtimeUncertaintyNanos() + ? GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0); + long elapsedRealtimeNanos = location.getElapsedRealtimeNanos(); + double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos(); + + mGnssHal.injectBestLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees, + altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters, + verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees, + timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos, + elapsedRealtimeUncertaintyNanos); + } + + /** + * Injects time information into the GNSS HAL. + */ + public void injectTime(long time, long timeReference, int uncertainty) { + Preconditions.checkState(mRegistered); + mGnssHal.injectTime(time, timeReference, uncertainty); + } + + /** + * Returns true if navigation message collection is supported. + */ + public boolean isNavigationMessageCollectionSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isNavigationMessageCollectionSupported(); + } + + /** + * Starts navigation message collection. + */ + public boolean startNavigationMessageCollection() { + Preconditions.checkState(mRegistered); + return mGnssHal.startNavigationMessageCollection(); + } + + /** + * Stops navigation message collection. + */ + public boolean stopNavigationMessageCollection() { + Preconditions.checkState(mRegistered); + return mGnssHal.stopNavigationMessageCollection(); + } + + /** + * Returns true if antenna info listening is supported. + */ + public boolean isAntennaInfoListeningSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isAntennaInfoListeningSupported(); + } + + /** + * Starts antenna info listening. + */ + public boolean startAntennaInfoListening() { + Preconditions.checkState(mRegistered); + return mGnssHal.startAntennaInfoListening(); + } + + /** + * Stops antenna info listening. + */ + public boolean stopAntennaInfoListening() { + Preconditions.checkState(mRegistered); + return mGnssHal.stopAntennaInfoListening(); + } + + /** + * Returns true if measurement collection is supported. + */ + public boolean isMeasurementSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isMeasurementSupported(); + } + + /** + * Starts measurement collection. + */ + public boolean startMeasurementCollection(boolean enableFullTracking) { + Preconditions.checkState(mRegistered); + return mGnssHal.startMeasurementCollection(enableFullTracking); + } + + /** + * Stops measurement collection. + */ + public boolean stopMeasurementCollection() { + Preconditions.checkState(mRegistered); + return mGnssHal.stopMeasurementCollection(); + } + + /** + * Returns true if measurement corrections are supported. + */ + public boolean isMeasurementCorrectionsSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isMeasurementCorrectionsSupported(); + } + + /** + * Injects measurement corrections into the GNSS HAL. + */ + public boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) { + Preconditions.checkState(mRegistered); + return mGnssHal.injectMeasurementCorrections(corrections); + } + + /** + * Initialize batching. + */ + public boolean initBatching() { + Preconditions.checkState(mRegistered); + return mGnssHal.initBatching(); + } + + /** + * Cleanup batching. + */ + public void cleanupBatching() { + Preconditions.checkState(mRegistered); + mGnssHal.cleanupBatching(); + } + + /** + * Start batching. + */ + public boolean startBatch(long periodNanos, boolean wakeOnFifoFull) { + Preconditions.checkState(mRegistered); + return mGnssHal.startBatch(periodNanos, wakeOnFifoFull); + } + + /** + * Flush batching. + */ + public void flushBatch() { + Preconditions.checkState(mRegistered); + mGnssHal.flushBatch(); + } + + /** + * Stop batching. + */ + public void stopBatch() { + Preconditions.checkState(mRegistered); + mGnssHal.stopBatch(); + } + + /** + * Get current batching size. + */ + public int getBatchSize() { + Preconditions.checkState(mRegistered); + return mGnssHal.getBatchSize(); + } + + /** + * Check if GNSS geofencing is supported. + */ + public boolean isGeofencingSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isGeofencingSupported(); + } + + /** + * Add geofence. + */ + public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius, + int lastTransition, int monitorTransitions, int notificationResponsiveness, + int unknownTimer) { + Preconditions.checkState(mRegistered); + return mGnssHal.addGeofence(geofenceId, latitude, longitude, radius, lastTransition, + monitorTransitions, notificationResponsiveness, unknownTimer); + } + + /** + * Resume geofence. + */ + public boolean resumeGeofence(int geofenceId, int monitorTransitions) { + Preconditions.checkState(mRegistered); + return mGnssHal.resumeGeofence(geofenceId, monitorTransitions); + } + + /** + * Pause geofence. + */ + public boolean pauseGeofence(int geofenceId) { + Preconditions.checkState(mRegistered); + return mGnssHal.pauseGeofence(geofenceId); + } + + /** + * Remove geofence. + */ + public boolean removeGeofence(int geofenceId) { + Preconditions.checkState(mRegistered); + return mGnssHal.removeGeofence(geofenceId); + } + + /** + * Returns true if visibility control is supported. + */ + public boolean isGnssVisibilityControlSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isGnssVisibilityControlSupported(); + } + + /** + * Send a network initiated respnse. + */ + public void sendNiResponse(int notificationId, int userResponse) { + Preconditions.checkState(mRegistered); + mGnssHal.sendNiResponse(notificationId, userResponse); + } + + /** + * Request an eventual update of GNSS power statistics. + */ + public void requestPowerStats() { + Preconditions.checkState(mRegistered); + mGnssHal.requestPowerStats(); + } + + /** + * Sets AGPS server information. + */ + public void setAgpsServer(int type, String hostname, int port) { + Preconditions.checkState(mRegistered); + mGnssHal.setAgpsServer(type, hostname, port); + } + + /** + * Sets AGPS set id. + */ + public void setAgpsSetId(@AgpsSetIdType int type, String setId) { + Preconditions.checkState(mRegistered); + mGnssHal.setAgpsSetId(type, setId); + } + + /** + * Sets AGPS reference cell id location. + */ + public void setAgpsReferenceLocationCellId(@AgpsReferenceLocationType int type, int mcc, + int mnc, int lac, int cid) { + Preconditions.checkState(mRegistered); + mGnssHal.setAgpsReferenceLocationCellId(type, mcc, mnc, lac, cid); + } + + /** + * Returns true if Predicted Satellite Data Service APIs are supported. + */ + public boolean isPsdsSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isPsdsSupported(); + } + + /** + * Injects Predicited Satellite Data Service data into the GNSS HAL. + */ + public void injectPsdsData(byte[] data, int length, int psdsType) { + Preconditions.checkState(mRegistered); + mGnssHal.injectPsdsData(data, length, psdsType); + } + + @NativeEntryPoint + void reportGnssServiceDied() { + Log.e(TAG, "gnss hal died - restarting shortly..."); + + // move to another thread just in case there is some awkward gnss thread dependency with + // the death notification. there shouldn't be, but you never know with gnss... + FgThread.getExecutor().execute(this::restartHal); + } + + @VisibleForTesting + void restartHal() { + initializeGnss(true); + Log.e(TAG, "gnss hal restarted"); + + for (int i = 0; i < mBaseCallbacks.length; i++) { + mBaseCallbacks[i].onHalRestarted(); + } + } + + @NativeEntryPoint + void reportLocation(boolean hasLatLong, Location location) { + if (hasLatLong && !mHasFirstFix) { + mHasFirstFix = true; + + // notify status listeners + int ttff = (int) (SystemClock.elapsedRealtime() - mStartRealtimeMs); + for (int i = 0; i < mStatusCallbacks.length; i++) { + mStatusCallbacks[i].onReportFirstFix(ttff); + } + } + + if (location.hasSpeed()) { + boolean exceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND; + if (!mItarSpeedLimitExceeded && exceeded) { + Log.w(TAG, "speed nearing ITAR threshold - blocking further GNSS output"); + } else if (mItarSpeedLimitExceeded && !exceeded) { + Log.w(TAG, "speed leaving ITAR threshold - allowing further GNSS output"); + } + mItarSpeedLimitExceeded = exceeded; + } + + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mLocationCallbacks.length; i++) { + mLocationCallbacks[i].onReportLocation(hasLatLong, location); + } + } + + @NativeEntryPoint + void reportStatus(@StatusCallbacks.GnssStatusValue int gnssStatus) { + for (int i = 0; i < mStatusCallbacks.length; i++) { + mStatusCallbacks[i].onReportStatus(gnssStatus); + } + } + + @NativeEntryPoint + void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, + float[] elevations, float[] azimuths, float[] carrierFrequencies, + float[] basebandCn0DbHzs) { + GnssStatus gnssStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations, + azimuths, carrierFrequencies, basebandCn0DbHzs); + for (int i = 0; i < mSvStatusCallbacks.length; i++) { + mSvStatusCallbacks[i].onReportSvStatus(gnssStatus); + } + } + + @NativeEntryPoint + void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { + mAGpsCallbacks.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); + } + + @NativeEntryPoint + void reportNmea(long timestamp) { + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mNmeaCallbacks.length; i++) { + mNmeaCallbacks[i].onReportNmea(timestamp); + } + } + + @NativeEntryPoint + void reportMeasurementData(GnssMeasurementsEvent event) { + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mMeasurementCallbacks.length; i++) { + mMeasurementCallbacks[i].onReportMeasurements(event); + } + } + + @NativeEntryPoint + void reportAntennaInfo(List antennaInfos) { + for (int i = 0; i < mAntennaInfoCallbacks.length; i++) { + mAntennaInfoCallbacks[i].onReportAntennaInfo(antennaInfos); + } + } + + @NativeEntryPoint + void reportNavigationMessage(GnssNavigationMessage event) { + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mNavigationMessageCallbacks.length; i++) { + mNavigationMessageCallbacks[i].onReportNavigationMessage(event); + } + } + + @NativeEntryPoint + void setTopHalCapabilities(@GnssCapabilities.TopHalCapabilityFlags int capabilities) { + GnssCapabilities oldCapabilities = mCapabilities; + mCapabilities = oldCapabilities.withTopHalFlags(capabilities); + onCapabilitiesChanged(oldCapabilities, mCapabilities); + } + + @NativeEntryPoint + void setSubHalMeasurementCorrectionsCapabilities( + @GnssCapabilities.SubHalMeasurementCorrectionsCapabilityFlags int capabilities) { + GnssCapabilities oldCapabilities = mCapabilities; + mCapabilities = oldCapabilities.withSubHalMeasurementCorrectionsFlags(capabilities); + onCapabilitiesChanged(oldCapabilities, mCapabilities); + } + + @NativeEntryPoint + void setSubHalPowerIndicationCapabilities( + @GnssCapabilities.SubHalPowerCapabilityFlags int capabilities) { + GnssCapabilities oldCapabilities = mCapabilities; + mCapabilities = oldCapabilities.withSubHalPowerFlags(capabilities); + onCapabilitiesChanged(oldCapabilities, mCapabilities); + } + + private void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) { + if (newCapabilities.equals(oldCapabilities)) { + return; + } + + Log.i(TAG, "gnss capabilities changed to " + newCapabilities); + + for (int i = 0; i < mBaseCallbacks.length; i++) { + mBaseCallbacks[i].onCapabilitiesChanged(oldCapabilities, newCapabilities); + } + } + + @NativeEntryPoint + void reportGnssPowerStats(GnssPowerStats powerStats) { + mPowerStats = powerStats; + } + + @NativeEntryPoint + void setGnssYearOfHardware(int year) { + mHardwareYear = year; + } + + @NativeEntryPoint + private void setGnssHardwareModelName(String modelName) { + mHardwareModelName = modelName; + } + + @NativeEntryPoint + void reportLocationBatch(Location[] locations) { + for (int i = 0; i < mLocationCallbacks.length; i++) { + mLocationCallbacks[i].onReportLocations(locations); + } + } + + @NativeEntryPoint + void psdsDownloadRequest(int psdsType) { + mPsdsCallbacks.onRequestPsdsDownload(psdsType); + } + + @NativeEntryPoint + void reportGeofenceTransition(int geofenceId, Location location, int transition, + long transitionTimestamp) { + mGeofenceCallbacks.onReportGeofenceTransition(geofenceId, location, transition, + transitionTimestamp); + } + + @NativeEntryPoint + void reportGeofenceStatus(int status, Location location) { + mGeofenceCallbacks.onReportGeofenceStatus(status, location); + } + + @NativeEntryPoint + void reportGeofenceAddStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofenceAddStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportGeofenceRemoveStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofenceRemoveStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportGeofencePauseStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofencePauseStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportGeofenceResumeStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofenceResumeStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportNiNotification(int notificationId, int niType, int notifyFlags, + int timeout, int defaultResponse, String requestorId, String text, + int requestorIdEncoding, int textEncoding) { + mNotificationCallbacks.onReportNiNotification(notificationId, niType, notifyFlags, timeout, + defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); + } + + @NativeEntryPoint + void requestSetID(int flags) { + mAGpsCallbacks.onRequestSetID(flags); + } + + @NativeEntryPoint + void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { + mLocationRequestCallbacks.onRequestLocation(independentFromGnss, isUserEmergency); + } + + @NativeEntryPoint + void requestUtcTime() { + mTimeCallbacks.onRequestUtcTime(); + } + + @NativeEntryPoint + void requestRefLocation() { + mLocationRequestCallbacks.onRequestRefLocation(); + } + + @NativeEntryPoint + void reportNfwNotification(String proxyAppPackageName, byte protocolStack, + String otherProtocolStackName, byte requestor, String requestorId, + byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { + mNotificationCallbacks.onReportNfwNotification(proxyAppPackageName, protocolStack, + otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, + isCachedLocation); + } + + @NativeEntryPoint + boolean isInEmergencySession() { + return mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec()); + } + + /** + * Encapsulates actual HAL methods for testing purposes. + */ + @VisibleForTesting + public static class GnssHal { + + protected GnssHal() {} + + protected void classInitOnce() { + native_class_init_once(); + } + + protected boolean isSupported() { + return native_is_supported(); + } + + protected void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) { + gnssNative.native_init_once(reinitializeGnssServiceHandle); + } + + protected boolean init() { + return native_init(); + } + + protected void cleanup() { + native_cleanup(); + } + + protected boolean start() { + return native_start(); + } + + protected boolean stop() { + return native_stop(); + } + + protected boolean setPositionMode(@GnssPositionMode int mode, + @GnssPositionRecurrence int recurrence, int minInterval, int preferredAccuracy, + int preferredTime, boolean lowPowerMode) { + return native_set_position_mode(mode, recurrence, minInterval, preferredAccuracy, + preferredTime, lowPowerMode); + } + + protected String getInternalState() { + return native_get_internal_state(); + } + + protected void deleteAidingData(@GnssAidingTypeFlags int flags) { + native_delete_aiding_data(flags); + } + + protected int readNmea(byte[] buffer, int bufferSize) { + return native_read_nmea(buffer, bufferSize); + } + + protected void injectLocation(double latitude, double longitude, float accuracy) { + native_inject_location(latitude, longitude, accuracy); + } + + protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude, + double longitude, double altitude, float speed, float bearing, + float horizontalAccuracy, float verticalAccuracy, float speedAccuracy, + float bearingAccuracy, long timestamp, @GnssRealtimeFlags int elapsedRealtimeFlags, + long elapsedRealtimeNanos, double elapsedRealtimeUncertaintyNanos) { + native_inject_best_location(gnssLocationFlags, latitude, longitude, altitude, speed, + bearing, horizontalAccuracy, verticalAccuracy, speedAccuracy, bearingAccuracy, + timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos, + elapsedRealtimeUncertaintyNanos); + } + + protected void injectTime(long time, long timeReference, int uncertainty) { + native_inject_time(time, timeReference, uncertainty); + } + + protected boolean isNavigationMessageCollectionSupported() { + return native_is_navigation_message_supported(); + } + + protected boolean startNavigationMessageCollection() { + return native_start_navigation_message_collection(); + } + + protected boolean stopNavigationMessageCollection() { + return native_stop_navigation_message_collection(); + } + + protected boolean isAntennaInfoListeningSupported() { + return native_is_antenna_info_supported(); + } + + protected boolean startAntennaInfoListening() { + return native_start_antenna_info_listening(); + } + + protected boolean stopAntennaInfoListening() { + return native_stop_antenna_info_listening(); + } + + protected boolean isMeasurementSupported() { + return native_is_measurement_supported(); + } + + protected boolean startMeasurementCollection(boolean enableFullTracking) { + return native_start_measurement_collection(enableFullTracking); + } + + protected boolean stopMeasurementCollection() { + return native_stop_measurement_collection(); + } + + protected boolean isMeasurementCorrectionsSupported() { + return native_is_measurement_corrections_supported(); + } + + protected boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) { + return native_inject_measurement_corrections(corrections); + } + + protected int getBatchSize() { + return native_get_batch_size(); + } + + protected boolean initBatching() { + return native_init_batching(); + } + + protected void cleanupBatching() { + native_cleanup_batching(); + } + + protected boolean startBatch(long periodNanos, boolean wakeOnFifoFull) { + return native_start_batch(periodNanos, wakeOnFifoFull); + } + + protected void flushBatch() { + native_flush_batch(); + } + + protected void stopBatch() { + native_stop_batch(); + } + + protected boolean isGeofencingSupported() { + return native_is_geofence_supported(); + } + + protected boolean addGeofence(int geofenceId, double latitude, double longitude, + double radius, int lastTransition, int monitorTransitions, + int notificationResponsiveness, int unknownTimer) { + return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition, + monitorTransitions, notificationResponsiveness, unknownTimer); + } + + protected boolean resumeGeofence(int geofenceId, int monitorTransitions) { + return native_resume_geofence(geofenceId, monitorTransitions); + } + + protected boolean pauseGeofence(int geofenceId) { + return native_pause_geofence(geofenceId); + } + + protected boolean removeGeofence(int geofenceId) { + return native_remove_geofence(geofenceId); + } + + protected boolean isGnssVisibilityControlSupported() { + return native_is_gnss_visibility_control_supported(); + } + + protected void sendNiResponse(int notificationId, int userResponse) { + native_send_ni_response(notificationId, userResponse); + } + + protected void requestPowerStats() { + native_request_power_stats(); + } + + protected void setAgpsServer(int type, String hostname, int port) { + native_set_agps_server(type, hostname, port); + } + + protected void setAgpsSetId(@AgpsSetIdType int type, String setId) { + native_agps_set_id(type, setId); + } + + protected void setAgpsReferenceLocationCellId(@AgpsReferenceLocationType int type, int mcc, + int mnc, int lac, int cid) { + native_agps_set_ref_location_cellid(type, mcc, mnc, lac, cid); + } + + protected boolean isPsdsSupported() { + return native_supports_psds(); + } + + protected void injectPsdsData(byte[] data, int length, int psdsType) { + native_inject_psds_data(data, length, psdsType); + } + } + + // basic APIs + + private static native void native_class_init_once(); + + private static native boolean native_is_supported(); + + private native void native_init_once(boolean reinitializeGnssServiceHandle); + + private static native boolean native_init(); + + private static native void native_cleanup(); + + private static native boolean native_start(); + + private static native boolean native_stop(); + + private static native boolean native_set_position_mode(int mode, int recurrence, + int minInterval, int preferredAccuracy, int preferredTime, boolean lowPowerMode); + + private static native String native_get_internal_state(); + + private static native void native_delete_aiding_data(int flags); + + // NMEA APIs + + private static native int native_read_nmea(byte[] buffer, int bufferSize); + + // location injection APIs + + private static native void native_inject_location(double latitude, double longitude, + float accuracy); + + + private static native void native_inject_best_location( + int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees, + double altitudeMeters, float speedMetersPerSec, float bearingDegrees, + float horizontalAccuracyMeters, float verticalAccuracyMeters, + float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees, + long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos, + double elapsedRealtimeUncertaintyNanos); + + // time injection APIs + + private static native void native_inject_time(long time, long timeReference, int uncertainty); + + // navigation message APIs + + private static native boolean native_is_navigation_message_supported(); + + private static native boolean native_start_navigation_message_collection(); + + private static native boolean native_stop_navigation_message_collection(); + + // antenna info APIS + + private static native boolean native_is_antenna_info_supported(); + + private static native boolean native_start_antenna_info_listening(); + + private static native boolean native_stop_antenna_info_listening(); + + // measurement APIs + + private static native boolean native_is_measurement_supported(); + + private static native boolean native_start_measurement_collection(boolean enableFullTracking); + + private static native boolean native_stop_measurement_collection(); + + // measurement corrections APIs + + private static native boolean native_is_measurement_corrections_supported(); + + private static native boolean native_inject_measurement_corrections( + GnssMeasurementCorrections corrections); + + // batching APIs + + private static native boolean native_init_batching(); + + private static native void native_cleanup_batching(); + + private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull); + + private static native void native_flush_batch(); + + private static native boolean native_stop_batch(); + + private static native int native_get_batch_size(); + + // geofence APIs + + private static native boolean native_is_geofence_supported(); + + private static native boolean native_add_geofence(int geofenceId, double latitude, + double longitude, double radius, int lastTransition, int monitorTransitions, + int notificationResponsivenes, int unknownTimer); + + private static native boolean native_resume_geofence(int geofenceId, int monitorTransitions); + + private static native boolean native_pause_geofence(int geofenceId); + + private static native boolean native_remove_geofence(int geofenceId); + + // network initiated (NI) APIs + + private static native boolean native_is_gnss_visibility_control_supported(); + + private static native void native_send_ni_response(int notificationId, int userResponse); + + // power stats APIs + + private static native void native_request_power_stats(); + + // AGPS APIs + + private static native void native_set_agps_server(int type, String hostname, int port); + + private static native void native_agps_set_id(int type, String setid); + + private static native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, + int lac, int cid); + + // PSDS APIs + + private static native boolean native_supports_psds(); + + private static native void native_inject_psds_data(byte[] data, int length, int psdsType); +} diff --git a/services/core/java/com/android/server/location/injector/EmergencyHelper.java b/services/core/java/com/android/server/location/injector/EmergencyHelper.java new file mode 100644 index 0000000000000..be4bf5083c65b --- /dev/null +++ b/services/core/java/com/android/server/location/injector/EmergencyHelper.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 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 com.android.server.location.injector; + +/** + * Provides helpers for emergency sessions. + */ +public abstract class EmergencyHelper { + + /** + * Returns true if the device is in an emergency session, or if an emergency session ended + * within the given extension time. + */ + public abstract boolean isInEmergency(long extensionTimeMs); +} diff --git a/services/core/java/com/android/server/location/injector/Injector.java b/services/core/java/com/android/server/location/injector/Injector.java index c42396da95a5f..03938b2b8ba2e 100644 --- a/services/core/java/com/android/server/location/injector/Injector.java +++ b/services/core/java/com/android/server/location/injector/Injector.java @@ -51,6 +51,9 @@ public interface Injector { /** Returns a LocationAttributionHelper. */ LocationAttributionHelper getLocationAttributionHelper(); + /** Returns an EmergencyHelper. */ + EmergencyHelper getEmergencyHelper(); + /** Returns a LocationUsageLogger. */ LocationUsageLogger getLocationUsageLogger(); diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java new file mode 100644 index 0000000000000..05d0aefe7c89c --- /dev/null +++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 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 com.android.server.location.injector; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.SystemClock; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; + +import com.android.server.FgThread; + +import java.util.Objects; + +/** + * Provides helpers for emergency sessions. + */ +public class SystemEmergencyHelper extends EmergencyHelper { + + private final Context mContext; + + private TelephonyManager mTelephonyManager; + + private boolean mIsInEmergencyCall; + private long mEmergencyCallEndRealtimeMs = Long.MIN_VALUE; + + public SystemEmergencyHelper(Context context) { + mContext = context; + } + + /** Called when system is ready. */ + public void onSystemReady() { + if (mTelephonyManager != null) { + return; + } + + mTelephonyManager = Objects.requireNonNull( + mContext.getSystemService(TelephonyManager.class)); + + // TODO: this doesn't account for multisim phones + + mTelephonyManager.registerPhoneStateListener(FgThread.getExecutor(), + new EmergencyCallPhoneStateListener()); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) { + return; + } + + mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber( + intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)); + } + }, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL)); + } + + @Override + public boolean isInEmergency(long extensionTimeMs) { + return mIsInEmergencyCall + || ((SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs) + || mTelephonyManager.getEmergencyCallbackMode() + || mTelephonyManager.isInEmergencySmsMode(); + } + + private class EmergencyCallPhoneStateListener extends PhoneStateListener implements + PhoneStateListener.CallStateChangedListener { + + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (state == TelephonyManager.CALL_STATE_IDLE) { + if (mIsInEmergencyCall) { + mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime(); + mIsInEmergencyCall = false; + } + } + } + } +} diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 49cf6f85855dd..858b7624891ac 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -1357,6 +1357,8 @@ public class LocationProviderManager extends public boolean isEnabled(int userId) { if (userId == UserHandle.USER_NULL) { return false; + } else if (userId == UserHandle.USER_CURRENT) { + return isEnabled(mUserHelper.getCurrentUserId()); } Preconditions.checkArgument(userId >= 0); @@ -1518,6 +1520,9 @@ public class LocationProviderManager extends } } return lastLocation; + } else if (userId == UserHandle.USER_CURRENT) { + return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel, + ignoreLocationSettings, maximumAgeMs); } Preconditions.checkArgument(userId >= 0); @@ -1560,6 +1565,9 @@ public class LocationProviderManager extends setLastLocation(location, runningUserIds[i]); } return; + } else if (userId == UserHandle.USER_CURRENT) { + setLastLocation(location, mUserHelper.getCurrentUserId()); + return; } Preconditions.checkArgument(userId >= 0); diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 066dbce89ca6e..e3a8bb4e405e7 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1442,7 +1442,7 @@ struct GnssBatchingCallback_V2_0 : public IGnssBatchingCallback_V2_0 { }; /* Initializes the GNSS service handle. */ -static void android_location_GnssLocationProvider_set_gps_service_handle() { +static void android_location_gnss_hal_GnssNative_set_gps_service_handle() { gnssHalAidl = waitForVintfService(); if (gnssHalAidl != nullptr) { ALOGD("Successfully got GNSS AIDL handle."); @@ -1489,9 +1489,9 @@ static void android_location_GnssLocationProvider_set_gps_service_handle() { } /* One time initialization at system boot */ -static void android_location_GnssNative_class_init_once(JNIEnv* env, jclass clazz) { +static void android_location_gnss_hal_GnssNative_class_init_once(JNIEnv* env, jclass clazz) { // Initialize the top level gnss HAL handle. - android_location_GnssLocationProvider_set_gps_service_handle(); + android_location_gnss_hal_GnssNative_set_gps_service_handle(); // Cache methodIDs and class IDs. method_reportLocation = env->GetMethodID(clazz, "reportLocation", @@ -1655,8 +1655,8 @@ static void android_location_GnssNative_class_init_once(JNIEnv* env, jclass claz } /* Initialization needed at system boot and whenever GNSS service dies. */ -static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj, - jboolean reinitializeGnssServiceHandle) { +static void android_location_gnss_hal_GnssNative_init_once(JNIEnv* env, jobject obj, + jboolean reinitializeGnssServiceHandle) { /* * Save a pointer to JVM. */ @@ -1666,7 +1666,7 @@ static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj, } if (reinitializeGnssServiceHandle) { - android_location_GnssLocationProvider_set_gps_service_handle(); + android_location_gnss_hal_GnssNative_set_gps_service_handle(); } if (gnssHal == nullptr) { @@ -1934,7 +1934,7 @@ static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj, } } -static jboolean android_location_GnssNative_is_supported(JNIEnv* /* env */, jclass /* clazz */) { +static jboolean android_location_gnss_hal_GnssNative_is_supported(JNIEnv* /* env */, jclass) { return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE; } @@ -1952,7 +1952,7 @@ static jobject android_location_GnssConfiguration_get_gnss_configuration_version } /* Initialization needed each time the GPS service is shutdown. */ -static jboolean android_location_GnssLocationProvider_init(JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_init(JNIEnv* /* env */, jclass) { /* * This must be set before calling into the HAL library. */ @@ -2087,7 +2087,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* /* env */, jo return JNI_TRUE; } -static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) { +static void android_location_gnss_hal_GnssNative_cleanup(JNIEnv* /* env */, jclass) { if (gnssHal == nullptr) { return; } @@ -2096,9 +2096,9 @@ static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, job checkHidlReturn(result, "IGnss cleanup() failed."); } -static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */, - jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, - jint preferred_time, jboolean low_power_mode) { +static jboolean android_location_gnss_hal_GnssNative_set_position_mode( + JNIEnv* /* env */, jclass, jint mode, jint recurrence, jint min_interval, + jint preferred_accuracy, jint preferred_time, jboolean low_power_mode) { Return result = false; if (gnssHal_V1_1 != nullptr) { result = gnssHal_V1_1->setPositionMode_1_1(static_cast(mode), @@ -2118,7 +2118,7 @@ static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* return checkHidlReturn(result, "IGnss setPositionMode() failed."); } -static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_start(JNIEnv* /* env */, jclass) { if (gnssHal == nullptr) { return JNI_FALSE; } @@ -2127,7 +2127,7 @@ static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, j return checkHidlReturn(result, "IGnss start() failed."); } -static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jclass) { if (gnssHal == nullptr) { return JNI_FALSE; } @@ -2136,8 +2136,7 @@ static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jo return checkHidlReturn(result, "IGnss stop() failed."); } -static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */, - jobject /* obj */, +static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass, jint flags) { if (gnssHal == nullptr) { return; @@ -2147,8 +2146,8 @@ static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* checkHidlReturn(result, "IGnss deleteAidingData() failed."); } -static void android_location_GnssLocationProvider_agps_set_reference_location_cellid( - JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid) { +static void android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid( + JNIEnv* /* env */, jclass, jint type, jint mcc, jint mnc, jint lac, jint cid) { IAGnssRil_V1_0::AGnssRefLocation location; if (agnssRilIface == nullptr) { @@ -2175,8 +2174,8 @@ static void android_location_GnssLocationProvider_agps_set_reference_location_ce checkHidlReturn(result, "IAGnssRil setRefLocation() failed."); } -static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobject /* obj */, - jint type, jstring setid_string) { +static void android_location_gnss_hal_GnssNative_agps_set_id(JNIEnv* env, jclass, jint type, + jstring setid_string) { if (agnssRilIface == nullptr) { ALOGE("%s: IAGnssRil interface not available.", __func__); return; @@ -2187,8 +2186,8 @@ static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobje checkHidlReturn(result, "IAGnssRil setSetId() failed."); } -static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */, - jbyteArray nmeaArray, jint buffer_size) { +static jint android_location_gnss_hal_GnssNative_read_nmea(JNIEnv* env, jclass, + jbyteArray nmeaArray, jint buffer_size) { // this should only be called from within a call to reportNmea jbyte* nmea = reinterpret_cast(env->GetPrimitiveArrayCritical(nmeaArray, 0)); int length = GnssCallback::sNmeaStringLength; @@ -2199,8 +2198,9 @@ static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject return (jint) length; } -static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */, - jlong time, jlong timeReference, jint uncertainty) { +static void android_location_gnss_hal_GnssNative_inject_time(JNIEnv* /* env */, jclass, jlong time, + jlong timeReference, + jint uncertainty) { if (gnssHal == nullptr) { return; } @@ -2209,22 +2209,12 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, checkHidlReturn(result, "IGnss injectTime() failed."); } -static void android_location_GnssLocationProvider_inject_best_location( - JNIEnv*, - jobject, - jint gnssLocationFlags, - jdouble latitudeDegrees, - jdouble longitudeDegrees, - jdouble altitudeMeters, - jfloat speedMetersPerSec, - jfloat bearingDegrees, - jfloat horizontalAccuracyMeters, - jfloat verticalAccuracyMeters, - jfloat speedAccuracyMetersPerSecond, - jfloat bearingAccuracyDegrees, - jlong timestamp, - jint elapsedRealtimeFlags, - jlong elapsedRealtimeNanos, +static void android_location_gnss_hal_GnssNative_inject_best_location( + JNIEnv* /* env */, jclass, jint gnssLocationFlags, jdouble latitudeDegrees, + jdouble longitudeDegrees, jdouble altitudeMeters, jfloat speedMetersPerSec, + jfloat bearingDegrees, jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters, + jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp, + jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos, jdouble elapsedRealtimeUncertaintyNanos) { if (gnssHal_V2_0 != nullptr) { GnssLocation_V2_0 location = createGnssLocation_V2_0( @@ -2267,8 +2257,10 @@ static void android_location_GnssLocationProvider_inject_best_location( ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available."); } -static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */, - jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) { +static void android_location_gnss_hal_GnssNative_inject_location(JNIEnv* /* env */, jclass, + jdouble latitude, + jdouble longitude, + jfloat accuracy) { if (gnssHal == nullptr) { return; } @@ -2277,16 +2269,15 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env checkHidlReturn(result, "IGnss injectLocation() failed."); } -static jboolean android_location_GnssLocationProvider_supports_psds( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_supports_psds(JNIEnv* /* env */, jclass) { return (gnssPsdsAidlIface != nullptr || gnssPsdsIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE; } -static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */, - jbyteArray data, jint length, - jint psdsType) { +static void android_location_gnss_hal_GnssNative_inject_psds_data(JNIEnv* env, jclass, + jbyteArray data, jint length, + jint psdsType) { if (gnssPsdsAidlIface == nullptr && gnssPsdsIface == nullptr && gnssXtraIface == nullptr) { ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__); return; @@ -2406,8 +2397,8 @@ static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_faile } } -static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */, - jint type, jstring hostname, jint port) { +static void android_location_gnss_hal_GnssNative_set_agps_server(JNIEnv* env, jclass, jint type, + jstring hostname, jint port) { if (agnssIface_V2_0 != nullptr) { AGnssDispatcher::setServer(agnssIface_V2_0, env, type, hostname, port); @@ -2420,8 +2411,8 @@ static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, j } } -static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */, - jobject /* obj */, jint notifId, jint response) { +static void android_location_gnss_hal_GnssNative_send_ni_response(JNIEnv* /* env */, jclass, + jint notifId, jint response) { if (gnssNiIface == nullptr) { ALOGE("%s: IGnssNi interface not available.", __func__); return; @@ -2504,8 +2495,7 @@ static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, con return (jstring) env->NewStringUTF(internalState.str().c_str()); } -static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env, - jobject /* obj */) { +static jstring android_location_gnss_hal_GnssNative_get_internal_state(JNIEnv* env, jclass) { jstring internalStateStr = nullptr; /* * TODO: Create a jobject to represent GnssDebug. @@ -2537,8 +2527,7 @@ static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* return internalStateStr; } -static void android_location_GnssLocationProvider_request_power_stats(JNIEnv* env, - jobject /* obj */) { +static void android_location_gnss_hal_GnssNative_request_power_stats(JNIEnv* env) { if (gnssPowerIndicationIface == nullptr) { return; } @@ -2546,8 +2535,8 @@ static void android_location_GnssLocationProvider_request_power_stats(JNIEnv* en checkAidlStatus(status, "IGnssPowerIndication requestGnssPowerStats() failed."); } -static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported( - JNIEnv* /* env */, jclass /* clazz */) { +static jboolean android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported( + JNIEnv* /* env */, jclass) { return (gnssVisibilityControlIface != nullptr) ? JNI_TRUE : JNI_FALSE; } @@ -2587,15 +2576,15 @@ static void android_location_GnssNetworkConnectivityHandler_update_network_state } } -static jboolean android_location_GnssGeofenceProvider_is_geofence_supported( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_is_geofence_supported(JNIEnv* /* env */, + jclass) { return (gnssGeofencingIface != nullptr) ? JNI_TRUE : JNI_FALSE; } -static jboolean android_location_GnssGeofenceProvider_add_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId, jdouble latitude, jdouble longitude, jdouble radius, - jint last_transition, jint monitor_transition, jint notification_responsiveness, - jint unknown_timer) { +static jboolean android_location_gnss_hal_GnssNative_add_geofence( + JNIEnv* /* env */, jclass, jint geofenceId, jdouble latitude, jdouble longitude, + jdouble radius, jint last_transition, jint monitor_transition, + jint notification_responsiveness, jint unknown_timer) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2608,8 +2597,8 @@ static jboolean android_location_GnssGeofenceProvider_add_geofence(JNIEnv* /* en return checkHidlReturn(result, "IGnssGeofencing addGeofence() failed."); } -static jboolean android_location_GnssGeofenceProvider_remove_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId) { +static jboolean android_location_gnss_hal_GnssNative_remove_geofence(JNIEnv* /* env */, jclass, + jint geofenceId) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2619,8 +2608,8 @@ static jboolean android_location_GnssGeofenceProvider_remove_geofence(JNIEnv* /* return checkHidlReturn(result, "IGnssGeofencing removeGeofence() failed."); } -static jboolean android_location_GnssGeofenceProvider_pause_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId) { +static jboolean android_location_gnss_hal_GnssNative_pause_geofence(JNIEnv* /* env */, jclass, + jint geofenceId) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2630,8 +2619,9 @@ static jboolean android_location_GnssGeofenceProvider_pause_geofence(JNIEnv* /* return checkHidlReturn(result, "IGnssGeofencing pauseGeofence() failed."); } -static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId, jint monitor_transition) { +static jboolean android_location_gnss_hal_GnssNative_resume_geofence(JNIEnv* /* env */, jclass, + jint geofenceId, + jint monitor_transition) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2641,16 +2631,16 @@ static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed."); } -static jboolean android_location_GnssAntennaInfoProvider_is_antenna_info_supported(JNIEnv* env, - jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_antenna_info_supported(JNIEnv* env, + jclass) { if (gnssAntennaInfoIface != nullptr) { return JNI_TRUE; } return JNI_FALSE; } -static jboolean android_location_GnssAntennaInfoProvider_start_antenna_info_listening( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_start_antenna_info_listening(JNIEnv* /* env */, + jclass) { if (gnssAntennaInfoIface == nullptr) { ALOGE("%s: IGnssAntennaInfo interface not available.", __func__); return JNI_FALSE; @@ -2676,8 +2666,8 @@ static jboolean android_location_GnssAntennaInfoProvider_start_antenna_info_list return JNI_TRUE; } -static jboolean android_location_GnssAntennaInfoProvider_stop_antenna_info_listening( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_stop_antenna_info_listening(JNIEnv* /* env */, + jclass) { if (gnssAntennaInfoIface == nullptr) { ALOGE("%s: IGnssAntennaInfo interface not available.", __func__); return JNI_FALSE; @@ -2687,8 +2677,7 @@ static jboolean android_location_GnssAntennaInfoProvider_stop_antenna_info_liste return checkHidlReturn(result, "IGnssAntennaInfo close() failed."); } -static jboolean android_location_GnssMeasurementsProvider_is_measurement_supported( - JNIEnv* env, jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_measurement_supported(JNIEnv* env, jclass) { if (gnssMeasurementIface != nullptr) { return JNI_TRUE; } @@ -2696,10 +2685,8 @@ static jboolean android_location_GnssMeasurementsProvider_is_measurement_support return JNI_FALSE; } -static jboolean android_location_GnssMeasurementsProvider_start_measurement_collection( - JNIEnv* /* env */, - jobject /* obj */, - jboolean enableFullTracking) { +static jboolean android_location_gnss_hal_GnssNative_start_measurement_collection( + JNIEnv* /* env */, jclass, jboolean enableFullTracking) { if (gnssMeasurementIface == nullptr) { ALOGE("%s: IGnssMeasurement interface not available.", __func__); return JNI_FALSE; @@ -2710,9 +2697,8 @@ static jboolean android_location_GnssMeasurementsProvider_start_measurement_coll enableFullTracking); } -static jboolean android_location_GnssMeasurementsProvider_stop_measurement_collection( - JNIEnv* env, - jobject obj) { +static jboolean android_location_gnss_hal_GnssNative_stop_measurement_collection(JNIEnv* env, + jclass) { if (gnssMeasurementIface == nullptr) { ALOGE("%s: IGnssMeasurement interface not available.", __func__); return JNI_FALSE; @@ -2721,9 +2707,8 @@ static jboolean android_location_GnssMeasurementsProvider_stop_measurement_colle return gnssMeasurementIface->close(); } -static jboolean - android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported( - JNIEnv* env, jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_measurement_corrections_supported( + JNIEnv* env, jclass) { if (gnssCorrectionsIface_V1_0 != nullptr || gnssCorrectionsIface_V1_1 != nullptr) { return JNI_TRUE; } @@ -2816,12 +2801,9 @@ static void getSingleSatCorrectionList_1_0(JNIEnv* env, jobject singleSatCorrect list[i] = singleSatCorrection; } } -static jboolean - android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections( - JNIEnv* env, - jobject obj /* clazz*/, - jobject correctionsObj) { +static jboolean android_location_gnss_hal_GnssNative_inject_measurement_corrections( + JNIEnv* env, jclass, jobject correctionsObj) { if (gnssCorrectionsIface_V1_0 == nullptr && gnssCorrectionsIface_V1_1 == nullptr) { ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not" " support them."); @@ -2893,18 +2875,16 @@ static jboolean return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed."); } -static jboolean android_location_GnssNavigationMessageProvider_is_navigation_message_supported( - JNIEnv* env, - jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_navigation_message_supported(JNIEnv* env, + jclass) { if (gnssNavigationMessageIface != nullptr) { return JNI_TRUE; } return JNI_FALSE; } -static jboolean android_location_GnssNavigationMessageProvider_start_navigation_message_collection( - JNIEnv* env, - jobject obj) { +static jboolean android_location_gnss_hal_GnssNative_start_navigation_message_collection( + JNIEnv* env, jclass) { if (gnssNavigationMessageIface == nullptr) { ALOGE("%s: IGnssNavigationMessage interface not available.", __func__); return JNI_FALSE; @@ -2926,9 +2906,8 @@ static jboolean android_location_GnssNavigationMessageProvider_start_navigation_ return JNI_TRUE; } -static jboolean android_location_GnssNavigationMessageProvider_stop_navigation_message_collection( - JNIEnv* env, - jobject obj) { +static jboolean android_location_gnss_hal_GnssNative_stop_navigation_message_collection(JNIEnv* env, + jclass) { if (gnssNavigationMessageIface == nullptr) { ALOGE("%s: IGnssNavigationMessage interface not available.", __func__); return JNI_FALSE; @@ -3027,7 +3006,7 @@ static jboolean android_location_GnssConfiguration_set_es_extension_sec( return gnssConfigurationIface->setEsExtensionSec(emergencyExtensionSeconds); } -static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) { +static jint android_location_gnss_hal_GnssNative_get_batch_size(JNIEnv*) { if (gnssBatchingIface == nullptr) { return 0; // batching not supported, size = 0 } @@ -3039,7 +3018,7 @@ static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass return static_cast(result); } -static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) { +static jboolean android_location_gnss_hal_GnssNative_init_batching(JNIEnv*, jclass) { if (gnssBatchingIface_V2_0 != nullptr) { sp gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0(); auto result = gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0); @@ -3053,7 +3032,7 @@ static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jcl } } -static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) { +static void android_location_gnss_hal_GnssNative_cleanup_batching(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return; // batching not supported } @@ -3061,9 +3040,8 @@ static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jcla checkHidlReturn(result, "IGnssBatching cleanup() failed."); } -static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass, - jlong periodNanos, - jboolean wakeOnFifoFull) { +static jboolean android_location_gnss_hal_GnssNative_start_batch(JNIEnv*, jclass, jlong periodNanos, + jboolean wakeOnFifoFull) { if (gnssBatchingIface == nullptr) { return JNI_FALSE; // batching not supported } @@ -3080,7 +3058,7 @@ static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclas return checkHidlReturn(result, "IGnssBatching start() failed."); } -static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) { +static void android_location_gnss_hal_GnssNative_flush_batch(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return; // batching not supported } @@ -3088,7 +3066,7 @@ static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) { checkHidlReturn(result, "IGnssBatching flush() failed."); } -static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) { +static jboolean android_location_gnss_hal_GnssNative_stop_batch(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return JNI_FALSE; // batching not supported } @@ -3118,156 +3096,146 @@ static jboolean android_location_GnssVisibilityControl_enable_nfw_location_acces static const JNINativeMethod sCoreMethods[] = { /* name, signature, funcPtr */ {"native_class_init_once", "()V", - reinterpret_cast(android_location_GnssNative_class_init_once)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_class_init_once)}, {"native_is_supported", "()Z", - reinterpret_cast(android_location_GnssNative_is_supported)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_is_supported)}, {"native_init_once", "(Z)V", - reinterpret_cast(android_location_GnssNative_init_once)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_init_once)}, }; static const JNINativeMethod sLocationProviderMethods[] = { /* name, signature, funcPtr */ - {"native_init", "()Z", reinterpret_cast(android_location_GnssLocationProvider_init)}, + {"native_init", "()Z", reinterpret_cast(android_location_gnss_hal_GnssNative_init)}, {"native_cleanup", "()V", - reinterpret_cast(android_location_GnssLocationProvider_cleanup)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_cleanup)}, {"native_set_position_mode", "(IIIIIZ)Z", - reinterpret_cast(android_location_GnssLocationProvider_set_position_mode)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_set_position_mode)}, {"native_start", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_start)}, - {"native_stop", "()Z", reinterpret_cast(android_location_GnssLocationProvider_stop)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_start)}, + {"native_stop", "()Z", reinterpret_cast(android_location_gnss_hal_GnssNative_stop)}, {"native_delete_aiding_data", "(I)V", - reinterpret_cast(android_location_GnssLocationProvider_delete_aiding_data)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_delete_aiding_data)}, {"native_read_nmea", "([BI)I", - reinterpret_cast(android_location_GnssLocationProvider_read_nmea)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_read_nmea)}, {"native_inject_time", "(JJI)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_time)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_time)}, {"native_inject_best_location", "(IDDDFFFFFFJIJD)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_best_location)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_best_location)}, {"native_inject_location", "(DDF)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_location)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_location)}, {"native_supports_psds", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_supports_psds)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_supports_psds)}, {"native_inject_psds_data", "([BII)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_psds_data)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_psds_data)}, {"native_agps_set_id", "(ILjava/lang/String;)V", - reinterpret_cast(android_location_GnssLocationProvider_agps_set_id)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_agps_set_id)}, {"native_agps_set_ref_location_cellid", "(IIIII)V", reinterpret_cast( - android_location_GnssLocationProvider_agps_set_reference_location_cellid)}, + android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid)}, {"native_set_agps_server", "(ILjava/lang/String;I)V", - reinterpret_cast(android_location_GnssLocationProvider_set_agps_server)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_set_agps_server)}, {"native_send_ni_response", "(II)V", - reinterpret_cast(android_location_GnssLocationProvider_send_ni_response)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_send_ni_response)}, {"native_get_internal_state", "()Ljava/lang/String;", - reinterpret_cast(android_location_GnssLocationProvider_get_internal_state)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_get_internal_state)}, {"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast( - android_location_GnssLocationProvider_is_gnss_visibility_control_supported)}, + android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported)}, }; -static const JNINativeMethod sMethodsBatching[] = { +static const JNINativeMethod sBatchingMethods[] = { /* name, signature, funcPtr */ {"native_get_batch_size", "()I", - reinterpret_cast(android_location_GnssLocationProvider_get_batch_size)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_get_batch_size)}, {"native_start_batch", "(JZ)Z", - reinterpret_cast(android_location_GnssLocationProvider_start_batch)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_start_batch)}, {"native_flush_batch", "()V", - reinterpret_cast(android_location_GnssLocationProvider_flush_batch)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_flush_batch)}, {"native_stop_batch", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_stop_batch)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_stop_batch)}, {"native_init_batching", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_init_batching)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_init_batching)}, {"native_cleanup_batching", "()V", - reinterpret_cast(android_location_GnssLocationProvider_cleanup_batching)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_cleanup_batching)}, }; static const JNINativeMethod sAntennaInfoMethods[] = { /* name, signature, funcPtr */ {"native_is_antenna_info_supported", "()Z", - reinterpret_cast( - android_location_GnssAntennaInfoProvider_is_antenna_info_supported)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_is_antenna_info_supported)}, {"native_start_antenna_info_listening", "()Z", reinterpret_cast( - android_location_GnssAntennaInfoProvider_start_antenna_info_listening)}, + android_location_gnss_hal_GnssNative_start_antenna_info_listening)}, {"native_stop_antenna_info_listening", "()Z", - reinterpret_cast( - android_location_GnssAntennaInfoProvider_stop_antenna_info_listening)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_stop_antenna_info_listening)}, }; static const JNINativeMethod sGeofenceMethods[] = { - /* name, signature, funcPtr */ - {"native_is_geofence_supported", - "()Z", - reinterpret_cast(android_location_GnssGeofenceProvider_is_geofence_supported)}, - {"native_add_geofence", - "(IDDDIIII)Z", - reinterpret_cast(android_location_GnssGeofenceProvider_add_geofence)}, - {"native_remove_geofence", - "(I)Z", - reinterpret_cast(android_location_GnssGeofenceProvider_remove_geofence)}, - {"native_pause_geofence", "(I)Z", reinterpret_cast( - android_location_GnssGeofenceProvider_pause_geofence)}, - {"native_resume_geofence", - "(II)Z", - reinterpret_cast(android_location_GnssGeofenceProvider_resume_geofence)}, + /* name, signature, funcPtr */ + {"native_is_geofence_supported", "()Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_is_geofence_supported)}, + {"native_add_geofence", "(IDDDIIII)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_add_geofence)}, + {"native_remove_geofence", "(I)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_remove_geofence)}, + {"native_pause_geofence", "(I)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_pause_geofence)}, + {"native_resume_geofence", "(II)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_resume_geofence)}, }; static const JNINativeMethod sMeasurementMethods[] = { - /* name, signature, funcPtr */ - {"native_is_measurement_supported", "()Z", - reinterpret_cast( - android_location_GnssMeasurementsProvider_is_measurement_supported)}, - {"native_start_measurement_collection", "(Z)Z", - reinterpret_cast( - android_location_GnssMeasurementsProvider_start_measurement_collection)}, - {"native_stop_measurement_collection", "()Z", - reinterpret_cast( - android_location_GnssMeasurementsProvider_stop_measurement_collection)}, + /* name, signature, funcPtr */ + {"native_is_measurement_supported", "()Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_is_measurement_supported)}, + {"native_start_measurement_collection", "(Z)Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_start_measurement_collection)}, + {"native_stop_measurement_collection", "()Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_stop_measurement_collection)}, }; static const JNINativeMethod sMeasurementCorrectionsMethods[] = { - /* name, signature, funcPtr */ - {"native_is_measurement_corrections_supported", "()Z", - reinterpret_cast( - android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)}, - {"native_inject_gnss_measurement_corrections", - "(Landroid/location/GnssMeasurementCorrections;)Z", - reinterpret_cast( - android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)}, + /* name, signature, funcPtr */ + {"native_is_measurement_corrections_supported", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_is_measurement_corrections_supported)}, + {"native_inject_measurement_corrections", + "(Landroid/location/GnssMeasurementCorrections;)Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_inject_measurement_corrections)}, }; static const JNINativeMethod sNavigationMessageMethods[] = { - /* name, signature, funcPtr */ - {"native_is_navigation_message_supported", - "()Z", - reinterpret_cast( - android_location_GnssNavigationMessageProvider_is_navigation_message_supported)}, - {"native_start_navigation_message_collection", - "()Z", - reinterpret_cast( - android_location_GnssNavigationMessageProvider_start_navigation_message_collection)}, - {"native_stop_navigation_message_collection", - "()Z", - reinterpret_cast( - android_location_GnssNavigationMessageProvider_stop_navigation_message_collection)}, + /* name, signature, funcPtr */ + {"native_is_navigation_message_supported", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_is_navigation_message_supported)}, + {"native_start_navigation_message_collection", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_start_navigation_message_collection)}, + {"native_stop_navigation_message_collection", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_stop_navigation_message_collection)}, }; static const JNINativeMethod sNetworkConnectivityMethods[] = { - /* name, signature, funcPtr */ - {"native_is_agps_ril_supported", "()Z", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)}, - {"native_update_network_state", - "(ZIZZLjava/lang/String;JS)V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_update_network_state)}, - {"native_agps_data_conn_open", - "(JLjava/lang/String;I)V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)}, - {"native_agps_data_conn_closed", - "()V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)}, - {"native_agps_data_conn_failed", - "()V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)}, + /* name, signature, funcPtr */ + {"native_is_agps_ril_supported", "()Z", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)}, + {"native_update_network_state", "(ZIZZLjava/lang/String;JS)V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_update_network_state)}, + {"native_agps_data_conn_open", "(JLjava/lang/String;I)V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)}, + {"native_agps_data_conn_closed", "()V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)}, + {"native_agps_data_conn_failed", "()V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)}, }; static const JNINativeMethod sConfigurationMethods[] = { @@ -3297,45 +3265,73 @@ static const JNINativeMethod sConfigurationMethods[] = { }; static const JNINativeMethod sVisibilityControlMethods[] = { - /* name, signature, funcPtr */ - {"native_enable_nfw_location_access", - "([Ljava/lang/String;)Z", - reinterpret_cast( - android_location_GnssVisibilityControl_enable_nfw_location_access)}, + /* name, signature, funcPtr */ + {"native_enable_nfw_location_access", "([Ljava/lang/String;)Z", + reinterpret_cast( + android_location_GnssVisibilityControl_enable_nfw_location_access)}, }; static const JNINativeMethod sPowerIndicationMethods[] = { /* name, signature, funcPtr */ {"native_request_power_stats", "()V", - reinterpret_cast(android_location_GnssLocationProvider_request_power_stats)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_request_power_stats)}, }; int register_android_server_location_GnssLocationProvider(JNIEnv* env) { - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssAntennaInfoProvider", - sAntennaInfoMethods, NELEM(sAntennaInfoMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider", - sMethodsBatching, NELEM(sMethodsBatching)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssGeofenceProvider", - sGeofenceMethods, NELEM(sGeofenceMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssMeasurementsProvider", - sMeasurementMethods, NELEM(sMeasurementMethods)); - jniRegisterNativeMethods(env, - "com/android/server/location/gnss/GnssMeasurementCorrectionsProvider", - sMeasurementCorrectionsMethods, NELEM(sMeasurementCorrectionsMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNavigationMessageProvider", - sNavigationMessageMethods, NELEM(sNavigationMessageMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNetworkConnectivityHandler", - sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssConfiguration", - sConfigurationMethods, NELEM(sConfigurationMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl", - sVisibilityControlMethods, NELEM(sVisibilityControlMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssPowerIndicationProvider", - sPowerIndicationMethods, NELEM(sPowerIndicationMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider", - sLocationProviderMethods, NELEM(sLocationProviderMethods)); - return jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNative", - sCoreMethods, NELEM(sCoreMethods)); + int res; + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sAntennaInfoMethods, NELEM(sAntennaInfoMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sBatchingMethods, NELEM(sBatchingMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sGeofenceMethods, NELEM(sGeofenceMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sMeasurementMethods, NELEM(sMeasurementMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sMeasurementCorrectionsMethods, + NELEM(sMeasurementCorrectionsMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sNavigationMessageMethods, NELEM(sNavigationMessageMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, + "com/android/server/location/gnss/" + "GnssNetworkConnectivityHandler", + sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssConfiguration", + sConfigurationMethods, NELEM(sConfigurationMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl", + sVisibilityControlMethods, NELEM(sVisibilityControlMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sPowerIndicationMethods, NELEM(sPowerIndicationMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sLocationProviderMethods, NELEM(sLocationProviderMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sCoreMethods, NELEM(sCoreMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + return 0; } } /* namespace android */ diff --git a/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java deleted file mode 100644 index 48e6ce8cf350d..0000000000000 --- a/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.server.location.gnss; - -import static org.mockito.ArgumentMatchers.anyDouble; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.os.RemoteException; -import android.platform.test.annotations.Presubmit; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; - -/** - * Unit tests for {@link GnssGeofenceProvider}. - */ -@RunWith(RobolectricTestRunner.class) -@Presubmit -public class GnssGeofenceProviderTest { - private static final int GEOFENCE_ID = 12345; - private static final double LATITUDE = 10.0; - private static final double LONGITUDE = 20.0; - private static final double RADIUS = 5.0; - private static final int LAST_TRANSITION = 0; - private static final int MONITOR_TRANSITIONS = 0; - private static final int NOTIFICATION_RESPONSIVENESS = 0; - private static final int UNKNOWN_TIMER = 0; - @Mock - private GnssGeofenceProvider.GnssGeofenceProviderNative mMockNative; - private GnssGeofenceProvider mTestProvider; - - /** - * Mocks native methods and adds a geofence to the GnssGeofenceProvider. - */ - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - when(mMockNative.addGeofence(anyInt(), anyDouble(), anyDouble(), anyDouble(), anyInt(), - anyInt(), anyInt(), anyInt())).thenReturn(true); - when(mMockNative.pauseGeofence(anyInt())).thenReturn(true); - when(mMockNative.removeGeofence(anyInt())).thenReturn(true); - when(mMockNative.resumeGeofence(anyInt(), anyInt())).thenReturn(true); - mTestProvider = new GnssGeofenceProvider(mMockNative); - mTestProvider.addCircularHardwareGeofence(GEOFENCE_ID, LATITUDE, - LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, - NOTIFICATION_RESPONSIVENESS, - UNKNOWN_TIMER); - } - - /** - * Verify native add geofence method is called. - */ - @Test - public void addGeofence_nativeAdded() { - verify(mMockNative).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - } - - /** - * Verify pauseHardwareGeofence calls native pauseGeofence method. - */ - @Test - public void pauseGeofence_nativePaused() { - mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); - verify(mMockNative).pauseGeofence(eq(GEOFENCE_ID)); - } - - /** - * Verify removeHardwareGeofence calls native removeGeofence method. - */ - @Test - public void removeGeofence_nativeRemoved() { - mTestProvider.removeHardwareGeofence(GEOFENCE_ID); - verify(mMockNative).removeGeofence(eq(GEOFENCE_ID)); - } - - /** - * Verify resumeHardwareGeofence, called after pauseHardwareGeofence, will call native - * resumeGeofence method. - */ - @Test - public void resumeGeofence_nativeResumed() { - mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); - mTestProvider.resumeHardwareGeofence(GEOFENCE_ID, MONITOR_TRANSITIONS); - verify(mMockNative).resumeGeofence(eq(GEOFENCE_ID), eq(MONITOR_TRANSITIONS)); - } - - /** - * Verify resumeIfStarted method will re-add previously added geofences. - */ - @Test - public void addGeofence_restart_added() throws RemoteException { - mTestProvider.resumeIfStarted(); - - verify(mMockNative, times(2)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - } - - /** - * Verify resumeIfStarted method will not re-add previously added geofences if they have been - * removed. - */ - @Test - public void removeGeofence_restart_notAdded() throws RemoteException { - mTestProvider.removeHardwareGeofence(GEOFENCE_ID); - mTestProvider.resumeIfStarted(); - - verify(mMockNative, times(1)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - } - - /** - * Verify resumeIfStarted, called after pauseHardwareGeofence, will re-add previously added - * geofences, and re-pause geofencing. - */ - @Test - public void pauseGeofence_restart_paused() throws RemoteException { - mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); - mTestProvider.resumeIfStarted(); - - verify(mMockNative, times(2)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - verify(mMockNative, times(2)).pauseGeofence(eq(GEOFENCE_ID)); - } -} diff --git a/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java b/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java deleted file mode 100644 index e7d3e513a142b..0000000000000 --- a/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.server.location.gnss; - -import static com.google.common.truth.Truth.assertThat; - -import android.platform.test.annotations.Presubmit; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -import java.util.HashSet; - -/** - * Unit tests for {@link GnssPositionMode}. - */ -@RunWith(RobolectricTestRunner.class) -@Presubmit -public class GnssPositionModeTest { - - private GnssPositionMode mPositionMode1 = createGnssPositionMode(0, 1000); - private GnssPositionMode mPositionMode2 = createGnssPositionMode(0, 1000); - private GnssPositionMode mPositionMode3 = createGnssPositionMode(1, 1000); - - /** - * Verifies hashcode method. - */ - @Test - public void testHashCode() { - assertThat(mPositionMode1.hashCode()).isEqualTo(mPositionMode2.hashCode()); - assertThat(mPositionMode1.hashCode()).isNotEqualTo(mPositionMode3.hashCode()); - assertThat(mPositionMode1.hashCode()).isNotEqualTo(mPositionMode3.hashCode()); - - HashSet hashSet = new HashSet<>(); - hashSet.add(mPositionMode1.hashCode()); - hashSet.add(mPositionMode2.hashCode()); - assertThat(hashSet.size()).isEqualTo(1); - hashSet.add(mPositionMode3.hashCode()); - assertThat(hashSet.size()).isEqualTo(2); - } - - /** - * Verify that GnssPositionMode objects that return true for equals() also have the same - * hashcode. - */ - @Test - public void checkIfEqualsImpliesSameHashCode() { - assertTEqualsImpliesSameHashCode(mPositionMode1, mPositionMode2); - assertTEqualsImpliesSameHashCode(mPositionMode2, mPositionMode3); - } - - private void assertTEqualsImpliesSameHashCode(GnssPositionMode mode1, GnssPositionMode mode2) { - if (mode1.equals(mode2)) { - assertThat(mode1.hashCode()).isEqualTo(mode2.hashCode()); - } - } - - private GnssPositionMode createGnssPositionMode(int mode, int minInterval) { - return new GnssPositionMode(mode, 0, minInterval, 0, 0, true); - } -} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java new file mode 100644 index 0000000000000..b480f24fb3710 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2020 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 com.android.server.location.gnss; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.location.gnss.hal.FakeGnssHal; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.TestInjector; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class GnssGeofenceProxyTest { + + private static final int GEOFENCE_ID = 12345; + private static final double LATITUDE = 10.0; + private static final double LONGITUDE = 20.0; + private static final double RADIUS = 5.0; + private static final int LAST_TRANSITION = 0; + private static final int MONITOR_TRANSITIONS = 0; + private static final int NOTIFICATION_RESPONSIVENESS = 0; + private static final int UNKNOWN_TIMER = 0; + + private @Mock GnssConfiguration mMockConfiguration; + private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks; + + private FakeGnssHal mFakeHal; + private GnssGeofenceProxy mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mFakeHal = new FakeGnssHal(); + GnssNative.setGnssHalForTest(mFakeHal); + + GnssNative gnssNative = Objects.requireNonNull( + GnssNative.create(new TestInjector(), mMockConfiguration)); + gnssNative.setGeofenceCallbacks(mGeofenceCallbacks); + mTestProvider = new GnssGeofenceProxy(gnssNative); + gnssNative.register(); + + mTestProvider.addCircularHardwareGeofence(GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, + LAST_TRANSITION, MONITOR_TRANSITIONS, NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER); + } + + @Test + public void testAddGeofence() { + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false)); + } + + @Test + public void testRemoveGeofence() { + mTestProvider.removeHardwareGeofence(GEOFENCE_ID); + + assertThat(mFakeHal.getGeofences()).isEmpty(); + } + + @Test + public void testPauseGeofence() { + mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, true)); + } + + @Test + public void testResumeGeofence() { + mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); + mTestProvider.resumeHardwareGeofence(GEOFENCE_ID, MONITOR_TRANSITIONS); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false)); + } + + @Test + public void testAddGeofence_restart() { + mFakeHal.restartHal(); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false)); + } + + @Test + public void testRemoveGeofence_restart() { + mTestProvider.removeHardwareGeofence(GEOFENCE_ID); + mFakeHal.restartHal(); + + assertThat(mFakeHal.getGeofences()).isEmpty(); + } + + @Test + public void testPauseGeofence_restart() { + mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); + mFakeHal.restartHal(); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, true)); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java deleted file mode 100644 index 2b21cc5820879..0000000000000 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.server.location.gnss; - -import static android.app.AppOpsManager.OP_COARSE_LOCATION; -import static android.app.AppOpsManager.OP_FINE_LOCATION; -import static android.location.LocationManager.GPS_PROVIDER; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.after; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertThrows; - -import android.Manifest; -import android.content.Context; -import android.content.pm.PackageManager; -import android.location.GnssAntennaInfo; -import android.location.GnssAntennaInfo.SphericalCorrections; -import android.location.GnssClock; -import android.location.GnssMeasurementCorrections; -import android.location.GnssMeasurementRequest; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; -import android.location.GnssSingleSatCorrection; -import android.location.IGnssAntennaInfoListener; -import android.location.IGnssMeasurementsListener; -import android.location.IGnssNavigationMessageListener; -import android.location.IGnssStatusListener; -import android.location.INetInitiatedListener; -import android.location.LocationManagerInternal; -import android.os.Handler; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Message; -import android.os.RemoteException; - -import com.android.server.LocalServices; -import com.android.server.location.gnss.GnssAntennaInfoProvider.GnssAntennaInfoProviderNative; -import com.android.server.location.gnss.GnssMeasurementsProvider.GnssMeasurementProviderNative; -import com.android.server.location.gnss.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative; -import com.android.server.location.injector.TestInjector; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.AdditionalMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Unit tests for {@link com.android.server.location.gnss.GnssManagerService}. - */ -public class GnssManagerServiceTest { - - private static final long TIMEOUT_MS = 5000; - private static final long FAILURE_TIMEOUT_MS = 200; - - private static final String TEST_PACKAGE = "com.test"; - - private TestInjector mInjector; - - @Mock private Handler mMockHandler; - @Mock private Context mMockContext; - @Mock private PackageManager mPackageManager; - @Mock private LocationManagerInternal mLocationManagerInternal; - @Mock private GnssNative.GnssNativeInitNative mGnssInitNative; - @Mock private GnssLocationProvider mMockGnssLocationProvider; - @Mock private GnssLocationProvider.GnssSystemInfoProvider mMockGnssSystemInfoProvider; - @Mock private GnssCapabilitiesProvider mMockGnssCapabilitiesProvider; - @Mock private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider; - @Mock private INetInitiatedListener mNetInitiatedListener; - - private GnssMeasurementsProvider mTestGnssMeasurementsProvider; - private GnssStatusProvider mTestGnssStatusProvider; - private GnssNavigationMessageProvider mTestGnssNavigationMessageProvider; - private GnssAntennaInfoProvider mTestGnssAntennaInfoProvider; - - private GnssManagerService mGnssManagerService; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - when(mGnssInitNative.isSupported()).thenReturn(true); - GnssNative.setInitNativeForTest(mGnssInitNative); - GnssNative.resetCallbacksForTest(); - - when(mMockContext.createAttributionContext(anyString())).thenReturn(mMockContext); - when(mMockContext.getPackageManager()).thenReturn(mPackageManager); - when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( - new String[]{TEST_PACKAGE}); - - mInjector = new TestInjector(); - - enableLocationPermissions(); - - LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal); - - // Mock Handler will execute posted runnables immediately - when(mMockHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer( - (InvocationOnMock invocation) -> { - Message msg = (Message) (invocation.getArguments()[0]); - msg.getCallback().run(); - return null; - }); - - // Setup providers - mTestGnssMeasurementsProvider = createGnssMeasurementsProvider(); - mTestGnssStatusProvider = createGnssStatusListenerHelper(); - mTestGnssNavigationMessageProvider = createGnssNavigationMessageProvider(); - mTestGnssAntennaInfoProvider = createGnssAntennaInfoProvider(); - - // Setup GnssLocationProvider to return providers - when(mMockGnssLocationProvider.getGnssStatusProvider()).thenReturn( - mTestGnssStatusProvider); - when(mMockGnssLocationProvider.getGnssCapabilitiesProvider()).thenReturn( - mMockGnssCapabilitiesProvider); - when(mMockGnssLocationProvider.getGnssSystemInfoProvider()).thenReturn( - mMockGnssSystemInfoProvider); - when(mMockGnssLocationProvider.getGnssMeasurementCorrectionsProvider()).thenReturn( - mMockGnssMeasurementCorrectionsProvider); - when(mMockGnssLocationProvider.getGnssMeasurementsProvider()).thenReturn( - mTestGnssMeasurementsProvider); - when(mMockGnssLocationProvider.getGnssNavigationMessageProvider()).thenReturn( - mTestGnssNavigationMessageProvider); - when(mMockGnssLocationProvider.getNetInitiatedListener()).thenReturn( - mNetInitiatedListener); - when(mMockGnssLocationProvider.getGnssAntennaInfoProvider()).thenReturn( - mTestGnssAntennaInfoProvider); - - // Create GnssManagerService - mGnssManagerService = new GnssManagerService(mMockContext, mInjector, - mMockGnssLocationProvider); - mGnssManagerService.onSystemReady(); - } - - @After - public void tearDown() { - LocalServices.removeServiceForTest(LocationManagerInternal.class); - } - - private void overrideAsBinder(IInterface mockListener) { - IBinder mockBinder = mock(IBinder.class); - when(mockListener.asBinder()).thenReturn(mockBinder); - } - - private IGnssStatusListener createMockGnssStatusListener() { - IGnssStatusListener mockListener = mock(IGnssStatusListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private IGnssMeasurementsListener createMockGnssMeasurementsListener() { - IGnssMeasurementsListener mockListener = mock( - IGnssMeasurementsListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private IGnssAntennaInfoListener createMockGnssAntennaInfoListener() { - IGnssAntennaInfoListener mockListener = mock(IGnssAntennaInfoListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private IGnssNavigationMessageListener createMockGnssNavigationMessageListener() { - IGnssNavigationMessageListener mockListener = mock(IGnssNavigationMessageListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private GnssMeasurementCorrections createDummyGnssMeasurementCorrections() { - GnssSingleSatCorrection gnssSingleSatCorrection = - new GnssSingleSatCorrection.Builder().build(); - return - new GnssMeasurementCorrections.Builder().setSingleSatelliteCorrectionList( - Collections.singletonList(gnssSingleSatCorrection)).build(); - } - - private static List createDummyGnssAntennaInfos() { - double carrierFrequencyMHz = 13758.0; - - GnssAntennaInfo.PhaseCenterOffset phaseCenterOffset = new - GnssAntennaInfo.PhaseCenterOffset( - 4.3d, - 1.4d, - 2.10d, - 2.1d, - 3.12d, - 0.5d); - - double[][] phaseCenterVariationCorrectionsMillimeters = new double[10][10]; - double[][] phaseCenterVariationCorrectionsUncertaintyMillimeters = new double[10][10]; - SphericalCorrections - phaseCenterVariationCorrections = - new SphericalCorrections( - phaseCenterVariationCorrectionsMillimeters, - phaseCenterVariationCorrectionsUncertaintyMillimeters); - - double[][] signalGainCorrectionsDbi = new double[10][10]; - double[][] signalGainCorrectionsUncertaintyDbi = new double[10][10]; - SphericalCorrections signalGainCorrections = new - SphericalCorrections( - signalGainCorrectionsDbi, - signalGainCorrectionsUncertaintyDbi); - - List gnssAntennaInfos = new ArrayList<>(); - gnssAntennaInfos.add(new GnssAntennaInfo.Builder() - .setCarrierFrequencyMHz(carrierFrequencyMHz) - .setPhaseCenterOffset(phaseCenterOffset) - .setPhaseCenterVariationCorrections(phaseCenterVariationCorrections) - .setSignalGainCorrections(signalGainCorrections) - .build()); - return gnssAntennaInfos; - } - - private void enableLocationPermissions() { - Mockito.doThrow(new SecurityException()).when( - mMockContext).enforceCallingOrSelfPermission( - AdditionalMatchers.and( - AdditionalMatchers.not(eq(Manifest.permission.LOCATION_HARDWARE)), - AdditionalMatchers.not(eq(Manifest.permission.ACCESS_FINE_LOCATION))), - anyString()); - when(mMockContext.checkPermission( - eq(android.Manifest.permission.LOCATION_HARDWARE), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_GRANTED); - when(mMockContext.checkPermission( - eq(Manifest.permission.ACCESS_FINE_LOCATION), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_GRANTED); - when(mMockContext.checkPermission( - eq(Manifest.permission.ACCESS_COARSE_LOCATION), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_GRANTED); - - mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, TEST_PACKAGE, true); - mInjector.getAppOpsHelper().setAppOpAllowed(OP_COARSE_LOCATION, TEST_PACKAGE, true); - - when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt())) - .thenReturn(true); - } - - private void disableLocationPermissions() { - Mockito.doThrow(new SecurityException()).when( - mMockContext).enforceCallingOrSelfPermission(anyString(), nullable(String.class)); - - when(mMockContext.checkPermission( - anyString(), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_DENIED); - - mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, TEST_PACKAGE, false); - mInjector.getAppOpsHelper().setAppOpAllowed(OP_COARSE_LOCATION, TEST_PACKAGE, false); - - when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt())) - .thenReturn(false); - } - - private GnssStatusProvider createGnssStatusListenerHelper() { - return new GnssStatusProvider(mInjector); - } - - private GnssMeasurementsProvider createGnssMeasurementsProvider() { - GnssMeasurementProviderNative - mockGnssMeasurementProviderNative = mock(GnssMeasurementProviderNative.class); - when(mockGnssMeasurementProviderNative.isMeasurementSupported()).thenReturn( - true); - return new GnssMeasurementsProvider(mInjector, mockGnssMeasurementProviderNative); - } - - private GnssNavigationMessageProvider createGnssNavigationMessageProvider() { - GnssNavigationMessageProviderNative mockGnssNavigationMessageProviderNative = mock( - GnssNavigationMessageProviderNative.class); - when(mockGnssNavigationMessageProviderNative.isNavigationMessageSupported()).thenReturn( - true); - return new GnssNavigationMessageProvider(mInjector, - mockGnssNavigationMessageProviderNative); - } - - private GnssAntennaInfoProvider createGnssAntennaInfoProvider() { - GnssAntennaInfoProviderNative mockGnssAntenaInfoProviderNative = mock( - GnssAntennaInfoProviderNative.class); - when(mockGnssAntenaInfoProviderNative.isAntennaInfoSupported()).thenReturn( - true); - return new GnssAntennaInfoProvider(mInjector, mockGnssAntenaInfoProviderNative); - } - - @Test - public void getGnssYearOfHardwareTest() { - final int gnssYearOfHardware = 2012; - when(mMockGnssSystemInfoProvider.getGnssYearOfHardware()).thenReturn(gnssYearOfHardware); - enableLocationPermissions(); - - assertThat(mGnssManagerService.getGnssYearOfHardware()).isEqualTo(gnssYearOfHardware); - } - - @Test - public void getGnssHardwareModelNameTest() { - final String gnssHardwareModelName = "hardwarename"; - when(mMockGnssSystemInfoProvider.getGnssHardwareModelName()).thenReturn( - gnssHardwareModelName); - enableLocationPermissions(); - - assertThat(mGnssManagerService.getGnssHardwareModelName()).isEqualTo( - gnssHardwareModelName); - } - - @Test - public void getGnssCapabilitiesWithPermissionsTest() { - final long mGnssCapabilities = 23132L; - when(mMockGnssCapabilitiesProvider.getGnssCapabilities()).thenReturn(mGnssCapabilities); - enableLocationPermissions(); - - assertThat(mGnssManagerService.getGnssCapabilities()).isEqualTo(mGnssCapabilities); - } - - @Test - public void registerGnssStatusCallbackWithoutPermissionsTest() throws RemoteException { - final int timeToFirstFix = 20000; - IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, () -> mGnssManagerService - .registerGnssStatusCallback( - mockGnssStatusListener, TEST_PACKAGE, "abcd123")); - - mTestGnssStatusProvider.onFirstFix(timeToFirstFix); - - verify(mockGnssStatusListener, after(FAILURE_TIMEOUT_MS).times(0)).onFirstFix( - timeToFirstFix); - } - - @Test - public void registerGnssStatusCallbackWithPermissionsTest() throws RemoteException { - final int timeToFirstFix = 20000; - IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener(); - - enableLocationPermissions(); - - mGnssManagerService.registerGnssStatusCallback( - mockGnssStatusListener, TEST_PACKAGE, "abcd123"); - - mTestGnssStatusProvider.onFirstFix(timeToFirstFix); - - verify(mockGnssStatusListener, timeout(TIMEOUT_MS).times(1)).onFirstFix(timeToFirstFix); - } - - @Test - public void unregisterGnssStatusCallbackWithPermissionsTest() throws RemoteException { - final int timeToFirstFix = 20000; - IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener(); - - enableLocationPermissions(); - - mGnssManagerService.registerGnssStatusCallback( - mockGnssStatusListener, TEST_PACKAGE, "abcd123"); - - mGnssManagerService.unregisterGnssStatusCallback(mockGnssStatusListener); - - mTestGnssStatusProvider.onFirstFix(timeToFirstFix); - - verify(mockGnssStatusListener, after(FAILURE_TIMEOUT_MS).times(0)).onFirstFix( - timeToFirstFix); - } - - @Test - public void addGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), mockGnssMeasurementsListener, - TEST_PACKAGE, null)); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void addGnssMeasurementsListenerWithPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - enableLocationPermissions(); - - mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), - mockGnssMeasurementsListener, - TEST_PACKAGE, null); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - timeout(TIMEOUT_MS).times(1)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void injectGnssMeasurementCorrectionsWithoutPermissionsTest() { - GnssMeasurementCorrections gnssMeasurementCorrections = - createDummyGnssMeasurementCorrections(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.injectGnssMeasurementCorrections( - gnssMeasurementCorrections)); - verify(mMockGnssMeasurementCorrectionsProvider, times(0)) - .injectGnssMeasurementCorrections( - gnssMeasurementCorrections); - } - - @Test - public void injectGnssMeasurementCorrectionsWithPermissionsTest() { - GnssMeasurementCorrections gnssMeasurementCorrections = - createDummyGnssMeasurementCorrections(); - - enableLocationPermissions(); - - mGnssManagerService.injectGnssMeasurementCorrections( - gnssMeasurementCorrections); - verify(mMockGnssMeasurementCorrectionsProvider, times(1)) - .injectGnssMeasurementCorrections( - gnssMeasurementCorrections); - } - - @Test - public void removeGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - enableLocationPermissions(); - - mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), - mockGnssMeasurementsListener, - TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssMeasurementsListener( - mockGnssMeasurementsListener); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void removeGnssMeasurementsListenerWithPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - enableLocationPermissions(); - - mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), - mockGnssMeasurementsListener, - TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssMeasurementsListener( - mockGnssMeasurementsListener); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void addGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.addGnssAntennaInfoListener( - mockGnssAntennaInfoListener, - TEST_PACKAGE, null)); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, after(FAILURE_TIMEOUT_MS).times(0)) - .onGnssAntennaInfoReceived(gnssAntennaInfos); - } - - @Test - public void addGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssAntennaInfoListener(mockGnssAntennaInfoListener, - TEST_PACKAGE, null); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, timeout(TIMEOUT_MS).times(1)) - .onGnssAntennaInfoReceived(gnssAntennaInfos); - } - - @Test - public void removeGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssAntennaInfoListener( - mockGnssAntennaInfoListener, - TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssAntennaInfoListener( - mockGnssAntennaInfoListener); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, after(FAILURE_TIMEOUT_MS).times(0)) - .onGnssAntennaInfoReceived(gnssAntennaInfos); - } - - @Test - public void removeGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssAntennaInfoListener( - mockGnssAntennaInfoListener, - TEST_PACKAGE, null); - - mGnssManagerService.removeGnssAntennaInfoListener( - mockGnssAntennaInfoListener); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssAntennaInfoReceived( - gnssAntennaInfos); - } - - @Test - public void addGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null)); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void addGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - timeout(TIMEOUT_MS).times(1)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void removeGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssNavigationMessageListener( - mockGnssNavigationMessageListener); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void removeGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null); - - mGnssManagerService.removeGnssNavigationMessageListener( - mockGnssNavigationMessageListener); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void sendNiResponseWithPermissionsTest() throws RemoteException { - int notifId = 0; - int userResponse = 0; - enableLocationPermissions(); - - mGnssManagerService.sendNiResponse(notifId, userResponse); - - verify(mNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse); - } -} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java new file mode 100644 index 0000000000000..675274bf82c4e --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java @@ -0,0 +1,674 @@ +/* + * Copyright (C) 2020 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 com.android.server.location.gnss.hal; + +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_ALTITUDE; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_BEARING; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_BEARING_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_LAT_LONG; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_SPEED; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_SPEED_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_VERTICAL_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_REALTIME_HAS_TIMESTAMP_NS; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_ERROR_ID_EXISTS; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_ERROR_ID_UNKNOWN; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_OPERATION_SUCCESS; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_TRANSITION_ENTERED; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_TRANSITION_EXITED; + +import android.annotation.Nullable; +import android.location.GnssAntennaInfo; +import android.location.GnssMeasurementCorrections; +import android.location.GnssMeasurementsEvent; +import android.location.GnssNavigationMessage; +import android.location.Location; + +import com.android.server.location.gnss.GnssPowerStats; +import com.android.server.location.gnss.hal.GnssNative.GnssLocationFlags; +import com.android.server.location.gnss.hal.GnssNative.GnssRealtimeFlags; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +/** + * Fake GNSS HAL for testing. + */ +public final class FakeGnssHal extends GnssNative.GnssHal { + + public static class GnssHalPositionMode { + + public final int Mode; + public final int Recurrence; + public final int MinInterval; + public final int PreferredAccuracy; + public final int PreferredTime; + public final boolean LowPowerMode; + + GnssHalPositionMode() { + Mode = 0; + Recurrence = 0; + MinInterval = 0; + PreferredAccuracy = 0; + PreferredTime = 0; + LowPowerMode = false; + } + + public GnssHalPositionMode(int mode, int recurrence, int minInterval, int preferredAccuracy, + int preferredTime, boolean lowPowerMode) { + Mode = mode; + Recurrence = recurrence; + MinInterval = minInterval; + PreferredAccuracy = preferredAccuracy; + PreferredTime = preferredTime; + LowPowerMode = lowPowerMode; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalPositionMode that = (GnssHalPositionMode) o; + return Mode == that.Mode + && Recurrence == that.Recurrence + && MinInterval == that.MinInterval + && PreferredAccuracy == that.PreferredAccuracy + && PreferredTime == that.PreferredTime + && LowPowerMode == that.LowPowerMode; + } + + @Override + public int hashCode() { + return Objects.hash(Recurrence, MinInterval); + } + } + + public static class GnssHalBatchingMode { + + public final long PeriodNanos; + public final boolean WakeOnFifoFull; + + GnssHalBatchingMode() { + PeriodNanos = 0; + WakeOnFifoFull = false; + } + + public GnssHalBatchingMode(long periodNanos, boolean wakeOnFifoFull) { + PeriodNanos = periodNanos; + WakeOnFifoFull = wakeOnFifoFull; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalBatchingMode that = (GnssHalBatchingMode) o; + return PeriodNanos == that.PeriodNanos + && WakeOnFifoFull == that.WakeOnFifoFull; + } + + @Override + public int hashCode() { + return Objects.hash(PeriodNanos, WakeOnFifoFull); + } + } + + public static class GnssHalInjectedTime { + + public final long Time; + public final long TimeReference; + public final int Uncertainty; + + public GnssHalInjectedTime(long time, long timeReference, int uncertainty) { + Time = time; + TimeReference = timeReference; + Uncertainty = uncertainty; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalInjectedTime that = (GnssHalInjectedTime) o; + return Time == that.Time + && TimeReference == that.TimeReference + && Uncertainty == that.Uncertainty; + } + + @Override + public int hashCode() { + return Objects.hash(Time); + } + } + + public static class GnssHalGeofence { + + public final int GeofenceId; + public final Location Center; + public final double Radius; + public int LastTransition; + public int MonitorTransitions; + public final int NotificationResponsiveness; + public final int UnknownTimer; + public boolean Paused; + + public GnssHalGeofence(int geofenceId, double latitude, double longitude, double radius, + int lastTransition, int monitorTransitions, int notificationResponsiveness, + int unknownTimer, boolean paused) { + GeofenceId = geofenceId; + Center = new Location(""); + Center.setLatitude(latitude); + Center.setLongitude(longitude); + Radius = radius; + LastTransition = lastTransition; + MonitorTransitions = monitorTransitions; + NotificationResponsiveness = notificationResponsiveness; + UnknownTimer = unknownTimer; + Paused = paused; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalGeofence that = (GnssHalGeofence) o; + return GeofenceId == that.GeofenceId + && Double.compare(that.Radius, Radius) == 0 + && LastTransition == that.LastTransition + && MonitorTransitions == that.MonitorTransitions + && NotificationResponsiveness == that.NotificationResponsiveness + && UnknownTimer == that.UnknownTimer + && Paused == that.Paused + && Center.equals(that.Center); + } + + @Override + public int hashCode() { + return Objects.hash(GeofenceId); + } + } + + private static class HalState { + private boolean mStarted = false; + private boolean mBatchingStarted = false; + private boolean mNavigationMessagesStarted = false; + private boolean mAntennaInfoListeningStarted = false; + private boolean mMeasurementCollectionStarted = false; + private boolean mMeasurementCollectionFullTracking = false; + private GnssHalPositionMode mPositionMode = new GnssHalPositionMode(); + private GnssHalBatchingMode mBatchingMode = new GnssHalBatchingMode(); + private final ArrayList mBatchedLocations = new ArrayList<>(); + private Location mInjectedLocation = null; + private Location mInjectedBestLocation = null; + private GnssHalInjectedTime mInjectedTime = null; + private GnssMeasurementCorrections mInjectedMeasurementCorrections = null; + private final HashMap mGeofences = new HashMap<>(); + private GnssPowerStats mPowerStats = new GnssPowerStats(0, 0, 0, 0, 0, 0, 0, 0, + new double[0]); + } + + private @Nullable GnssNative mGnssNative; + private HalState mState = new HalState(); + + private boolean mIsNavigationMessageCollectionSupported = true; + private boolean mIsAntennaInfoListeningSupported = true; + private boolean mIsMeasurementSupported = true; + private boolean mIsMeasurementCorrectionsSupported = true; + private int mBatchSize = 0; + private boolean mIsGeofencingSupported = true; + private boolean mIsVisibilityControlSupported = true; + + public FakeGnssHal() {} + + public void restartHal() { + mState = new HalState(); + Objects.requireNonNull(mGnssNative).restartHal(); + } + + public void setIsNavigationMessageCollectionSupported(boolean supported) { + mIsNavigationMessageCollectionSupported = supported; + } + + public void setIsAntennaInfoListeningSupported(boolean supported) { + mIsAntennaInfoListeningSupported = supported; + } + + public void setIsMeasurementSupported(boolean supported) { + mIsMeasurementSupported = supported; + } + + public void setIsMeasurementCorrectionsSupported(boolean supported) { + mIsMeasurementCorrectionsSupported = supported; + } + + public void setBatchSize(int batchSize) { + mBatchSize = batchSize; + } + + public void setIsGeofencingSupported(boolean supported) { + mIsGeofencingSupported = supported; + } + + public void setPowerStats(GnssPowerStats powerStats) { + mState.mPowerStats = powerStats; + } + + public void setIsVisibilityControlSupported(boolean supported) { + mIsVisibilityControlSupported = supported; + } + + public GnssHalPositionMode getPositionMode() { + return mState.mPositionMode; + } + + public void reportLocation(Location location) { + if (mState.mStarted) { + Objects.requireNonNull(mGnssNative).reportLocation(true, location); + } + if (mState.mBatchingStarted) { + mState.mBatchedLocations.add(location); + if (mState.mBatchedLocations.size() >= mBatchSize) { + if (mState.mBatchingMode.WakeOnFifoFull) { + flushBatch(); + } else { + mState.mBatchedLocations.remove(0); + } + } + } + for (GnssHalGeofence geofence : mState.mGeofences.values()) { + if (!geofence.Paused) { + if (geofence.Center.distanceTo(location) > geofence.Radius) { + if (geofence.LastTransition != GEOFENCE_TRANSITION_EXITED) { + geofence.LastTransition = GEOFENCE_TRANSITION_EXITED; + if ((geofence.MonitorTransitions & GEOFENCE_TRANSITION_EXITED) != 0) { + Objects.requireNonNull(mGnssNative).reportGeofenceTransition( + geofence.GeofenceId, location, GEOFENCE_TRANSITION_EXITED, + location.getTime()); + } + } + } else { + if (geofence.LastTransition != GEOFENCE_TRANSITION_ENTERED) { + geofence.LastTransition = GEOFENCE_TRANSITION_ENTERED; + if ((geofence.MonitorTransitions & GEOFENCE_TRANSITION_ENTERED) != 0) { + Objects.requireNonNull(mGnssNative).reportGeofenceTransition( + geofence.GeofenceId, location, GEOFENCE_TRANSITION_ENTERED, + location.getTime()); + } + } + } + } + } + } + + public void reportNavigationMessage(GnssNavigationMessage message) { + if (mState.mNavigationMessagesStarted) { + Objects.requireNonNull(mGnssNative).reportNavigationMessage(message); + } + } + + public void reportAntennaInfo(List antennaInfos) { + if (mState.mAntennaInfoListeningStarted) { + Objects.requireNonNull(mGnssNative).reportAntennaInfo(antennaInfos); + } + } + + public boolean isMeasurementCollectionFullTracking() { + return mState.mMeasurementCollectionFullTracking; + } + + public void reportMeasurement(GnssMeasurementsEvent event) { + if (mState.mMeasurementCollectionStarted) { + Objects.requireNonNull(mGnssNative).reportMeasurementData(event); + } + } + + public GnssHalInjectedTime getLastInjectedTime() { + return mState.mInjectedTime; + } + + public GnssMeasurementCorrections getLastInjectedCorrections() { + return mState.mInjectedMeasurementCorrections; + } + + public Collection getGeofences() { + return mState.mGeofences.values(); + } + + @Override + protected void classInitOnce() {} + + @Override + protected boolean isSupported() { + return true; + } + + @Override + protected void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) { + mGnssNative = Objects.requireNonNull(gnssNative); + } + + @Override + protected boolean init() { + return true; + } + + @Override + protected void cleanup() {} + + @Override + protected boolean start() { + mState.mStarted = true; + return true; + } + + @Override + protected boolean stop() { + mState.mStarted = false; + return true; + } + + @Override + protected boolean setPositionMode(int mode, int recurrence, int minInterval, + int preferredAccuracy, int preferredTime, boolean lowPowerMode) { + mState.mPositionMode = new GnssHalPositionMode(mode, recurrence, minInterval, + preferredAccuracy, preferredTime, lowPowerMode); + return true; + } + + @Override + protected String getInternalState() { + return "DebugState"; + } + + @Override + protected void deleteAidingData(int flags) {} + + @Override + protected int readNmea(byte[] buffer, int bufferSize) { + return 0; + } + + @Override + protected void injectLocation(double latitude, double longitude, float accuracy) { + mState.mInjectedLocation = new Location("injected"); + mState.mInjectedLocation.setLatitude(latitude); + mState.mInjectedLocation.setLongitude(longitude); + mState.mInjectedLocation.setAccuracy(accuracy); + } + + @Override + protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude, + double longitude, double altitude, float speed, float bearing, float horizontalAccuracy, + float verticalAccuracy, float speedAccuracy, float bearingAccuracy, long timestamp, + @GnssRealtimeFlags int elapsedRealtimeFlags, long elapsedRealtimeNanos, + double elapsedRealtimeUncertaintyNanos) { + mState.mInjectedBestLocation = new Location("injectedBest"); + if ((gnssLocationFlags & GNSS_LOCATION_HAS_LAT_LONG) != 0) { + mState.mInjectedBestLocation.setLatitude(latitude); + mState.mInjectedBestLocation.setLongitude(longitude); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_ALTITUDE) != 0) { + mState.mInjectedBestLocation.setAltitude(altitude); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_SPEED) != 0) { + mState.mInjectedBestLocation.setSpeed(speed); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_BEARING) != 0) { + mState.mInjectedBestLocation.setBearing(bearing); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY) != 0) { + mState.mInjectedBestLocation.setAccuracy(horizontalAccuracy); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_VERTICAL_ACCURACY) != 0) { + mState.mInjectedBestLocation.setVerticalAccuracyMeters(verticalAccuracy); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_SPEED_ACCURACY) != 0) { + mState.mInjectedBestLocation.setSpeedAccuracyMetersPerSecond(speedAccuracy); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_BEARING_ACCURACY) != 0) { + mState.mInjectedBestLocation.setBearingAccuracyDegrees(bearingAccuracy); + } + mState.mInjectedBestLocation.setTime(timestamp); + if ((elapsedRealtimeFlags & GNSS_REALTIME_HAS_TIMESTAMP_NS) != 0) { + mState.mInjectedBestLocation.setElapsedRealtimeNanos(elapsedRealtimeNanos); + } + if ((elapsedRealtimeFlags & GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS) != 0) { + mState.mInjectedBestLocation.setElapsedRealtimeUncertaintyNanos( + elapsedRealtimeUncertaintyNanos); + } + } + + @Override + protected void injectTime(long time, long timeReference, int uncertainty) { + mState.mInjectedTime = new GnssHalInjectedTime(time, timeReference, uncertainty); + } + + @Override + protected boolean isNavigationMessageCollectionSupported() { + return mIsNavigationMessageCollectionSupported; + } + + @Override + protected boolean startNavigationMessageCollection() { + mState.mNavigationMessagesStarted = true; + return true; + } + + @Override + protected boolean stopNavigationMessageCollection() { + mState.mNavigationMessagesStarted = false; + return true; + } + + @Override + protected boolean isAntennaInfoListeningSupported() { + return mIsAntennaInfoListeningSupported; + } + + @Override + protected boolean startAntennaInfoListening() { + mState.mAntennaInfoListeningStarted = true; + return true; + } + + @Override + protected boolean stopAntennaInfoListening() { + mState.mAntennaInfoListeningStarted = false; + return true; + } + + @Override + protected boolean isMeasurementSupported() { + return mIsMeasurementSupported; + } + + @Override + protected boolean startMeasurementCollection(boolean enableFullTracking) { + mState.mMeasurementCollectionStarted = true; + mState.mMeasurementCollectionFullTracking = enableFullTracking; + return true; + } + + @Override + protected boolean stopMeasurementCollection() { + mState.mMeasurementCollectionStarted = false; + mState.mMeasurementCollectionFullTracking = false; + return true; + } + + @Override + protected boolean isMeasurementCorrectionsSupported() { + return mIsMeasurementCorrectionsSupported; + } + + @Override + protected boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) { + mState.mInjectedMeasurementCorrections = corrections; + return true; + } + + @Override + protected int getBatchSize() { + return mBatchSize; + } + + @Override + protected boolean initBatching() { + return true; + } + + @Override + protected void cleanupBatching() {} + + @Override + protected boolean startBatch(long periodNanos, boolean wakeOnFifoFull) { + mState.mBatchingStarted = true; + mState.mBatchingMode = new GnssHalBatchingMode(periodNanos, wakeOnFifoFull); + return true; + } + + @Override + protected void flushBatch() { + Location[] locations = mState.mBatchedLocations.toArray(new Location[0]); + mState.mBatchedLocations.clear(); + Objects.requireNonNull(mGnssNative).reportLocationBatch(locations); + } + + @Override + protected void stopBatch() { + mState.mBatchingStarted = false; + mState.mBatchingMode = new GnssHalBatchingMode(); + mState.mBatchedLocations.clear(); + } + + @Override + protected boolean isGeofencingSupported() { + return mIsGeofencingSupported; + } + + @Override + protected boolean addGeofence(int geofenceId, double latitude, double longitude, double radius, + int lastTransition, int monitorTransitions, int notificationResponsiveness, + int unknownTimer) { + if (mState.mGeofences.containsKey(geofenceId)) { + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_EXISTS); + } else { + mState.mGeofences.put(geofenceId, + new GnssHalGeofence(geofenceId, latitude, longitude, radius, lastTransition, + monitorTransitions, notificationResponsiveness, unknownTimer, false)); + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } + return true; + } + + @Override + protected boolean resumeGeofence(int geofenceId, int monitorTransitions) { + GnssHalGeofence geofence = mState.mGeofences.get(geofenceId); + if (geofence != null) { + geofence.Paused = false; + geofence.MonitorTransitions = monitorTransitions; + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } else { + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN); + } + return true; + } + + @Override + protected boolean pauseGeofence(int geofenceId) { + GnssHalGeofence geofence = mState.mGeofences.get(geofenceId); + if (geofence != null) { + geofence.Paused = true; + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } else { + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN); + } + return true; + } + + @Override + protected boolean removeGeofence(int geofenceId) { + if (mState.mGeofences.remove(geofenceId) != null) { + Objects.requireNonNull(mGnssNative).reportGeofenceRemoveStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } else { + Objects.requireNonNull(mGnssNative).reportGeofenceRemoveStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN); + } + return true; + } + + @Override + protected boolean isGnssVisibilityControlSupported() { + return mIsVisibilityControlSupported; + } + + @Override + protected void sendNiResponse(int notificationId, int userResponse) {} + + @Override + protected void requestPowerStats() { + Objects.requireNonNull(mGnssNative).reportGnssPowerStats(mState.mPowerStats); + } + + @Override + protected void setAgpsServer(int type, String hostname, int port) {} + + @Override + protected void setAgpsSetId(int type, String setId) {} + + @Override + protected void setAgpsReferenceLocationCellId(int type, int mcc, int mnc, int lac, int cid) {} + + @Override + protected boolean isPsdsSupported() { + return true; + } + + @Override + protected void injectPsdsData(byte[] data, int length, int psdsType) {} +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java new file mode 100644 index 0000000000000..2cf57dafc7d9a --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 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 com.android.server.location.injector; + +/** + * Version of EmergencyHelper for testing. + */ +public class FakeEmergencyHelper extends EmergencyHelper { + + private boolean mInEmergency; + + public FakeEmergencyHelper() {} + + public void setInEmergency(boolean inEmergency) { + mInEmergency = inEmergency; + } + + @Override + public boolean isInEmergency(long extensionTimeMs) { + return mInEmergency; + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java index f3c31c2cdd2b7..8e5b16e1ee3ac 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java @@ -28,6 +28,7 @@ public class TestInjector implements Injector { private final FakeLocationPowerSaveModeHelper mLocationPowerSaveModeHelper; private final FakeScreenInteractiveHelper mScreenInteractiveHelper; private final LocationAttributionHelper mLocationAttributionHelper; + private final FakeEmergencyHelper mEmergencyHelper; private final LocationUsageLogger mLocationUsageLogger; public TestInjector() { @@ -41,6 +42,7 @@ public class TestInjector implements Injector { mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper(mLocationEventLog); mScreenInteractiveHelper = new FakeScreenInteractiveHelper(); mLocationAttributionHelper = new LocationAttributionHelper(mAppOpsHelper); + mEmergencyHelper = new FakeEmergencyHelper(); mLocationUsageLogger = new LocationUsageLogger(); } @@ -89,6 +91,11 @@ public class TestInjector implements Injector { return mLocationAttributionHelper; } + @Override + public EmergencyHelper getEmergencyHelper() { + return mEmergencyHelper; + } + @Override public LocationUsageLogger getLocationUsageLogger() { return mLocationUsageLogger;