From 2c743b51cc660c646e7d7c718d36e388c377bef6 Mon Sep 17 00:00:00 2001 From: rituj Date: Sat, 25 Jul 2020 17:48:03 +0800 Subject: [PATCH] base: Introduce automated DC Dimming [1/3] * Schedule based on sunset/sunrise * Add QS Tile to control DC Dimming * Disable the service on devices with no DC dimming support * Set config_deviceDcDimmingSysfsNode to point to the relevant sysfs kernel node [ghostrider-reborn: adapt to 12, remove brightness-based schedule] Co-authored-by: Andrew Fluck Co-authored-by: Adithya R Change-Id: Iaebf6624a8311722de3443c0ff5b033381749d20 Signed-off-by: miwu04 --- .../android/app/SystemServiceRegistry.java | 15 + core/java/android/content/Context.java | 9 + .../hardware/display/DcDimmingManager.java | 113 +++++++ .../hardware/display/IDcDimmingManager.aidl | 30 ++ core/java/android/provider/Settings.java | 31 ++ core/res/res/values/spark_config.xml | 12 + core/res/res/values/spark_symbols.xml | 6 + .../res/drawable/ic_dc_dimming_tile.xml | 10 + packages/SystemUI/res/values/config.xml | 4 +- .../SystemUI/res/values/spark_strings.xml | 3 + .../systemui/qs/tileimpl/QSFactoryImpl.java | 10 +- .../systemui/qs/tiles/DcDimmingTile.java | 160 ++++++++++ .../server/display/DcDimmingService.java | 287 ++++++++++++++++++ .../java/com/android/server/SystemServer.java | 10 + 14 files changed, 696 insertions(+), 4 deletions(-) create mode 100644 core/java/android/hardware/display/DcDimmingManager.java create mode 100644 core/java/android/hardware/display/IDcDimmingManager.aidl create mode 100644 packages/SystemUI/res/drawable/ic_dc_dimming_tile.xml create mode 100644 packages/SystemUI/src/com/android/systemui/qs/tiles/DcDimmingTile.java create mode 100644 services/core/java/com/android/server/display/DcDimmingService.java diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 6f51f6a51d27..de1aa913b68a 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -96,7 +96,9 @@ import android.hardware.camera2.CameraManager; import android.hardware.devicestate.DeviceStateManager; import android.hardware.display.ColorDisplayManager; +import android.hardware.display.DcDimmingManager; import android.hardware.display.DisplayManager; +import android.hardware.display.IDcDimmingManager; import android.hardware.face.FaceManager; import android.hardware.face.IFaceService; import android.hardware.fingerprint.FingerprintManager; @@ -971,6 +973,19 @@ public PocketManager createService(ContextImpl ctx) { return new PocketManager(ctx.getOuterContext(), service); }}); + registerService(Context.DC_DIM_SERVICE, DcDimmingManager.class, + new CachedServiceFetcher() { + @Override + public DcDimmingManager createService(ContextImpl ctx) throws ServiceNotFoundException { + if (Resources.getSystem().getString( + com.android.internal.R.string.config_deviceDcDimmingSysfsNode).isEmpty()) { + return null; + } + IBinder b = ServiceManager.getServiceOrThrow(Context.DC_DIM_SERVICE); + IDcDimmingManager service = IDcDimmingManager.Stub.asInterface(b); + return new DcDimmingManager(service); + }}); + registerService(Context.TV_INPUT_SERVICE, TvInputManager.class, new CachedServiceFetcher() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d2418775fc47..e676a69f2629 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -6066,6 +6066,15 @@ public abstract boolean startInstrumentation(@NonNull ComponentName className, */ public static final String APP_LOCK_SERVICE = "app_lock"; + /** + * {@link android.hardware.display.DcDimManager} for accessing and setting locked apps state. + * + * @see #getSystemService + * @see android.hardware.display.DcDimmingManager + * @hide + */ + public static final String DC_DIM_SERVICE = "dc_dim_service"; + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. diff --git a/core/java/android/hardware/display/DcDimmingManager.java b/core/java/android/hardware/display/DcDimmingManager.java new file mode 100644 index 000000000000..e4815c1783f7 --- /dev/null +++ b/core/java/android/hardware/display/DcDimmingManager.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020 Paranoid Android + * + * 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 android.hardware.display; + +import android.content.Context; +import android.annotation.SystemService; +import android.os.RemoteException; + +/** + * Manages the DC Dimming mode + * @author Rituj Beniwal + * @hide + */ +@SystemService(Context.DC_DIM_SERVICE) +public class DcDimmingManager { + private static final String TAG = "DcDimmingManager"; + + public static final int MODE_AUTO_OFF = 0; + public static final int MODE_AUTO_TIME = 1; + + private IDcDimmingManager mService; + + public DcDimmingManager (IDcDimmingManager service) { + mService = service; + } + + /** + * Set the DC Dimming mode + * @hide + */ + public void setAutoMode(int mode) { + if (mService != null) { + try { + mService.setAutoMode(mode); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Get the DC Dimming mode + * @hide + */ + public int getAutoMode() { + if (mService != null) { + try { + return mService.getAutoMode(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return 0; + } + + /** + * Whether the DC Dimming service is available + * @hide + */ + public boolean isAvailable() { + if (mService != null) { + try { + return mService.isAvailable(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Enable or disable DC Dimming + * @hide + */ + public void setDcDimming(boolean enable) { + if (mService != null) { + try { + mService.setDcDimming(enable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Whether DC Dimming is enabled currently + * @hide + */ + public boolean isDcDimmingOn() { + if (mService != null) { + try { + return mService.isDcDimmingOn(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } +} diff --git a/core/java/android/hardware/display/IDcDimmingManager.aidl b/core/java/android/hardware/display/IDcDimmingManager.aidl new file mode 100644 index 000000000000..7be3c05932da --- /dev/null +++ b/core/java/android/hardware/display/IDcDimmingManager.aidl @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2020 Paranoid Android + * + * 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 android.hardware.display; + +/** @hide */ +interface IDcDimmingManager { + void setAutoMode(in int mode); + + int getAutoMode(); + + boolean isAvailable(); + + void setDcDimming(in boolean enable); + + boolean isDcDimmingOn(); +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 08a124afc164..309dcba7ffe1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -953,6 +953,21 @@ public final class Settings { public static final String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS"; + /** + * Activity Action: Show settings to allow configuration of DC Dimming. + *

+ * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

+ * Input: Nothing. + *

+ * Output: Nothing. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_DC_DIMMING_SETTINGS = + "android.settings.DC_DIMMING_SETTINGS"; + /** * Activity Action: Show settings to allow configuration of Dark theme. *

@@ -4664,6 +4679,22 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean */ public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; + /** + * Indicates the state of DC dimming AUTO mode: + * 0 - Off + * 1 - On + * @hide + */ + public static final String DC_DIMMING_AUTO_MODE = "dc_dimming_auto_mode"; + + /** + * Indicates the state of DC dimming: + * 0 - Off + * 1 - On + * @hide + */ + public static final String DC_DIMMING_STATE = "dc_dimming_state"; + /** * Control whether to enable adaptive sleep mode. * @deprecated Use {@link android.provider.Settings.Secure#ADAPTIVE_SLEEP} instead. diff --git a/core/res/res/values/spark_config.xml b/core/res/res/values/spark_config.xml index 99794b31e0f4..a59154963816 100644 --- a/core/res/res/values/spark_config.xml +++ b/core/res/res/values/spark_config.xml @@ -290,4 +290,16 @@ + + + + + + 1 + + + 0 diff --git a/core/res/res/values/spark_symbols.xml b/core/res/res/values/spark_symbols.xml index f500e27e060b..9efb76cf1693 100644 --- a/core/res/res/values/spark_symbols.xml +++ b/core/res/res/values/spark_symbols.xml @@ -262,4 +262,10 @@ + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_dc_dimming_tile.xml b/packages/SystemUI/res/drawable/ic_dc_dimming_tile.xml new file mode 100644 index 000000000000..04a2276c1526 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_dc_dimming_tile.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index f985909de88d..3457093cdb0d 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -81,7 +81,7 @@ - internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,nfc,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,onthego,aod,powershare,caffeine,ambient_display,usb_tether,sync,sound,heads_up,reboot,volume_panel,dataswitch,fpsinfo,livedisplay,reading_mode,anti_flicker,compass,cpuinfo,soundsearch,smartpixels,refresh_rate,preferred_network,screenshot,spark_idle,spark_boost + internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,nfc,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,onthego,aod,powershare,caffeine,ambient_display,usb_tether,sync,sound,heads_up,reboot,volume_panel,dataswitch,fpsinfo,livedisplay,reading_mode,anti_flicker,compass,cpuinfo,soundsearch,smartpixels,refresh_rate,preferred_network,screenshot,spark_idle,spark_boost,dc_dimming @@ -773,7 +773,7 @@ @color/dream_overlay_aqi_very_unhealthy @color/dream_overlay_aqi_hazardous - + 80 0.88 diff --git a/packages/SystemUI/res/values/spark_strings.xml b/packages/SystemUI/res/values/spark_strings.xml index 0fb49075b3b5..e0d50ba38734 100644 --- a/packages/SystemUI/res/values/spark_strings.xml +++ b/packages/SystemUI/res/values/spark_strings.xml @@ -307,4 +307,7 @@ used today Data Wi-Fi + + + DC Dimming diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 3f0574c2a9b1..b62d2e6ae4d1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -44,6 +44,7 @@ import com.android.systemui.qs.tiles.CompassTile; import com.android.systemui.qs.tiles.DataSaverTile; import com.android.systemui.qs.tiles.DataSwitchTile; +import com.android.systemui.qs.tiles.DcDimmingTile; import com.android.systemui.qs.tiles.DeviceControlsTile; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.DreamTile; @@ -148,6 +149,7 @@ public class QSFactoryImpl implements QSFactory { private final Provider mScreenshotTileProvider; private final Provider mSparkIdleManagerTileProvider; private final Provider mSparkBoostManagerTileProvider; + private final Provider mDcDimmingTileProvider; private final Lazy mQsHostLazy; private final Provider mCustomTileBuilderProvider; @@ -210,10 +212,11 @@ public QSFactoryImpl( Provider preferredNetworkTileProvider, Provider screenshotTileProvider, Provider sparkIdleManagerTileProvider, - Provider sparkBoostManagerTileProvider) { + Provider sparkBoostManagerTileProvider, + Provider dcDimTileProvider) { mQsHostLazy = qsHostLazy; mCustomTileBuilderProvider = customTileBuilderProvider; - + mWifiTileProvider = wifiTileProvider; mInternetTileProvider = internetTileProvider; mBluetoothTileProvider = bluetoothTileProvider; @@ -269,6 +272,7 @@ public QSFactoryImpl( mScreenshotTileProvider = screenshotTileProvider; mSparkIdleManagerTileProvider = sparkIdleManagerTileProvider; mSparkBoostManagerTileProvider = sparkBoostManagerTileProvider; + mDcDimmingTileProvider = dcDimTileProvider; } /** Creates a tile with a type based on {@code tileSpec} */ @@ -394,6 +398,8 @@ protected QSTileImpl createTileInternal(String tileSpec) { return mSparkIdleManagerTileProvider.get(); case "spark_boost": return mSparkBoostManagerTileProvider.get(); + case "dc_dimming": + return mDcDimmingTileProvider.get(); } // Custom tiles if (tileSpec.startsWith(CustomTile.PREFIX)) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DcDimmingTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DcDimmingTile.java new file mode 100644 index 000000000000..8ddc50155f34 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DcDimmingTile.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2020 Paranoid Android + * + * 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.systemui.qs.tiles; + +import static android.hardware.display.DcDimmingManager.MODE_AUTO_TIME; + +import android.content.Context; +import android.content.ContentResolver; +import android.content.Intent; +import android.database.ContentObserver; +import android.hardware.display.DcDimmingManager; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.os.Looper; +import android.provider.Settings; +import android.service.quicksettings.Tile; +import android.text.TextUtils; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.tileimpl.QSTileImpl; + +import javax.inject.Inject; + +/** Quick settings tile: DC Dimming **/ +public class DcDimmingTile extends QSTileImpl { + + private DcDimmingManager mDcDimmingManager; + private final Icon mIcon = ResourceIcon.get(R.drawable.ic_dc_dimming_tile); + + @Inject + public DcDimmingTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + FalsingManager falsingManager, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger + ) { + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, + activityStarter, qsLogger); + mDcDimmingManager = (DcDimmingManager) mContext.getSystemService(Context.DC_DIM_SERVICE); + if (isAvailable()) { + SettingsObserver settingsObserver = new SettingsObserver(new Handler()); + settingsObserver.observe(); + } + } + + @Override + public boolean isAvailable() { + return mDcDimmingManager != null && mDcDimmingManager.isAvailable(); + } + + @Override + public BooleanState newTileState() { + return new BooleanState(); + } + + @Override + protected void handleClick(@Nullable View view) { + if (getState().state == Tile.STATE_UNAVAILABLE) { + return; + } + mDcDimmingManager.setDcDimming(!mState.value); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final int mode = mDcDimmingManager.getAutoMode(); + final boolean dcOn = mDcDimmingManager.isDcDimmingOn(); + + state.value = dcOn; + state.label = mContext.getString(R.string.quick_settings_dc_dimming_label); + state.icon = mIcon; + switch (mode) { + case MODE_AUTO_TIME: + state.secondaryLabel = mContext.getResources().getString(dcOn + ? R.string.quick_settings_dark_mode_secondary_label_until_sunrise + : R.string.quick_settings_dark_mode_secondary_label_on_at_sunset); + break; + default: + state.secondaryLabel = null; + break; + } + state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; + state.contentDescription = TextUtils.isEmpty(state.secondaryLabel) + ? state.label + : TextUtils.concat(state.label, ", ", state.secondaryLabel); + state.showRippleEffect = false; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.QS_CUSTOM; + } + + @Override + public Intent getLongClickIntent() { + return new Intent(Settings.ACTION_DC_DIMMING_SETTINGS); + } + + @Override + protected void handleSetListening(boolean listening) { + } + + @Override + public CharSequence getTileLabel() { + return getState().label; + } + + private class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.DC_DIMMING_AUTO_MODE), false, this, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.DC_DIMMING_STATE), false, this, + UserHandle.USER_ALL); + } + + @Override + public void onChange(boolean selfChange) { + refreshState(); + } + } +} diff --git a/services/core/java/com/android/server/display/DcDimmingService.java b/services/core/java/com/android/server/display/DcDimmingService.java new file mode 100644 index 000000000000..cbb6933a2ce0 --- /dev/null +++ b/services/core/java/com/android/server/display/DcDimmingService.java @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2020 Paranoid Android + * + * 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 static android.hardware.display.DcDimmingManager.MODE_AUTO_OFF; +import static android.hardware.display.DcDimmingManager.MODE_AUTO_TIME; + +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.display.DcDimmingManager; +import android.hardware.display.IDcDimmingManager; +import android.os.Binder; +import android.os.Handler; +import android.os.SystemClock; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Slog; + +import com.android.server.SystemService; +import com.android.server.SystemService.TargetUser; +import com.android.server.twilight.TwilightListener; +import com.android.server.twilight.TwilightManager; +import com.android.server.twilight.TwilightState; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +public class DcDimmingService extends SystemService { + + private static final String TAG = "DcDimmingService"; + + private final Context mContext; + private final Handler mHandler = new Handler(); + private final Object mLock = new Object(); + private final String mDcNode; + private final String mDcOnValue; + private final String mDcOffValue; + private TwilightManager mTwilightManager; + private TwilightState mTwilightState; + + private int mAutoMode; + private boolean mAvailable; + private boolean mDcOn; + private boolean mScreenOff; + private boolean mPendingOnScreenOn; + + private final TwilightListener mTwilightListener = (state) -> { + Slog.v(TAG, "onTwilightStateChanged state:" + state); + boolean changed = mTwilightState == null || (state.isNight() != mTwilightState.isNight()); + mPendingOnScreenOn = mScreenOff && changed; + mTwilightState = state; + if (mAutoMode == MODE_AUTO_TIME) { + if (!mScreenOff && changed) { + synchronized (mLock) { + updateLocked(false, false); + } + } + } + }; + + private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { + Slog.v(TAG, "mIntentReceiver ACTION_SCREEN_ON" + + " mPendingOnScreenOn:" + mPendingOnScreenOn); + mScreenOff = false; + mHandler.postDelayed(() -> { + if (mPendingOnScreenOn) { + synchronized (mLock) { + updateLocked(false, false); + } + } + mPendingOnScreenOn = false; + }, 300); + } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { + Slog.v(TAG, "mIntentReceiver ACTION_SCREEN_OFF"); + mScreenOff = true; + } + } + }; + + public DcDimmingService(Context context) { + super(context); + mContext = context; + mDcNode = context.getResources().getString( + com.android.internal.R.string.config_deviceDcDimmingSysfsNode); + mDcOnValue = context.getResources().getString( + com.android.internal.R.string.config_deviceDcDimmingEnableValue); + mDcOffValue = context.getResources().getString( + com.android.internal.R.string.config_deviceDcDimmingDisableValue); + final IntentFilter intentFilter = + new IntentFilter(Intent.ACTION_SCREEN_OFF); + intentFilter.addAction(Intent.ACTION_SCREEN_ON); + mContext.registerReceiver(mIntentReceiver, intentFilter); + } + + @Override + public void onStart() { + Slog.v(TAG, "Starting DcDimmingService"); + publishBinderService(Context.DC_DIM_SERVICE, mService); + publishLocalService(DcDimmingService.class, this); + mAvailable = nodeExists(); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + Slog.v(TAG, "onBootPhase PHASE_SYSTEM_SERVICES_READY"); + mTwilightManager = getLocalService(TwilightManager.class); + } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { + Slog.v(TAG, "onBootPhase PHASE_BOOT_COMPLETED"); + mTwilightManager.registerListener(mTwilightListener, mHandler); + mTwilightState = mTwilightManager.getLastTwilightState(); + } + } + + @Override + public void onUserUnlocking(TargetUser user) { + mAvailable = nodeExists(); + Slog.v(TAG, "onUnlockUser mAvailable:" + mAvailable); + if (!mAvailable) { + return; + } + mAutoMode = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.DC_DIMMING_AUTO_MODE, 0, UserHandle.USER_CURRENT); + mDcOn = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.DC_DIMMING_STATE, 0, UserHandle.USER_CURRENT) == 1; + synchronized (mLock) { + updateLocked(false, true); + } + } + + private void updateLocked(boolean force, boolean initial) { + if (!mAvailable) { + return; + } + boolean enable = shouldEnableDc(); + Slog.v(TAG, "updateLocked mDcOn:" + mDcOn + " force:" + force + + " initial:" + initial + " shouldEnableDc:" + enable); + if (!force) { + if ((!initial && mDcOn == enable) || (initial && !enable)) { + return; + } + mDcOn = enable; + } + writeSysfsNode(mDcOn ? mDcOnValue : mDcOffValue); + Settings.System.putIntForUser(mContext.getContentResolver(), + Settings.System.DC_DIMMING_STATE, mDcOn ? 1 : 0, + UserHandle.USER_CURRENT); + } + + private boolean shouldEnableDc() { + switch (mAutoMode) { + case MODE_AUTO_TIME: + return shouldEnableDcTime(); + default: + return mDcOn; + } + } + + private boolean shouldEnableDcTime() { + if (mTwilightState == null) { + mTwilightState = mTwilightManager.getLastTwilightState(); + } + return mTwilightState != null && mTwilightState.isNight(); + } + + private final IDcDimmingManager.Stub mService = new IDcDimmingManager.Stub() { + @Override + public void setAutoMode(int mode) { + synchronized (mLock) { + final long ident = Binder.clearCallingIdentity(); + try { + if (mAutoMode != mode) { + Slog.v(TAG, "setAutoMode(" + mode + ")"); + mAutoMode = mode; + Settings.System.putIntForUser(mContext.getContentResolver(), + Settings.System.DC_DIMMING_AUTO_MODE, mode, + UserHandle.USER_CURRENT); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + @Override + public void setDcDimming(boolean enable) { + synchronized (mLock) { + final long ident = Binder.clearCallingIdentity(); + try { + Slog.v(TAG, "setDcDimming(" + enable + ")"); + mDcOn = enable; + updateLocked(true, false); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + @Override + public int getAutoMode() { + return mAutoMode; + } + + @Override + public boolean isAvailable() { + return mAvailable; + } + + @Override + public boolean isDcDimmingOn() { + return mDcOn; + } + }; + + private void writeSysfsNode(String value) { + Slog.v(TAG, "writeSysfsNode value:" + value); + BufferedWriter writer = null; + try { + writer = new BufferedWriter(new FileWriter(mDcNode)); + writer.write(value); + } catch (FileNotFoundException e) { + Slog.w(TAG, "No such file " + mDcNode + " for writing", e); + } catch (IOException e) { + Slog.e(TAG, "Could not write to file " + mDcNode, e); + } finally { + try { + if (writer != null) { + writer.close(); + } + } catch (IOException e) { + // Ignored, not much we can do anyway + } + } + } + + private String readSysfsNode() { + String line = null; + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(mDcNode), 512); + line = reader.readLine(); + } catch (FileNotFoundException e) { + Slog.w(TAG, "No such file " + mDcNode + " for reading", e); + } catch (IOException e) { + Slog.e(TAG, "Could not read from file " + mDcNode, e); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (IOException e) { + // Ignored, not much we can do anyway + } + } + return line; + } + + private boolean nodeExists() { + final File file = new File(mDcNode); + return file.exists() && file.canRead() && file.canWrite(); + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b58e8966f941..842b6a113812 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -124,6 +124,7 @@ import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.coverage.CoverageService; import com.android.server.devicepolicy.DevicePolicyManagerService; +import com.android.server.display.DcDimmingService; import com.android.server.devicestate.DeviceStateManagerService; import com.android.server.display.AutoAODService; import com.android.server.display.DisplayManagerService; @@ -1667,6 +1668,15 @@ private void startOtherServices(@NonNull TimingsTraceAndSlog t) { t.traceEnd(); } + if (!context.getResources().getString(R.string.config_deviceDcDimmingSysfsNode) + .isEmpty()) { + t.traceBegin("StartDcDimmingService"); + mSystemServiceManager.startService(DcDimmingService.class); + t.traceEnd(); + } else { + Slog.i(TAG, "Dc Dimming not supported"); + } + t.traceBegin("SignedConfigService"); SignedConfigService.registerUpdateReceiver(mSystemContext); t.traceEnd();