summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/provider/Settings.java63
-rw-r--r--core/res/res/drawable/ic_livedisplay_notif.xml29
-rw-r--r--core/res/res/values/cm_arrays.xml23
-rw-r--r--core/res/res/values/cm_strings.xml33
-rw-r--r--core/res/res/values/cm_symbols.xml19
-rwxr-xr-xcore/res/res/values/config.xml5
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java24
-rw-r--r--services/core/Android.mk4
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java17
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java17
-rw-r--r--services/core/java/com/android/server/display/LiveDisplayController.java823
13 files changed, 1056 insertions, 6 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d5d54ab..166f588 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3445,6 +3445,54 @@ public final class Settings {
public static final String KEY_APP_SWITCH_LONG_PRESS_ACTION = "key_app_switch_long_press_action";
/**
+ * Color temperature of the display during the day
+ * @hide
+ */
+ public static final String DISPLAY_TEMPERATURE_DAY = "display_temperature_day";
+
+ /**
+ * Color temperature of the display at night
+ * @hide
+ */
+ public static final String DISPLAY_TEMPERATURE_NIGHT = "display_temperature_night";
+
+ /**
+ * Display color temperature adjustment mode, one of DAY (default), NIGHT, or AUTO.
+ * @hide
+ */
+ public static final String DISPLAY_TEMPERATURE_MODE = "display_temperature_mode";
+
+ /**
+ * Automatic outdoor mode
+ * @hide
+ */
+ public static final String DISPLAY_AUTO_OUTDOOR_MODE = "display_auto_outdoor_mode";
+
+ /**
+ * Use display power saving features such as CABC or CABL
+ * @hide
+ */
+ public static final String DISPLAY_LOW_POWER = "display_low_power";
+
+ /**
+ * Use color enhancement feature of display
+ * @hide
+ */
+ public static final String DISPLAY_COLOR_ENHANCE = "display_color_enhance";
+
+ /**
+ * Manual display color adjustments (RGB values as floats, separated by spaces)
+ * @hide
+ */
+ public static final String DISPLAY_COLOR_ADJUSTMENT = "display_color_adjustment";
+
+ /**
+ * Did we tell about how they can stop breaking their eyes?
+ * @hide
+ */
+ public static final String LIVE_DISPLAY_HINTED = "live_display_hinted";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -3497,7 +3545,12 @@ public final class Settings {
RINGTONE,
LOCK_TO_APP_ENABLED,
NOTIFICATION_SOUND,
- WIFI_AUTO_CONNECT_TYPE
+ WIFI_AUTO_CONNECT_TYPE,
+ DISPLAY_TEMPERATURE_NIGHT,
+ DISPLAY_TEMPERATURE_DAY,
+ DISPLAY_TEMPERATURE_MODE,
+ DISPLAY_AUTO_OUTDOOR_MODE,
+ LIVE_DISPLAY_HINTED
};
/**
@@ -5919,6 +5972,14 @@ public final class Settings {
public static final String ASSISTANT = "assistant";
/**
+ * Stored color matrix for LiveDisplay. This is used to allow co-existence with
+ * display tuning done by DisplayAdjustmentUtils when hardware support isn't
+ * available.
+ * @hide
+ */
+ public static final String LIVE_DISPLAY_COLOR_MATRIX = "live_display_color_matrix";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/res/res/drawable/ic_livedisplay_notif.xml b/core/res/res/drawable/ic_livedisplay_notif.xml
new file mode 100644
index 0000000..a7cb8c6
--- /dev/null
+++ b/core/res/res/drawable/ic_livedisplay_notif.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M15.5,15.5c0.4-0.4,0.7-0.8,0.9-1.2c-1.9,1-4.3,0.7-5.8-0.9s-1.9-4-0.9-5.8C9.2,7.8,8.8,8.1,8.5,8.5
+c-2,2-2,5.1,0,7.1S13.6,17.5,15.5,15.5z M19,5v14H5V5H19
+M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5
+C21,3.9,20.1,3,19,3L19,3z" />
+</vector> \ No newline at end of file
diff --git a/core/res/res/values/cm_arrays.xml b/core/res/res/values/cm_arrays.xml
index aeb1e7f..2f22539 100644
--- a/core/res/res/values/cm_arrays.xml
+++ b/core/res/res/values/cm_arrays.xml
@@ -23,4 +23,27 @@
<item>com.google.android.gsf|com.google.android.talk</item>
</string-array>
+ <string-array name="live_display_entries" translatable="false">
+ <item>@string/live_display_auto</item>
+ <item>@string/live_display_off</item>
+ <item>@string/live_display_day</item>
+ <item>@string/live_display_night</item>
+ <item>@string/live_display_outdoor</item>
+ </string-array>
+
+ <string-array name="live_display_summaries" translatable="false">
+ <item>@string/live_display_auto_summary</item>
+ <item>@string/live_display_off_summary</item>
+ <item>@string/live_display_day_summary</item>
+ <item>@string/live_display_night_summary</item>
+ <item>@string/live_display_outdoor_summary</item>
+ </string-array>
+
+ <string-array name="live_display_values" translatable="false">
+ <item>2</item>
+ <item>0</item>
+ <item>4</item>
+ <item>1</item>
+ <item>3</item>
+ </string-array>
</resources>
diff --git a/core/res/res/values/cm_strings.xml b/core/res/res/values/cm_strings.xml
new file mode 100644
index 0000000..d34b865
--- /dev/null
+++ b/core/res/res/values/cm_strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012-2014 The CyanogenMod Project
+ Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- LiveDisplay strings -->
+ <string name="live_display_title" translatable="false">LiveDisplay</string>
+ <string name="live_display_auto">Automatic</string>
+ <string name="live_display_auto_summary">Automatically adjust color temperature of screen after sunset and sunrise</string>
+ <string name="live_display_off">Off</string>
+ <string name="live_display_off_summary">Disable all adjustments</string>
+ <string name="live_display_day">Day</string>
+ <string name="live_display_day_summary">Use day settings only</string>
+ <string name="live_display_night">Night</string>
+ <string name="live_display_night_summary">Use night settings only</string>
+ <string name="live_display_outdoor">Outdoor (bright sun)</string>
+ <string name="live_display_outdoor_summary">Use outdoor settings only</string>
+ <string name="live_display_hint">LiveDisplay can help reduce eyestrain and help you sleep at night. Click here to try it out!</string>
+</resources>
diff --git a/core/res/res/values/cm_symbols.xml b/core/res/res/values/cm_symbols.xml
index 6ed09b9..7f7b052 100644
--- a/core/res/res/values/cm_symbols.xml
+++ b/core/res/res/values/cm_symbols.xml
@@ -26,4 +26,23 @@
-->
<!-- External CM specific core services -->
<java-symbol type="array" name="config_externalCMServices" />
+ <!-- LiveDisplay -->
+ <java-symbol type="string" name="live_display_title" />
+ <java-symbol type="string" name="live_display_hint" />
+ <java-symbol type="string" name="live_display_auto" />
+ <java-symbol type="string" name="live_display_auto_summary" />
+ <java-symbol type="string" name="live_display_day" />
+ <java-symbol type="string" name="live_display_day_summary" />
+ <java-symbol type="string" name="live_display_night" />
+ <java-symbol type="string" name="live_display_night_summary" />
+ <java-symbol type="string" name="live_display_outdoor" />
+ <java-symbol type="string" name="live_display_outdoor_summary" />
+ <java-symbol type="array" name="live_display_entries" />
+ <java-symbol type="array" name="live_display_summaries" />
+ <java-symbol type="array" name="live_display_values" />
+ <java-symbol type="drawable" name="ic_livedisplay_notif" />
+
+ <java-symbol type="integer" name="config_dayColorTemperature" />
+ <java-symbol type="integer" name="config_nightColorTemperature" />
+ <java-symbol type="integer" name="config_outdoorAmbientLux" />
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 08ca823..6a10f4c 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2388,4 +2388,9 @@
<!-- External CM Services list -->
<string-array name="config_externalCMServices"></string-array>
+
+ <!-- Default values for display color temperature -->
+ <integer name="config_dayColorTemperature">6500</integer>
+ <integer name="config_nightColorTemperature">4500</integer>
+ <integer name="config_outdoorAmbientLux">9000</integer>
</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 02abdb1..8375197 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -132,6 +132,9 @@
android:protectionLevel="signature" />
<uses-permission android:name="com.android.systemui.permission.SELF" />
+ <!-- LiveDisplay -->
+ <uses-permission android:name="android.permission.HARDWARE_ABSTRACTION_ACCESS" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index d0b5898..ab8eacf 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -30,7 +30,7 @@ import android.view.accessibility.AccessibilityManager;
/**
* Utility methods for performing accessibility display adjustments.
*/
-class DisplayAdjustmentUtils {
+public class DisplayAdjustmentUtils {
private static final String LOG_TAG = DisplayAdjustmentUtils.class.getSimpleName();
/** Matrix and offset used for converting color to gray-scale. */
@@ -76,6 +76,11 @@ class DisplayAdjustmentUtils {
return true;
}
+ if (Settings.Secure.getStringForUser(cr,
+ Settings.Secure.LIVE_DISPLAY_COLOR_MATRIX, userId) != null) {
+ return true;
+ }
+
return false;
}
@@ -91,6 +96,23 @@ class DisplayAdjustmentUtils {
colorMatrix = multiply(colorMatrix, INVERSION_MATRIX_VALUE_ONLY);
}
+ String adj = Settings.Secure.getStringForUser(cr,
+ Settings.Secure.LIVE_DISPLAY_COLOR_MATRIX, userId);
+ if (adj != null) {
+ String[] tmp = adj.split(" ");
+ if (tmp.length == 16) {
+ float[] adjMatrix = new float[16];
+ try {
+ for (int i = 0; i < 16; i++) {
+ adjMatrix[i] = Float.parseFloat(tmp[i]);
+ }
+ colorMatrix = multiply(colorMatrix, adjMatrix);
+ } catch (NumberFormatException e) {
+ Slog.e(LOG_TAG, e.getMessage(), e);
+ }
+ }
+ }
+
if (Settings.Secure.getIntForUser(cr,
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
final int daltonizerMode = Settings.Secure.getIntForUser(cr,
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 64b6134..54dade1 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -12,4 +12,8 @@ LOCAL_SRC_FILES += \
LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
+LOCAL_JAVA_LIBRARIES += services.accessibility
+
+LOCAL_JAVA_LIBRARIES += org.cyanogenmod.platform.sdk
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index e15bca6..575701a 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -22,6 +22,8 @@ import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import android.content.Context;
+import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -193,11 +195,18 @@ class AutomaticBrightnessController {
private int mBrightnessAdjustmentSampleOldBrightness;
private float mBrightnessAdjustmentSampleOldGamma;
- public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
+ // Night mode color temperature adjustments
+ private final LiveDisplayController mLiveDisplay;
+
+ private final Context mContext;
+
+ public AutomaticBrightnessController(Context context, Callbacks callbacks, Looper looper,
SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor,
int lightSensorRate, long brighteningLightDebounceConfig,
- long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig) {
+ long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
+ LiveDisplayController ldc) {
+ mContext = context;
mCallbacks = callbacks;
mTwilight = LocalServices.getService(TwilightManager.class);
mSensorManager = sensorManager;
@@ -210,6 +219,7 @@ class AutomaticBrightnessController {
mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
+ mLiveDisplay = ldc;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate);
@@ -478,6 +488,9 @@ class AutomaticBrightnessController {
}
}
+ // Update LiveDisplay with the current lux
+ mLiveDisplay.updateLiveDisplay(mAmbientLux);
+
if (USE_TWILIGHT_ADJUSTMENT) {
TwilightState state = mTwilight.getCurrentState();
if (state != null && state.isNight()) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b2ab797..81c3791 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -287,6 +287,8 @@ public final class DisplayManagerService extends SystemService {
mOnlyCore = onlyCore;
}
+ mDisplayPowerController.systemReady();
+
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 315d3ab..f2a6b4c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -251,6 +251,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
+ // The controller for LiveDisplay
+ private final LiveDisplayController mLiveDisplayController;
+
// Animators.
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
@@ -272,6 +275,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mBlanker = blanker;
mContext = context;
+ mLiveDisplayController = new LiveDisplayController(context, handler.getLooper());
+
final Resources resources = context.getResources();
final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
@@ -348,12 +353,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (bottom < screenBrightnessRangeMinimum) {
screenBrightnessRangeMinimum = bottom;
}
- mAutomaticBrightnessController = new AutomaticBrightnessController(this,
+ mAutomaticBrightnessController = new AutomaticBrightnessController(mContext, this,
handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
brighteningLightDebounce, darkeningLightDebounce,
- autoBrightnessResetAmbientLuxAfterWarmUp);
+ autoBrightnessResetAmbientLuxAfterWarmUp, mLiveDisplayController);
}
}
@@ -705,6 +710,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
+ // Update LiveDisplay now
+ mLiveDisplayController.updateLiveDisplay();
+
// Determine whether the display is ready for use in the newly requested state.
// Note that we do not wait for the brightness ramp animation to complete before
// reporting the display is ready because we only need to ensure the screen is in the
@@ -1142,6 +1150,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mAutomaticBrightnessController.dump(pw);
}
+ mLiveDisplayController.dump(pw);
}
private static String proximityToString(int state) {
@@ -1203,6 +1212,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
+ void systemReady() {
+ mLiveDisplayController.systemReady();
+ }
+
private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
diff --git a/services/core/java/com/android/server/display/LiveDisplayController.java b/services/core/java/com/android/server/display/LiveDisplayController.java
new file mode 100644
index 0000000..1ed81da
--- /dev/null
+++ b/services/core/java/com/android/server/display/LiveDisplayController.java
@@ -0,0 +1,823 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.display;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.PowerManagerInternal;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.MathUtils;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.accessibility.DisplayAdjustmentUtils;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
+
+import cyanogenmod.hardware.CMHardwareManager;
+
+import java.io.PrintWriter;
+
+public class LiveDisplayController {
+
+ private static final String TAG = "LiveDisplay";
+
+ private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 1;
+
+ private static final int OFF_TEMPERATURE = 6500;
+
+ public static final int MODE_OFF = 0;
+ public static final int MODE_NIGHT = 1;
+ public static final int MODE_AUTO = 2;
+ public static final int MODE_OUTDOOR = 3;
+ public static final int MODE_DAY = 4;
+
+ private int mColorTemperature = OFF_TEMPERATURE;
+ private float mCurrentLux = 0.0f;
+
+ private int mHintCounter;
+ private int mMode;
+
+ private boolean mOutdoorMode;
+ private boolean mColorEnhancement;
+ private boolean mLowPower;
+
+ private final Context mContext;
+ private final Handler mHandler;
+
+ private CMHardwareManager mHardware;
+
+ private int mDayTemperature;
+ private int mNightTemperature;
+
+ private boolean mUseOutdoorMode;
+ private boolean mUseColorEnhancement;
+ private boolean mUseLowPower;
+
+ private final float[] mColorAdjustment = new float[] { 1.0f, 1.0f, 1.0f };
+ private final float[] mRGB = new float[] { 0.0f, 0.0f, 0.0f };
+
+ private TwilightManager mTwilightManager;
+ private boolean mSunset = false;
+
+ private SettingsObserver mObserver;
+
+ private ValueAnimator mAnimator;
+
+ private int mDefaultDayTemperature;
+ private int mDefaultNightTemperature;
+ private int mDefaultOutdoorLux;
+
+ private boolean mInitialized = false;
+
+ private static final int MSG_UPDATE_LIVE_DISPLAY = 1;
+
+ // Display postprocessing can have power impact. Disable it if powersave mode is on.
+ private boolean mLowPerformance = false;
+ private PowerManagerInternal.LowPowerModeListener mLowPowerModeListener =
+ new PowerManagerInternal.LowPowerModeListener() {
+ @Override
+ public void onLowPowerModeChanged(boolean enabled) {
+ mLowPerformance = enabled;
+ updateLiveDisplay(mCurrentLux);
+ }
+ };
+
+ LiveDisplayController(Context context, Looper looper) {
+ mContext = context;
+ mHandler = new LiveDisplayHandler(looper);
+ }
+
+ void systemReady() {
+ mHardware = CMHardwareManager.getInstance(mContext);
+
+ mDefaultDayTemperature = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_dayColorTemperature);
+ mDefaultNightTemperature = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_nightColorTemperature);
+ mDefaultOutdoorLux = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_outdoorAmbientLux);
+
+ // Counter used to determine when we should tell the user about this feature.
+ // If it's not used after 3 sunsets, we'll show the hint once.
+ mHintCounter = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.LIVE_DISPLAY_HINTED,
+ -3,
+ UserHandle.USER_CURRENT);
+
+ mUseOutdoorMode =
+ mHardware.isSupported(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT);
+
+ mUseLowPower =
+ mHardware.isSupported(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
+ if (mUseLowPower) {
+ mLowPower = mHardware.get(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
+ }
+
+ mUseColorEnhancement =
+ mHardware.isSupported(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
+ if (mUseColorEnhancement) {
+ mColorEnhancement =
+ mHardware.get(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
+ }
+
+ updateSettings();
+
+ mObserver = new SettingsObserver();
+ mObserver.register(true);
+
+ PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
+ pmi.registerLowPowerModeObserver(mLowPowerModeListener);
+ mLowPerformance = pmi.getLowPowerModeEnabled();
+
+ mTwilightManager = LocalServices.getService(TwilightManager.class);
+ mTwilightManager.registerListener(mTwilightListener, mHandler);
+
+ mInitialized = true;
+ }
+
+ private void updateSettings() {
+ mDayTemperature = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.DISPLAY_TEMPERATURE_DAY,
+ mDefaultDayTemperature,
+ UserHandle.USER_CURRENT);
+ mNightTemperature = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.DISPLAY_TEMPERATURE_NIGHT,
+ mDefaultNightTemperature,
+ UserHandle.USER_CURRENT);
+ mMode = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.DISPLAY_TEMPERATURE_MODE,
+ MODE_OFF,
+ UserHandle.USER_CURRENT);
+
+ // Clear the hint forever
+ if (mMode != MODE_OFF) {
+ saveUserHint(1);
+ }
+
+ // Manual color adjustment will be set as a space separated string of float values
+ String colorAdjustmentTemp = Settings.System.getStringForUser(mContext.getContentResolver(),
+ Settings.System.DISPLAY_COLOR_ADJUSTMENT,
+ UserHandle.USER_CURRENT);
+ String[] colorAdjustment = colorAdjustmentTemp == null ?
+ null : colorAdjustmentTemp.split(" ");
+ if (colorAdjustment == null || colorAdjustment.length != 3) {
+ colorAdjustment = new String[] { "1.0", "1.0", "1.0" };
+ }
+ try {
+ mColorAdjustment[0] = Float.parseFloat(colorAdjustment[0]);
+ mColorAdjustment[1] = Float.parseFloat(colorAdjustment[1]);
+ mColorAdjustment[2] = Float.parseFloat(colorAdjustment[2]);
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, e.getMessage(), e);
+ mColorAdjustment[0] = 1.0f;
+ mColorAdjustment[1] = 1.0f;
+ mColorAdjustment[2] = 1.0f;
+ }
+
+ updateLiveDisplay(mCurrentLux);
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri DISPLAY_TEMPERATURE_DAY_URI =
+ Settings.System.getUriFor(Settings.System.DISPLAY_TEMPERATURE_DAY);
+ private final Uri DISPLAY_TEMPERATURE_NIGHT_URI =
+ Settings.System.getUriFor(Settings.System.DISPLAY_TEMPERATURE_NIGHT);
+ private final Uri DISPLAY_TEMPERATURE_MODE_URI =
+ Settings.System.getUriFor(Settings.System.DISPLAY_TEMPERATURE_MODE);
+ private final Uri DISPLAY_AUTO_OUTDOOR_MODE_URI =
+ Settings.System.getUriFor(Settings.System.DISPLAY_AUTO_OUTDOOR_MODE);
+ private final Uri DISPLAY_LOW_POWER_URI =
+ Settings.System.getUriFor(Settings.System.DISPLAY_LOW_POWER);
+ private final Uri DISPLAY_COLOR_ENHANCE_URI =
+ Settings.System.getUriFor(Settings.System.DISPLAY_COLOR_ENHANCE);
+ private final Uri DISPLAY_COLOR_ADJUSTMENT_URI =
+ Settings.System.getUriFor(Settings.System.DISPLAY_COLOR_ADJUSTMENT);
+ public SettingsObserver() {
+ super(mHandler);
+ }
+
+ public void register(boolean register) {
+ final ContentResolver cr = mContext.getContentResolver();
+ if (register) {
+ cr.registerContentObserver(DISPLAY_TEMPERATURE_DAY_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_TEMPERATURE_NIGHT_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_TEMPERATURE_MODE_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_AUTO_OUTDOOR_MODE_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_LOW_POWER_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_COLOR_ENHANCE_URI, false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(DISPLAY_COLOR_ADJUSTMENT_URI, false, this, UserHandle.USER_ALL);
+ } else {
+ cr.unregisterContentObserver(this);
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ updateSettings();
+ }
+ }
+
+ public void updateLiveDisplay() {
+ updateLiveDisplay(mCurrentLux);
+ }
+
+ synchronized void updateLiveDisplay(float lux) {
+ mCurrentLux = lux;
+ mHandler.removeMessages(MSG_UPDATE_LIVE_DISPLAY);
+ mHandler.sendEmptyMessage(MSG_UPDATE_LIVE_DISPLAY);
+ }
+
+ private synchronized void updateColorTemperature(TwilightState twilight) {
+ int temperature = mDayTemperature;
+ if (mMode == MODE_OFF || mLowPerformance) {
+ temperature = OFF_TEMPERATURE;
+ } else if (mMode == MODE_NIGHT) {
+ temperature = mNightTemperature;
+ } else if (mMode == MODE_AUTO) {
+ temperature = getTwilightK(twilight);
+ }
+
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ mAnimator = ValueAnimator.ofInt(mColorTemperature, temperature);
+ mAnimator.setDuration(Math.abs(mColorTemperature - temperature) / 2);
+ mAnimator.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setDisplayTemperature((Integer)animation.getAnimatedValue());
+ }
+ });
+ mAnimator.start();
+ }
+
+ private synchronized void setDisplayTemperature(int temperature) {
+ mColorTemperature = temperature;
+
+ final float[] rgb = temperatureToRGB(temperature);
+
+ if (!mLowPerformance) {
+ rgb[0] *= mColorAdjustment[0];
+ rgb[1] *= mColorAdjustment[1];
+ rgb[2] *= mColorAdjustment[2];
+ }
+
+ if (rgb[0] == mRGB[0] && rgb[1] == mRGB[1] && rgb[2] == mRGB[2]) {
+ // no changes
+ return;
+ }
+
+ System.arraycopy(rgb, 0, mRGB, 0, 3);
+
+ Slog.d(TAG, "Adjust display temperature to " + temperature +
+ "K [r=" + rgb[0] + " g=" + rgb[1] + " b=" + rgb[2] + "]");
+
+ if (mHardware.isSupported(CMHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION)) {
+ // Clear this out in case of an upgrade
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.LIVE_DISPLAY_COLOR_MATRIX,
+ null,
+ UserHandle.USER_CURRENT);
+
+ int max = mHardware.getDisplayColorCalibrationMax();
+ mHardware.setDisplayColorCalibration(new int[] {
+ (int) Math.ceil(rgb[0] * max),
+ (int) Math.ceil(rgb[1] * max),
+ (int) Math.ceil(rgb[2] * max)
+ });
+ screenRefresh();
+ } else {
+ String colorMatrixStr = null;
+ if (rgb[0] != 1.0f || rgb[1] != 1.0f || rgb[2] != 1.0f) {
+ final Float[] colorMatrix = new Float[] {
+ rgb[0], 0.0f, 0.0f, 0.0f,
+ 0.0f, rgb[1], 0.0f, 0.0f,
+ 0.0f, 0.0f, rgb[2], 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+ colorMatrixStr = TextUtils.join(" ", colorMatrix);
+ }
+
+ // For GPU color transform, go thru DisplayAdjustmentUtils in
+ // order to coexist with accessibility settings
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.LIVE_DISPLAY_COLOR_MATRIX,
+ colorMatrixStr,
+ UserHandle.USER_CURRENT);
+
+ DisplayAdjustmentUtils.applyAdjustments(mContext, UserHandle.USER_CURRENT);
+ }
+ }
+
+ /**
+ * Outdoor mode is optionally enabled when ambient lux > 10000 and it's daytime
+ * Melt faces!
+ *
+ * TODO: Use the camera or RGB sensor to determine if it's really sunlight
+ */
+ private synchronized void updateOutdoorMode(TwilightState twilight) {
+ if (!mUseOutdoorMode) {
+ return;
+ }
+
+ boolean value = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.DISPLAY_AUTO_OUTDOOR_MODE,
+ 1,
+ UserHandle.USER_CURRENT) == 1;
+
+ boolean enabled = !mLowPerformance &&
+ ((mMode == MODE_OUTDOOR) ||
+ (value && mMode == MODE_AUTO &&
+ twilight != null && !twilight.isNight() &&
+ mCurrentLux > mDefaultOutdoorLux));
+
+ if (enabled == mOutdoorMode) {
+ return;
+ }
+
+ mHardware.set(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT, enabled);
+ mOutdoorMode = enabled;
+ }
+
+ /**
+ * Color enhancement is optional, but can look bad with night mode
+ */
+ private synchronized void updateColorEnhancement(TwilightState twilight) {
+ if (!mUseColorEnhancement) {
+ return;
+ }
+
+ boolean value = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.DISPLAY_COLOR_ENHANCE,
+ 1,
+ UserHandle.USER_CURRENT) == 1;
+
+ boolean enabled = !mLowPerformance && value &&
+ !(mMode == MODE_NIGHT ||
+ (mMode == MODE_AUTO && twilight != null && twilight.isNight()));
+
+ if (enabled == mColorEnhancement) {
+ return;
+ }
+
+ mHardware.set(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT, enabled);
+ mColorEnhancement = enabled;
+ }
+
+ /**
+ * Adaptive backlight / low power mode. Turn it off when under very bright light.
+ */
+ private synchronized void updateLowPowerMode() {
+ if (!mUseLowPower) {
+ return;
+ }
+
+ boolean value = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.DISPLAY_LOW_POWER,
+ 1,
+ UserHandle.USER_CURRENT) == 1;
+
+ boolean enabled = value && (mCurrentLux < mDefaultOutdoorLux);
+
+ if (enabled == mLowPower) {
+ return;
+ }
+
+ mHardware.set(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT, enabled);
+ mLowPower = enabled;
+ }
+
+ /**
+ * Convert a color temperature value (in Kelvin) to a RGB units as floats.
+ * This can be used in a transform matrix or hardware gamma control.
+ *
+ * @param tempK
+ * @return
+ */
+ private static float[] temperatureToRGB(int degreesK) {
+ int k = MathUtils.constrain(degreesK, 1000, 20000);
+ float a = (k % 100) / 100.0f;
+ int i = ((k - 1000)/ 100) * 3;
+
+ return new float[] { interp(i, a), interp(i+1, a), interp(i+2, a) };
+ }
+
+ private static float interp(int i, float a) {
+ return MathUtils.lerp((float)sColorTable[i], (float)sColorTable[i+3], a);
+ }
+
+ /**
+ * Where is the sun anyway? This calculation determines day or night, and scales
+ * the value around sunset/sunrise for a smooth transition.
+ *
+ * @param now
+ * @param sunset
+ * @param sunrise
+ * @return float between 0 and 1
+ */
+ private static float adj(long now, long sunset, long sunrise) {
+ if (sunset < 0 || sunrise < 0
+ || now < sunset || now > sunrise) {
+ return 1.0f;
+ }
+
+ if (now < sunset + TWILIGHT_ADJUSTMENT_TIME) {
+ return MathUtils.lerp(1.0f, 0.0f,
+ (float)(now - sunset) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ if (now > sunrise - TWILIGHT_ADJUSTMENT_TIME) {
+ return MathUtils.lerp(1.0f, 0.0f,
+ (float)(sunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ return 0.0f;
+ }
+
+ /**
+ * Determine the color temperature we should use for the display based on
+ * the position of the sun.
+ *
+ * @param state
+ * @return color temperature in Kelvin
+ */
+ private int getTwilightK(TwilightState state) {
+ float adjustment = 1.0f;
+
+ if (state != null) {
+ final long now = System.currentTimeMillis();
+ adjustment = adj(now, state.getYesterdaySunset(), state.getTodaySunrise()) *
+ adj(now, state.getTodaySunset(), state.getTomorrowSunrise());
+ }
+
+ return (int)MathUtils.lerp(mNightTemperature, mDayTemperature, adjustment);
+ }
+
+ /**
+ * Tell SurfaceFlinger to repaint the screen. This is called after updating
+ * hardware registers for display calibration to have an immediate effect.
+ */
+ private static void screenRefresh() {
+ try {
+ final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+ if (flinger != null) {
+ final Parcel data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ flinger.transact(1004, data, null, 0);
+ data.recycle();
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to refresh screen", ex);
+ }
+ }
+
+ private void saveUserHint(int value) {
+ if (mHintCounter == value) {
+ return;
+ }
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.LIVE_DISPLAY_HINTED,
+ value,
+ UserHandle.USER_CURRENT);
+ mHintCounter = value;
+ }
+
+ /**
+ * Show a friendly notification to the user about the potential benefits of decreasing
+ * blue light at night. Do this only once if the feature has not been used after
+ * three sunsets. It would be great to enable this by default, but we don't want
+ * the change of screen color to be considered a "bug" by a user who doesn't
+ * understand what's happening.
+ *
+ * @param state
+ */
+ private void updateUserHint(TwilightState state) {
+ // check if we should send the hint only once after sunset
+ if (state == null || mHintCounter == 1) {
+ return;
+ }
+ boolean transition = state.isNight() && !mSunset;
+ mSunset = state.isNight();
+ if (!transition) {
+ return;
+ }
+
+ if (mHintCounter <= 0) {
+ mHintCounter++;
+ saveUserHint(mHintCounter);
+ }
+ if (mHintCounter == 0) {
+ //show the notification and don't come back here
+ final Intent intent = new Intent("android.settings.LIVEDISPLAY_SETTINGS");
+ PendingIntent result = PendingIntent.getActivity(
+ mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ Notification.Builder builder = new Notification.Builder(mContext)
+ .setContentTitle(mContext.getResources().getString(
+ com.android.internal.R.string.live_display_title))
+ .setContentText(mContext.getResources().getString(
+ com.android.internal.R.string.live_display_hint))
+ .setSmallIcon(com.android.internal.R.drawable.ic_livedisplay_notif)
+ .setStyle(new Notification.BigTextStyle().bigText(mContext.getResources()
+ .getString(com.android.internal.R.string.live_display_hint)))
+ .setContentIntent(result);
+
+ NotificationManager nm =
+ (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ nm.notifyAsUser(null, 1, builder.build(), UserHandle.CURRENT);
+
+ saveUserHint(1);
+ }
+ }
+
+ private final TwilightListener mTwilightListener = new TwilightListener() {
+ @Override
+ public void onTwilightStateChanged() {
+ updateLiveDisplay(mCurrentLux);
+ }
+ };
+
+ private final class LiveDisplayHandler extends Handler {
+ public LiveDisplayHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_LIVE_DISPLAY:
+ if (!mInitialized) {
+ break;
+ }
+ TwilightState twilight = mTwilightManager.getCurrentState();
+
+ updateColorTemperature(twilight);
+ updateOutdoorMode(twilight);
+ updateColorEnhancement(twilight);
+ updateLowPowerMode();
+ updateUserHint(twilight);
+
+ boolean transition = mMode == MODE_AUTO &&
+ mColorTemperature != mDayTemperature &&
+ mColorTemperature != mNightTemperature;
+ if (transition) {
+ // fire again in a minute
+ sendEmptyMessageDelayed(MSG_UPDATE_LIVE_DISPLAY,
+ DateUtils.MINUTE_IN_MILLIS);
+ }
+ break;
+ }
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println();
+ pw.println("LiveDisplay Controller Configuration:");
+ pw.println(" mDayTemperature=" + mDayTemperature);
+ pw.println(" mNightTemperature=" + mNightTemperature);
+ pw.println();
+ pw.println("LiveDisplay Controller State:");
+ pw.println(" mMode=" + (mLowPerformance ? "disabled in powersave mode" : mMode));
+ pw.println(" mSunset=" + mSunset);
+ pw.println(" mColorTemperature=" + mColorTemperature);
+ pw.println(" mColorAdjustment=[r: " + mColorAdjustment[0] + " g:" + mColorAdjustment[1] +
+ " b:" + mColorAdjustment[2] + "]");
+ pw.println(" mRGB=[r:" + mRGB[0] + " g:" + mRGB[1] + " b:" + mRGB[2] + "]");
+ pw.println(" mOutdoorMode=" + (mUseOutdoorMode ? mOutdoorMode : "N/A"));
+ pw.println(" mColorEnhancement=" + (mUseColorEnhancement ? mColorEnhancement : "N/A"));
+ pw.println(" mLowPower=" + (mUseLowPower ? mLowPower : "N/A"));
+ }
+
+ /**
+ * This table is a modified version of the original blackbody chart, found here:
+ * http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html
+ *
+ * Created by Ingo Thiel.
+ */
+ private static final double[] sColorTable = new double[] {
+ 1.00000000, 0.18172716, 0.00000000,
+ 1.00000000, 0.25503671, 0.00000000,
+ 1.00000000, 0.30942099, 0.00000000,
+ 1.00000000, 0.35357379, 0.00000000,
+ 1.00000000, 0.39091524, 0.00000000,
+ 1.00000000, 0.42322816, 0.00000000,
+ 1.00000000, 0.45159884, 0.00000000,
+ 1.00000000, 0.47675916, 0.00000000,
+ 1.00000000, 0.49923747, 0.00000000,
+ 1.00000000, 0.51943421, 0.00000000,
+ 1.00000000, 0.54360078, 0.08679949,
+ 1.00000000, 0.56618736, 0.14065513,
+ 1.00000000, 0.58734976, 0.18362641,
+ 1.00000000, 0.60724493, 0.22137978,
+ 1.00000000, 0.62600248, 0.25591950,
+ 1.00000000, 0.64373109, 0.28819679,
+ 1.00000000, 0.66052319, 0.31873863,
+ 1.00000000, 0.67645822, 0.34786758,
+ 1.00000000, 0.69160518, 0.37579588,
+ 1.00000000, 0.70602449, 0.40267128,
+ 1.00000000, 0.71976951, 0.42860152,
+ 1.00000000, 0.73288760, 0.45366838,
+ 1.00000000, 0.74542112, 0.47793608,
+ 1.00000000, 0.75740814, 0.50145662,
+ 1.00000000, 0.76888303, 0.52427322,
+ 1.00000000, 0.77987699, 0.54642268,
+ 1.00000000, 0.79041843, 0.56793692,
+ 1.00000000, 0.80053332, 0.58884417,
+ 1.00000000, 0.81024551, 0.60916971,
+ 1.00000000, 0.81957693, 0.62893653,
+ 1.00000000, 0.82854786, 0.64816570,
+ 1.00000000, 0.83717703, 0.66687674,
+ 1.00000000, 0.84548188, 0.68508786,
+ 1.00000000, 0.85347859, 0.70281616,
+ 1.00000000, 0.86118227, 0.72007777,
+ 1.00000000, 0.86860704, 0.73688797,
+ 1.00000000, 0.87576611, 0.75326132,
+ 1.00000000, 0.88267187, 0.76921169,
+ 1.00000000, 0.88933596, 0.78475236,
+ 1.00000000, 0.89576933, 0.79989606,
+ 1.00000000, 0.90198230, 0.81465502,
+ 1.00000000, 0.90963069, 0.82838210,
+ 1.00000000, 0.91710889, 0.84190889,
+ 1.00000000, 0.92441842, 0.85523742,
+ 1.00000000, 0.93156127, 0.86836903,
+ 1.00000000, 0.93853986, 0.88130458,
+ 1.00000000, 0.94535695, 0.89404470,
+ 1.00000000, 0.95201559, 0.90658983,
+ 1.00000000, 0.95851906, 0.91894041,
+ 1.00000000, 0.96487079, 0.93109690,
+ 1.00000000, 0.97107439, 0.94305985,
+ 1.00000000, 0.97713351, 0.95482993,
+ 1.00000000, 0.98305189, 0.96640795,
+ 1.00000000, 0.98883326, 0.97779486,
+ 1.00000000, 0.99448139, 0.98899179,
+ 1.00000000, 1.00000000, 1.00000000,
+ 0.98947904, 0.99348723, 1.00000000,
+ 0.97940448, 0.98722715, 1.00000000,
+ 0.96975025, 0.98120637, 1.00000000,
+ 0.96049223, 0.97541240, 1.00000000,
+ 0.95160805, 0.96983355, 1.00000000,
+ 0.94303638, 0.96443333, 1.00000000,
+ 0.93480451, 0.95923080, 1.00000000,
+ 0.92689056, 0.95421394, 1.00000000,
+ 0.91927697, 0.94937330, 1.00000000,
+ 0.91194747, 0.94470005, 1.00000000,
+ 0.90488690, 0.94018594, 1.00000000,
+ 0.89808115, 0.93582323, 1.00000000,
+ 0.89151710, 0.93160469, 1.00000000,
+ 0.88518247, 0.92752354, 1.00000000,
+ 0.87906581, 0.92357340, 1.00000000,
+ 0.87315640, 0.91974827, 1.00000000,
+ 0.86744421, 0.91604254, 1.00000000,
+ 0.86191983, 0.91245088, 1.00000000,
+ 0.85657444, 0.90896831, 1.00000000,
+ 0.85139976, 0.90559011, 1.00000000,
+ 0.84638799, 0.90231183, 1.00000000,
+ 0.84153180, 0.89912926, 1.00000000,
+ 0.83682430, 0.89603843, 1.00000000,
+ 0.83225897, 0.89303558, 1.00000000,
+ 0.82782969, 0.89011714, 1.00000000,
+ 0.82353066, 0.88727974, 1.00000000,
+ 0.81935641, 0.88452017, 1.00000000,
+ 0.81530175, 0.88183541, 1.00000000,
+ 0.81136180, 0.87922257, 1.00000000,
+ 0.80753191, 0.87667891, 1.00000000,
+ 0.80380769, 0.87420182, 1.00000000,
+ 0.80018497, 0.87178882, 1.00000000,
+ 0.79665980, 0.86943756, 1.00000000,
+ 0.79322843, 0.86714579, 1.00000000,
+ 0.78988728, 0.86491137, 1.00000000,
+ 0.78663296, 0.86273225, 1.00000000,
+ 0.78346225, 0.86060650, 1.00000000,
+ 0.78037207, 0.85853224, 1.00000000,
+ 0.77735950, 0.85650771, 1.00000000,
+ 0.77442176, 0.85453121, 1.00000000,
+ 0.77155617, 0.85260112, 1.00000000,
+ 0.76876022, 0.85071588, 1.00000000,
+ 0.76603147, 0.84887402, 1.00000000,
+ 0.76336762, 0.84707411, 1.00000000,
+ 0.76076645, 0.84531479, 1.00000000,
+ 0.75822586, 0.84359476, 1.00000000,
+ 0.75574383, 0.84191277, 1.00000000,
+ 0.75331843, 0.84026762, 1.00000000,
+ 0.75094780, 0.83865816, 1.00000000,
+ 0.74863017, 0.83708329, 1.00000000,
+ 0.74636386, 0.83554194, 1.00000000,
+ 0.74414722, 0.83403311, 1.00000000,
+ 0.74197871, 0.83255582, 1.00000000,
+ 0.73985682, 0.83110912, 1.00000000,
+ 0.73778012, 0.82969211, 1.00000000,
+ 0.73574723, 0.82830393, 1.00000000,
+ 0.73375683, 0.82694373, 1.00000000,
+ 0.73180765, 0.82561071, 1.00000000,
+ 0.72989845, 0.82430410, 1.00000000,
+ 0.72802807, 0.82302316, 1.00000000,
+ 0.72619537, 0.82176715, 1.00000000,
+ 0.72439927, 0.82053539, 1.00000000,
+ 0.72263872, 0.81932722, 1.00000000,
+ 0.72091270, 0.81814197, 1.00000000,
+ 0.71922025, 0.81697905, 1.00000000,
+ 0.71756043, 0.81583783, 1.00000000,
+ 0.71593234, 0.81471775, 1.00000000,
+ 0.71433510, 0.81361825, 1.00000000,
+ 0.71276788, 0.81253878, 1.00000000,
+ 0.71122987, 0.81147883, 1.00000000,
+ 0.70972029, 0.81043789, 1.00000000,
+ 0.70823838, 0.80941546, 1.00000000,
+ 0.70678342, 0.80841109, 1.00000000,
+ 0.70535469, 0.80742432, 1.00000000,
+ 0.70395153, 0.80645469, 1.00000000,
+ 0.70257327, 0.80550180, 1.00000000,
+ 0.70121928, 0.80456522, 1.00000000,
+ 0.69988894, 0.80364455, 1.00000000,
+ 0.69858167, 0.80273941, 1.00000000,
+ 0.69729688, 0.80184943, 1.00000000,
+ 0.69603402, 0.80097423, 1.00000000,
+ 0.69479255, 0.80011347, 1.00000000,
+ 0.69357196, 0.79926681, 1.00000000,
+ 0.69237173, 0.79843391, 1.00000000,
+ 0.69119138, 0.79761446, 1.00000000,
+ 0.69003044, 0.79680814, 1.00000000,
+ 0.68888844, 0.79601466, 1.00000000,
+ 0.68776494, 0.79523371, 1.00000000,
+ 0.68665951, 0.79446502, 1.00000000,
+ 0.68557173, 0.79370830, 1.00000000,
+ 0.68450119, 0.79296330, 1.00000000,
+ 0.68344751, 0.79222975, 1.00000000,
+ 0.68241029, 0.79150740, 1.00000000,
+ 0.68138918, 0.79079600, 1.00000000,
+ 0.68038380, 0.79009531, 1.00000000,
+ 0.67939381, 0.78940511, 1.00000000,
+ 0.67841888, 0.78872517, 1.00000000,
+ 0.67745866, 0.78805526, 1.00000000,
+ 0.67651284, 0.78739518, 1.00000000,
+ 0.67558112, 0.78674472, 1.00000000,
+ 0.67466317, 0.78610368, 1.00000000,
+ 0.67375872, 0.78547186, 1.00000000,
+ 0.67286748, 0.78484907, 1.00000000,
+ 0.67198916, 0.78423512, 1.00000000,
+ 0.67112350, 0.78362984, 1.00000000,
+ 0.67027024, 0.78303305, 1.00000000,
+ 0.66942911, 0.78244457, 1.00000000,
+ 0.66859988, 0.78186425, 1.00000000,
+ 0.66778228, 0.78129191, 1.00000000,
+ 0.66697610, 0.78072740, 1.00000000,
+ 0.66618110, 0.78017057, 1.00000000,
+ 0.66539706, 0.77962127, 1.00000000,
+ 0.66462376, 0.77907934, 1.00000000,
+ 0.66386098, 0.77854465, 1.00000000,
+ 0.66310852, 0.77801705, 1.00000000,
+ 0.66236618, 0.77749642, 1.00000000,
+ 0.66163375, 0.77698261, 1.00000000,
+ 0.66091106, 0.77647551, 1.00000000,
+ 0.66019791, 0.77597498, 1.00000000,
+ 0.65949412, 0.77548090, 1.00000000,
+ 0.65879952, 0.77499315, 1.00000000,
+ 0.65811392, 0.77451161, 1.00000000,
+ 0.65743716, 0.77403618, 1.00000000,
+ 0.65676908, 0.77356673, 1.00000000,
+ 0.65610952, 0.77310316, 1.00000000,
+ 0.65545831, 0.77264537, 1.00000000,
+ 0.65481530, 0.77219324, 1.00000000,
+ 0.65418036, 0.77174669, 1.00000000,
+ 0.65355332, 0.77130560, 1.00000000,
+ 0.65293404, 0.77086988, 1.00000000,
+ 0.65232240, 0.77043944, 1.00000000,
+ 0.65171824, 0.77001419, 1.00000000,
+ 0.65112144, 0.76959404, 1.00000000,
+ 0.65053187, 0.76917889, 1.00000000,
+ 0.64994941, 0.76876866, 1.00000000,
+ 0.64937392, 0.76836326, 1.00000000
+ };
+}