replicant-vendor_cmsdk/cm/lib/main/java/org/cyanogenmod/platform/internal/display/OutdoorModeController.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;
}
}