1a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu/* 2a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * Copyright (C) 2016 The Android Open Source Project 3a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * 4a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * you may not use this file except in compliance with the License. 6a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * You may obtain a copy of the License at 7a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * 8a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * http://www.apache.org/licenses/LICENSE-2.0 9a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * 10a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * Unless required by applicable law or agreed to in writing, software 11a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * distributed under the License is distributed on an "AS IS" BASIS, 12a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * See the License for the specific language governing permissions and 14a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu * limitations under the License. 15a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu */ 16a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 17a35b5539a95342799a18e95616c5e5751a198e4cPeng Xupackage com.android.server; 18a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 19a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.content.BroadcastReceiver; 20a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.content.Context; 21a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.content.Intent; 22a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.content.IntentFilter; 231cfde25e4019bc050c7f030896825fd90d69baf5Peng Xuimport android.hardware.GeomagneticField; 24a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.hardware.Sensor; 251cfde25e4019bc050c7f030896825fd90d69baf5Peng Xuimport android.hardware.SensorAdditionalInfo; 26a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.hardware.SensorEvent; 27a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.hardware.SensorEventListener; 28a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.hardware.SensorManager; 291cfde25e4019bc050c7f030896825fd90d69baf5Peng Xuimport android.location.Location; 301cfde25e4019bc050c7f030896825fd90d69baf5Peng Xuimport android.location.LocationListener; 311cfde25e4019bc050c7f030896825fd90d69baf5Peng Xuimport android.location.LocationManager; 321cfde25e4019bc050c7f030896825fd90d69baf5Peng Xuimport android.os.Bundle; 33a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.os.SystemClock; 34a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.os.SystemProperties; 35a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.os.UserHandle; 36a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.provider.Settings; 37a35b5539a95342799a18e95616c5e5751a198e4cPeng Xuimport android.util.Slog; 38a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 391cfde25e4019bc050c7f030896825fd90d69baf5Peng Xupublic class SensorNotificationService extends SystemService 401cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu implements SensorEventListener, LocationListener { 411cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private static final boolean DBG = false; 42a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu private static final String TAG = "SensorNotificationService"; 43a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 441cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private static final long MINUTE_IN_MS = 60 * 1000; 451cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private static final long KM_IN_M = 1000; 461cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 471cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private static final long LOCATION_MIN_TIME = 30 * MINUTE_IN_MS; 481cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private static final long LOCATION_MIN_DISTANCE = 100 * KM_IN_M; 491cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 501cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private static final String PROPERTY_USE_MOCKED_LOCATION = 511cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu "sensor.notification.use_mocked"; // max key length is 32 521cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 531cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private static final long MILLIS_2010_1_1 = 1262358000000l; 541cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 551cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private Context mContext; 56a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu private SensorManager mSensorManager; 571cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private LocationManager mLocationManager; 58a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu private Sensor mMetaSensor; 59a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 601cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu // for rate limiting 611cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME; 621cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 63a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu public SensorNotificationService(Context context) { 64a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu super(context); 65a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu mContext = context; 66a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 67a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 68a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu public void onStart() { 69a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu LocalServices.addService(SensorNotificationService.class, this); 70a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 71a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 72a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu public void onBootPhase(int phase) { 73a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 74a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); 75a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu mMetaSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DYNAMIC_SENSOR_META); 76a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu if (mMetaSensor == null) { 77a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu if (DBG) Slog.d(TAG, "Cannot obtain dynamic meta sensor, not supported."); 78a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } else { 79a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu mSensorManager.registerListener(this, mMetaSensor, 80a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu SensorManager.SENSOR_DELAY_FASTEST); 81a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 82a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 831cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 841cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (phase == PHASE_BOOT_COMPLETED) { 851cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu // LocationManagerService is initialized after PHASE_THIRD_PARTY_APPS_CAN_START 861cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu mLocationManager = 871cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 881cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (mLocationManager == null) { 891cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (DBG) Slog.d(TAG, "Cannot obtain location service."); 901cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } else { 911cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu mLocationManager.requestLocationUpdates( 921cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu LocationManager.PASSIVE_PROVIDER, 931cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu LOCATION_MIN_TIME, 941cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu LOCATION_MIN_DISTANCE, 951cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu this); 961cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 971cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 98a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 99a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 100a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu private void broadcastDynamicSensorChanged() { 101a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu Intent i = new Intent(Intent.ACTION_DYNAMIC_SENSOR_CHANGED); 102a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); // avoid waking up manifest receivers 103a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu mContext.sendBroadcastAsUser(i, UserHandle.ALL); 1041cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (DBG) Slog.d(TAG, "dynamic sensor broadcast sent"); 105a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 106a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 107a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu @Override 108a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu public void onSensorChanged(SensorEvent event) { 109a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu if (event.sensor == mMetaSensor) { 110a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu broadcastDynamicSensorChanged(); 111a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 112a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 113a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 114a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu @Override 1151cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu public void onLocationChanged(Location location) { 1161cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (DBG) Slog.d(TAG, String.format( 1171cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu "Location is (%f, %f), h %f, acc %f, mocked %b", 1181cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu location.getLatitude(), location.getLongitude(), 1191cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu location.getAltitude(), location.getAccuracy(), 1201cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu location.isFromMockProvider())); 1211cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 1221cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu // lat long == 0 usually means invalid location 1231cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (location.getLatitude() == 0 && location.getLongitude() == 0) { 1241cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu return; 1251cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 1261cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 1271cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu // update too often, ignore 1281cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (SystemClock.elapsedRealtime() - mLocalGeomagneticFieldUpdateTime < 10 * MINUTE_IN_MS) { 1291cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu return; 1301cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 1311cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 1321cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu long time = System.currentTimeMillis(); 1331cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu // Mocked location should not be used. Except in test, only use mocked location 1341cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu // Wrong system clock also gives bad values so ignore as well. 1351cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (useMockedLocation() == location.isFromMockProvider() || time < MILLIS_2010_1_1) { 1361cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu return; 1371cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 1381cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 1391cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu GeomagneticField field = new GeomagneticField( 1401cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu (float) location.getLatitude(), (float) location.getLongitude(), 1411cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu (float) location.getAltitude(), time); 1421cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (DBG) Slog.d(TAG, String.format( 1431cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu "Nominal mag field, norm %fuT, decline %f deg, incline %f deg", 1441cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu field.getFieldStrength() / 1000, field.getDeclination(), field.getInclination())); 1451cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 1461cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu try { 1471cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu SensorAdditionalInfo info = SensorAdditionalInfo.createLocalGeomagneticField( 1481cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu field.getFieldStrength() / 1000, // convert from nT to uT 1491cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu (float)(field.getDeclination() * Math.PI / 180), // from degree to rad 1501cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu (float)(field.getInclination() * Math.PI / 180)); // from degree to rad 1511cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu if (info != null) { 1521cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu mSensorManager.setOperationParameter(info); 1531cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu mLocalGeomagneticFieldUpdateTime = SystemClock.elapsedRealtime(); 1541cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 1551cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } catch (IllegalArgumentException e) { 1561cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu Slog.e(TAG, "Invalid local geomagnetic field, ignore."); 1571cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 1581cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu } 1591cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu 1601cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu @Override 1611cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu public void onAccuracyChanged(Sensor sensor, int accuracy) {} 1621cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu @Override 1631cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu public void onStatusChanged(String provider, int status, Bundle extras) {} 1641cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu @Override 1651cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu public void onProviderEnabled(String provider) {} 1661cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu @Override 1671cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu public void onProviderDisabled(String provider) {} 168a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 1691cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu private boolean useMockedLocation() { 1701cfde25e4019bc050c7f030896825fd90d69baf5Peng Xu return "false".equals(System.getProperty(PROPERTY_USE_MOCKED_LOCATION, "false")); 171a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu } 172a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu} 173a35b5539a95342799a18e95616c5e5751a198e4cPeng Xu 174