Loading core/java/android/content/Intent.java +20 −0 Original line number Diff line number Diff line Loading @@ -3986,6 +3986,26 @@ public class Intent implements Parcelable, Cloneable { */ public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2; /** * Broadcast Action: Indicates the dock in idle state while device is docked. * * <p class="note">This is a protected intent that can only be sent * by the system. * * @hide */ public static final String ACTION_DOCK_IDLE = "android.intent.action.DOCK_IDLE"; /** * Broadcast Action: Indicates the dock in active state while device is docked. * * <p class="note">This is a protected intent that can only be sent * by the system. * * @hide */ public static final String ACTION_DOCK_ACTIVE = "android.intent.action.DOCK_ACTIVE"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- Loading core/res/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -599,6 +599,10 @@ <protected-broadcast android:name="android.app.action.DATA_SHARING_RESTRICTION_CHANGED" /> <protected-broadcast android:name="android.app.action.STATSD_STARTED" /> <!-- For IdleController --> <protected-broadcast android:name="android.intent.action.DOCK_IDLE" /> <protected-broadcast android:name="android.intent.action.DOCK_ACTIVE" /> <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> Loading services/core/java/com/android/server/job/JobSchedulerService.java +12 −0 Original line number Diff line number Diff line Loading @@ -2961,6 +2961,18 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; } void triggerDockState(boolean idleState) { final Intent dockIntent; if (idleState) { dockIntent = new Intent(Intent.ACTION_DOCK_IDLE); } else { dockIntent = new Intent(Intent.ACTION_DOCK_ACTIVE); } dockIntent.setPackage("android"); dockIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); getContext().sendBroadcastAsUser(dockIntent, UserHandle.ALL); } private String printContextIdToJobMap(JobStatus[] map, String initial) { StringBuilder s = new StringBuilder(initial + ": "); for (int i=0; i<map.length; i++) { Loading services/core/java/com/android/server/job/JobSchedulerShellCommand.java +27 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,8 @@ public final class JobSchedulerShellCommand extends ShellCommand { return getJobState(pw); case "heartbeat": return doHeartbeat(pw); case "trigger-dock-state": return triggerDockState(pw); default: return handleDefaultCommands(cmd); } Loading Loading @@ -349,6 +351,29 @@ public final class JobSchedulerShellCommand extends ShellCommand { } } private int triggerDockState(PrintWriter pw) throws Exception { checkPermission("trigger wireless charging dock state"); final String opt = getNextArgRequired(); boolean idleState; if ("idle".equals(opt)) { idleState = true; } else if ("active".equals(opt)) { idleState = false; } else { getErrPrintWriter().println("Error: unknown option " + opt); return 1; } final long ident = Binder.clearCallingIdentity(); try { mInternal.triggerDockState(idleState); } finally { Binder.restoreCallingIdentity(ident); } return 0; } @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); Loading Loading @@ -403,6 +428,8 @@ public final class JobSchedulerShellCommand extends ShellCommand { pw.println(" Options:"); pw.println(" -u or --user: specify which user's job is to be run; the default is"); pw.println(" the primary or system user"); pw.println(" trigger-dock-state [idle|active]"); pw.println(" Trigger wireless charging dock state. Active by default."); pw.println(); } Loading services/core/java/com/android/server/job/controllers/IdleController.java +36 −8 Original line number Diff line number Diff line Loading @@ -42,7 +42,7 @@ public final class IdleController extends StateController { || Log.isLoggable(TAG, Log.DEBUG); // Policy: we decide that we're "idle" if the device has been unused / // screen off or dreaming for at least this long // screen off or dreaming or wireless charging dock idle for at least this long private long mInactivityIdleThreshold; private long mIdleWindowSlop; final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>(); Loading Loading @@ -105,6 +105,7 @@ public final class IdleController extends StateController { // on the main looper thread, either in onReceive() or in an alarm callback. private boolean mIdle; private boolean mScreenOn; private boolean mDockIdle; private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> { handleIdleTrigger(); Loading @@ -117,6 +118,7 @@ public final class IdleController extends StateController { // device in some meaningful way. mIdle = false; mScreenOn = true; mDockIdle = false; } public boolean isIdle() { Loading @@ -137,6 +139,10 @@ public final class IdleController extends StateController { // Debugging/instrumentation filter.addAction(ActivityManagerService.ACTION_TRIGGER_IDLE); // Wireless charging dock state filter.addAction(Intent.ACTION_DOCK_IDLE); filter.addAction(Intent.ACTION_DOCK_ACTIVE); mContext.registerReceiver(this, filter); } Loading @@ -144,11 +150,22 @@ public final class IdleController extends StateController { 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)) { || action.equals(Intent.ACTION_DREAMING_STOPPED) || action.equals(Intent.ACTION_DOCK_ACTIVE)) { if (action.equals(Intent.ACTION_DOCK_ACTIVE)) { if (!mScreenOn) { // Ignore this intent during screen off return; } else { mDockIdle = false; } } else { mScreenOn = true; mDockIdle = false; } if (DEBUG) { Slog.v(TAG,"exiting idle : " + action); } mScreenOn = true; //cancel the alarm mAlarm.cancel(mIdleAlarmListener); if (mIdle) { Loading @@ -157,17 +174,28 @@ public final class IdleController extends StateController { 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 || action.equals(Intent.ACTION_DREAMING_STARTED) || action.equals(Intent.ACTION_DOCK_IDLE)) { // when the screen goes off or dreaming starts or wireless charging dock in idle, // we schedule the alarm that will tell us when we have decided the device is // truly idle. if (action.equals(Intent.ACTION_DOCK_IDLE)) { if (!mScreenOn) { // Ignore this intent during screen off return; } else { mDockIdle = true; } } else { mScreenOn = false; mDockIdle = false; } final long nowElapsed = sElapsedRealtimeClock.millis(); final long when = nowElapsed + mInactivityIdleThreshold; if (DEBUG) { Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when=" + when); } mScreenOn = false; mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mIdleWindowSlop, "JS idleness", mIdleAlarmListener, null); } else if (action.equals(ActivityManagerService.ACTION_TRIGGER_IDLE)) { Loading @@ -177,7 +205,7 @@ public final class IdleController extends StateController { private void handleIdleTrigger() { // idle time starts now. Do not set mIdle if screen is on. if (!mIdle && !mScreenOn) { if (!mIdle && (!mScreenOn || mDockIdle)) { if (DEBUG) { Slog.v(TAG, "Idle trigger fired @ " + sElapsedRealtimeClock.millis()); } Loading Loading
core/java/android/content/Intent.java +20 −0 Original line number Diff line number Diff line Loading @@ -3986,6 +3986,26 @@ public class Intent implements Parcelable, Cloneable { */ public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2; /** * Broadcast Action: Indicates the dock in idle state while device is docked. * * <p class="note">This is a protected intent that can only be sent * by the system. * * @hide */ public static final String ACTION_DOCK_IDLE = "android.intent.action.DOCK_IDLE"; /** * Broadcast Action: Indicates the dock in active state while device is docked. * * <p class="note">This is a protected intent that can only be sent * by the system. * * @hide */ public static final String ACTION_DOCK_ACTIVE = "android.intent.action.DOCK_ACTIVE"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- Loading
core/res/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -599,6 +599,10 @@ <protected-broadcast android:name="android.app.action.DATA_SHARING_RESTRICTION_CHANGED" /> <protected-broadcast android:name="android.app.action.STATSD_STARTED" /> <!-- For IdleController --> <protected-broadcast android:name="android.intent.action.DOCK_IDLE" /> <protected-broadcast android:name="android.intent.action.DOCK_ACTIVE" /> <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> Loading
services/core/java/com/android/server/job/JobSchedulerService.java +12 −0 Original line number Diff line number Diff line Loading @@ -2961,6 +2961,18 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; } void triggerDockState(boolean idleState) { final Intent dockIntent; if (idleState) { dockIntent = new Intent(Intent.ACTION_DOCK_IDLE); } else { dockIntent = new Intent(Intent.ACTION_DOCK_ACTIVE); } dockIntent.setPackage("android"); dockIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); getContext().sendBroadcastAsUser(dockIntent, UserHandle.ALL); } private String printContextIdToJobMap(JobStatus[] map, String initial) { StringBuilder s = new StringBuilder(initial + ": "); for (int i=0; i<map.length; i++) { Loading
services/core/java/com/android/server/job/JobSchedulerShellCommand.java +27 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,8 @@ public final class JobSchedulerShellCommand extends ShellCommand { return getJobState(pw); case "heartbeat": return doHeartbeat(pw); case "trigger-dock-state": return triggerDockState(pw); default: return handleDefaultCommands(cmd); } Loading Loading @@ -349,6 +351,29 @@ public final class JobSchedulerShellCommand extends ShellCommand { } } private int triggerDockState(PrintWriter pw) throws Exception { checkPermission("trigger wireless charging dock state"); final String opt = getNextArgRequired(); boolean idleState; if ("idle".equals(opt)) { idleState = true; } else if ("active".equals(opt)) { idleState = false; } else { getErrPrintWriter().println("Error: unknown option " + opt); return 1; } final long ident = Binder.clearCallingIdentity(); try { mInternal.triggerDockState(idleState); } finally { Binder.restoreCallingIdentity(ident); } return 0; } @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); Loading Loading @@ -403,6 +428,8 @@ public final class JobSchedulerShellCommand extends ShellCommand { pw.println(" Options:"); pw.println(" -u or --user: specify which user's job is to be run; the default is"); pw.println(" the primary or system user"); pw.println(" trigger-dock-state [idle|active]"); pw.println(" Trigger wireless charging dock state. Active by default."); pw.println(); } Loading
services/core/java/com/android/server/job/controllers/IdleController.java +36 −8 Original line number Diff line number Diff line Loading @@ -42,7 +42,7 @@ public final class IdleController extends StateController { || Log.isLoggable(TAG, Log.DEBUG); // Policy: we decide that we're "idle" if the device has been unused / // screen off or dreaming for at least this long // screen off or dreaming or wireless charging dock idle for at least this long private long mInactivityIdleThreshold; private long mIdleWindowSlop; final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>(); Loading Loading @@ -105,6 +105,7 @@ public final class IdleController extends StateController { // on the main looper thread, either in onReceive() or in an alarm callback. private boolean mIdle; private boolean mScreenOn; private boolean mDockIdle; private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> { handleIdleTrigger(); Loading @@ -117,6 +118,7 @@ public final class IdleController extends StateController { // device in some meaningful way. mIdle = false; mScreenOn = true; mDockIdle = false; } public boolean isIdle() { Loading @@ -137,6 +139,10 @@ public final class IdleController extends StateController { // Debugging/instrumentation filter.addAction(ActivityManagerService.ACTION_TRIGGER_IDLE); // Wireless charging dock state filter.addAction(Intent.ACTION_DOCK_IDLE); filter.addAction(Intent.ACTION_DOCK_ACTIVE); mContext.registerReceiver(this, filter); } Loading @@ -144,11 +150,22 @@ public final class IdleController extends StateController { 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)) { || action.equals(Intent.ACTION_DREAMING_STOPPED) || action.equals(Intent.ACTION_DOCK_ACTIVE)) { if (action.equals(Intent.ACTION_DOCK_ACTIVE)) { if (!mScreenOn) { // Ignore this intent during screen off return; } else { mDockIdle = false; } } else { mScreenOn = true; mDockIdle = false; } if (DEBUG) { Slog.v(TAG,"exiting idle : " + action); } mScreenOn = true; //cancel the alarm mAlarm.cancel(mIdleAlarmListener); if (mIdle) { Loading @@ -157,17 +174,28 @@ public final class IdleController extends StateController { 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 || action.equals(Intent.ACTION_DREAMING_STARTED) || action.equals(Intent.ACTION_DOCK_IDLE)) { // when the screen goes off or dreaming starts or wireless charging dock in idle, // we schedule the alarm that will tell us when we have decided the device is // truly idle. if (action.equals(Intent.ACTION_DOCK_IDLE)) { if (!mScreenOn) { // Ignore this intent during screen off return; } else { mDockIdle = true; } } else { mScreenOn = false; mDockIdle = false; } final long nowElapsed = sElapsedRealtimeClock.millis(); final long when = nowElapsed + mInactivityIdleThreshold; if (DEBUG) { Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when=" + when); } mScreenOn = false; mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mIdleWindowSlop, "JS idleness", mIdleAlarmListener, null); } else if (action.equals(ActivityManagerService.ACTION_TRIGGER_IDLE)) { Loading @@ -177,7 +205,7 @@ public final class IdleController extends StateController { private void handleIdleTrigger() { // idle time starts now. Do not set mIdle if screen is on. if (!mIdle && !mScreenOn) { if (!mIdle && (!mScreenOn || mDockIdle)) { if (DEBUG) { Slog.v(TAG, "Idle trigger fired @ " + sElapsedRealtimeClock.millis()); } Loading