blob: 8103d7cee64af2e2d04419d9f516e9c7836f0d8e [file] [log] [blame]
Dianne Hackborn7299c412010-03-04 18:41:49 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.Activity;
20import android.app.ActivityManagerNative;
21import android.app.AlarmManager;
22import android.app.IActivityManager;
Mike Lockwood924e1642010-03-05 11:56:53 -050023import android.app.KeyguardManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080024import android.app.IUiModeManager;
25import android.app.Notification;
26import android.app.NotificationManager;
27import android.app.PendingIntent;
28import android.app.StatusBarManager;
29import android.app.UiModeManager;
30import android.content.ActivityNotFoundException;
31import android.content.BroadcastReceiver;
32import android.content.Context;
33import android.content.Intent;
34import android.content.IntentFilter;
35import android.content.pm.PackageManager;
36import android.content.res.Configuration;
37import android.location.Criteria;
38import android.location.Location;
39import android.location.LocationListener;
40import android.location.LocationManager;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050041import android.os.BatteryManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080042import android.os.Binder;
43import android.os.Bundle;
44import android.os.Handler;
45import android.os.Message;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050046import android.os.PowerManager;
Dianne Hackborn7299c412010-03-04 18:41:49 -080047import android.os.RemoteException;
48import android.os.ServiceManager;
49import android.text.format.DateUtils;
50import android.text.format.Time;
51import android.util.Slog;
52
53import java.io.FileDescriptor;
54import java.io.PrintWriter;
55
56import com.android.internal.R;
57import com.android.internal.app.DisableCarModeActivity;
58
59class UiModeManagerService extends IUiModeManager.Stub {
60 private static final String TAG = UiModeManager.class.getSimpleName();
61 private static final boolean LOG = false;
62
63 private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL";
64
65 private static final int MSG_UPDATE_TWILIGHT = 0;
66 private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
67
68 private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
69 private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
70 private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
71 private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS;
72 private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
73
74 private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE";
75
76 private final Context mContext;
77
78 final Object mLock = new Object();
79
80 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
81 private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
82
83 private int mNightMode = UiModeManager.MODE_NIGHT_NO;
84 private boolean mCarModeEnabled = false;
Mike Lockwoode29db6a2010-03-05 13:45:51 -050085 private boolean mCharging = false;
86 private final boolean mCarModeKeepsScreenOn;
87 private final boolean mDeskModeKeepsScreenOn;
Dianne Hackborn7299c412010-03-04 18:41:49 -080088
89 private boolean mComputedNightMode;
90 private int mCurUiMode = 0;
Dianne Hackbornb8b11a02010-03-10 15:53:11 -080091 private int mSetUiMode = 0;
Dianne Hackborn7299c412010-03-04 18:41:49 -080092
Dianne Hackbornb8b11a02010-03-10 15:53:11 -080093 private boolean mHoldingConfiguration = false;
Dianne Hackborn7299c412010-03-04 18:41:49 -080094 private Configuration mConfiguration = new Configuration();
95
96 private boolean mSystemReady;
97
98 private NotificationManager mNotificationManager;
99
100 private AlarmManager mAlarmManager;
101
102 private LocationManager mLocationManager;
103 private Location mLocation;
104 private StatusBarManager mStatusBarManager;
Mike Lockwood924e1642010-03-05 11:56:53 -0500105 private KeyguardManager.KeyguardLock mKeyguardLock;
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500106 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800107
108 // The broadcast receiver which receives the result of the ordered broadcast sent when
109 // the dock state changes. The original ordered broadcast is sent with an initial result
110 // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
111 // to RESULT_CANCELED, then the intent to start a dock app will not be sent.
112 private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
113 @Override
114 public void onReceive(Context context, Intent intent) {
115 if (getResultCode() != Activity.RESULT_OK) {
116 return;
117 }
118
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800119 synchronized (mLock) {
120 // Launch a dock activity
121 String category;
122 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
123 // Only launch car home when car mode is enabled.
124 category = Intent.CATEGORY_CAR_DOCK;
125 } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) {
126 category = Intent.CATEGORY_DESK_DOCK;
127 } else {
128 category = null;
129 }
130 if (category != null) {
131 intent = new Intent(Intent.ACTION_MAIN);
132 intent.addCategory(category);
133 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
134 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
135 try {
136 mContext.startActivity(intent);
137 } catch (ActivityNotFoundException e) {
138 Slog.w(TAG, e.getCause());
139 }
140 }
141
142 if (mHoldingConfiguration) {
143 mHoldingConfiguration = false;
144 updateConfigurationLocked();
Dianne Hackborn7299c412010-03-04 18:41:49 -0800145 }
146 }
147 }
148 };
149
150 private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() {
151 @Override
152 public void onReceive(Context context, Intent intent) {
153 if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
154 mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
155 }
156 }
157 };
158
159 private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() {
160 @Override
161 public void onReceive(Context context, Intent intent) {
162 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
163 Intent.EXTRA_DOCK_STATE_UNDOCKED);
164 updateDockState(state);
165 }
166 };
167
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500168 private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
169 @Override
170 public void onReceive(Context context, Intent intent) {
171 mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
172 synchronized (mLock) {
173 if (mSystemReady) {
174 updateLocked();
175 }
176 }
177 }
178 };
179
Dianne Hackborn7299c412010-03-04 18:41:49 -0800180 // A LocationListener to initialize the network location provider. The location updates
181 // are handled through the passive location provider.
182 private final LocationListener mEmptyLocationListener = new LocationListener() {
183 public void onLocationChanged(Location location) {
184 }
185
186 public void onProviderDisabled(String provider) {
187 }
188
189 public void onProviderEnabled(String provider) {
190 }
191
192 public void onStatusChanged(String provider, int status, Bundle extras) {
193 }
194 };
195
196 private final LocationListener mLocationListener = new LocationListener() {
197
198 public void onLocationChanged(Location location) {
199 final boolean hasMoved = hasMoved(location);
200 final boolean hasBetterAccuracy = mLocation == null
201 || location.getAccuracy() < mLocation.getAccuracy();
202 if (hasMoved || hasBetterAccuracy) {
203 synchronized (mLock) {
204 mLocation = location;
205 if (hasMoved && isDoingNightMode()
206 && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
207 mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
208 }
209 }
210 }
211 }
212
213 public void onProviderDisabled(String provider) {
214 }
215
216 public void onProviderEnabled(String provider) {
217 }
218
219 public void onStatusChanged(String provider, int status, Bundle extras) {
220 }
221
222 /*
223 * The user has moved if the accuracy circles of the two locations
224 * don't overlap.
225 */
226 private boolean hasMoved(Location location) {
227 if (location == null) {
228 return false;
229 }
230 if (mLocation == null) {
231 return true;
232 }
233
234 /* if new location is older than the current one, the devices hasn't
235 * moved.
236 */
237 if (location.getTime() < mLocation.getTime()) {
238 return false;
239 }
240
241 /* Get the distance between the two points */
242 float distance = mLocation.distanceTo(location);
243
244 /* Get the total accuracy radius for both locations */
245 float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy();
246
247 /* If the distance is greater than the combined accuracy of the two
248 * points then they can't overlap and hence the user has moved.
249 */
250 return distance >= totalAccuracy;
251 }
252 };
253
254 public UiModeManagerService(Context context) {
255 mContext = context;
256
257 ServiceManager.addService(Context.UI_MODE_SERVICE, this);
258
259 mAlarmManager =
260 (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
261 mLocationManager =
262 (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
263 mContext.registerReceiver(mTwilightUpdateReceiver,
264 new IntentFilter(ACTION_UPDATE_NIGHT_MODE));
265 mContext.registerReceiver(mDockModeReceiver,
266 new IntentFilter(Intent.ACTION_DOCK_EVENT));
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500267 mContext.registerReceiver(mBatteryReceiver,
268 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
269
270 PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
271 mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800272
273 mConfiguration.setToDefaults();
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500274
275 mCarModeKeepsScreenOn = (context.getResources().getInteger(
276 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
277 mDeskModeKeepsScreenOn = (context.getResources().getInteger(
278 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800279 }
280
281 public void disableCarMode() {
282 synchronized (mLock) {
283 setCarModeLocked(false);
Mike Lockwood924e1642010-03-05 11:56:53 -0500284 if (mSystemReady) {
285 updateLocked();
286 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800287 }
288 }
289
290 public void enableCarMode() {
291 mContext.enforceCallingOrSelfPermission(
292 android.Manifest.permission.ENABLE_CAR_MODE,
293 "Need ENABLE_CAR_MODE permission");
294 synchronized (mLock) {
295 setCarModeLocked(true);
Mike Lockwood924e1642010-03-05 11:56:53 -0500296 if (mSystemReady) {
297 updateLocked();
298 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800299 }
300 }
301
302 public int getCurrentModeType() {
303 synchronized (mLock) {
304 return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
305 }
306 }
307
308 public void setNightMode(int mode) throws RemoteException {
309 synchronized (mLock) {
310 switch (mode) {
311 case UiModeManager.MODE_NIGHT_NO:
312 case UiModeManager.MODE_NIGHT_YES:
313 case UiModeManager.MODE_NIGHT_AUTO:
314 break;
315 default:
316 throw new IllegalArgumentException("Unknown mode: " + mode);
317 }
318 if (!isDoingNightMode()) {
319 return;
320 }
321
322 if (mNightMode != mode) {
323 mNightMode = mode;
324 updateLocked();
325 }
326 }
327 }
328
329 public int getNightMode() throws RemoteException {
330 return mNightMode;
331 }
332
333 void systemReady() {
334 synchronized (mLock) {
335 mSystemReady = true;
336 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
337 updateLocked();
338 mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
339 }
340 }
341
342 boolean isDoingNightMode() {
343 return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
344 }
345
346 void setCarModeLocked(boolean enabled) {
347 if (mCarModeEnabled != enabled) {
348 mCarModeEnabled = enabled;
Mike Lockwood924e1642010-03-05 11:56:53 -0500349
350 // Disable keyguard when in car mode
351 if (mKeyguardLock == null) {
352 KeyguardManager km =
353 (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
354 if (km != null) {
355 mKeyguardLock = km.newKeyguardLock(TAG);
356 }
357 }
358 if (mKeyguardLock != null) {
Tobias Haamel9f938812010-03-08 11:21:59 +0100359 long ident = Binder.clearCallingIdentity();
Mike Lockwood924e1642010-03-05 11:56:53 -0500360 if (enabled) {
361 mKeyguardLock.disableKeyguard();
362 } else {
363 mKeyguardLock.reenableKeyguard();
364 }
Tobias Haamel9f938812010-03-08 11:21:59 +0100365 Binder.restoreCallingIdentity(ident);
Mike Lockwood924e1642010-03-05 11:56:53 -0500366 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800367 }
368 }
369
370 void updateDockState(int newState) {
371 synchronized (mLock) {
372 if (newState != mDockState) {
373 mDockState = newState;
Mike Lockwood924e1642010-03-05 11:56:53 -0500374 setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800375 if (mSystemReady) {
376 updateLocked();
377 }
378 }
379 }
380 }
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500381
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800382 final void updateConfigurationLocked() {
383 int uiMode = 0;
384 if (mCarModeEnabled) {
385 uiMode = Configuration.UI_MODE_TYPE_CAR;
386 } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
387 uiMode = Configuration.UI_MODE_TYPE_DESK;
388 }
389 if (uiMode != 0) {
390 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
391 updateTwilightLocked();
392 uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
393 : Configuration.UI_MODE_NIGHT_NO;
394 } else {
395 uiMode |= mNightMode << 4;
396 }
397 } else {
398 // Disabling the car mode clears the night mode.
399 uiMode = Configuration.UI_MODE_TYPE_NORMAL |
400 Configuration.UI_MODE_NIGHT_NO;
401 }
402
403 mCurUiMode = uiMode;
404
405 if (!mHoldingConfiguration && uiMode != mSetUiMode) {
406 mSetUiMode = uiMode;
407
408 try {
409 final IActivityManager am = ActivityManagerNative.getDefault();
410 mConfiguration.uiMode = uiMode;
411 am.updateConfiguration(mConfiguration);
412 } catch (RemoteException e) {
413 Slog.w(TAG, "Failure communicating with activity manager", e);
414 }
415 }
416 }
417
Dianne Hackborn7299c412010-03-04 18:41:49 -0800418 final void updateLocked() {
419 long ident = Binder.clearCallingIdentity();
420
421 try {
Dianne Hackborn7299c412010-03-04 18:41:49 -0800422 String action = null;
423 String oldAction = null;
424 if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
425 oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
426 } else if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_DESK) {
427 oldAction = UiModeManager.ACTION_EXIT_DESK_MODE;
428 }
429
430 if (mCarModeEnabled) {
431 if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) {
432 adjustStatusBarCarModeLocked();
433
434 if (oldAction != null) {
435 mContext.sendBroadcast(new Intent(oldAction));
436 }
437 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
438 action = UiModeManager.ACTION_ENTER_CAR_MODE;
439 }
440 } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
441 if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_DESK) {
442 if (oldAction != null) {
443 mContext.sendBroadcast(new Intent(oldAction));
444 }
445 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_DESK;
446 action = UiModeManager.ACTION_ENTER_DESK_MODE;
447 }
448 } else {
449 if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
450 adjustStatusBarCarModeLocked();
451 }
452
453 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
454 action = oldAction;
455 }
456
457 if (action != null) {
458 // Send the ordered broadcast; the result receiver will receive after all
459 // broadcasts have been sent. If any broadcast receiver changes the result
460 // code from the initial value of RESULT_OK, then the result receiver will
461 // not launch the corresponding dock application. This gives apps a chance
462 // to override the behavior and stay in their app even when the device is
463 // placed into a dock.
464 mContext.sendOrderedBroadcast(new Intent(action), null,
465 mResultReceiver, null, Activity.RESULT_OK, null, null);
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800466 // Attempting to make this transition a little more clean, we are going
467 // to hold off on doing a configuration change until we have finished
468 // the broacast and started the home activity.
469 mHoldingConfiguration = true;
Dianne Hackborn7299c412010-03-04 18:41:49 -0800470 }
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800471
472 updateConfigurationLocked();
Mike Lockwoode29db6a2010-03-05 13:45:51 -0500473
474 // keep screen on when charging and in car mode
475 boolean keepScreenOn = mCharging &&
476 ((mCarModeEnabled && mCarModeKeepsScreenOn) ||
477 (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
478 if (keepScreenOn != mWakeLock.isHeld()) {
479 if (keepScreenOn) {
480 mWakeLock.acquire();
481 } else {
482 mWakeLock.release();
483 }
484 }
Dianne Hackborn7299c412010-03-04 18:41:49 -0800485 } finally {
486 Binder.restoreCallingIdentity(ident);
487 }
488 }
489
490 private void adjustStatusBarCarModeLocked() {
491 if (mStatusBarManager == null) {
492 mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
493 }
494
495 // Fear not: StatusBarService manages a list of requests to disable
496 // features of the status bar; these are ORed together to form the
497 // active disabled list. So if (for example) the device is locked and
498 // the status bar should be totally disabled, the calls below will
499 // have no effect until the device is unlocked.
500 if (mStatusBarManager != null) {
501 mStatusBarManager.disable(mCarModeEnabled
502 ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
503 : StatusBarManager.DISABLE_NONE);
504 }
505
506 if (mNotificationManager == null) {
507 mNotificationManager = (NotificationManager)
508 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
509 }
510
511 if (mNotificationManager != null) {
512 if (mCarModeEnabled) {
513 Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
514
515 Notification n = new Notification();
516 n.icon = R.drawable.stat_notify_car_mode;
517 n.defaults = Notification.DEFAULT_LIGHTS;
518 n.flags = Notification.FLAG_ONGOING_EVENT;
519 n.when = 0;
520 n.setLatestEventInfo(
521 mContext,
522 mContext.getString(R.string.car_mode_disable_notification_title),
523 mContext.getString(R.string.car_mode_disable_notification_message),
524 PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0));
525 mNotificationManager.notify(0, n);
526 } else {
527 mNotificationManager.cancel(0);
528 }
529 }
530 }
531
532 private final Handler mHandler = new Handler() {
533
534 boolean mPassiveListenerEnabled;
535 boolean mNetworkListenerEnabled;
536
537 @Override
538 public void handleMessage(Message msg) {
539 switch (msg.what) {
540 case MSG_UPDATE_TWILIGHT:
541 synchronized (mLock) {
542 if (isDoingNightMode() && mLocation != null
543 && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
544 updateTwilightLocked();
545 updateLocked();
546 }
547 }
548 break;
549 case MSG_ENABLE_LOCATION_UPDATES:
550 // enable network provider to receive at least location updates for a given
551 // distance.
552 boolean networkLocationEnabled;
553 try {
554 networkLocationEnabled =
555 mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
556 } catch (Exception e) {
557 // we may get IllegalArgumentException if network location provider
558 // does not exist or is not yet installed.
559 networkLocationEnabled = false;
560 }
561 if (!mNetworkListenerEnabled && networkLocationEnabled) {
562 mNetworkListenerEnabled = true;
563 mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
564 LOCATION_UPDATE_MS, 0, mEmptyLocationListener);
565
566 if (mLocation == null) {
567 retrieveLocation();
568 }
569 synchronized (mLock) {
570 if (isDoingNightMode() && mLocation != null
571 && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
572 updateTwilightLocked();
573 updateLocked();
574 }
575 }
576 }
577 // enable passive provider to receive updates from location fixes (gps
578 // and network).
579 boolean passiveLocationEnabled;
580 try {
581 passiveLocationEnabled =
582 mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
583 } catch (Exception e) {
584 // we may get IllegalArgumentException if passive location provider
585 // does not exist or is not yet installed.
586 passiveLocationEnabled = false;
587 }
588 if (!mPassiveListenerEnabled && passiveLocationEnabled) {
589 mPassiveListenerEnabled = true;
590 mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
591 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener);
592 }
593 if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) {
594 long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL);
595 interval *= 1.5;
596 if (interval == 0) {
597 interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN;
598 } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) {
599 interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX;
600 }
601 Bundle bundle = new Bundle();
602 bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval);
603 Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES);
604 newMsg.setData(bundle);
605 mHandler.sendMessageDelayed(newMsg, interval);
606 }
607 break;
608 }
609 }
610
611 private void retrieveLocation() {
612 Location location;
613 Criteria criteria = new Criteria();
614 criteria.setSpeedRequired(false);
615 criteria.setAltitudeRequired(false);
616 criteria.setBearingRequired(false);
617 criteria.setAccuracy(Criteria.ACCURACY_FINE);
618 final String bestProvider = mLocationManager.getBestProvider(criteria, true);
619 location = mLocationManager.getLastKnownLocation(bestProvider);
620 // In the case there is no location available (e.g. GPS fix or network location
621 // is not available yet), the longitude of the location is estimated using the timezone,
622 // latitude and accuracy are set to get a good average.
623 if (location == null) {
624 Time currentTime = new Time();
625 currentTime.set(System.currentTimeMillis());
626 double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE *
627 (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0));
628 location = new Location("fake");
629 location.setLongitude(lngOffset);
630 location.setLatitude(0);
631 location.setAccuracy(417000.0f);
632 location.setTime(System.currentTimeMillis());
633 }
634 synchronized (mLock) {
635 mLocation = location;
636 }
637 }
638 };
639
640 void updateTwilightLocked() {
641 if (mLocation == null) {
642 return;
643 }
644 final long currentTime = System.currentTimeMillis();
645 boolean nightMode;
646 // calculate current twilight
647 TwilightCalculator tw = new TwilightCalculator();
648 tw.calculateTwilight(currentTime,
649 mLocation.getLatitude(), mLocation.getLongitude());
650 if (tw.mState == TwilightCalculator.DAY) {
651 nightMode = false;
652 } else {
653 nightMode = true;
654 }
655
656 // schedule next update
657 long nextUpdate = 0;
658 if (tw.mSunrise == -1 || tw.mSunset == -1) {
659 // In the case the day or night never ends the update is scheduled 12 hours later.
660 nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS;
661 } else {
662 final int mLastTwilightState = tw.mState;
663 // add some extra time to be on the save side.
664 nextUpdate += DateUtils.MINUTE_IN_MILLIS;
665 if (currentTime > tw.mSunset) {
666 // next update should be on the following day
667 tw.calculateTwilight(currentTime
668 + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(),
669 mLocation.getLongitude());
670 }
671
672 if (mLastTwilightState == TwilightCalculator.NIGHT) {
673 nextUpdate += tw.mSunrise;
674 } else {
675 nextUpdate += tw.mSunset;
676 }
677 }
678
679 Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE);
680 PendingIntent pendingIntent =
681 PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
682 mAlarmManager.cancel(pendingIntent);
683 mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
684
685 mComputedNightMode = nightMode;
686 }
687
688 @Override
689 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
690 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
691 != PackageManager.PERMISSION_GRANTED) {
692
693 pw.println("Permission Denial: can't dump uimode service from from pid="
694 + Binder.getCallingPid()
695 + ", uid=" + Binder.getCallingUid());
696 return;
697 }
698
699 synchronized (mLock) {
700 pw.println("Current UI Mode Service state:");
701 pw.print(" mDockState="); pw.print(mDockState);
702 pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
703 pw.print(" mNightMode="); pw.print(mNightMode);
704 pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
705 pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
706 pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
Dianne Hackbornb8b11a02010-03-10 15:53:11 -0800707 pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
708 pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
Dianne Hackborn7299c412010-03-04 18:41:49 -0800709 pw.print(" mSystemReady="); pw.println(mSystemReady);
710 if (mLocation != null) {
711 pw.print(" mLocation="); pw.println(mLocation);
712 }
713 }
714 }
715}