summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2014-05-14 17:01:58 -0700
committerChristopher Tate <ctate@google.com>2014-05-16 16:55:22 -0700
commit851f3d5110c48bcdba4762739c4ad9b9b479d9af (patch)
tree6ba4359f33ae3fa8dece90fb85b04ba8e827bfe2
parente78e6f923774ac2cadee43fbf09b4df6b2b4ee87 (diff)
downloadframeworks_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.java180
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);
+ }
+ }
+ }
+ }
+}