1 /*
2  * Copyright (C) 2012 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.power;
18 
19 import android.annotation.Nullable;
20 import android.annotation.UserIdInt;
21 import android.app.ActivityManagerInternal;
22 import android.app.AppOpsManager;
23 import android.app.trust.TrustManager;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.hardware.input.InputManagerInternal;
28 import android.media.AudioAttributes;
29 import android.media.AudioManager;
30 import android.media.Ringtone;
31 import android.media.RingtoneManager;
32 import android.metrics.LogMaker;
33 import android.net.Uri;
34 import android.os.BatteryStats;
35 import android.os.Handler;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.PowerManager;
39 import android.os.PowerManagerInternal;
40 import android.os.Process;
41 import android.os.RemoteException;
42 import android.os.SystemClock;
43 import android.os.UserHandle;
44 import android.os.VibrationEffect;
45 import android.os.Vibrator;
46 import android.os.WorkSource;
47 import android.provider.Settings;
48 import android.util.EventLog;
49 import android.util.Slog;
50 import android.view.inputmethod.InputMethodManagerInternal;
51 
52 import com.android.internal.app.IBatteryStats;
53 import com.android.internal.logging.MetricsLogger;
54 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
55 import com.android.server.EventLogTags;
56 import com.android.server.LocalServices;
57 import com.android.server.policy.WindowManagerPolicy;
58 import com.android.server.statusbar.StatusBarManagerInternal;
59 
60 /**
61  * Sends broadcasts about important power state changes.
62  * <p>
63  * This methods of this class may be called by the power manager service while
64  * its lock is being held.  Internally it takes care of sending broadcasts to
65  * notify other components of the system or applications asynchronously.
66  * </p><p>
67  * The notifier is designed to collapse unnecessary broadcasts when it is not
68  * possible for the system to have observed an intermediate state.
69  * </p><p>
70  * For example, if the device wakes up, goes to sleep, wakes up again and goes to
71  * sleep again before the wake up notification is sent, then the system will
72  * be told about only one wake up and sleep.  However, we always notify the
73  * fact that at least one transition occurred.  It is especially important to
74  * tell the system when we go to sleep so that it can lock the keyguard if needed.
75  * </p>
76  */
77 final class Notifier {
78     private static final String TAG = "PowerManagerNotifier";
79 
80     private static final boolean DEBUG = false;
81 
82     private static final int INTERACTIVE_STATE_UNKNOWN = 0;
83     private static final int INTERACTIVE_STATE_AWAKE = 1;
84     private static final int INTERACTIVE_STATE_ASLEEP = 2;
85 
86     private static final int MSG_USER_ACTIVITY = 1;
87     private static final int MSG_BROADCAST = 2;
88     private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
89     private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4;
90     private static final int MSG_PROFILE_TIMED_OUT = 5;
91     private static final int MSG_WIRED_CHARGING_STARTED = 6;
92 
93     private static final long[] WIRELESS_VIBRATION_TIME = {
94             40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms
95             40, 40, 40, 40, 40, 40, 40 // ramp-down sampling rate = 40ms
96     };
97     private static final int[] WIRELESS_VIBRATION_AMPLITUDE = {
98             1, 4, 11, 25, 44, 67, 91, 114, 123, // ramp-up amplitude (from 0 to 50%)
99             103, 79, 55, 34, 17, 7, 2 // ramp-up amplitude
100     };
101     private static final VibrationEffect WIRELESS_CHARGING_VIBRATION_EFFECT =
102             VibrationEffect.createWaveform(WIRELESS_VIBRATION_TIME, WIRELESS_VIBRATION_AMPLITUDE,
103                     -1);
104     private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
105             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
106             .build();
107 
108     private final Object mLock = new Object();
109 
110     private final Context mContext;
111     private final IBatteryStats mBatteryStats;
112     private final AppOpsManager mAppOps;
113     private final SuspendBlocker mSuspendBlocker;
114     private final WindowManagerPolicy mPolicy;
115     private final ActivityManagerInternal mActivityManagerInternal;
116     private final InputManagerInternal mInputManagerInternal;
117     private final InputMethodManagerInternal mInputMethodManagerInternal;
118     @Nullable private final StatusBarManagerInternal mStatusBarManagerInternal;
119     private final TrustManager mTrustManager;
120     private final Vibrator mVibrator;
121 
122     private final NotifierHandler mHandler;
123     private final Intent mScreenOnIntent;
124     private final Intent mScreenOffIntent;
125     private final Intent mScreenBrightnessBoostIntent;
126 
127     // True if the device should suspend when the screen is off due to proximity.
128     private final boolean mSuspendWhenScreenOffDueToProximityConfig;
129 
130     // The current interactive state.  This is set as soon as an interactive state
131     // transition begins so as to capture the reason that it happened.  At some point
132     // this state will propagate to the pending state then eventually to the
133     // broadcasted state over the course of reporting the transition asynchronously.
134     private boolean mInteractive = true;
135     private int mInteractiveChangeReason;
136     private boolean mInteractiveChanging;
137 
138     // The pending interactive state that we will eventually want to broadcast.
139     // This is designed so that we can collapse redundant sequences of awake/sleep
140     // transition pairs while still guaranteeing that at least one transition is observed
141     // whenever this happens.
142     private int mPendingInteractiveState;
143     private boolean mPendingWakeUpBroadcast;
144     private boolean mPendingGoToSleepBroadcast;
145 
146     // The currently broadcasted interactive state.  This reflects what other parts of the
147     // system have observed.
148     private int mBroadcastedInteractiveState;
149     private boolean mBroadcastInProgress;
150     private long mBroadcastStartTime;
151 
152     // True if a user activity message should be sent.
153     private boolean mUserActivityPending;
154 
Notifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy)155     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
156             SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
157         mContext = context;
158         mBatteryStats = batteryStats;
159         mAppOps = mContext.getSystemService(AppOpsManager.class);
160         mSuspendBlocker = suspendBlocker;
161         mPolicy = policy;
162         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
163         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
164         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
165         mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
166         mTrustManager = mContext.getSystemService(TrustManager.class);
167         mVibrator = mContext.getSystemService(Vibrator.class);
168 
169         mHandler = new NotifierHandler(looper);
170         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
171         mScreenOnIntent.addFlags(
172                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
173                 | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
174         mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
175         mScreenOffIntent.addFlags(
176                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
177                 | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
178         mScreenBrightnessBoostIntent =
179                 new Intent(PowerManager.ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED);
180         mScreenBrightnessBoostIntent.addFlags(
181                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
182 
183         mSuspendWhenScreenOffDueToProximityConfig = context.getResources().getBoolean(
184                 com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
185 
186         // Initialize interactive state for battery stats.
187         try {
188             mBatteryStats.noteInteractive(true);
189         } catch (RemoteException ex) { }
190     }
191 
192     /**
193      * Called when a wake lock is acquired.
194      */
onWakeLockAcquired(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag)195     public void onWakeLockAcquired(int flags, String tag, String packageName,
196             int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
197         if (DEBUG) {
198             Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
199                     + "\", packageName=" + packageName
200                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
201                     + ", workSource=" + workSource);
202         }
203 
204         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
205         if (monitorType >= 0) {
206             try {
207                 final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
208                         && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
209                 if (workSource != null) {
210                     mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
211                             historyTag, monitorType, unimportantForLogging);
212                 } else {
213                     mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
214                             monitorType, unimportantForLogging);
215                     // XXX need to deal with disabled operations.
216                     mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
217                 }
218             } catch (RemoteException ex) {
219                 // Ignore
220             }
221         }
222     }
223 
onLongPartialWakeLockStart(String tag, int ownerUid, WorkSource workSource, String historyTag)224     public void onLongPartialWakeLockStart(String tag, int ownerUid, WorkSource workSource,
225             String historyTag) {
226         if (DEBUG) {
227             Slog.d(TAG, "onLongPartialWakeLockStart: ownerUid=" + ownerUid
228                     + ", workSource=" + workSource);
229         }
230 
231         try {
232             if (workSource != null) {
233                 mBatteryStats.noteLongPartialWakelockStartFromSource(tag, historyTag, workSource);
234             } else {
235                 mBatteryStats.noteLongPartialWakelockStart(tag, historyTag, ownerUid);
236             }
237         } catch (RemoteException ex) {
238             // Ignore
239         }
240     }
241 
onLongPartialWakeLockFinish(String tag, int ownerUid, WorkSource workSource, String historyTag)242     public void onLongPartialWakeLockFinish(String tag, int ownerUid, WorkSource workSource,
243             String historyTag) {
244         if (DEBUG) {
245             Slog.d(TAG, "onLongPartialWakeLockFinish: ownerUid=" + ownerUid
246                     + ", workSource=" + workSource);
247         }
248 
249         try {
250             if (workSource != null) {
251                 mBatteryStats.noteLongPartialWakelockFinishFromSource(tag, historyTag, workSource);
252             } else {
253                 mBatteryStats.noteLongPartialWakelockFinish(tag, historyTag, ownerUid);
254             }
255         } catch (RemoteException ex) {
256             // Ignore
257         }
258     }
259 
260     /**
261      * Called when a wake lock is changing.
262      */
onWakeLockChanging(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag, int newFlags, String newTag, String newPackageName, int newOwnerUid, int newOwnerPid, WorkSource newWorkSource, String newHistoryTag)263     public void onWakeLockChanging(int flags, String tag, String packageName,
264             int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
265             int newFlags, String newTag, String newPackageName, int newOwnerUid,
266             int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) {
267 
268         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
269         final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
270         if (workSource != null && newWorkSource != null
271                 && monitorType >= 0 && newMonitorType >= 0) {
272             if (DEBUG) {
273                 Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag
274                         + "\", packageName=" + newPackageName
275                         + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid
276                         + ", workSource=" + newWorkSource);
277             }
278 
279             final boolean unimportantForLogging = newOwnerUid == Process.SYSTEM_UID
280                     && (newFlags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
281             try {
282                 mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
283                         monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
284                         newMonitorType, unimportantForLogging);
285             } catch (RemoteException ex) {
286                 // Ignore
287             }
288         } else {
289             onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
290             onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
291                     newWorkSource, newHistoryTag);
292         }
293     }
294 
295     /**
296      * Called when a wake lock is released.
297      */
onWakeLockReleased(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag)298     public void onWakeLockReleased(int flags, String tag, String packageName,
299             int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
300         if (DEBUG) {
301             Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
302                     + "\", packageName=" + packageName
303                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
304                     + ", workSource=" + workSource);
305         }
306 
307         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
308         if (monitorType >= 0) {
309             try {
310                 if (workSource != null) {
311                     mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
312                             historyTag, monitorType);
313                 } else {
314                     mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
315                             historyTag, monitorType);
316                     mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
317                 }
318             } catch (RemoteException ex) {
319                 // Ignore
320             }
321         }
322     }
323 
getBatteryStatsWakeLockMonitorType(int flags)324     private int getBatteryStatsWakeLockMonitorType(int flags) {
325         switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
326             case PowerManager.PARTIAL_WAKE_LOCK:
327                 return BatteryStats.WAKE_TYPE_PARTIAL;
328 
329             case PowerManager.SCREEN_DIM_WAKE_LOCK:
330             case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
331                 return BatteryStats.WAKE_TYPE_FULL;
332 
333             case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
334                 if (mSuspendWhenScreenOffDueToProximityConfig) {
335                     return -1;
336                 }
337                 return BatteryStats.WAKE_TYPE_PARTIAL;
338 
339             case PowerManager.DRAW_WAKE_LOCK:
340                 return BatteryStats.WAKE_TYPE_DRAW;
341 
342             case PowerManager.DOZE_WAKE_LOCK:
343                 // Doze wake locks are an internal implementation detail of the
344                 // communication between dream manager service and power manager
345                 // service.  They have no additive battery impact.
346                 return -1;
347 
348             default:
349                 return -1;
350         }
351     }
352 
353     /**
354      * Notifies that the device is changing wakefulness.
355      * This function may be called even if the previous change hasn't finished in
356      * which case it will assume that the state did not fully converge before the
357      * next transition began and will recover accordingly.
358      */
onWakefulnessChangeStarted(final int wakefulness, int reason)359     public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
360         final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
361         if (DEBUG) {
362             Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
363                     + ", reason=" + reason + ", interactive=" + interactive);
364         }
365 
366         // Tell the activity manager about changes in wakefulness, not just interactivity.
367         // It needs more granularity than other components.
368         mHandler.post(new Runnable() {
369             @Override
370             public void run() {
371                 mActivityManagerInternal.onWakefulnessChanged(wakefulness);
372             }
373         });
374 
375         // Handle any early interactive state changes.
376         // Finish pending incomplete ones from a previous cycle.
377         if (mInteractive != interactive) {
378             // Finish up late behaviors if needed.
379             if (mInteractiveChanging) {
380                 handleLateInteractiveChange();
381             }
382 
383             // Start input as soon as we start waking up or going to sleep.
384             mInputManagerInternal.setInteractive(interactive);
385             mInputMethodManagerInternal.setInteractive(interactive);
386 
387             // Notify battery stats.
388             try {
389                 mBatteryStats.noteInteractive(interactive);
390             } catch (RemoteException ex) { }
391 
392             // Handle early behaviors.
393             mInteractive = interactive;
394             mInteractiveChangeReason = reason;
395             mInteractiveChanging = true;
396             handleEarlyInteractiveChange();
397         }
398     }
399 
400     /**
401      * Notifies that the device has finished changing wakefulness.
402      */
onWakefulnessChangeFinished()403     public void onWakefulnessChangeFinished() {
404         if (DEBUG) {
405             Slog.d(TAG, "onWakefulnessChangeFinished");
406         }
407 
408         if (mInteractiveChanging) {
409             mInteractiveChanging = false;
410             handleLateInteractiveChange();
411         }
412     }
413 
414     /**
415      * Handle early interactive state changes such as getting applications or the lock
416      * screen running and ready for the user to see (such as when turning on the screen).
417      */
handleEarlyInteractiveChange()418     private void handleEarlyInteractiveChange() {
419         synchronized (mLock) {
420             if (mInteractive) {
421                 // Waking up...
422                 mHandler.post(new Runnable() {
423                     @Override
424                     public void run() {
425                         // Note a SCREEN tron event is logged in PowerManagerService.
426                         mPolicy.startedWakingUp();
427                     }
428                 });
429 
430                 // Send interactive broadcast.
431                 mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
432                 mPendingWakeUpBroadcast = true;
433                 updatePendingBroadcastLocked();
434             } else {
435                 // Going to sleep...
436                 // Tell the policy that we started going to sleep.
437                 final int why = translateOffReason(mInteractiveChangeReason);
438                 mHandler.post(new Runnable() {
439                     @Override
440                     public void run() {
441                         mPolicy.startedGoingToSleep(why);
442                     }
443                 });
444             }
445         }
446     }
447 
448     /**
449      * Handle late interactive state changes once they are finished so that the system can
450      * finish pending transitions (such as turning the screen off) before causing
451      * applications to change state visibly.
452      */
handleLateInteractiveChange()453     private void handleLateInteractiveChange() {
454         synchronized (mLock) {
455             if (mInteractive) {
456                 // Finished waking up...
457                 mHandler.post(new Runnable() {
458                     @Override
459                     public void run() {
460                         mPolicy.finishedWakingUp();
461                     }
462                 });
463             } else {
464                 // Finished going to sleep...
465                 // This is a good time to make transitions that we don't want the user to see,
466                 // such as bringing the key guard to focus.  There's no guarantee for this
467                 // however because the user could turn the device on again at any time.
468                 // Some things may need to be protected by other mechanisms that defer screen on.
469 
470                 // Cancel pending user activity.
471                 if (mUserActivityPending) {
472                     mUserActivityPending = false;
473                     mHandler.removeMessages(MSG_USER_ACTIVITY);
474                 }
475 
476                 // Tell the policy we finished going to sleep.
477                 final int why = translateOffReason(mInteractiveChangeReason);
478                 mHandler.post(new Runnable() {
479                     @Override
480                     public void run() {
481                         LogMaker log = new LogMaker(MetricsEvent.SCREEN);
482                         log.setType(MetricsEvent.TYPE_CLOSE);
483                         log.setSubtype(why);
484                         MetricsLogger.action(log);
485                         EventLogTags.writePowerScreenState(0, why, 0, 0, 0);
486                         mPolicy.finishedGoingToSleep(why);
487                     }
488                 });
489 
490                 // Send non-interactive broadcast.
491                 mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
492                 mPendingGoToSleepBroadcast = true;
493                 updatePendingBroadcastLocked();
494             }
495         }
496     }
497 
translateOffReason(int reason)498     private static int translateOffReason(int reason) {
499         switch (reason) {
500             case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
501                 return WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
502             case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
503                 return WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
504             default:
505                 return WindowManagerPolicy.OFF_BECAUSE_OF_USER;
506         }
507     }
508 
509     /**
510      * Called when screen brightness boost begins or ends.
511      */
onScreenBrightnessBoostChanged()512     public void onScreenBrightnessBoostChanged() {
513         if (DEBUG) {
514             Slog.d(TAG, "onScreenBrightnessBoostChanged");
515         }
516 
517         mSuspendBlocker.acquire();
518         Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED);
519         msg.setAsynchronous(true);
520         mHandler.sendMessage(msg);
521     }
522 
523     /**
524      * Called when there has been user activity.
525      */
onUserActivity(int event, int uid)526     public void onUserActivity(int event, int uid) {
527         if (DEBUG) {
528             Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
529         }
530 
531         try {
532             mBatteryStats.noteUserActivity(uid, event);
533         } catch (RemoteException ex) {
534             // Ignore
535         }
536 
537         synchronized (mLock) {
538             if (!mUserActivityPending) {
539                 mUserActivityPending = true;
540                 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
541                 msg.setAsynchronous(true);
542                 mHandler.sendMessage(msg);
543             }
544         }
545     }
546 
547     /**
548      * Called when the screen has turned on.
549      */
onWakeUp(String reason, int reasonUid, String opPackageName, int opUid)550     public void onWakeUp(String reason, int reasonUid, String opPackageName, int opUid) {
551         if (DEBUG) {
552             Slog.d(TAG, "onWakeUp: event=" + reason + ", reasonUid=" + reasonUid
553                     + " opPackageName=" + opPackageName + " opUid=" + opUid);
554         }
555 
556         try {
557             mBatteryStats.noteWakeUp(reason, reasonUid);
558             if (opPackageName != null) {
559                 mAppOps.noteOpNoThrow(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName);
560             }
561         } catch (RemoteException ex) {
562             // Ignore
563         }
564     }
565 
566     /**
567      * Called when profile screen lock timeout has expired.
568      */
onProfileTimeout(@serIdInt int userId)569     public void onProfileTimeout(@UserIdInt int userId) {
570         final Message msg = mHandler.obtainMessage(MSG_PROFILE_TIMED_OUT);
571         msg.setAsynchronous(true);
572         msg.arg1 = userId;
573         mHandler.sendMessage(msg);
574     }
575 
576     /**
577      * Called when wireless charging has started so as to provide user feedback (sound and visual).
578      */
onWirelessChargingStarted(int batteryLevel)579     public void onWirelessChargingStarted(int batteryLevel) {
580         if (DEBUG) {
581             Slog.d(TAG, "onWirelessChargingStarted");
582         }
583 
584         mSuspendBlocker.acquire();
585         Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
586         msg.setAsynchronous(true);
587         msg.arg1 = batteryLevel;
588         mHandler.sendMessage(msg);
589     }
590 
591     /**
592      * Called when wired charging has started so as to provide user feedback
593      */
onWiredChargingStarted()594     public void onWiredChargingStarted() {
595         if (DEBUG) {
596             Slog.d(TAG, "onWiredChargingStarted");
597         }
598 
599         mSuspendBlocker.acquire();
600         Message msg = mHandler.obtainMessage(MSG_WIRED_CHARGING_STARTED);
601         msg.setAsynchronous(true);
602         mHandler.sendMessage(msg);
603     }
604 
updatePendingBroadcastLocked()605     private void updatePendingBroadcastLocked() {
606         if (!mBroadcastInProgress
607                 && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
608                 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
609                         || mPendingInteractiveState != mBroadcastedInteractiveState)) {
610             mBroadcastInProgress = true;
611             mSuspendBlocker.acquire();
612             Message msg = mHandler.obtainMessage(MSG_BROADCAST);
613             msg.setAsynchronous(true);
614             mHandler.sendMessage(msg);
615         }
616     }
617 
finishPendingBroadcastLocked()618     private void finishPendingBroadcastLocked() {
619         mBroadcastInProgress = false;
620         mSuspendBlocker.release();
621     }
622 
sendUserActivity()623     private void sendUserActivity() {
624         synchronized (mLock) {
625             if (!mUserActivityPending) {
626                 return;
627             }
628             mUserActivityPending = false;
629         }
630         mPolicy.userActivity();
631     }
632 
sendNextBroadcast()633     private void sendNextBroadcast() {
634         final int powerState;
635         synchronized (mLock) {
636             if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
637                 // Broadcasted power state is unknown.  Send wake up.
638                 mPendingWakeUpBroadcast = false;
639                 mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
640             } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
641                 // Broadcasted power state is awake.  Send asleep if needed.
642                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
643                         || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
644                     mPendingGoToSleepBroadcast = false;
645                     mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
646                 } else {
647                     finishPendingBroadcastLocked();
648                     return;
649                 }
650             } else {
651                 // Broadcasted power state is asleep.  Send awake if needed.
652                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
653                         || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
654                     mPendingWakeUpBroadcast = false;
655                     mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
656                 } else {
657                     finishPendingBroadcastLocked();
658                     return;
659                 }
660             }
661 
662             mBroadcastStartTime = SystemClock.uptimeMillis();
663             powerState = mBroadcastedInteractiveState;
664         }
665 
666         EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
667 
668         if (powerState == INTERACTIVE_STATE_AWAKE) {
669             sendWakeUpBroadcast();
670         } else {
671             sendGoToSleepBroadcast();
672         }
673     }
674 
sendBrightnessBoostChangedBroadcast()675     private void sendBrightnessBoostChangedBroadcast() {
676         if (DEBUG) {
677             Slog.d(TAG, "Sending brightness boost changed broadcast.");
678         }
679 
680         mContext.sendOrderedBroadcastAsUser(mScreenBrightnessBoostIntent, UserHandle.ALL, null,
681                 mScreeBrightnessBoostChangedDone, mHandler, 0, null, null);
682     }
683 
684     private final BroadcastReceiver mScreeBrightnessBoostChangedDone = new BroadcastReceiver() {
685         @Override
686         public void onReceive(Context context, Intent intent) {
687             mSuspendBlocker.release();
688         }
689     };
690 
sendWakeUpBroadcast()691     private void sendWakeUpBroadcast() {
692         if (DEBUG) {
693             Slog.d(TAG, "Sending wake up broadcast.");
694         }
695 
696         if (mActivityManagerInternal.isSystemReady()) {
697             mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
698                     mWakeUpBroadcastDone, mHandler, 0, null, null);
699         } else {
700             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
701             sendNextBroadcast();
702         }
703     }
704 
705     private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
706         @Override
707         public void onReceive(Context context, Intent intent) {
708             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
709                     SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
710             sendNextBroadcast();
711         }
712     };
713 
sendGoToSleepBroadcast()714     private void sendGoToSleepBroadcast() {
715         if (DEBUG) {
716             Slog.d(TAG, "Sending go to sleep broadcast.");
717         }
718 
719         if (mActivityManagerInternal.isSystemReady()) {
720             mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
721                     mGoToSleepBroadcastDone, mHandler, 0, null, null);
722         } else {
723             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
724             sendNextBroadcast();
725         }
726     }
727 
728     private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
729         @Override
730         public void onReceive(Context context, Intent intent) {
731             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
732                     SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
733             sendNextBroadcast();
734         }
735     };
736 
737     /**
738      * Plays the wireless charging sound for both wireless and non-wireless charging
739      */
playChargingStartedSound()740     private void playChargingStartedSound() {
741         final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
742                 Settings.Global.CHARGING_STARTED_SOUND);
743         if (isChargingFeedbackEnabled() && soundPath != null) {
744             final Uri soundUri = Uri.parse("file://" + soundPath);
745             if (soundUri != null) {
746                 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
747                 if (sfx != null) {
748                     sfx.setStreamType(AudioManager.STREAM_SYSTEM);
749                     sfx.play();
750                 }
751             }
752         }
753     }
754 
showWirelessChargingStarted(int batteryLevel)755     private void showWirelessChargingStarted(int batteryLevel) {
756         playWirelessChargingVibration();
757         playChargingStartedSound();
758         if (mStatusBarManagerInternal != null) {
759             mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
760         }
761         mSuspendBlocker.release();
762     }
763 
showWiredChargingStarted()764     private void showWiredChargingStarted() {
765         playChargingStartedSound();
766         mSuspendBlocker.release();
767     }
768 
lockProfile(@serIdInt int userId)769     private void lockProfile(@UserIdInt int userId) {
770         mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
771     }
772 
playWirelessChargingVibration()773     private void playWirelessChargingVibration() {
774         final boolean vibrateEnabled = Settings.Global.getInt(mContext.getContentResolver(),
775                 Settings.Global.CHARGING_VIBRATION_ENABLED, 0) != 0;
776         if (vibrateEnabled && isChargingFeedbackEnabled()) {
777             mVibrator.vibrate(WIRELESS_CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES);
778         }
779     }
780 
isChargingFeedbackEnabled()781     private boolean isChargingFeedbackEnabled() {
782         final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
783                 Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
784         final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(),
785                 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
786                 == Settings.Global.ZEN_MODE_OFF;
787         return enabled && dndOff;
788     }
789 
790     private final class NotifierHandler extends Handler {
791 
NotifierHandler(Looper looper)792         public NotifierHandler(Looper looper) {
793             super(looper, null, true /*async*/);
794         }
795         @Override
handleMessage(Message msg)796         public void handleMessage(Message msg) {
797             switch (msg.what) {
798                 case MSG_USER_ACTIVITY:
799                     sendUserActivity();
800                     break;
801                 case MSG_BROADCAST:
802                     sendNextBroadcast();
803                     break;
804                 case MSG_WIRELESS_CHARGING_STARTED:
805                     showWirelessChargingStarted(msg.arg1);
806                     break;
807                 case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED:
808                     sendBrightnessBoostChangedBroadcast();
809                     break;
810                 case MSG_PROFILE_TIMED_OUT:
811                     lockProfile(msg.arg1);
812                     break;
813                 case MSG_WIRED_CHARGING_STARTED:
814                     showWiredChargingStarted();
815                     break;
816             }
817         }
818     }
819 }
820