1c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski/* 2c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * Copyright (C) 2015 The Android Open Source Project 3c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * 4c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * Licensed under the Apache License, Version 2.0 (the "License"); 5c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * you may not use this file except in compliance with the License. 6c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * You may obtain a copy of the License at 7c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * 8c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * http://www.apache.org/licenses/LICENSE-2.0 9c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * 10c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * Unless required by applicable law or agreed to in writing, software 11c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * distributed under the License is distributed on an "AS IS" BASIS, 12c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * See the License for the specific language governing permissions and 14c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski * limitations under the License 15c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski */ 16c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynski 17c045208fef869e71622f7a1596314766138a13c4Filip Gruszczynskipackage com.android.server.policy; 18d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 1917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynskiimport android.animation.Animator; 2017413eb575f020e399bee3257f3221b85445d950Filip Gruszczynskiimport android.animation.ValueAnimator; 21d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.app.AlarmManager; 22d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.app.PendingIntent; 23d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.content.BroadcastReceiver; 24d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.content.Context; 25d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.content.Intent; 26d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.content.IntentFilter; 27d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.hardware.display.DisplayManager; 28d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.hardware.display.DisplayManagerInternal; 29d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.os.SystemClock; 30c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynskiimport android.util.Slog; 31d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport android.view.Display; 3217413eb575f020e399bee3257f3221b85445d950Filip Gruszczynskiimport android.view.animation.LinearInterpolator; 33d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 34d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport com.android.server.LocalServices; 35d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 36d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport java.io.PrintWriter; 37d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynskiimport java.util.concurrent.TimeUnit; 38d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 3917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynskipublic class BurnInProtectionHelper implements DisplayManager.DisplayListener, 4017413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { 41d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private static final String TAG = "BurnInProtection"; 42d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 43d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // Default value when max burnin radius is not set. 44c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf public static final int BURN_IN_MAX_RADIUS_DEFAULT = -1; 45d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 46d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1); 47d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10); 48d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 49c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski private static final boolean DEBUG = false; 50c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski 51d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private static final String ACTION_BURN_IN_PROTECTION = 52d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski "android.internal.policy.action.BURN_IN_PROTECTION"; 53d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 54d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private static final int BURN_IN_SHIFT_STEP = 2; 5517413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski private static final long CENTERING_ANIMATION_DURATION_MS = 100; 5617413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski private final ValueAnimator mCenteringAnimator; 57d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 58d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private boolean mBurnInProtectionActive; 5917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski private boolean mFirstUpdate; 60d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 61d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final int mMinHorizontalBurnInOffset; 62d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final int mMaxHorizontalBurnInOffset; 63d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final int mMinVerticalBurnInOffset; 64d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final int mMaxVerticalBurnInOffset; 65d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 66d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final int mBurnInRadiusMaxSquared; 67d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 68d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private int mLastBurnInXOffset = 0; 69d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski /* 1 means increasing, -1 means decreasing */ 70d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private int mXOffsetDirection = 1; 71d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private int mLastBurnInYOffset = 0; 72d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski /* 1 means increasing, -1 means decreasing */ 73d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private int mYOffsetDirection = 1; 74d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 75d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final AlarmManager mAlarmManager; 76d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final PendingIntent mBurnInProtectionIntent; 77d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final DisplayManagerInternal mDisplayManagerInternal; 78d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private final Display mDisplay; 79d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 80d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() { 81d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski @Override 82d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski public void onReceive(Context context, Intent intent) { 83c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski if (DEBUG) { 84c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski Slog.d(TAG, "onReceive " + intent); 85c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski } 86d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski updateBurnInProtection(); 87d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 88d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski }; 89c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski 90c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf public BurnInProtectionHelper(Context context, int minHorizontalOffset, 91c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf int maxHorizontalOffset, int minVerticalOffset, int maxVerticalOffset, 92c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf int maxOffsetRadius) { 93c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf mMinHorizontalBurnInOffset = minHorizontalOffset; 94c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf mMaxHorizontalBurnInOffset = maxHorizontalOffset; 95c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf mMinVerticalBurnInOffset = minVerticalOffset; 9617413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mMaxVerticalBurnInOffset = maxVerticalOffset; 97c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf if (maxOffsetRadius != BURN_IN_MAX_RADIUS_DEFAULT) { 98c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf mBurnInRadiusMaxSquared = maxOffsetRadius * maxOffsetRadius; 99d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } else { 100c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf mBurnInRadiusMaxSquared = BURN_IN_MAX_RADIUS_DEFAULT; 101d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 102d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 103d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); 104d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 105d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski context.registerReceiver(mBurnInProtectionReceiver, 106d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski new IntentFilter(ACTION_BURN_IN_PROTECTION)); 107d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski Intent intent = new Intent(ACTION_BURN_IN_PROTECTION); 108d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski intent.setPackage(context.getPackageName()); 109d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 110d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0, 111d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski intent, PendingIntent.FLAG_UPDATE_CURRENT); 112d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski DisplayManager displayManager = 113d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 114d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 115d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski displayManager.registerDisplayListener(this, null /* handler */); 11617413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski 11717413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mCenteringAnimator = ValueAnimator.ofFloat(1f, 0f); 11817413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mCenteringAnimator.setDuration(CENTERING_ANIMATION_DURATION_MS); 11917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mCenteringAnimator.setInterpolator(new LinearInterpolator()); 12017413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mCenteringAnimator.addListener(this); 12117413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mCenteringAnimator.addUpdateListener(this); 122d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 123d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 124d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski public void startBurnInProtection() { 125d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski if (!mBurnInProtectionActive) { 126d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mBurnInProtectionActive = true; 12717413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mFirstUpdate = true; 12817413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mCenteringAnimator.cancel(); 129d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski updateBurnInProtection(); 130d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 131d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 132d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 133d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private void updateBurnInProtection() { 134d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski if (mBurnInProtectionActive) { 13517413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski // We don't want to adjust offsets immediately after the device goes into ambient mode. 13617413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski // Instead, we want to wait until it's more likely that the user is not observing the 13717413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski // screen anymore. 13817413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski if (mFirstUpdate) { 13917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mFirstUpdate = false; 14017413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } else { 14117413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski adjustOffsets(); 14217413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 14317413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mLastBurnInXOffset, mLastBurnInYOffset); 14417413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 145c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski // We use currentTimeMillis to compute the next wakeup time since we want to wake up at 146c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski // the same time as we wake up to update ambient mode to minimize power consumption. 147c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski // However, we use elapsedRealtime to schedule the alarm so that setting the time can't 148c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski // disable burn-in protection for extended periods. 149c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski final long nowWall = System.currentTimeMillis(); 150c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski final long nowElapsed = SystemClock.elapsedRealtime(); 151d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // Next adjustment at least ten seconds in the future. 152c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski long nextWall = nowWall + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS; 153d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // And aligned to the minute. 154c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski nextWall = nextWall - nextWall % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS 155d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS; 156c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski // Use elapsed real time that is adjusted to full minute on wall clock. 157c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski final long nextElapsed = nowElapsed + (nextWall - nowWall); 158c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski if (DEBUG) { 159c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski Slog.d(TAG, "scheduling next wake-up, now wall time " + nowWall 160c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski + ", next wall: " + nextWall + ", now elapsed: " + nowElapsed 161c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski + ", next elapsed: " + nextElapsed); 162c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski } 163c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextElapsed, 164c069f921d9bf9acf8d14f43049ac01ce43bc3a7eFilip Gruszczynski mBurnInProtectionIntent); 165d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } else { 166d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mAlarmManager.cancel(mBurnInProtectionIntent); 16717413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mCenteringAnimator.start(); 168d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 169d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 170d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 171d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski public void cancelBurnInProtection() { 172d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski if (mBurnInProtectionActive) { 173d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mBurnInProtectionActive = false; 174d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski updateBurnInProtection(); 175d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 176d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 177d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 178d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski /** 179d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * Gently shifts current burn-in offsets, minimizing the change for the user. 180d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * 181d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * Shifts are applied in following fashion: 182d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * 1) shift horizontally from minimum to the maximum; 183d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * 2) shift vertically by one from minimum to the maximum; 184d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * 3) shift horizontally from maximum to the minimum; 185d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * 4) shift vertically by one from minimum to the maximum. 186d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum. 187d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * 188d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * On top of that, stay within specified radius. If the shift distance from the center is 189d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski * higher than the radius, skip these values and go the next position that is within the radius. 190d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski */ 191d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski private void adjustOffsets() { 192d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski do { 193d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // By default, let's just shift the X offset. 194d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP; 195d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mLastBurnInXOffset += xChange; 196d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset 197d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski || mLastBurnInXOffset < mMinHorizontalBurnInOffset) { 198d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // Whoops, we went too far horizontally. Let's retract.. 199d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mLastBurnInXOffset -= xChange; 200d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // change horizontal direction.. 201d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mXOffsetDirection *= -1; 202d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // and let's shift the Y offset. 203d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP; 204d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mLastBurnInYOffset += yChange; 205d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski if (mLastBurnInYOffset > mMaxVerticalBurnInOffset 206d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski || mLastBurnInYOffset < mMinVerticalBurnInOffset) { 207d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // Whoops, we went to far vertically. Let's retract.. 208d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mLastBurnInYOffset -= yChange; 209d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // and change vertical direction. 210d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski mYOffsetDirection *= -1; 211d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 212d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 213d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski // If we are outside of the radius, let's try again. 214c12569110d558e584fb9074dbe0c1aaf79ccdcd6Mark Renouf } while (mBurnInRadiusMaxSquared != BURN_IN_MAX_RADIUS_DEFAULT 215d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset 216d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski > mBurnInRadiusMaxSquared); 217d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 218d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 219d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski public void dump(String prefix, PrintWriter pw) { 220d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski pw.println(prefix + TAG); 221d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski prefix += " "; 222d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive); 223d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", " 224d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski + mMaxHorizontalBurnInOffset + ")"); 225d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", " 226d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski + mMaxVerticalBurnInOffset + ")"); 227d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared); 228d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", " 229d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski + mLastBurnInYOffset + ")"); 230d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", " 231d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski + mYOffsetDirection + ")"); 232d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 233d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 234d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski @Override 235d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski public void onDisplayAdded(int i) { 236d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 237d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 238d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski @Override 239d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski public void onDisplayRemoved(int i) { 240d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 241d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski 242d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski @Override 243d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski public void onDisplayChanged(int displayId) { 244d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski if (displayId == mDisplay.getDisplayId()) { 245d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski if (mDisplay.getState() == Display.STATE_DOZE 246d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) { 247d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski startBurnInProtection(); 248d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } else { 249d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski cancelBurnInProtection(); 250d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 251d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 252d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski } 25317413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski 25417413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski @Override 25517413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski public void onAnimationStart(Animator animator) { 25617413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 25717413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski 25817413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski @Override 25917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski public void onAnimationEnd(Animator animator) { 26017413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski if (animator == mCenteringAnimator && !mBurnInProtectionActive) { 26117413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski // No matter how the animation finishes, we want to zero the offsets. 26217413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0); 26317413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 26417413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 26517413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski 26617413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski @Override 26717413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski public void onAnimationCancel(Animator animator) { 26817413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 26917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski 27017413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski @Override 27117413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski public void onAnimationRepeat(Animator animator) { 27217413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 27317413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski 27417413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski @Override 27517413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski public void onAnimationUpdate(ValueAnimator valueAnimator) { 27617413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski if (!mBurnInProtectionActive) { 27717413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski final float value = (Float) valueAnimator.getAnimatedValue(); 27817413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 27917413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski (int) (mLastBurnInXOffset * value), (int) (mLastBurnInYOffset * value)); 28017413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 28117413eb575f020e399bee3257f3221b85445d950Filip Gruszczynski } 282d2e8640c2c1972d4f2e92d48660fa9e17d9291c4Filip Gruszczynski} 283