Loading location/java/android/location/flags/gnss.aconfig +8 −1 Original line number Diff line number Diff line Loading @@ -6,3 +6,10 @@ flag { description: "Flag for GNSS API for NavIC L1" bug: "302199306" } flag { name: "gnss_call_stop_before_set_position_mode" namespace: "location" description: "Flag for calling stop() before setPositionMode()" bug: "306874828" } services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +43 −9 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; import android.location.LocationResult; import android.location.flags.Flags; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; import android.location.util.identity.CallerIdentity; Loading Loading @@ -1048,11 +1049,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements stopBatching(); if (mStarted && mGnssNative.getCapabilities().hasScheduling()) { if (Flags.gnssCallStopBeforeSetPositionMode()) { GnssPositionMode positionMode = new GnssPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval, /* preferredAccuracy= */ 0, /* preferredTime= */ 0, mProviderRequest.isLowPower()); if (!positionMode.equals(mLastPositionMode)) { stopNavigating(); startNavigating(); } } else { // change period and/or lowPowerMode if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval, mProviderRequest.isLowPower())) { Log.e(TAG, "set_position_mode failed in updateRequirements"); } } } else if (!mStarted) { // start GPS startNavigating(); Loading Loading @@ -1234,12 +1247,33 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000; if (Flags.gnssCallStopBeforeSetPositionMode()) { boolean success = mGnssNative.setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, /* preferredAccuracy= */ 0, /* preferredTime= */ 0, mProviderRequest.isLowPower()); if (success) { mLastPositionMode = new GnssPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, /* preferredAccuracy= */ 0, /* preferredTime= */ 0, mProviderRequest.isLowPower()); } else { mLastPositionMode = null; setStarted(false); Log.e(TAG, "set_position_mode failed in startNavigating()"); return; } } else { if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, mProviderRequest.isLowPower())) { setStarted(false); Log.e(TAG, "set_position_mode failed in startNavigating()"); return; } } if (!mGnssNative.start()) { setStarted(false); Log.e(TAG, "native_start failed in startNavigating()"); Loading services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssLocationProviderTest.java 0 → 100644 +179 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.AlarmManager; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; import android.location.GnssCapabilities; import android.location.LocationManager; import android.location.LocationManagerInternal; import android.location.flags.Flags; import android.location.provider.ProviderRequest; import android.os.PowerManager; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.telephony.TelephonyManager; import androidx.test.runner.AndroidJUnit4; import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.location.gnss.hal.FakeGnssHal; import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import com.android.server.location.injector.TestInjector; import com.android.server.timedetector.TimeDetectorInternal; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.quality.Strictness; import java.util.HashSet; import java.util.Objects; import java.util.Set; @Presubmit @androidx.test.filters.SmallTest @RunWith(AndroidJUnit4.class) public class GnssLocationProviderTest { @Rule public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) .setStrictness(Strictness.WARN) .mockStatic(Settings.Global.class) .build(); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private @Mock Context mContext; private @Mock LocationManagerInternal mLocationManagerInternal; private @Mock LocationManager mLocationManager; private @Mock TimeDetectorInternal mTimeDetectorInternal; private @Mock GnssConfiguration mMockConfiguration; private @Mock GnssMetrics mGnssMetrics; private @Mock PowerManager mPowerManager; private @Mock TelephonyManager mTelephonyManager; private @Mock AppOpsManager mAppOpsManager; private @Mock AlarmManager mAlarmManager; private @Mock PowerManager.WakeLock mWakeLock; private @Mock ContentResolver mContentResolver; private @Mock UserManager mUserManager; private @Mock UserHandle mUserHandle; private Set<UserHandle> mUserHandleSet = new HashSet<>(); private GnssNative mGnssNative; private GnssLocationProvider mTestProvider; @Before public void setUp() { MockitoAnnotations.initMocks(this); doReturn("mypackage").when(mContext).getPackageName(); doReturn("attribution").when(mContext).getAttributionTag(); doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class); doReturn(mPowerManager).when(mContext).getSystemService("power"); doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); doReturn(mAlarmManager).when(mContext).getSystemService(Context.ALARM_SERVICE); doReturn(mLocationManager).when(mContext).getSystemService(LocationManager.class); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); mUserHandleSet.add(mUserHandle); doReturn(true).when(mLocationManager).isLocationEnabledForUser(eq(mUserHandle)); doReturn(mUserHandleSet).when(mUserManager).getVisibleUsers(); doReturn(mContentResolver).when(mContext).getContentResolver(); doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString()); LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal); LocalServices.addService(TimeDetectorInternal.class, mTimeDetectorInternal); FakeGnssHal fakeGnssHal = new FakeGnssHal(); GnssNative.setGnssHalForTest(fakeGnssHal); Injector injector = new TestInjector(mContext); mGnssNative = spy(Objects.requireNonNull( GnssNative.create(injector, mMockConfiguration))); doReturn(true).when(mGnssNative).init(); GnssCapabilities gnssCapabilities = new GnssCapabilities.Builder().setHasScheduling( true).build(); doReturn(gnssCapabilities).when(mGnssNative).getCapabilities(); mTestProvider = new GnssLocationProvider(mContext, mGnssNative, mGnssMetrics); mGnssNative.register(); } @After public void tearDown() { LocalServices.removeServiceForTest(LocationManagerInternal.class); LocalServices.removeServiceForTest(TimeDetectorInternal.class); } @Test public void testStartNavigating() { ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis( 0).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).start(); } @Test public void testUpdateRequirements_sameRequest() { mSetFlagsRule.enableFlags(Flags.FLAG_GNSS_CALL_STOP_BEFORE_SET_POSITION_MODE); ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis( 0).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).start(); // set the same request mTestProvider.onSetRequest(providerRequest); verify(mGnssNative, never()).stop(); verify(mGnssNative, times(1)).start(); } @Test public void testUpdateRequirements_differentRequest() { mSetFlagsRule.enableFlags(Flags.FLAG_GNSS_CALL_STOP_BEFORE_SET_POSITION_MODE); ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis( 0).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).start(); // set a different request providerRequest = new ProviderRequest.Builder().setIntervalMillis(2000).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).stop(); verify(mGnssNative, times(2)).start(); } } Loading
location/java/android/location/flags/gnss.aconfig +8 −1 Original line number Diff line number Diff line Loading @@ -6,3 +6,10 @@ flag { description: "Flag for GNSS API for NavIC L1" bug: "302199306" } flag { name: "gnss_call_stop_before_set_position_mode" namespace: "location" description: "Flag for calling stop() before setPositionMode()" bug: "306874828" }
services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +43 −9 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; import android.location.LocationResult; import android.location.flags.Flags; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; import android.location.util.identity.CallerIdentity; Loading Loading @@ -1048,11 +1049,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements stopBatching(); if (mStarted && mGnssNative.getCapabilities().hasScheduling()) { if (Flags.gnssCallStopBeforeSetPositionMode()) { GnssPositionMode positionMode = new GnssPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval, /* preferredAccuracy= */ 0, /* preferredTime= */ 0, mProviderRequest.isLowPower()); if (!positionMode.equals(mLastPositionMode)) { stopNavigating(); startNavigating(); } } else { // change period and/or lowPowerMode if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval, mProviderRequest.isLowPower())) { Log.e(TAG, "set_position_mode failed in updateRequirements"); } } } else if (!mStarted) { // start GPS startNavigating(); Loading Loading @@ -1234,12 +1247,33 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000; if (Flags.gnssCallStopBeforeSetPositionMode()) { boolean success = mGnssNative.setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, /* preferredAccuracy= */ 0, /* preferredTime= */ 0, mProviderRequest.isLowPower()); if (success) { mLastPositionMode = new GnssPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, /* preferredAccuracy= */ 0, /* preferredTime= */ 0, mProviderRequest.isLowPower()); } else { mLastPositionMode = null; setStarted(false); Log.e(TAG, "set_position_mode failed in startNavigating()"); return; } } else { if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, mProviderRequest.isLowPower())) { setStarted(false); Log.e(TAG, "set_position_mode failed in startNavigating()"); return; } } if (!mGnssNative.start()) { setStarted(false); Log.e(TAG, "native_start failed in startNavigating()"); Loading
services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssLocationProviderTest.java 0 → 100644 +179 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.AlarmManager; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; import android.location.GnssCapabilities; import android.location.LocationManager; import android.location.LocationManagerInternal; import android.location.flags.Flags; import android.location.provider.ProviderRequest; import android.os.PowerManager; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.telephony.TelephonyManager; import androidx.test.runner.AndroidJUnit4; import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.location.gnss.hal.FakeGnssHal; import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import com.android.server.location.injector.TestInjector; import com.android.server.timedetector.TimeDetectorInternal; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.quality.Strictness; import java.util.HashSet; import java.util.Objects; import java.util.Set; @Presubmit @androidx.test.filters.SmallTest @RunWith(AndroidJUnit4.class) public class GnssLocationProviderTest { @Rule public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) .setStrictness(Strictness.WARN) .mockStatic(Settings.Global.class) .build(); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private @Mock Context mContext; private @Mock LocationManagerInternal mLocationManagerInternal; private @Mock LocationManager mLocationManager; private @Mock TimeDetectorInternal mTimeDetectorInternal; private @Mock GnssConfiguration mMockConfiguration; private @Mock GnssMetrics mGnssMetrics; private @Mock PowerManager mPowerManager; private @Mock TelephonyManager mTelephonyManager; private @Mock AppOpsManager mAppOpsManager; private @Mock AlarmManager mAlarmManager; private @Mock PowerManager.WakeLock mWakeLock; private @Mock ContentResolver mContentResolver; private @Mock UserManager mUserManager; private @Mock UserHandle mUserHandle; private Set<UserHandle> mUserHandleSet = new HashSet<>(); private GnssNative mGnssNative; private GnssLocationProvider mTestProvider; @Before public void setUp() { MockitoAnnotations.initMocks(this); doReturn("mypackage").when(mContext).getPackageName(); doReturn("attribution").when(mContext).getAttributionTag(); doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class); doReturn(mPowerManager).when(mContext).getSystemService("power"); doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); doReturn(mAlarmManager).when(mContext).getSystemService(Context.ALARM_SERVICE); doReturn(mLocationManager).when(mContext).getSystemService(LocationManager.class); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); mUserHandleSet.add(mUserHandle); doReturn(true).when(mLocationManager).isLocationEnabledForUser(eq(mUserHandle)); doReturn(mUserHandleSet).when(mUserManager).getVisibleUsers(); doReturn(mContentResolver).when(mContext).getContentResolver(); doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString()); LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal); LocalServices.addService(TimeDetectorInternal.class, mTimeDetectorInternal); FakeGnssHal fakeGnssHal = new FakeGnssHal(); GnssNative.setGnssHalForTest(fakeGnssHal); Injector injector = new TestInjector(mContext); mGnssNative = spy(Objects.requireNonNull( GnssNative.create(injector, mMockConfiguration))); doReturn(true).when(mGnssNative).init(); GnssCapabilities gnssCapabilities = new GnssCapabilities.Builder().setHasScheduling( true).build(); doReturn(gnssCapabilities).when(mGnssNative).getCapabilities(); mTestProvider = new GnssLocationProvider(mContext, mGnssNative, mGnssMetrics); mGnssNative.register(); } @After public void tearDown() { LocalServices.removeServiceForTest(LocationManagerInternal.class); LocalServices.removeServiceForTest(TimeDetectorInternal.class); } @Test public void testStartNavigating() { ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis( 0).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).start(); } @Test public void testUpdateRequirements_sameRequest() { mSetFlagsRule.enableFlags(Flags.FLAG_GNSS_CALL_STOP_BEFORE_SET_POSITION_MODE); ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis( 0).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).start(); // set the same request mTestProvider.onSetRequest(providerRequest); verify(mGnssNative, never()).stop(); verify(mGnssNative, times(1)).start(); } @Test public void testUpdateRequirements_differentRequest() { mSetFlagsRule.enableFlags(Flags.FLAG_GNSS_CALL_STOP_BEFORE_SET_POSITION_MODE); ProviderRequest providerRequest = new ProviderRequest.Builder().setIntervalMillis( 0).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).start(); // set a different request providerRequest = new ProviderRequest.Builder().setIntervalMillis(2000).build(); mTestProvider.onSetRequest(providerRequest); verify(mGnssNative).stop(); verify(mGnssNative, times(2)).start(); } }