diff options
author | Christopher Tate <ctate@google.com> | 2014-05-14 17:01:58 -0700 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2014-05-16 16:55:22 -0700 |
commit | 851f3d5110c48bcdba4762739c4ad9b9b479d9af (patch) | |
tree | 6ba4359f33ae3fa8dece90fb85b04ba8e827bfe2 | |
parent | e78e6f923774ac2cadee43fbf09b4df6b2b4ee87 (diff) | |
download | frameworks_base-851f3d5110c48bcdba4762739c4ad9b9b479d9af.zip frameworks_base-851f3d5110c48bcdba4762739c4ad9b9b479d9af.tar.gz frameworks_base-851f3d5110c48bcdba4762739c4ad9b9b479d9af.tar.bz2 |
Add idle-state controller for the Task Manager
"Idle time" is currently defined to begin ~ an hour (actually slightly
more) after the screen turns off and/or dreaming begins. Screen-on
and dreams-ending are the triggers for declaring "idle" time to be
over.
Bug 14993295
Change-Id: I0898871d5b76a52d647ae2ebcb1b2f941ec45e79
-rw-r--r-- | services/core/java/com/android/server/task/controllers/IdleController.java | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/task/controllers/IdleController.java new file mode 100644 index 0000000..a319a31 --- /dev/null +++ b/services/core/java/com/android/server/task/controllers/IdleController.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.task.controllers; + +import java.util.ArrayList; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.SystemClock; +import android.util.Slog; + +import com.android.server.task.TaskManagerService; + +public class IdleController extends StateController { + private static final String TAG = "IdleController"; + private static final boolean DEBUG = false; + + // Policy: we decide that we're "idle" if the device has been unused / + // screen off or dreaming for at least this long + private static final long INACTIVITY_IDLE_THRESHOLD = 71 * 60 * 1000; // millis; 71 min + private static final long IDLE_WINDOW_SLOP = 5 * 60 * 1000; // 5 minute window, to be nice + + private static final String ACTION_TRIGGER_IDLE = + "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"; + + final ArrayList<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>(); + IdlenessTracker mIdleTracker; + + // Singleton factory + private static Object sCreationLock = new Object(); + private static volatile IdleController sController; + + public IdleController getController(TaskManagerService service) { + synchronized (sCreationLock) { + if (sController == null) { + sController = new IdleController(service); + } + return sController; + } + } + + private IdleController(TaskManagerService service) { + super(service); + initIdleStateTracking(); + } + + /** + * StateController interface + */ + @Override + public void maybeTrackTaskState(TaskStatus taskStatus) { + if (taskStatus.hasIdleConstraint()) { + synchronized (mTrackedTasks) { + mTrackedTasks.add(taskStatus); + taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle()); + } + } + } + + @Override + public void removeTaskStateIfTracked(TaskStatus taskStatus) { + synchronized (mTrackedTasks) { + mTrackedTasks.remove(taskStatus); + } + } + + /** + * Interaction with the task manager service + */ + void reportNewIdleState(boolean isIdle) { + synchronized (mTrackedTasks) { + for (TaskStatus task : mTrackedTasks) { + task.idleConstraintSatisfied.set(isIdle); + mStateChangedListener.onTaskStateChanged(task); + } + } + } + + /** + * Idle state tracking, and messaging with the task manager when + * significant state changes occur + */ + private void initIdleStateTracking() { + mIdleTracker = new IdlenessTracker(); + mIdleTracker.startTracking(); + } + + class IdlenessTracker extends BroadcastReceiver { + private AlarmManager mAlarm; + private PendingIntent mIdleTriggerIntent; + boolean mIdle; + + public IdlenessTracker() { + mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + + Intent intent = new Intent(ACTION_TRIGGER_IDLE); + intent.setComponent(new ComponentName(mContext, this.getClass())); + mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); + + // at boot we presume that the user has just "interacted" with the + // device in some meaningful way + mIdle = false; + } + + public boolean isIdle() { + return mIdle; + } + + public void startTracking() { + IntentFilter filter = new IntentFilter(); + + // Screen state + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + + // Dreaming state + filter.addAction(Intent.ACTION_DREAMING_STARTED); + filter.addAction(Intent.ACTION_DREAMING_STOPPED); + + mContext.registerReceiver(this, filter); + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + if (action.equals(Intent.ACTION_SCREEN_ON) + || action.equals(Intent.ACTION_DREAMING_STOPPED)) { + // possible transition to not-idle + if (mIdle) { + if (DEBUG) { + Slog.v(TAG, "exiting idle : " + action); + } + mAlarm.cancel(mIdleTriggerIntent); + mIdle = false; + reportNewIdleState(mIdle); + } + } else if (action.equals(Intent.ACTION_SCREEN_OFF) + || action.equals(Intent.ACTION_DREAMING_STARTED)) { + // when the screen goes off or dreaming starts, we schedule the + // alarm that will tell us when we have decided the device is + // truly idle. + long when = SystemClock.elapsedRealtime() + INACTIVITY_IDLE_THRESHOLD; + if (DEBUG) { + Slog.v(TAG, "Scheduling idle : " + action + " when=" + when); + } + mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, + when, IDLE_WINDOW_SLOP, mIdleTriggerIntent); + } else if (action.equals(ACTION_TRIGGER_IDLE)) { + // idle time starts now + if (!mIdle) { + if (DEBUG) { + Slog.v(TAG, "Idle trigger fired @ " + SystemClock.elapsedRealtime()); + } + mIdle = true; + reportNewIdleState(mIdle); + } + } + } + } +} |