How to Realize Automatic Brightness Adjustment in Android

  • 2021-12-12 05:35:04
  • OfStack

Directory source code version Overview Source code combing 1. BrightnessDialog # onCreate: 2. Here, BrightnessController initialization is carried out. Look at it: 3. Go back to BrightnessDialog # onStart: 4 and call mBrightnessController. registerCallbacks (); Finally, go to mStartListeningRunnable: 5, skip to ToggleSliderView # setValue: 6, first, initialize DisplayPowerController in DisplayManagerService, as follows: 7, then look at the construction method of DisplayPowerController, as follows: 8, go back to DisplayPowerController # updatePowerState (), 9, BrightnessMapper # setAutoBrightnessAdjustment

The drop-down status bar has a brightness progress bar. If the brightness automatic adjustment switch is turned on, it will change with the surrounding light, and this progress bar will also change. Next, let's see how this function is realized.

Source version

Based on Android 9.0 analysis.

BrightnessDialog, located at:
frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java

ToggleSliderView, located at:
frameworks/base/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java

DisplayPowerController, located at:
frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

AutomaticBrightnessController, located at:
frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java

BrightnessMappingStrategy,

Overview

The brightness page in the status bar is BrightnessDialog, in which the progress bar is set to ToggleSliderView, and the automatic brightness adjustment is mainly DisplayPowerController and AutomaticBrightnessController. When the brightness changes, if it is associated with ToggleSliderView, ContentObserver is used, and Uri is Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ.

Source code combing

1. BrightnessDialog # onCreate:


@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // Omit part of the code 
  mBrightnessController = new BrightnessController(this, icon, slider);
}

2. BrightnessController initialization has been carried out here. Let's look at:


public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
  // Omit part of the code 
  mBrightnessObserver = new BrightnessObserver(mHandler);
  // Omit part of the code 
}

BrightnessObserver initialization is performed again:


/** ContentObserver to watch brightness **/
private class BrightnessObserver extends ContentObserver {
  // Omit part of the code 
  private final Uri BRIGHTNESS_FOR_VR_URI =
      Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR);
  //Add By WuXiaolong for AutomaticBrightness
  private final Uri BRIGHTNESS_ADJ_URI =
      Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
  public BrightnessObserver(Handler handler) {
    super(handler);
  }
  @Override
  public void onChange(boolean selfChange) {
    onChange(selfChange, null);
  }
  @Override
  public void onChange(boolean selfChange, Uri uri) {
    if (selfChange) return;
    if (BRIGHTNESS_MODE_URI.equals(uri)) {
      mBackgroundHandler.post(mUpdateModeRunnable);
      mBackgroundHandler.post(mUpdateSliderRunnable);
    } 
    // Omit part of the code 
    //Add By WuXiaolong for AutomaticBrightness
    else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
      mBackgroundHandler.post(mUpdateSliderRunnable);
    } else {
      mBackgroundHandler.post(mUpdateModeRunnable);
      mBackgroundHandler.post(mUpdateSliderRunnable);
    }
    for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
      cb.onBrightnessLevelChanged();
    }
  }
  public void startObserving() {
    final ContentResolver cr = mContext.getContentResolver();
    cr.unregisterContentObserver(this);
    // Omit part of the code 
    cr.registerContentObserver(
        BRIGHTNESS_FOR_VR_URI,
        false, this, UserHandle.USER_ALL);
    //Add By WuXiaolong for AutomaticBrightness
    cr.registerContentObserver(
        BRIGHTNESS_ADJ_URI,
        false, this, UserHandle.USER_ALL);
  }
  public void stopObserving() {
    final ContentResolver cr = mContext.getContentResolver();
    cr.unregisterContentObserver(this);
  }
}

In fact, I currently download the source code, this function is not complete, I have added, where BrightnessObserver ContentObserver registration?

3. Go back to BrightnessDialog # onStart:


@Override
protected void onStart() {
  super.onStart();
  mBrightnessController.registerCallbacks();
  MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
}

4. Call mBrightnessController. registerCallbacks (); Eventually go to mStartListeningRunnable:


private final Runnable mStartListeningRunnable = new Runnable() {
  @Override
  public void run() {
    //BrightnessObserver  Registration 
    mBrightnessObserver.startObserving();
    mUserTracker.startTracking();
    // Update the slider and mode before attaching the listener so we don't
    // receive the onChanged notifications for the initial values.
    mUpdateModeRunnable.run();
    mUpdateSliderRunnable.run();
    mHandler.sendEmptyMessage(MSG_ATTACH_LISTENER);
  }
};

When the brightness changes, you will go BrightnessObserver # onChange, and finally you will go to:


private final Handler mHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
    mExternalChange = true;
    try {
      switch (msg.what) {
        // Omit part of the code 
        case MSG_UPDATE_SLIDER:
          updateSlider(msg.arg1, msg.arg2 != 0);
          break;
        // Omit part of the code 
        default:
          super.handleMessage(msg);
      }
    } finally {
      mExternalChange = false;
    }
  }
};

Take the updateSlider method to:


private void animateSliderTo(int target) {
  if (!mControlValueInitialized) {
    // Don't animate the first value since it's default state isn't mea
    mControl.setValue(target);
    mControlValueInitialized = true;
  }
  // Omit part of the code 
}

5. Skip to ToggleSliderView # setValue:


@Override
public void setValue(int value) {
  // This is the modification progress bar 
  mSlider.setProgress(value);
  if (mMirror != null) {
    mMirror.setValue(value);
  }
}

Next, look at the two main classes of automatic brightness adjustment, DisplayPowerController and AutomaticBrightnessController. DisplayPowerController belongs to Display module, which controls the screen on and off and backlight of equipment, which is closely related to Power. Here, we mainly look at the logic of screen brightness control.

6. First, initialize DisplayPowerController in DisplayManagerService as follows:


private final class LocalService extends DisplayManagerInternal {
  @Override
  public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
      SensorManager sensorManager) {
    synchronized (mSyncRoot) {
      // Omit part of the code 
      mDisplayPowerController = new DisplayPowerController(
          mContext, callbacks, handler, sensorManager, blanker);
    }
    mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
  }

7. Next, look at the DisplayPowerController construction method, as follows:


public DisplayPowerController(Context context,
    DisplayPowerCallbacks callbacks, Handler handler,
    SensorManager sensorManager, DisplayBlanker blanker) {
  // Omit part of the code 
  mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
      com.android.internal.R.bool.config_automatic_brightness_available);
  // Omit part of the code 
  if (mUseSoftwareAutoBrightnessConfig) {
    // Omit part of the code 
    mBrightnessMapper = BrightnessMappingStrategy.create(resources);
    if (mBrightnessMapper != null) {
      mAutomaticBrightnessController = new AutomaticBrightnessController(this,
          handler.getLooper(), sensorManager, mBrightnessMapper,
          lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
          mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
          initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
          autoBrightnessResetAmbientLuxAfterWarmUp, hysteresisLevels);
    } else {
      mUseSoftwareAutoBrightnessConfig = false;
    }
  }
  // Omit part of the code 
  mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
  mTemporaryAutoBrightnessAdjustment = Float.NaN;
  // Omit part of the code 
}

Since the automatic brightness of the screen will not take effect until the screen is lit up, the process will go to the core function updatePowerState () in DisplayPowerController when the screen is lit up:


public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
  // Omit part of the code 
  mBrightnessObserver = new BrightnessObserver(mHandler);
  // Omit part of the code 
}
0

Next, let's take a look at how autoBrightnessAdjustment and newAutoBrightnessAdjustment came from.

autoBrightnessAdjustment is assigned from mTemporaryAutoBrightnessAdjustment or mAutoBrightnessAdjustment, mAutoBrightnessAdjustment in Step 7 mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting (); With initialization, look at getAutoBrightnessAdjustmentSetting ():


public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
  // Omit part of the code 
  mBrightnessObserver = new BrightnessObserver(mHandler);
  // Omit part of the code 
}
1

Keep looking at clampAutoBrightnessAdjustment:


public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
  // Omit part of the code 
  mBrightnessObserver = new BrightnessObserver(mHandler);
  // Omit part of the code 
}
2

Note here that MathUtils. constrain () represents a percentage scaling function, such as MathUtils. constrain (0.5, 0, 255) for (255-0) * 0.5.

After understanding autoBrightnessAdjustment in this way, look at newAutoBrightnessAdjustment next.

8. Go back to DisplayPowerController # updatePowerState (),

See that newAutoBrightnessAdjustment calls AutomaticBrightnessController. getAutomaticScreenBrightnessAdjustment (), and finally comes to BrightnessMapper # getAutoBrightnessAdjustment () where the mAutoBrightnessAdjustment variable is assigned in BrightnessMapper # setAutoBrightnessAdjustment:


@Override
public boolean setAutoBrightnessAdjustment(float adjustment) {
  adjustment = MathUtils.constrain(adjustment, -1, 1);
  if (adjustment == mAutoBrightnessAdjustment) {
    return false;
  }
  if (DEBUG) {
    Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
        adjustment);
    PLOG.start("auto-brightness adjustment");
  }
  mAutoBrightnessAdjustment = adjustment;
  computeSpline();
  return true;
}

9. BrightnessMapper # setAutoBrightnessAdjustment

This method call goes back to AutomaticBrightnessController # setAutoBrightnessAdjustment:


public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
  // Omit part of the code 
  mBrightnessObserver = new BrightnessObserver(mHandler);
  // Omit part of the code 
}
4

The AutomaticBrightnessController # setAutoBrightnessAdjustment call comes to the AutomaticBrightnessController # configure () method:


public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
  // Omit part of the code 
  mBrightnessObserver = new BrightnessObserver(mHandler);
  // Omit part of the code 
}
5

The AutomaticBrightnessController # configure () call comes to DisplayPowerController # updatePowerState ().

Now that you know newAutoBrightnessAdjustment, continue with putAutoBrightnessAdjustmentSetting:


public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
  // Omit part of the code 
  mBrightnessObserver = new BrightnessObserver(mHandler);
  // Omit part of the code 
}
6

Go to step 4 BrightnessObserver # onChange, and the progress bar will change accordingly, Over!

The above is Android how to achieve automatic brightness adjustment details, more information about Android automatic brightness adjustment please pay attention to other related articles on this site!


Related articles: