| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 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 | |
| 17 | package com.android.server; |
| 18 | |
| 19 | import android.app.Activity; |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 20 | import android.app.ActivityManagerNative; |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 21 | import android.app.AlarmManager; |
| 22 | import android.app.PendingIntent; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 23 | import android.content.BroadcastReceiver; |
| 24 | import android.content.Context; |
| 25 | import android.content.Intent; |
| 26 | import android.content.IntentFilter; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 27 | import android.os.Handler; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 28 | import android.os.PowerManager; |
| 29 | import android.os.PowerManager.WakeLock; |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 30 | import android.os.RemoteException; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 31 | import android.os.SystemClock; |
| 32 | import android.os.UserHandle; |
| 33 | import android.util.Log; |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 34 | import android.util.Slog; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 35 | |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 36 | /** |
| 37 | * This service observes the device state and when applicable sends |
| 38 | * broadcasts at the beginning and at the end of a period during which |
| 39 | * observers can perform idle maintenance tasks. Typical use of the |
| 40 | * idle maintenance is to perform somehow expensive tasks that can be |
| 41 | * postponed to a moment when they will not degrade user experience. |
| 42 | * |
| 43 | * The current implementation is very simple. The start of a maintenance |
| 44 | * window is announced if: the screen is off or showing a dream AND the |
| 45 | * battery level is more than twenty percent AND at least one hour passed |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 46 | * activity). |
| 47 | * |
| 48 | * The end of a maintenance window is announced only if: a start was |
| 49 | * announced AND the screen turned on or a dream was stopped. |
| 50 | */ |
| 51 | public class IdleMaintenanceService extends BroadcastReceiver { |
| 52 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 53 | private static final boolean DEBUG = false; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 54 | |
| 55 | private static final String LOG_TAG = IdleMaintenanceService.class.getSimpleName(); |
| 56 | |
| 57 | private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1; |
| 58 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 59 | private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 60 | |
| Svetoslav | f23b64d | 2013-04-25 14:45:54 -0700 | [diff] [blame] | 61 | private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent |
| 62 | |
| 63 | private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent |
| 64 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 65 | private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent |
| Svetoslav | f23b64d | 2013-04-25 14:45:54 -0700 | [diff] [blame] | 66 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 67 | private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 68 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 69 | private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 70 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 71 | private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE = |
| 72 | "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE"; |
| 73 | |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 74 | private static final String ACTION_FORCE_IDLE_MAINTENANCE = |
| 75 | "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE"; |
| 76 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 77 | private static final Intent sIdleMaintenanceStartIntent; |
| 78 | static { |
| 79 | sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START); |
| 80 | sIdleMaintenanceStartIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); |
| 81 | }; |
| 82 | |
| 83 | private static final Intent sIdleMaintenanceEndIntent; |
| 84 | static { |
| 85 | sIdleMaintenanceEndIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_END); |
| 86 | sIdleMaintenanceEndIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); |
| 87 | } |
| 88 | |
| 89 | private final AlarmManager mAlarmService; |
| 90 | |
| 91 | private final BatteryService mBatteryService; |
| 92 | |
| 93 | private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 94 | |
| 95 | private final Context mContext; |
| 96 | |
| 97 | private final WakeLock mWakeLock; |
| 98 | |
| 99 | private final Handler mHandler; |
| 100 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 101 | private long mLastIdleMaintenanceStartTimeMillis; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 102 | |
| 103 | private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; |
| 104 | |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 105 | private boolean mIdleMaintenanceStarted; |
| 106 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 107 | public IdleMaintenanceService(Context context, BatteryService batteryService) { |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 108 | mContext = context; |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 109 | mBatteryService = batteryService; |
| 110 | |
| 111 | mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 112 | |
| 113 | PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); |
| 114 | mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); |
| 115 | |
| 116 | mHandler = new Handler(mContext.getMainLooper()); |
| 117 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 118 | Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); |
| 119 | intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); |
| 120 | mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0, |
| 121 | intent, PendingIntent.FLAG_UPDATE_CURRENT); |
| 122 | |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 123 | register(mHandler); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 124 | } |
| 125 | |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 126 | public void register(Handler handler) { |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 127 | IntentFilter intentFilter = new IntentFilter(); |
| 128 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 129 | // Alarm actions. |
| 130 | intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); |
| 131 | |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 132 | // Battery actions. |
| 133 | intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); |
| 134 | |
| 135 | // Screen actions. |
| 136 | intentFilter.addAction(Intent.ACTION_SCREEN_ON); |
| 137 | intentFilter.addAction(Intent.ACTION_SCREEN_OFF); |
| 138 | |
| 139 | // Dream actions. |
| 140 | intentFilter.addAction(Intent.ACTION_DREAMING_STARTED); |
| 141 | intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED); |
| 142 | |
| 143 | mContext.registerReceiverAsUser(this, UserHandle.ALL, |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 144 | intentFilter, null, mHandler); |
| 145 | |
| 146 | intentFilter = new IntentFilter(); |
| 147 | intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE); |
| 148 | mContext.registerReceiverAsUser(this, UserHandle.ALL, |
| 149 | intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 150 | } |
| 151 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 152 | private void scheduleUpdateIdleMaintenanceState(long delayMillis) { |
| 153 | final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis; |
| 154 | mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis, |
| 155 | mUpdateIdleMaintenanceStatePendingIntent); |
| 156 | } |
| 157 | |
| 158 | private void unscheduleUpdateIdleMaintenanceState() { |
| 159 | mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent); |
| 160 | } |
| 161 | |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 162 | private void updateIdleMaintenanceState(boolean noisy) { |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 163 | if (mIdleMaintenanceStarted) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 164 | // Idle maintenance can be interrupted by user activity, or duration |
| 165 | // time out, or low battery. |
| 166 | if (!lastUserActivityPermitsIdleMaintenanceRunning() |
| 167 | || !batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) { |
| 168 | unscheduleUpdateIdleMaintenanceState(); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 169 | mIdleMaintenanceStarted = false; |
| Svetoslav | f23b64d | 2013-04-25 14:45:54 -0700 | [diff] [blame] | 170 | EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(), |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 171 | mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), |
| 172 | isBatteryCharging() ? 1 : 0); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 173 | sendIdleMaintenanceEndIntent(); |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 174 | // We stopped since we don't have enough battery or timed out but the |
| 175 | // user is not using the device, so we should be able to run maintenance |
| 176 | // in the next maintenance window since the battery may be charged |
| 177 | // without interaction and the min interval between maintenances passed. |
| 178 | if (!batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) { |
| 179 | scheduleUpdateIdleMaintenanceState( |
| 180 | getNextIdleMaintenanceIntervalStartFromNow()); |
| 181 | } |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 182 | } |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 183 | } else if (deviceStatePermitsIdleMaintenanceStart(noisy) |
| 184 | && lastUserActivityPermitsIdleMaintenanceStart(noisy) |
| 185 | && lastRunPermitsIdleMaintenanceStart(noisy)) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 186 | // Now that we started idle maintenance, we should schedule another |
| 187 | // update for the moment when the idle maintenance times out. |
| 188 | scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 189 | mIdleMaintenanceStarted = true; |
| Svetoslav | f23b64d | 2013-04-25 14:45:54 -0700 | [diff] [blame] | 190 | EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(), |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 191 | mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), |
| 192 | isBatteryCharging() ? 1 : 0); |
| Svetoslav | f23b64d | 2013-04-25 14:45:54 -0700 | [diff] [blame] | 193 | mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime(); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 194 | sendIdleMaintenanceStartIntent(); |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 195 | } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) { |
| 196 | if (lastRunPermitsIdleMaintenanceStart(noisy)) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 197 | // The user does not use the device and we did not run maintenance in more |
| 198 | // than the min interval between runs, so schedule an update - maybe the |
| 199 | // battery will be charged latter. |
| 200 | scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); |
| 201 | } else { |
| 202 | // The user does not use the device but we have run maintenance in the min |
| 203 | // interval between runs, so schedule an update after the min interval ends. |
| 204 | scheduleUpdateIdleMaintenanceState( |
| 205 | getNextIdleMaintenanceIntervalStartFromNow()); |
| 206 | } |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 207 | } |
| 208 | } |
| 209 | |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 210 | private long getNextIdleMaintenanceIntervalStartFromNow() { |
| 211 | return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS |
| 212 | - SystemClock.elapsedRealtime(); |
| 213 | } |
| 214 | |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 215 | private void sendIdleMaintenanceStartIntent() { |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 216 | mWakeLock.acquire(); |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 217 | try { |
| 218 | ActivityManagerNative.getDefault().performIdleMaintenance(); |
| 219 | } catch (RemoteException e) { |
| 220 | } |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 221 | mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL, |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 222 | null, this, mHandler, Activity.RESULT_OK, null, null); |
| 223 | } |
| 224 | |
| 225 | private void sendIdleMaintenanceEndIntent() { |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 226 | mWakeLock.acquire(); |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 227 | mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceEndIntent, UserHandle.ALL, |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 228 | null, this, mHandler, Activity.RESULT_OK, null, null); |
| 229 | } |
| 230 | |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 231 | private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 232 | final int minBatteryLevel = isBatteryCharging() |
| Svetoslav | f23b64d | 2013-04-25 14:45:54 -0700 | [diff] [blame] | 233 | ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING |
| 234 | : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING; |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 235 | boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 236 | && mBatteryService.getBatteryLevel() > minBatteryLevel); |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 237 | if (!allowed && noisy) { |
| 238 | Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power"); |
| 239 | } |
| 240 | return allowed; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 241 | } |
| 242 | |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 243 | private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 244 | // The last time the user poked the device is above the threshold. |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 245 | boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 246 | && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis |
| 247 | > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 248 | if (!allowed && noisy) { |
| 249 | Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity"); |
| 250 | } |
| 251 | return allowed; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 252 | } |
| 253 | |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 254 | private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 255 | // Enough time passed since the last maintenance run. |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 256 | boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 257 | > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS; |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 258 | if (!allowed && noisy) { |
| 259 | Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last"); |
| 260 | } |
| 261 | return allowed; |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 262 | } |
| 263 | |
| 264 | private boolean lastUserActivityPermitsIdleMaintenanceRunning() { |
| 265 | // The user is not using the device. |
| 266 | return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID); |
| 267 | } |
| 268 | |
| 269 | private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() { |
| 270 | // Battery not too low and the maintenance duration did not timeout. |
| 271 | return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING |
| 272 | && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION |
| 273 | > SystemClock.elapsedRealtime()); |
| 274 | } |
| 275 | |
| 276 | private boolean isBatteryCharging() { |
| 277 | return mBatteryService.getPlugType() > 0 |
| 278 | && mBatteryService.getInvalidCharger() == 0; |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 279 | } |
| 280 | |
| 281 | @Override |
| 282 | public void onReceive(Context context, Intent intent) { |
| 283 | if (DEBUG) { |
| 284 | Log.i(LOG_TAG, intent.getAction()); |
| 285 | } |
| 286 | String action = intent.getAction(); |
| 287 | if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 288 | // We care about battery only if maintenance is in progress so we can |
| 289 | // stop it if battery is too low. Note that here we assume that the |
| 290 | // maintenance clients are properly holding a wake lock. We will |
| 291 | // refactor the maintenance to use services instead of intents for the |
| 292 | // next release. The only client for this for now is internal an holds |
| 293 | // a wake lock correctly. |
| 294 | if (mIdleMaintenanceStarted) { |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 295 | updateIdleMaintenanceState(false); |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 296 | } |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 297 | } else if (Intent.ACTION_SCREEN_ON.equals(action) |
| 298 | || Intent.ACTION_DREAMING_STOPPED.equals(action)) { |
| 299 | mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 300 | // Unschedule any future updates since we already know that maintenance |
| 301 | // cannot be performed since the user is back. |
| 302 | unscheduleUpdateIdleMaintenanceState(); |
| 303 | // If the screen went on/stopped dreaming, we know the user is using the |
| 304 | // device which means that idle maintenance should be stopped if running. |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 305 | updateIdleMaintenanceState(false); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 306 | } else if (Intent.ACTION_SCREEN_OFF.equals(action) |
| 307 | || Intent.ACTION_DREAMING_STARTED.equals(action)) { |
| 308 | mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime(); |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 309 | // If screen went off/started dreaming, we may be able to start idle maintenance |
| 310 | // after the minimal user inactivity elapses. We schedule an alarm for when |
| 311 | // this timeout elapses since the device may go to sleep by then. |
| 312 | scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); |
| 313 | } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) { |
| Dianne Hackborn | 35f72be | 2013-09-16 10:57:39 -0700 | [diff] [blame] | 314 | updateIdleMaintenanceState(false); |
| 315 | } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) { |
| 316 | long now = SystemClock.elapsedRealtime() - 1; |
| 317 | mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START; |
| 318 | mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS; |
| 319 | updateIdleMaintenanceState(true); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 320 | } else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action) |
| 321 | || Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) { |
| Svetoslav | 6a08a12 | 2013-05-03 11:24:26 -0700 | [diff] [blame] | 322 | // We were holding a wake lock while broadcasting the idle maintenance |
| 323 | // intents but now that we finished the broadcast release the wake lock. |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 324 | mWakeLock.release(); |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 325 | } |
| Svetoslav | b3038ec | 2013-02-13 14:39:30 -0800 | [diff] [blame] | 326 | } |
| 327 | } |