diff options
Diffstat (limited to 'services/java/com/android/server/DockObserver.java')
-rw-r--r-- | services/java/com/android/server/DockObserver.java | 519 |
1 files changed, 2 insertions, 517 deletions
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 28236f0..bee8872 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -16,53 +16,24 @@ package com.android.server; -import android.app.Activity; -import android.app.ActivityManagerNative; -import android.app.AlarmManager; -import android.app.IActivityManager; -import android.app.IUiModeManager; -import android.app.KeyguardManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.StatusBarManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Configuration; -import android.location.Criteria; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.location.LocationProvider; -import android.os.Binder; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; -import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.UEventObserver; import android.provider.Settings; import android.server.BluetoothService; -import android.text.format.DateUtils; -import android.text.format.Time; import android.util.Log; import android.util.Slog; -import com.android.internal.R; -import com.android.internal.app.DisableCarModeActivity; -import com.android.internal.widget.LockPatternUtils; - import java.io.FileNotFoundException; import java.io.FileReader; @@ -76,187 +47,22 @@ class DockObserver extends UEventObserver { private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock"; private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state"; - private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL"; - private static final int MSG_DOCK_STATE = 0; - private static final int MSG_UPDATE_TWILIGHT = 1; - private static final int MSG_ENABLE_LOCATION_UPDATES = 2; - - public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_MASK >> 4; - public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4; - public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4; - - private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; - private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS; - private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; - - private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE"; private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; - private int mNightMode = MODE_NIGHT_NO; - private boolean mCarModeEnabled = false; - private boolean mSystemReady; private final Context mContext; private PowerManagerService mPowerManager; - private NotificationManager mNotificationManager; - - private KeyguardManager.KeyguardLock mKeyguardLock; - private boolean mKeyguardDisabled; - private LockPatternUtils mLockPatternUtils; - - private AlarmManager mAlarmManager; - - private LocationManager mLocationManager; - private Location mLocation; - private StatusBarManager mStatusBarManager; - - // The broadcast receiver which receives the result of the ordered broadcast sent when - // the dock state changes. The original ordered broadcast is sent with an initial result - // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., - // to RESULT_CANCELED, then the intent to start a dock app will not be sent. - private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getResultCode() != Activity.RESULT_OK) { - return; - } - - // Launch a dock activity - String category; - if (mCarModeEnabled) { - // Only launch car home when car mode is enabled. - category = Intent.CATEGORY_CAR_DOCK; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { - category = Intent.CATEGORY_DESK_DOCK; - } else { - category = null; - } - if (category != null) { - intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(category); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - try { - mContext.startActivity(intent); - } catch (ActivityNotFoundException e) { - Slog.w(TAG, e.getCause()); - } - } - } - }; - - private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); - } - } - }; - - // A LocationListener to initialize the network location provider. The location updates - // are handled through the passive location provider. - private final LocationListener mEmptyLocationListener = new LocationListener() { - public void onLocationChanged(Location location) { - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - }; - - private final LocationListener mLocationListener = new LocationListener() { - - public void onLocationChanged(Location location) { - final boolean hasMoved = hasMoved(location); - if (hasMoved || hasBetterAccuracy(location)) { - synchronized (this) { - mLocation = location; - } - if (hasMoved && mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); - } - } - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - - private boolean hasBetterAccuracy(Location location) { - if (location == null) { - return false; - } - if (mLocation == null) { - return true; - } - return location.getAccuracy() < mLocation.getAccuracy(); - } - - /* - * The user has moved if the accuracy circles of the two locations - * don't overlap. - */ - private boolean hasMoved(Location location) { - if (location == null) { - return false; - } - if (mLocation == null) { - return true; - } - - /* if new location is older than the current one, the devices hasn't - * moved. - */ - if (location.getTime() < mLocation.getTime()) { - return false; - } - - /* Get the distance between the two points */ - float distance = mLocation.distanceTo(location); - - /* Get the total accuracy radius for both locations */ - float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy(); - - /* If the distance is greater than the combined accuracy of the two - * points then they can't overlap and hence the user has moved. - */ - return distance >= totalAccuracy; - } - }; public DockObserver(Context context, PowerManagerService pm) { mContext = context; mPowerManager = pm; - mLockPatternUtils = new LockPatternUtils(context); init(); // set initial status - ServiceManager.addService("uimode", mBinder); - - mAlarmManager = - (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - mLocationManager = - (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); - mContext.registerReceiver(mTwilightUpdateReceiver, - new IntentFilter(ACTION_UPDATE_NIGHT_MODE)); - startObserving(DOCK_UEVENT_MATCH); } @@ -272,14 +78,6 @@ class DockObserver extends UEventObserver { if (newState != mDockState) { mPreviousDockState = mDockState; mDockState = newState; - boolean carModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - if (mCarModeEnabled != carModeEnabled) { - try { - setCarMode(carModeEnabled); - } catch (RemoteException e1) { - Slog.w(TAG, "Unable to change car mode.", e1); - } - } if (mSystemReady) { // Don't force screen on when undocking from the desk dock. // The change in power state will do this anyway. @@ -315,24 +113,11 @@ class DockObserver extends UEventObserver { void systemReady() { synchronized (this) { - KeyguardManager keyguardManager = - (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); - mKeyguardLock = keyguardManager.newKeyguardLock(TAG); - - final boolean enableCarMode = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - if (enableCarMode) { - try { - setCarMode(enableCarMode); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change car mode.", e); - } - } // don't bother broadcasting undocked here if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { update(); } mSystemReady = true; - mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); } } @@ -341,10 +126,6 @@ class DockObserver extends UEventObserver { } private final Handler mHandler = new Handler() { - - boolean mPassiveListenerEnabled; - boolean mNetworkListenerEnabled; - @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -362,17 +143,7 @@ class DockObserver extends UEventObserver { // Pack up the values and broadcast them to everyone Intent intent = new Intent(Intent.ACTION_DOCK_EVENT); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) { - // Pretend to be in DOCK_STATE_CAR. - intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR); - } else if (!mCarModeEnabled && mDockState == Intent.EXTRA_DOCK_STATE_CAR) { - // Pretend to be in DOCK_STATE_UNDOCKED. - intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); - } else { - intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); - } - intent.putExtra(Intent.EXTRA_PHYSICAL_DOCK_STATE, mDockState); - intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled); + intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); // Check if this is Bluetooth Dock String address = BluetoothService.readDockBluetoothAddress(); @@ -415,296 +186,10 @@ class DockObserver extends UEventObserver { } } - // Send the ordered broadcast; the result receiver will receive after all - // broadcasts have been sent. If any broadcast receiver changes the result - // code from the initial value of RESULT_OK, then the result receiver will - // not launch the corresponding dock application. This gives apps a chance - // to override the behavior and stay in their app even when the device is - // placed into a dock. - mContext.sendStickyOrderedBroadcast( - intent, mResultReceiver, null, Activity.RESULT_OK, null, null); - - } - break; - case MSG_UPDATE_TWILIGHT: - synchronized (this) { - if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) { - try { - DockObserver.this.updateTwilight(); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change night mode.", e); - } - } - } - break; - case MSG_ENABLE_LOCATION_UPDATES: - // enable passive provider to receive updates from location fixes (gps - // and network). - boolean passiveLocationEnabled; - try { - passiveLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if passive location provider - // does not exist or is not yet installed. - passiveLocationEnabled = false; - } - if (!mPassiveListenerEnabled && passiveLocationEnabled) { - mPassiveListenerEnabled = true; - mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener); - } - // enable network provider to receive at least location updates for a given - // distance. - boolean networkLocationEnabled; - try { - networkLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if network location provider - // does not exist or is not yet installed. - networkLocationEnabled = false; - } - if (!mNetworkListenerEnabled && networkLocationEnabled) { - mNetworkListenerEnabled = true; - mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, - LOCATION_UPDATE_MS, 0, mEmptyLocationListener); - - retrieveLocation(); - if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) { - try { - DockObserver.this.updateTwilight(); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change night mode.", e); - } - } - } - if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { - long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL); - interval *= 1.5; - if (interval == 0) { - interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; - } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { - interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; - } - Bundle bundle = new Bundle(); - bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval); - Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES); - newMsg.setData(bundle); - mHandler.sendMessageDelayed(newMsg, interval); + mContext.sendStickyBroadcast(intent); } break; } } - - private void retrieveLocation() { - final Location gpsLocation = - mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); - Location location; - Criteria criteria = new Criteria(); - criteria.setSpeedRequired(false); - criteria.setAltitudeRequired(false); - criteria.setBearingRequired(false); - criteria.setAccuracy(Criteria.ACCURACY_FINE); - final String bestProvider = mLocationManager.getBestProvider(criteria, true); - location = mLocationManager.getLastKnownLocation(bestProvider); - // In the case there is no location available (e.g. GPS fix or network location - // is not available yet), the longitude of the location is estimated using the timezone, - // latitude and accuracy are set to get a good average. - if (location == null) { - Time currentTime = new Time(); - currentTime.set(System.currentTimeMillis()); - double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * - (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); - location = new Location("fake"); - location.setLongitude(lngOffset); - location.setLatitude(0); - location.setAccuracy(417000.0f); - location.setTime(System.currentTimeMillis()); - } - synchronized (this) { - mLocation = location; - } - } - }; - - private void adjustStatusBarCarMode() { - if (mStatusBarManager == null) { - mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - - // Fear not: StatusBarService manages a list of requests to disable - // features of the status bar; these are ORed together to form the - // active disabled list. So if (for example) the device is locked and - // the status bar should be totally disabled, the calls below will - // have no effect until the device is unlocked. - if (mStatusBarManager != null) { - long ident = Binder.clearCallingIdentity(); - mStatusBarManager.disable(mCarModeEnabled - ? StatusBarManager.DISABLE_NOTIFICATION_TICKER - : StatusBarManager.DISABLE_NONE); - Binder.restoreCallingIdentity(ident); - } - - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - } - - if (mNotificationManager != null) { - long ident = Binder.clearCallingIdentity(); - if (mCarModeEnabled) { - Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class); - - Notification n = new Notification(); - n.icon = R.drawable.stat_notify_car_mode; - n.defaults = Notification.DEFAULT_LIGHTS; - n.flags = Notification.FLAG_ONGOING_EVENT; - n.when = 0; - n.setLatestEventInfo( - mContext, - mContext.getString(R.string.car_mode_disable_notification_title), - mContext.getString(R.string.car_mode_disable_notification_message), - PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0)); - mNotificationManager.notify(0, n); - } else { - mNotificationManager.cancel(0); - } - Binder.restoreCallingIdentity(ident); - } - } - - private void setCarMode(boolean enabled) throws RemoteException { - mCarModeEnabled = enabled; - if (enabled) { - if (mNightMode == MODE_NIGHT_AUTO) { - updateTwilight(); - } else { - setMode(Configuration.UI_MODE_TYPE_CAR, mNightMode << 4); - } - } else { - // Disabling the car mode clears the night mode. - setMode(Configuration.UI_MODE_TYPE_NORMAL, - Configuration.UI_MODE_NIGHT_UNDEFINED); - } - adjustStatusBarCarMode(); - } - - private void setMode(int modeType, int modeNight) throws RemoteException { - long ident = Binder.clearCallingIdentity(); - final IActivityManager am = ActivityManagerNative.getDefault(); - Configuration config = am.getConfiguration(); - if (config.uiMode != (modeType | modeNight)) { - config.uiMode = modeType | modeNight; - am.updateConfiguration(config); - } - Binder.restoreCallingIdentity(ident); - } - - private void setNightMode(int mode) throws RemoteException { - if (mNightMode != mode) { - mNightMode = mode; - switch (mode) { - case MODE_NIGHT_NO: - case MODE_NIGHT_YES: - setMode(Configuration.UI_MODE_TYPE_CAR, mode << 4); - break; - case MODE_NIGHT_AUTO: - long ident = Binder.clearCallingIdentity(); - updateTwilight(); - Binder.restoreCallingIdentity(ident); - break; - default: - setMode(Configuration.UI_MODE_TYPE_CAR, MODE_NIGHT_NO << 4); - break; - } - } - } - - private void updateTwilight() throws RemoteException { - synchronized (this) { - if (mLocation == null) { - return; - } - final long currentTime = System.currentTimeMillis(); - int nightMode; - // calculate current twilight - TwilightCalculator tw = new TwilightCalculator(); - tw.calculateTwilight(currentTime, - mLocation.getLatitude(), mLocation.getLongitude()); - if (tw.mState == TwilightCalculator.DAY) { - nightMode = MODE_NIGHT_NO; - } else { - nightMode = MODE_NIGHT_YES; - } - - // schedule next update - long nextUpdate = 0; - if (tw.mSunrise == -1 || tw.mSunset == -1) { - // In the case the day or night never ends the update is scheduled 12 hours later. - nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS; - } else { - final int mLastTwilightState = tw.mState; - // add some extra time to be on the save side. - nextUpdate += DateUtils.MINUTE_IN_MILLIS; - if (currentTime > tw.mSunset) { - // next update should be on the following day - tw.calculateTwilight(currentTime - + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(), - mLocation.getLongitude()); - } - - if (mLastTwilightState == TwilightCalculator.NIGHT) { - nextUpdate += tw.mSunrise; - } else { - nextUpdate += tw.mSunset; - } - } - - Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE); - PendingIntent pendingIntent = - PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); - mAlarmManager.cancel(pendingIntent); - mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent); - - // Make sure that we really set the new mode only if we're in car mode and - // automatic switching is enables. - if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - setMode(Configuration.UI_MODE_TYPE_CAR, nightMode << 4); - } - } - } - - /** - * Wrapper class implementing the IUiModeManager interface. - */ - private final IUiModeManager.Stub mBinder = new IUiModeManager.Stub() { - - public void disableCarMode() throws RemoteException { - if (mCarModeEnabled) { - setCarMode(false); - update(); - } - } - - public void enableCarMode() throws RemoteException { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ENABLE_CAR_MODE, - "Need ENABLE_CAR_MODE permission"); - if (!mCarModeEnabled) { - setCarMode(true); - update(); - } - } - - public void setNightMode(int mode) throws RemoteException { - if (mCarModeEnabled) { - DockObserver.this.setNightMode(mode); - } - } - - public int getNightMode() throws RemoteException { - return mNightMode; - } }; } |