Home | History | Annotate | Download | only in power
      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 
    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      */
    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 
    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 
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    618     private void finishPendingBroadcastLocked() {
    619         mBroadcastInProgress = false;
    620         mSuspendBlocker.release();
    621     }
    622 
    623     private void sendUserActivity() {
    624         synchronized (mLock) {
    625             if (!mUserActivityPending) {
    626                 return;
    627             }
    628             mUserActivityPending = false;
    629         }
    630         mPolicy.userActivity();
    631     }
    632 
    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 
    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 
    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 
    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      */
    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 
    755     private void showWirelessChargingStarted(int batteryLevel) {
    756         playWirelessChargingVibration();
    757         playChargingStartedSound();
    758         if (mStatusBarManagerInternal != null) {
    759             mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
    760         }
    761         mSuspendBlocker.release();
    762     }
    763 
    764     private void showWiredChargingStarted() {
    765         playChargingStartedSound();
    766         mSuspendBlocker.release();
    767     }
    768 
    769     private void lockProfile(@UserIdInt int userId) {
    770         mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
    771     }
    772 
    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 
    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 
    792         public NotifierHandler(Looper looper) {
    793             super(looper, null, true /*async*/);
    794         }
    795         @Override
    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