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