1b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav/* 2b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * Copyright (C) 2013 The Android Open Source Project 3b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 4b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * Licensed under the Apache License, Version 2.0 (the "License"); 5b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * you may not use this file except in compliance with the License. 6b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * You may obtain a copy of the License at 7b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 8b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * http://www.apache.org/licenses/LICENSE-2.0 9b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 10b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * Unless required by applicable law or agreed to in writing, software 11b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * distributed under the License is distributed on an "AS IS" BASIS, 12b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * See the License for the specific language governing permissions and 14b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * limitations under the License. 15b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav */ 16b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 17b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavpackage com.android.server; 18b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 19b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.app.Activity; 206a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslavimport android.app.AlarmManager; 216a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslavimport android.app.PendingIntent; 22b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.BroadcastReceiver; 23b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.Context; 24b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.Intent; 25b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.content.IntentFilter; 26b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.Handler; 27b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.Looper; 28b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.PowerManager; 29b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.PowerManager.WakeLock; 30b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.SystemClock; 31b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.os.UserHandle; 32b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavimport android.util.Log; 33b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 34b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav/** 35b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * This service observes the device state and when applicable sends 36b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * broadcasts at the beginning and at the end of a period during which 37b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * observers can perform idle maintenance tasks. Typical use of the 38b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * idle maintenance is to perform somehow expensive tasks that can be 39b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * postponed to a moment when they will not degrade user experience. 40b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 41b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * The current implementation is very simple. The start of a maintenance 42b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * window is announced if: the screen is off or showing a dream AND the 43b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * battery level is more than twenty percent AND at least one hour passed 44b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * activity). 45b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * 46b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * The end of a maintenance window is announced only if: a start was 47b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav * announced AND the screen turned on or a dream was stopped. 48b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav */ 49b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslavpublic class IdleMaintenanceService extends BroadcastReceiver { 50b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 516a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final boolean DEBUG = false; 52b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 53b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private static final String LOG_TAG = IdleMaintenanceService.class.getSimpleName(); 54b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 55b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1; 56b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 576a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day 58f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 59f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent 60f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 61f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent 62b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 636a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent 64f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 656a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min 66b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 676a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min 68b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 696a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE = 706a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE"; 716a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 726a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final Intent sIdleMaintenanceStartIntent; 736a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav static { 746a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START); 756a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceStartIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 766a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav }; 776a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 786a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private static final Intent sIdleMaintenanceEndIntent; 796a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav static { 806a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceEndIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_END); 816a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav sIdleMaintenanceEndIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 826a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 836a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 846a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private final AlarmManager mAlarmService; 856a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 866a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private final BatteryService mBatteryService; 876a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 886a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent; 89b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 90b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private final Context mContext; 91b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 92b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private final WakeLock mWakeLock; 93b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 94b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private final Handler mHandler; 95b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 966a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private long mLastIdleMaintenanceStartTimeMillis; 97b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 98b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; 99b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 100b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private boolean mIdleMaintenanceStarted; 101b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1026a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav public IdleMaintenanceService(Context context, BatteryService batteryService) { 103b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mContext = context; 1046a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mBatteryService = batteryService; 1056a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 1066a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 107b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 108b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 109b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 110b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 111b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mHandler = new Handler(mContext.getMainLooper()); 112b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1136a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); 1146a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1156a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0, 1166a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav intent, PendingIntent.FLAG_UPDATE_CURRENT); 1176a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 118b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav register(mContext.getMainLooper()); 119b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 120b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 121b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav public void register(Looper looper) { 122b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav IntentFilter intentFilter = new IntentFilter(); 123b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1246a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Alarm actions. 1256a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE); 1266a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 127b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav // Battery actions. 128b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 129b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 130b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav // Screen actions. 131b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_SCREEN_ON); 132b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 133b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 134b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav // Dream actions. 135b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_DREAMING_STARTED); 136b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED); 137b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 138b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mContext.registerReceiverAsUser(this, UserHandle.ALL, 139b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav intentFilter, null, new Handler(looper)); 140b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 141b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 1426a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private void scheduleUpdateIdleMaintenanceState(long delayMillis) { 1436a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis; 1446a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis, 1456a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mUpdateIdleMaintenanceStatePendingIntent); 1466a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 1476a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 1486a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private void unscheduleUpdateIdleMaintenanceState() { 1496a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent); 1506a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 1516a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 152b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private void updateIdleMaintenanceState() { 153b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav if (mIdleMaintenanceStarted) { 1546a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Idle maintenance can be interrupted by user activity, or duration 1556a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // time out, or low battery. 1566a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav if (!lastUserActivityPermitsIdleMaintenanceRunning() 1576a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav || !batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) { 1586a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav unscheduleUpdateIdleMaintenanceState(); 159b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mIdleMaintenanceStarted = false; 160f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(), 1616a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), 1626a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav isBatteryCharging() ? 1 : 0); 163b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav sendIdleMaintenanceEndIntent(); 1646a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // We stopped since we don't have enough battery or timed out but the 1656a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // user is not using the device, so we should be able to run maintenance 1666a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // in the next maintenance window since the battery may be charged 1676a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // without interaction and the min interval between maintenances passed. 1686a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav if (!batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) { 1696a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState( 1706a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav getNextIdleMaintenanceIntervalStartFromNow()); 1716a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 172b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 173f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav } else if (deviceStatePermitsIdleMaintenanceStart() 174b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav && lastUserActivityPermitsIdleMaintenanceStart() 175b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav && lastRunPermitsIdleMaintenanceStart()) { 1766a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Now that we started idle maintenance, we should schedule another 1776a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // update for the moment when the idle maintenance times out. 1786a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION); 179b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mIdleMaintenanceStarted = true; 180f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(), 1816a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), 1826a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav isBatteryCharging() ? 1 : 0); 183f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime(); 184b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav sendIdleMaintenanceStartIntent(); 1856a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } else if (lastUserActivityPermitsIdleMaintenanceStart()) { 1866a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav if (lastRunPermitsIdleMaintenanceStart()) { 1876a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The user does not use the device and we did not run maintenance in more 1886a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // than the min interval between runs, so schedule an update - maybe the 1896a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // battery will be charged latter. 1906a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); 1916a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } else { 1926a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The user does not use the device but we have run maintenance in the min 1936a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // interval between runs, so schedule an update after the min interval ends. 1946a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState( 1956a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav getNextIdleMaintenanceIntervalStartFromNow()); 1966a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 197b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 198b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 199b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 2006a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private long getNextIdleMaintenanceIntervalStartFromNow() { 2016a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS 2026a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav - SystemClock.elapsedRealtime(); 2036a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 2046a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 205b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private void sendIdleMaintenanceStartIntent() { 206b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock.acquire(); 2076a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL, 208b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav null, this, mHandler, Activity.RESULT_OK, null, null); 209b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 210b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 211b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav private void sendIdleMaintenanceEndIntent() { 212b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock.acquire(); 2136a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceEndIntent, UserHandle.ALL, 214b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav null, this, mHandler, Activity.RESULT_OK, null, null); 215b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 216b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 217f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav private boolean deviceStatePermitsIdleMaintenanceStart() { 2186a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav final int minBatteryLevel = isBatteryCharging() 219f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING 220f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING; 221f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID 2226a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && mBatteryService.getBatteryLevel() > minBatteryLevel); 223f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav } 224f23b64df94bbff9ac8c87832dea9c1bc0ae9a950Svetoslav 2256a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean lastUserActivityPermitsIdleMaintenanceStart() { 2266a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The last time the user poked the device is above the threshold. 227b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID 2286a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis 2296a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); 230b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 231b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 2326a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean lastRunPermitsIdleMaintenanceStart() { 2336a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Enough time passed since the last maintenance run. 2346a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis 2356a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS; 236b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 237b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 2386a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean lastUserActivityPermitsIdleMaintenanceRunning() { 2396a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // The user is not using the device. 2406a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID); 2416a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 2426a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 2436a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() { 2446a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Battery not too low and the maintenance duration did not timeout. 2456a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING 2466a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION 2476a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav > SystemClock.elapsedRealtime()); 2486a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 2496a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav 2506a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav private boolean isBatteryCharging() { 2516a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav return mBatteryService.getPlugType() > 0 2526a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav && mBatteryService.getInvalidCharger() == 0; 253b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 254b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav 255b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav @Override 256b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav public void onReceive(Context context, Intent intent) { 257b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav if (DEBUG) { 258b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav Log.i(LOG_TAG, intent.getAction()); 259b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 260b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav String action = intent.getAction(); 261b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 2626a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // We care about battery only if maintenance is in progress so we can 2636a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // stop it if battery is too low. Note that here we assume that the 2646a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // maintenance clients are properly holding a wake lock. We will 2656a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // refactor the maintenance to use services instead of intents for the 2666a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // next release. The only client for this for now is internal an holds 2676a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // a wake lock correctly. 2686a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav if (mIdleMaintenanceStarted) { 2696a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav updateIdleMaintenanceState(); 2706a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } 271b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } else if (Intent.ACTION_SCREEN_ON.equals(action) 272b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav || Intent.ACTION_DREAMING_STOPPED.equals(action)) { 273b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID; 2746a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // Unschedule any future updates since we already know that maintenance 2756a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // cannot be performed since the user is back. 2766a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav unscheduleUpdateIdleMaintenanceState(); 2776a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // If the screen went on/stopped dreaming, we know the user is using the 2786a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // device which means that idle maintenance should be stopped if running. 2796a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav updateIdleMaintenanceState(); 280b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } else if (Intent.ACTION_SCREEN_OFF.equals(action) 281b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav || Intent.ACTION_DREAMING_STARTED.equals(action)) { 282b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime(); 2836a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // If screen went off/started dreaming, we may be able to start idle maintenance 2846a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // after the minimal user inactivity elapses. We schedule an alarm for when 2856a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // this timeout elapses since the device may go to sleep by then. 2866a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START); 2876a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) { 2886a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav updateIdleMaintenanceState(); 289b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action) 290b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav || Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) { 2916a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // We were holding a wake lock while broadcasting the idle maintenance 2926a08a12b8e8ef6fa04932c7a1c5255e3f158a3c8Svetoslav // intents but now that we finished the broadcast release the wake lock. 293b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav mWakeLock.release(); 294b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 295b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav } 296b3038ec7cfc5d26eb0be18ae65c62825556bca0fSvetoslav} 297