Home | History | Annotate | Download | only in doze
      1 /*
      2  * Copyright (C) 2017 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.systemui.doze;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.hardware.Sensor;
     24 import android.hardware.SensorEvent;
     25 import android.hardware.SensorEventListener;
     26 import android.hardware.SensorManager;
     27 import android.os.Handler;
     28 import android.os.SystemProperties;
     29 import android.os.Trace;
     30 import android.os.UserHandle;
     31 import android.provider.Settings;
     32 
     33 import com.android.internal.annotations.VisibleForTesting;
     34 
     35 /**
     36  * Controls the screen brightness when dozing.
     37  */
     38 public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachine.Part,
     39         SensorEventListener {
     40     private static final boolean DEBUG_AOD_BRIGHTNESS = SystemProperties
     41             .getBoolean("debug.aod_brightness", false);
     42     protected static final String ACTION_AOD_BRIGHTNESS =
     43             "com.android.systemui.doze.AOD_BRIGHTNESS";
     44     protected static final String BRIGHTNESS_BUCKET = "brightness_bucket";
     45 
     46     private final Context mContext;
     47     private final DozeMachine.Service mDozeService;
     48     private final DozeHost mDozeHost;
     49     private final Handler mHandler;
     50     private final SensorManager mSensorManager;
     51     private final Sensor mLightSensor;
     52     private final int[] mSensorToBrightness;
     53     private final int[] mSensorToScrimOpacity;
     54     private final boolean mDebuggable;
     55 
     56     private boolean mRegistered;
     57     private int mDefaultDozeBrightness;
     58     private boolean mPaused = false;
     59     private boolean mScreenOff = false;
     60     private int mLastSensorValue = -1;
     61 
     62     /**
     63      * Debug value used for emulating various display brightness buckets:
     64      *
     65      * {@code am broadcast -p com.android.systemui -a com.android.systemui.doze.AOD_BRIGHTNESS
     66      * --ei brightness_bucket 1}
     67      */
     68     private int mDebugBrightnessBucket = -1;
     69 
     70     @VisibleForTesting
     71     public DozeScreenBrightness(Context context, DozeMachine.Service service,
     72             SensorManager sensorManager, Sensor lightSensor, DozeHost host,
     73             Handler handler, int defaultDozeBrightness, int[] sensorToBrightness,
     74             int[] sensorToScrimOpacity, boolean debuggable) {
     75         mContext = context;
     76         mDozeService = service;
     77         mSensorManager = sensorManager;
     78         mLightSensor = lightSensor;
     79         mDozeHost = host;
     80         mHandler = handler;
     81         mDebuggable = debuggable;
     82 
     83         mDefaultDozeBrightness = defaultDozeBrightness;
     84         mSensorToBrightness = sensorToBrightness;
     85         mSensorToScrimOpacity = sensorToScrimOpacity;
     86 
     87         if (mDebuggable) {
     88             IntentFilter filter = new IntentFilter();
     89             filter.addAction(ACTION_AOD_BRIGHTNESS);
     90             mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, handler);
     91         }
     92     }
     93 
     94     public DozeScreenBrightness(Context context, DozeMachine.Service service,
     95             SensorManager sensorManager, Sensor lightSensor, DozeHost host,
     96             Handler handler, AlwaysOnDisplayPolicy policy) {
     97         this(context, service, sensorManager, lightSensor, host, handler,
     98                 context.getResources().getInteger(
     99                         com.android.internal.R.integer.config_screenBrightnessDoze),
    100                 policy.screenBrightnessArray, policy.dimmingScrimArray, DEBUG_AOD_BRIGHTNESS);
    101     }
    102 
    103     @Override
    104     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
    105         switch (newState) {
    106             case INITIALIZED:
    107                 resetBrightnessToDefault();
    108                 break;
    109             case DOZE_AOD:
    110             case DOZE_REQUEST_PULSE:
    111                 setLightSensorEnabled(true);
    112                 break;
    113             case DOZE:
    114                 setLightSensorEnabled(false);
    115                 resetBrightnessToDefault();
    116                 break;
    117             case FINISH:
    118                 onDestroy();
    119                 break;
    120         }
    121         if (newState != DozeMachine.State.FINISH) {
    122             setScreenOff(newState == DozeMachine.State.DOZE);
    123             setPaused(newState == DozeMachine.State.DOZE_AOD_PAUSED);
    124         }
    125     }
    126 
    127     private void onDestroy() {
    128         setLightSensorEnabled(false);
    129         if (mDebuggable) {
    130             mContext.unregisterReceiver(this);
    131         }
    132     }
    133 
    134     @Override
    135     public void onSensorChanged(SensorEvent event) {
    136         Trace.beginSection("DozeScreenBrightness.onSensorChanged" + event.values[0]);
    137         try {
    138             if (mRegistered) {
    139                 mLastSensorValue = (int) event.values[0];
    140                 updateBrightnessAndReady(false /* force */);
    141             }
    142         } finally {
    143             Trace.endSection();
    144         }
    145     }
    146 
    147     private void updateBrightnessAndReady(boolean force) {
    148         if (force || mRegistered || mDebugBrightnessBucket != -1) {
    149             int sensorValue = mDebugBrightnessBucket == -1
    150                     ? mLastSensorValue : mDebugBrightnessBucket;
    151             int brightness = computeBrightness(sensorValue);
    152             boolean brightnessReady = brightness > 0;
    153             if (brightnessReady) {
    154                 mDozeService.setDozeScreenBrightness(clampToUserSetting(brightness));
    155             }
    156 
    157             int scrimOpacity = -1;
    158             if (mPaused || mScreenOff) {
    159                 // If AOD is paused, force the screen black until the
    160                 // sensor reports a new brightness. This ensures that when the screen comes on
    161                 // again, it will only show after the brightness sensor has stabilized,
    162                 // avoiding a potential flicker.
    163                 scrimOpacity = 255;
    164             } else if (brightnessReady) {
    165                 // Only unblank scrim once brightness is ready.
    166                 scrimOpacity = computeScrimOpacity(sensorValue);
    167             }
    168             if (scrimOpacity >= 0) {
    169                 mDozeHost.setAodDimmingScrim(scrimOpacity / 255f);
    170             }
    171         }
    172     }
    173 
    174     private int computeScrimOpacity(int sensorValue) {
    175         if (sensorValue < 0 || sensorValue >= mSensorToScrimOpacity.length) {
    176             return -1;
    177         }
    178         return mSensorToScrimOpacity[sensorValue];
    179     }
    180 
    181     private int computeBrightness(int sensorValue) {
    182         if (sensorValue < 0 || sensorValue >= mSensorToBrightness.length) {
    183             return -1;
    184         }
    185         return mSensorToBrightness[sensorValue];
    186     }
    187 
    188     @Override
    189     public void onAccuracyChanged(Sensor sensor, int accuracy) {
    190     }
    191 
    192     private void resetBrightnessToDefault() {
    193         mDozeService.setDozeScreenBrightness(clampToUserSetting(mDefaultDozeBrightness));
    194         mDozeHost.setAodDimmingScrim(0f);
    195     }
    196 
    197     private int clampToUserSetting(int brightness) {
    198         int userSetting = Settings.System.getIntForUser(mContext.getContentResolver(),
    199                 Settings.System.SCREEN_BRIGHTNESS, Integer.MAX_VALUE,
    200                 UserHandle.USER_CURRENT);
    201         return Math.min(brightness, userSetting);
    202     }
    203 
    204     private void setLightSensorEnabled(boolean enabled) {
    205         if (enabled && !mRegistered && mLightSensor != null) {
    206             // Wait until we get an event from the sensor until indicating ready.
    207             mRegistered = mSensorManager.registerListener(this, mLightSensor,
    208                     SensorManager.SENSOR_DELAY_NORMAL, mHandler);
    209             mLastSensorValue = -1;
    210         } else if (!enabled && mRegistered) {
    211             mSensorManager.unregisterListener(this);
    212             mRegistered = false;
    213             mLastSensorValue = -1;
    214             // Sensor is not enabled, hence we use the default brightness and are always ready.
    215         }
    216     }
    217 
    218     private void setPaused(boolean paused) {
    219         if (mPaused != paused) {
    220             mPaused = paused;
    221             updateBrightnessAndReady(false /* force */);
    222         }
    223     }
    224 
    225     private void setScreenOff(boolean screenOff) {
    226         if (mScreenOff != screenOff) {
    227             mScreenOff = screenOff;
    228             updateBrightnessAndReady(true /* force */);
    229         }
    230     }
    231 
    232     @Override
    233     public void onReceive(Context context, Intent intent) {
    234         mDebugBrightnessBucket = intent.getIntExtra(BRIGHTNESS_BUCKET, -1);
    235         updateBrightnessAndReady(false /* force */);
    236     }
    237 }
    238