255 lines
8.6 KiB
Java
255 lines
8.6 KiB
Java
/*
|
|
* Copyright (C) 2016 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 org.cyanogenmod.platform.internal.display;
|
|
|
|
import static cyanogenmod.hardware.LiveDisplayManager.MODE_AUTO;
|
|
import static cyanogenmod.hardware.LiveDisplayManager.MODE_DAY;
|
|
import static cyanogenmod.hardware.LiveDisplayManager.MODE_OUTDOOR;
|
|
|
|
import android.content.Context;
|
|
import android.net.Uri;
|
|
import android.os.Handler;
|
|
|
|
import java.io.PrintWriter;
|
|
import java.util.BitSet;
|
|
|
|
import cyanogenmod.hardware.CMHardwareManager;
|
|
import cyanogenmod.hardware.LiveDisplayManager;
|
|
import cyanogenmod.providers.CMSettings;
|
|
|
|
public class OutdoorModeController extends LiveDisplayFeature {
|
|
|
|
private final CMHardwareManager mHardware;
|
|
private AmbientLuxObserver mLuxObserver;
|
|
|
|
// hardware capabilities
|
|
private final boolean mUseOutdoorMode;
|
|
|
|
// default values
|
|
private final int mDefaultOutdoorLux;
|
|
private final boolean mDefaultAutoOutdoorMode;
|
|
private final boolean mSelfManaged;
|
|
|
|
// internal state
|
|
private boolean mIsOutdoor;
|
|
private boolean mIsSensorEnabled;
|
|
|
|
// sliding window for sensor event smoothing
|
|
private static final int SENSOR_WINDOW_MS = 3000;
|
|
|
|
public OutdoorModeController(Context context, Handler handler) {
|
|
super(context, handler);
|
|
|
|
mHardware = CMHardwareManager.getInstance(mContext);
|
|
mUseOutdoorMode = mHardware.isSupported(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT);
|
|
mSelfManaged = mUseOutdoorMode && mHardware.isSunlightEnhancementSelfManaged();
|
|
|
|
mDefaultOutdoorLux = mContext.getResources().getInteger(
|
|
org.cyanogenmod.platform.internal.R.integer.config_outdoorAmbientLux);
|
|
mDefaultAutoOutdoorMode = mContext.getResources().getBoolean(
|
|
org.cyanogenmod.platform.internal.R.bool.config_defaultAutoOutdoorMode);
|
|
}
|
|
|
|
@Override
|
|
public void onStart() {
|
|
if (!mUseOutdoorMode) {
|
|
return;
|
|
}
|
|
|
|
if (!mSelfManaged) {
|
|
mLuxObserver = new AmbientLuxObserver(mContext, mHandler.getLooper(),
|
|
mDefaultOutdoorLux, SENSOR_WINDOW_MS);
|
|
}
|
|
|
|
registerSettings(
|
|
CMSettings.System.getUriFor(CMSettings.System.DISPLAY_AUTO_OUTDOOR_MODE));
|
|
}
|
|
|
|
@Override
|
|
public boolean getCapabilities(final BitSet caps) {
|
|
if (mUseOutdoorMode) {
|
|
caps.set(LiveDisplayManager.MODE_OUTDOOR);
|
|
if (mSelfManaged) {
|
|
caps.set(LiveDisplayManager.FEATURE_MANAGED_OUTDOOR_MODE);
|
|
}
|
|
}
|
|
return mUseOutdoorMode;
|
|
}
|
|
|
|
@Override
|
|
protected void onUpdate() {
|
|
updateOutdoorMode();
|
|
}
|
|
|
|
@Override
|
|
protected void onTwilightUpdated() {
|
|
updateOutdoorMode();
|
|
}
|
|
|
|
@Override
|
|
protected synchronized void onScreenStateChanged() {
|
|
if (!mUseOutdoorMode) {
|
|
return;
|
|
}
|
|
|
|
// toggle the sensor when screen on/off
|
|
updateSensorState();
|
|
|
|
// Disable outdoor mode on screen off so that we don't melt the users
|
|
// face if they turn it back on in normal conditions
|
|
if (!isScreenOn() && !mSelfManaged && getMode() != MODE_OUTDOOR) {
|
|
mIsOutdoor = false;
|
|
mHardware.set(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT, false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void onSettingsChanged(Uri uri) {
|
|
updateOutdoorMode();
|
|
}
|
|
|
|
@Override
|
|
public void dump(PrintWriter pw) {
|
|
pw.println();
|
|
pw.println("OutdoorModeController Configuration:");
|
|
pw.println(" mSelfManaged=" + mSelfManaged);
|
|
if (!mSelfManaged) {
|
|
pw.println(" mDefaultOutdoorLux=" + mDefaultOutdoorLux);
|
|
pw.println();
|
|
pw.println(" OutdoorModeController State:");
|
|
pw.println(" mAutoOutdoorMode=" + isAutomaticOutdoorModeEnabled());
|
|
pw.println(" mIsOutdoor=" + mIsOutdoor);
|
|
pw.println(" mIsNight=" + isNight());
|
|
pw.println(" hardware state=" +
|
|
mHardware.get(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT));
|
|
}
|
|
mLuxObserver.dump(pw);
|
|
}
|
|
|
|
private synchronized void updateSensorState() {
|
|
if (!mUseOutdoorMode || mLuxObserver == null || mSelfManaged) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Light sensor:
|
|
*/
|
|
boolean sensorEnabled = false;
|
|
// no sensor if low power mode or when the screen is off
|
|
if (isScreenOn() && !isLowPowerMode()) {
|
|
if (isAutomaticOutdoorModeEnabled()) {
|
|
int mode = getMode();
|
|
if (mode == MODE_DAY) {
|
|
// always turn it on if day mode is selected
|
|
sensorEnabled = true;
|
|
} else if (mode == MODE_AUTO && !isNight()) {
|
|
// in auto mode we turn it on during actual daytime
|
|
sensorEnabled = true;
|
|
}
|
|
}
|
|
}
|
|
if (mIsSensorEnabled != sensorEnabled) {
|
|
mIsSensorEnabled = sensorEnabled;
|
|
mLuxObserver.setTransitionListener(sensorEnabled ? mListener : null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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() {
|
|
if (!mUseOutdoorMode) {
|
|
return;
|
|
}
|
|
|
|
updateSensorState();
|
|
|
|
/*
|
|
* Should we turn on outdoor mode or not?
|
|
*
|
|
* Do nothing if the screen is off.
|
|
*/
|
|
if (isScreenOn()) {
|
|
boolean enabled = false;
|
|
// turn it off in low power mode
|
|
if (!isLowPowerMode()) {
|
|
int mode = getMode();
|
|
// turn it on if the user manually selected the mode
|
|
if (mode == MODE_OUTDOOR) {
|
|
enabled = true;
|
|
} else if (isAutomaticOutdoorModeEnabled()) {
|
|
// self-managed mode means we just flip a switch and an external
|
|
// implementation does all the sensing. this allows the user
|
|
// to turn on/off the feature.
|
|
if (mSelfManaged) {
|
|
enabled = true;
|
|
} else if (mIsOutdoor) {
|
|
// if we're here, the sensor detects extremely bright light.
|
|
if (mode == MODE_DAY) {
|
|
// if the user manually selected day mode, go ahead and
|
|
// melt their face
|
|
enabled = true;
|
|
} else if (mode == MODE_AUTO && !isNight()) {
|
|
// if we're in auto mode, we should also check if it's
|
|
// night time, since we don't get much sun at night
|
|
// on this planet :)
|
|
enabled = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
mHardware.set(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT, enabled);
|
|
}
|
|
}
|
|
|
|
private final AmbientLuxObserver.TransitionListener mListener =
|
|
new AmbientLuxObserver.TransitionListener() {
|
|
@Override
|
|
public void onTransition(final int state, float ambientLux) {
|
|
final boolean outdoor = state == 1;
|
|
synchronized (OutdoorModeController.this) {
|
|
if (mIsOutdoor == outdoor) {
|
|
return;
|
|
}
|
|
|
|
mIsOutdoor = outdoor;
|
|
updateOutdoorMode();
|
|
}
|
|
}
|
|
};
|
|
|
|
boolean setAutomaticOutdoorModeEnabled(boolean enabled) {
|
|
if (!mUseOutdoorMode) {
|
|
return false;
|
|
}
|
|
putBoolean(CMSettings.System.DISPLAY_AUTO_OUTDOOR_MODE, enabled);
|
|
return true;
|
|
}
|
|
|
|
boolean isAutomaticOutdoorModeEnabled() {
|
|
return mUseOutdoorMode &&
|
|
getBoolean(CMSettings.System.DISPLAY_AUTO_OUTDOOR_MODE,
|
|
getDefaultAutoOutdoorMode());
|
|
}
|
|
|
|
boolean getDefaultAutoOutdoorMode() {
|
|
return mDefaultAutoOutdoorMode;
|
|
}
|
|
}
|