Switch GnssTimeUpdateService to internal service
Switch GnssTimeUpdateService to calling TimeDetectorInternal, not TimeDetectorService over AIDL. TimeDetectorInternal was recently added for NetworkTimeUpdateService and this commit follows the same pattern. Bug: 219693030 Bug: 222295093 Test: atest services/tests/servicestests/src/com/android/server/timedetector/ Test: atest services/tests/servicestests/src/com/android/server/timezonedetector/ Test: atest core/tests/coretests/src/android/app/timedetector/ Change-Id: I916cf878469280e6c9498baf2cf930e140c3a386
This commit is contained in:
@@ -1,19 +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 android.app.timedetector;
|
||||
|
||||
parcelable GnssTimeSuggestion;
|
||||
@@ -20,7 +20,6 @@ import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.time.ITimeDetectorListener;
|
||||
import android.app.time.TimeCapabilitiesAndConfig;
|
||||
import android.app.time.TimeConfiguration;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
import android.app.timedetector.TimePoint;
|
||||
@@ -46,7 +45,6 @@ interface ITimeDetectorService {
|
||||
boolean updateConfiguration(in TimeConfiguration timeConfiguration);
|
||||
|
||||
void suggestExternalTime(in ExternalTimeSuggestion timeSuggestion);
|
||||
void suggestGnssTime(in GnssTimeSuggestion timeSuggestion);
|
||||
boolean suggestManualTime(in ManualTimeSuggestion timeSuggestion);
|
||||
void suggestTelephonyTime(in TelephonyTimeSuggestion timeSuggestion);
|
||||
|
||||
|
||||
@@ -111,12 +111,4 @@ public interface TimeDetector {
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
|
||||
boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
|
||||
|
||||
/**
|
||||
* Suggests the time according to a gnss time source.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.SET_TIME)
|
||||
void suggestGnssTime(GnssTimeSuggestion timeSuggestion);
|
||||
}
|
||||
|
||||
@@ -62,16 +62,4 @@ public final class TimeDetectorImpl implements TimeDetector {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "suggestGnssTime called: " + timeSuggestion);
|
||||
}
|
||||
try {
|
||||
mITimeDetectorService.suggestGnssTime(timeSuggestion);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timedetector;
|
||||
package com.android.server.timedetector;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.app.timedetector.TimeSuggestionHelper;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.TimestampedValue;
|
||||
|
||||
@@ -30,23 +29,8 @@ import java.util.Objects;
|
||||
* A time signal from a GNSS source.
|
||||
*
|
||||
* <p>See {@link TimeSuggestionHelper} for property information.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class GnssTimeSuggestion implements Parcelable {
|
||||
|
||||
public static final @NonNull Creator<GnssTimeSuggestion> CREATOR =
|
||||
new Creator<GnssTimeSuggestion>() {
|
||||
public GnssTimeSuggestion createFromParcel(Parcel in) {
|
||||
TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
|
||||
GnssTimeSuggestion.class, in);
|
||||
return new GnssTimeSuggestion(helper);
|
||||
}
|
||||
|
||||
public GnssTimeSuggestion[] newArray(int size) {
|
||||
return new GnssTimeSuggestion[size];
|
||||
}
|
||||
};
|
||||
public final class GnssTimeSuggestion {
|
||||
|
||||
@NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
|
||||
|
||||
@@ -58,16 +42,6 @@ public final class GnssTimeSuggestion implements Parcelable {
|
||||
mTimeSuggestionHelper = Objects.requireNonNull(helper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public TimestampedValue<Long> getUnixEpochTime() {
|
||||
return mTimeSuggestionHelper.getUnixEpochTime();
|
||||
@@ -19,8 +19,6 @@ package com.android.server.timedetector;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.TimeDetector;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
@@ -42,12 +40,13 @@ import com.android.server.SystemService;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Monitors the GNSS time.
|
||||
*
|
||||
* <p>When available, the time is always suggested to the {@link
|
||||
* com.android.server.timedetector.TimeDetectorService} where it may be used to set the device
|
||||
* com.android.server.timedetector.TimeDetectorInternal} where it may be used to set the device
|
||||
* system clock, depending on user settings and what other signals are available.
|
||||
*/
|
||||
public final class GnssTimeUpdateService extends Binder {
|
||||
@@ -66,7 +65,16 @@ public final class GnssTimeUpdateService extends Binder {
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mService = new GnssTimeUpdateService(getContext());
|
||||
Context context = getContext().createAttributionContext(ATTRIBUTION_TAG);
|
||||
AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
|
||||
LocationManager locationManager = context.getSystemService(LocationManager.class);
|
||||
LocationManagerInternal locationManagerInternal =
|
||||
LocalServices.getService(LocationManagerInternal.class);
|
||||
TimeDetectorInternal timeDetectorInternal =
|
||||
LocalServices.getService(TimeDetectorInternal.class);
|
||||
|
||||
mService = new GnssTimeUpdateService(context, alarmManager, locationManager,
|
||||
locationManagerInternal, timeDetectorInternal);
|
||||
publishBinderService("gnss_time_update_service", mService);
|
||||
}
|
||||
|
||||
@@ -88,7 +96,7 @@ public final class GnssTimeUpdateService extends Binder {
|
||||
private static final String ATTRIBUTION_TAG = "GnssTimeUpdateService";
|
||||
|
||||
private final Context mContext;
|
||||
private final TimeDetector mTimeDetector;
|
||||
private final TimeDetectorInternal mTimeDetectorInternal;
|
||||
private final AlarmManager mAlarmManager;
|
||||
private final LocationManager mLocationManager;
|
||||
private final LocationManagerInternal mLocationManagerInternal;
|
||||
@@ -98,12 +106,15 @@ public final class GnssTimeUpdateService extends Binder {
|
||||
@Nullable private TimestampedValue<Long> mLastSuggestedGnssTime;
|
||||
|
||||
@VisibleForTesting
|
||||
GnssTimeUpdateService(@NonNull Context context) {
|
||||
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
|
||||
mTimeDetector = mContext.getSystemService(TimeDetector.class);
|
||||
mLocationManager = mContext.getSystemService(LocationManager.class);
|
||||
mAlarmManager = mContext.getSystemService(AlarmManager.class);
|
||||
mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
|
||||
GnssTimeUpdateService(@NonNull Context context, @NonNull AlarmManager alarmManager,
|
||||
@NonNull LocationManager locationManager,
|
||||
@NonNull LocationManagerInternal locationManagerInternal,
|
||||
@NonNull TimeDetectorInternal timeDetectorInternal) {
|
||||
mContext = Objects.requireNonNull(context);
|
||||
mAlarmManager = Objects.requireNonNull(alarmManager);
|
||||
mLocationManager = Objects.requireNonNull(locationManager);
|
||||
mLocationManagerInternal = Objects.requireNonNull(locationManagerInternal);
|
||||
mTimeDetectorInternal = Objects.requireNonNull(timeDetectorInternal);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,7 +202,7 @@ public final class GnssTimeUpdateService extends Binder {
|
||||
mLastSuggestedGnssTime = timeSignal;
|
||||
|
||||
GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
|
||||
mTimeDetector.suggestGnssTime(timeSuggestion);
|
||||
mTimeDetectorInternal.suggestGnssTime(timeSuggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,4 +29,7 @@ public interface TimeDetectorInternal {
|
||||
|
||||
/** Used to pass new network time suggestions to the time detector. */
|
||||
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal);
|
||||
|
||||
/** Used to pass new GNSS time suggestions to the time detector. */
|
||||
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal);
|
||||
}
|
||||
@@ -46,4 +46,11 @@ public class TimeDetectorInternalImpl implements TimeDetectorInternal {
|
||||
|
||||
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
|
||||
Objects.requireNonNull(timeSignal);
|
||||
|
||||
mHandler.post(() -> mTimeDetectorStrategy.suggestGnssTime(timeSignal));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.time.ITimeDetectorListener;
|
||||
import android.app.time.TimeCapabilitiesAndConfig;
|
||||
import android.app.time.TimeConfiguration;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ITimeDetectorService;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
@@ -301,8 +300,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
|
||||
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
|
||||
enforceSuggestGnssTimePermission();
|
||||
Objects.requireNonNull(timeSignal);
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIG
|
||||
|
||||
import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.time.TimeConfiguration;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
import android.os.ShellCommand;
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
import android.os.TimestampedValue;
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
import android.content.Context;
|
||||
|
||||
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.timedetector;
|
||||
package com.android.server.timedetector;
|
||||
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
|
||||
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
|
||||
import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
|
||||
import static com.android.server.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
@@ -55,17 +53,6 @@ public class GnssTimeSuggestionTest {
|
||||
assertEquals(one, two);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
GnssTimeSuggestion suggestion = new GnssTimeSuggestion(ARBITRARY_TIME);
|
||||
assertRoundTripParcelable(suggestion);
|
||||
|
||||
// DebugInfo should also be stored (but is not checked by equals()
|
||||
suggestion.addDebugInfo("This is debug info");
|
||||
GnssTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
|
||||
assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testParseCommandLineArg_noReferenceTime() {
|
||||
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
|
||||
@@ -19,15 +19,12 @@ package com.android.server.timedetector;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyLong;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.TimeDetector;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
@@ -56,10 +53,10 @@ public final class GnssTimeUpdateServiceTest {
|
||||
private static final long ELAPSED_REALTIME_MS = ELAPSED_REALTIME_NS / 1_000_000L;
|
||||
|
||||
@Mock private Context mMockContext;
|
||||
@Mock private TimeDetector mMockTimeDetector;
|
||||
@Mock private AlarmManager mMockAlarmManager;
|
||||
@Mock private LocationManager mMockLocationManager;
|
||||
@Mock private LocationManagerInternal mLocationManagerInternal;
|
||||
@Mock private LocationManagerInternal mMockLocationManagerInternal;
|
||||
@Mock private TimeDetectorInternal mMockTimeDetectorInternal;
|
||||
|
||||
private GnssTimeUpdateService mGnssTimeUpdateService;
|
||||
|
||||
@@ -67,31 +64,12 @@ public final class GnssTimeUpdateServiceTest {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mMockContext.createAttributionContext(anyString()))
|
||||
.thenReturn(mMockContext);
|
||||
|
||||
when(mMockContext.getSystemServiceName(TimeDetector.class))
|
||||
.thenReturn((TimeDetector.class).getSimpleName());
|
||||
when(mMockContext.getSystemService(TimeDetector.class))
|
||||
.thenReturn(mMockTimeDetector);
|
||||
|
||||
when(mMockContext.getSystemServiceName(LocationManager.class))
|
||||
.thenReturn((LocationManager.class).getSimpleName());
|
||||
when(mMockContext.getSystemService(LocationManager.class))
|
||||
.thenReturn(mMockLocationManager);
|
||||
|
||||
when(mMockContext.getSystemServiceName(AlarmManager.class))
|
||||
.thenReturn((AlarmManager.class).getSimpleName());
|
||||
when(mMockContext.getSystemService(AlarmManager.class))
|
||||
.thenReturn(mMockAlarmManager);
|
||||
|
||||
when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
|
||||
.thenReturn(true);
|
||||
|
||||
LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
|
||||
|
||||
mGnssTimeUpdateService =
|
||||
new GnssTimeUpdateService(mMockContext);
|
||||
mGnssTimeUpdateService = new GnssTimeUpdateService(
|
||||
mMockContext, mMockAlarmManager, mMockLocationManager, mMockLocationManagerInternal,
|
||||
mMockTimeDetectorInternal);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -105,7 +83,7 @@ public final class GnssTimeUpdateServiceTest {
|
||||
ELAPSED_REALTIME_MS, GNSS_TIME);
|
||||
GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
|
||||
LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
|
||||
doReturn(locationTime).when(mLocationManagerInternal).getGnssTimeMillis();
|
||||
doReturn(locationTime).when(mMockLocationManagerInternal).getGnssTimeMillis();
|
||||
|
||||
mGnssTimeUpdateService.requestGnssTimeUpdates();
|
||||
|
||||
@@ -124,7 +102,7 @@ public final class GnssTimeUpdateServiceTest {
|
||||
locationListener.onLocationChanged(location);
|
||||
|
||||
verify(mMockLocationManager).removeUpdates(locationListener);
|
||||
verify(mMockTimeDetector).suggestGnssTime(timeSuggestion);
|
||||
verify(mMockTimeDetectorInternal).suggestGnssTime(timeSuggestion);
|
||||
verify(mMockAlarmManager).set(
|
||||
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
|
||||
anyLong(),
|
||||
@@ -135,7 +113,7 @@ public final class GnssTimeUpdateServiceTest {
|
||||
|
||||
@Test
|
||||
public void testLocationListenerOnLocationChanged_nullLocationTime_doesNotSuggestGnssTime() {
|
||||
doReturn(null).when(mLocationManagerInternal).getGnssTimeMillis();
|
||||
doReturn(null).when(mMockLocationManagerInternal).getGnssTimeMillis();
|
||||
|
||||
mGnssTimeUpdateService.requestGnssTimeUpdates();
|
||||
|
||||
@@ -154,7 +132,7 @@ public final class GnssTimeUpdateServiceTest {
|
||||
locationListener.onLocationChanged(location);
|
||||
|
||||
verify(mMockLocationManager).removeUpdates(locationListener);
|
||||
verify(mMockTimeDetector, never()).suggestGnssTime(any());
|
||||
verify(mMockTimeDetectorInternal, never()).suggestGnssTime(any());
|
||||
verify(mMockAlarmManager).set(
|
||||
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
|
||||
anyLong(),
|
||||
|
||||
@@ -77,4 +77,20 @@ public class TimeDetectorInternalImplTest {
|
||||
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
|
||||
return new NetworkTimeSuggestion(timeValue, 123);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestGnssTime() throws Exception {
|
||||
GnssTimeSuggestion gnssTimeSuggestion = createGnssTimeSuggestion();
|
||||
|
||||
mTimeDetectorInternal.suggestGnssTime(gnssTimeSuggestion);
|
||||
mTestHandler.assertTotalMessagesEnqueued(1);
|
||||
|
||||
mTestHandler.waitForMessagesToBeProcessed();
|
||||
mFakeTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
|
||||
}
|
||||
|
||||
private static GnssTimeSuggestion createGnssTimeSuggestion() {
|
||||
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
|
||||
return new GnssTimeSuggestion(timeValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import static org.mockito.Mockito.when;
|
||||
import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.time.ITimeDetectorListener;
|
||||
import android.app.time.TimeConfiguration;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
import android.app.timedetector.TimePoint;
|
||||
|
||||
@@ -29,7 +29,6 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.timedetector.GnssTimeSuggestion;
|
||||
import android.app.timedetector.ManualTimeSuggestion;
|
||||
import android.app.timedetector.TelephonyTimeSuggestion;
|
||||
import android.os.TimestampedValue;
|
||||
|
||||
Reference in New Issue
Block a user