1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.settings.qc;
18 
19 import static com.android.car.qc.QCItem.QC_ACTION_SLIDER_VALUE;
20 import static com.android.car.settings.qc.QCUtils.getActionDisabledDialogIntent;
21 import static com.android.car.settings.qc.QCUtils.getAvailabilityStatusForZoneFromXml;
22 import static com.android.car.settings.qc.SettingsQCRegistry.BRIGHTNESS_SLIDER_URI;
23 import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX;
24 import static com.android.settingslib.display.BrightnessUtils.convertGammaToLinear;
25 import static com.android.settingslib.display.BrightnessUtils.convertLinearToGamma;
26 
27 import android.app.PendingIntent;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.hardware.display.DisplayManager;
31 import android.net.Uri;
32 import android.os.PowerManager;
33 import android.os.UserHandle;
34 import android.os.UserManager;
35 import android.provider.Settings;
36 
37 import androidx.annotation.VisibleForTesting;
38 
39 import com.android.car.qc.QCItem;
40 import com.android.car.qc.QCList;
41 import com.android.car.qc.QCRow;
42 import com.android.car.qc.QCSlider;
43 import com.android.car.settings.CarSettingsApplication;
44 import com.android.car.settings.R;
45 import com.android.car.settings.common.Logger;
46 import com.android.car.settings.enterprise.EnterpriseUtils;
47 import com.android.internal.display.BrightnessSynchronizer;
48 
49 /**
50  *  QCItem for showing a brightness slider.
51  */
52 public class BrightnessSlider extends SettingsQCItem {
53     private static final Logger LOG = new Logger(BrightnessSlider.class);
54     private final int mMaximumBacklight;
55     private final int mMinimumBacklight;
56     private final Context mContextForUser;
57     private final Context mContext;
58     private final boolean mIsVisibleBackgroundUsersSupported;
59     private DisplayManager mDisplayManager;
60 
BrightnessSlider(Context context)61     public BrightnessSlider(Context context) {
62         super(context);
63         setAvailabilityStatusForZone(getAvailabilityStatusForZoneFromXml(context,
64                 R.xml.display_settings_fragment, R.string.pk_brightness_level));
65         PowerManager powerManager = context.getSystemService(PowerManager.class);
66         mMaximumBacklight = powerManager.getMaximumScreenBrightnessSetting();
67         mMinimumBacklight = powerManager.getMinimumScreenBrightnessSetting();
68         mContext = context;
69         mContextForUser = context
70                 .createContextAsUser(
71                         UserHandle.of(UserHandle.myUserId()), /* flags= */ 0);
72         UserManager userManager = context.getSystemService(UserManager.class);
73         mIsVisibleBackgroundUsersSupported =
74                 userManager != null ? userManager.isVisibleBackgroundUsersSupported() : false;
75         if (mIsVisibleBackgroundUsersSupported) {
76             mDisplayManager = context.getSystemService(DisplayManager.class);
77         }
78     }
79 
80     @Override
getQCItem()81     QCItem getQCItem() {
82         if (isHiddenForZone()) {
83             return null;
84         }
85         QCList.Builder listBuilder = new QCList.Builder()
86                 .addRow(getBrightnessRowBuilder().build());
87 
88         return listBuilder.build();
89     }
90 
91     @Override
getUri()92     Uri getUri() {
93         return BRIGHTNESS_SLIDER_URI;
94     }
95 
96     @Override
onNotifyChange(Intent intent)97     void onNotifyChange(Intent intent) {
98         int value = intent.getIntExtra(QC_ACTION_SLIDER_VALUE, Integer.MIN_VALUE);
99         if (value == Integer.MIN_VALUE) {
100             return;
101         }
102         int linear = convertGammaToLinear(value, mMinimumBacklight, mMaximumBacklight);
103 
104         if (mIsVisibleBackgroundUsersSupported) {
105             if (mDisplayManager != null) {
106                 float linearFloat = BrightnessSynchronizer.brightnessIntToFloat(linear);
107                 mDisplayManager.setBrightness(getMyOccupantZoneDisplayId(), linearFloat);
108             }
109         } else {
110             Settings.System.putInt(mContextForUser.getContentResolver(),
111                     Settings.System.SCREEN_BRIGHTNESS, linear);
112         }
113     }
114 
getBrightnessRowBuilder()115     protected QCRow.Builder getBrightnessRowBuilder() {
116         String userRestriction = UserManager.DISALLOW_CONFIG_BRIGHTNESS;
117         boolean hasDpmRestrictions = EnterpriseUtils.hasUserRestrictionByDpm(getContext(),
118                 userRestriction);
119         boolean hasUmRestrictions = EnterpriseUtils.hasUserRestrictionByUm(getContext(),
120                 userRestriction);
121 
122         boolean isReadOnlyForZone = isReadOnlyForZone();
123         PendingIntent disabledPendingIntent = isReadOnlyForZone
124                 ? QCUtils.getDisabledToastBroadcastIntent(getContext())
125                 : getActionDisabledDialogIntent(getContext(), userRestriction);
126 
127         return new QCRow.Builder()
128                 .setTitle(getContext().getString(R.string.qc_display_brightness))
129                 .addSlider(new QCSlider.Builder()
130                         .setMax(GAMMA_SPACE_MAX)
131                         .setValue(getSeekbarValue())
132                         .setInputAction(getBroadcastIntent())
133                         .setEnabled(!hasUmRestrictions && !hasDpmRestrictions
134                                 && isWritableForZone())
135                         .setClickableWhileDisabled(hasDpmRestrictions || isReadOnlyForZone)
136                         .setDisabledClickAction(disabledPendingIntent)
137                         .build()
138                 );
139     }
140 
141     @VisibleForTesting
getSeekbarValue()142     int getSeekbarValue() {
143         int gamma = GAMMA_SPACE_MAX;
144         if (mIsVisibleBackgroundUsersSupported) {
145             if (mDisplayManager != null) {
146                 float linearFloat = mDisplayManager.getBrightness(getMyOccupantZoneDisplayId());
147                 int linear = BrightnessSynchronizer.brightnessFloatToInt(linearFloat);
148                 gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight);
149             }
150         } else {
151             try {
152                 int linear = Settings.System.getInt(mContextForUser.getContentResolver(),
153                         Settings.System.SCREEN_BRIGHTNESS);
154                 gamma = convertLinearToGamma(linear, mMinimumBacklight, mMaximumBacklight);
155             } catch (Settings.SettingNotFoundException e) {
156                 LOG.w("Can't find setting for SCREEN_BRIGHTNESS.");
157             }
158         }
159         return gamma;
160     }
161 
getMyOccupantZoneDisplayId()162     private int getMyOccupantZoneDisplayId() {
163         return ((CarSettingsApplication) mContext.getApplicationContext())
164                 .getMyOccupantZoneDisplayId();
165     }
166 }
167