Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0fbcc708 authored by Filip Gruszczynski's avatar Filip Gruszczynski Committed by Android Git Automerger
Browse files

am 1e74b5d6: Merge "Burn in protection." into lmp-mr1-modular-dev

* commit '1e74b5d6':
  Burn in protection.
parents 892609ad 1e74b5d6
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -131,6 +131,19 @@ public abstract class DisplayManagerInternal {
    public abstract void setDisplayProperties(int displayId, boolean hasContent,
            float requestedRefreshRate, boolean inTraversal);

    /**
     * Applies an offset to the contents of a display, for example to avoid burn-in.
     * <p>
     * TODO: Technically this should be associated with a physical rather than logical
     * display but this is good enough for now.
     * </p>
     *
     * @param displayId The logical display id to update.
     * @param x The X offset by which to shift the contents of the display.
     * @param y The Y offset by which to shift the contents of the display.
     */
    public abstract void setDisplayOffsets(int displayId, int x, int y);

    /**
     * Describes the requested power state of the display.
     *
+2 −0
Original line number Diff line number Diff line
@@ -303,6 +303,8 @@
    <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" />
    <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />

    <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />

    <!-- ====================================== -->
    <!-- Permissions for things that cost money -->
    <!-- ====================================== -->
+19 −0
Original line number Diff line number Diff line
@@ -2066,4 +2066,23 @@
    <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
         panning to scaling the magnification viewport. -->
    <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>

    <!-- If true, the display will be shifted around in ambient mode. -->
    <bool name="config_enableBurnInProtection">false</bool>

    <!-- Specifies the maximum burn-in offset displacement from the center. If -1, no maximum value
         will be used. -->
    <integer name="config_burnInProtectionMaxRadius">-1</integer>

    <!-- Specifies the minimum burn-in offset horizontally. -->
    <integer name="config_burnInProtectionMinHorizontalOffset">0</integer>

    <!-- Specifies the maximum burn-in offset horizontally. -->
    <integer name="config_burnInProtectionMaxHorizontalOffset">0</integer>

    <!-- Specifies the minimum burn-in offset vertically. -->
    <integer name="config_burnInProtectionMinVerticalOffset">0</integer>

    <!-- Specifies the maximum burn-in offset vertically. -->
    <integer name="config_burnInProtectionMaxVerticalOffset">0</integer>
</resources>
+6 −0
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@
  <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
  <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
  <java-symbol type="bool" name="config_enable_puk_unlock_screen" />
  <java-symbol type="bool" name="config_enableBurnInProtection" />
  <java-symbol type="bool" name="config_hotswapCapable" />
  <java-symbol type="bool" name="config_mms_content_disposition_support" />
  <java-symbol type="bool" name="config_networkSamplingWakesDevice" />
@@ -344,6 +345,11 @@
  <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
  <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
  <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
  <java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
  <java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
  <java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
  <java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
  <java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
  <java-symbol type="integer" name="config_cursorWindowSize" />
  <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
  <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
+203 −0
Original line number Diff line number Diff line
package com.android.internal.policy.impl;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.Display;

import com.android.server.LocalServices;

import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;

public class BurnInProtectionHelper implements DisplayManager.DisplayListener {
    private static final String TAG = "BurnInProtection";

    // Default value when max burnin radius is not set.
    public static final int BURN_IN_RADIUS_MAX_DEFAULT = -1;

    private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
    private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);

    private static final String ACTION_BURN_IN_PROTECTION =
            "android.internal.policy.action.BURN_IN_PROTECTION";

    private static final int BURN_IN_SHIFT_STEP = 2;

    private boolean mBurnInProtectionActive;

    private final int mMinHorizontalBurnInOffset;
    private final int mMaxHorizontalBurnInOffset;
    private final int mMinVerticalBurnInOffset;
    private final int mMaxVerticalBurnInOffset;

    private final int mBurnInRadiusMaxSquared;

    private int mLastBurnInXOffset = 0;
    /* 1 means increasing, -1 means decreasing */
    private int mXOffsetDirection = 1;
    private int mLastBurnInYOffset = 0;
    /* 1 means increasing, -1 means decreasing */
    private int mYOffsetDirection = 1;

    private final AlarmManager mAlarmManager;
    private final PendingIntent mBurnInProtectionIntent;
    private final DisplayManagerInternal mDisplayManagerInternal;
    private final Display mDisplay;

    private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updateBurnInProtection();
        }
    };

    public BurnInProtectionHelper(Context context) {
        final Resources resources = context.getResources();
        mMinHorizontalBurnInOffset = resources.getInteger(
                com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
        mMaxHorizontalBurnInOffset = resources.getInteger(
                com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
        mMinVerticalBurnInOffset = resources.getInteger(
                com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
        mMaxVerticalBurnInOffset = resources.getInteger(
                com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
        int burnInRadiusMax = resources.getInteger(
                com.android.internal.R.integer.config_burnInProtectionMaxRadius);
        if (burnInRadiusMax != BURN_IN_RADIUS_MAX_DEFAULT) {
            mBurnInRadiusMaxSquared = burnInRadiusMax * burnInRadiusMax;
        } else {
            mBurnInRadiusMaxSquared = BURN_IN_RADIUS_MAX_DEFAULT;
        }

        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        context.registerReceiver(mBurnInProtectionReceiver,
                new IntentFilter(ACTION_BURN_IN_PROTECTION));
        Intent intent = new Intent(ACTION_BURN_IN_PROTECTION);
        intent.setPackage(context.getPackageName());
        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        DisplayManager displayManager =
                (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
        mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
        displayManager.registerDisplayListener(this, null /* handler */);
    }

    public void startBurnInProtection() {
        if (!mBurnInProtectionActive) {
            mBurnInProtectionActive = true;
            updateBurnInProtection();
        }
    }

    private void updateBurnInProtection() {
        if (mBurnInProtectionActive) {
            adjustOffsets();
            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
                    mLastBurnInXOffset, mLastBurnInYOffset);
            // Next adjustment at least ten seconds in the future.
            long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
            // And aligned to the minute.
            next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
                    + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent);
        } else {
            mAlarmManager.cancel(mBurnInProtectionIntent);
            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0);
        }
    }

    public void cancelBurnInProtection() {
        if (mBurnInProtectionActive) {
            mBurnInProtectionActive = false;
            updateBurnInProtection();
        }
    }

    /**
     * Gently shifts current burn-in offsets, minimizing the change for the user.
     *
     * Shifts are applied in following fashion:
     * 1) shift horizontally from minimum to the maximum;
     * 2) shift vertically by one from minimum to the maximum;
     * 3) shift horizontally from maximum to the minimum;
     * 4) shift vertically by one from minimum to the maximum.
     * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum.
     *
     * On top of that, stay within specified radius. If the shift distance from the center is
     * higher than the radius, skip these values and go the next position that is within the radius.
     */
    private void adjustOffsets() {
        do {
            // By default, let's just shift the X offset.
            final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP;
            mLastBurnInXOffset += xChange;
            if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset
                    || mLastBurnInXOffset < mMinHorizontalBurnInOffset) {
                // Whoops, we went too far horizontally. Let's retract..
                mLastBurnInXOffset -= xChange;
                // change horizontal direction..
                mXOffsetDirection *= -1;
                // and let's shift the Y offset.
                final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP;
                mLastBurnInYOffset += yChange;
                if (mLastBurnInYOffset > mMaxVerticalBurnInOffset
                        || mLastBurnInYOffset < mMinVerticalBurnInOffset) {
                    // Whoops, we went to far vertically. Let's retract..
                    mLastBurnInYOffset -= yChange;
                    // and change vertical direction.
                    mYOffsetDirection *= -1;
                }
            }
            // If we are outside of the radius, let's try again.
        } while (mBurnInRadiusMaxSquared != BURN_IN_RADIUS_MAX_DEFAULT
                && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset
                        > mBurnInRadiusMaxSquared);
    }

    public void dump(String prefix, PrintWriter pw) {
        pw.println(prefix + TAG);
        prefix += "  ";
        pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive);
        pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", "
                + mMaxHorizontalBurnInOffset + ")");
        pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", "
                + mMaxVerticalBurnInOffset + ")");
        pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared);
        pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", "
                + mLastBurnInYOffset + ")");
        pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", "
                + mYOffsetDirection + ")");
    }

    @Override
    public void onDisplayAdded(int i) {
    }

    @Override
    public void onDisplayRemoved(int i) {
    }

    @Override
    public void onDisplayChanged(int displayId) {
        if (displayId == mDisplay.getDisplayId()) {
            if (mDisplay.getState() == Display.STATE_DOZE
                    || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
                startBurnInProtection();
            } else {
                cancelBurnInProtection();
            }
        }
    }
}
Loading