1 /*
2  * Copyright (C) 2017 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 package com.android.settings.display;
17 
18 import android.content.Context;
19 import android.content.pm.PackageManager;
20 import android.hardware.display.AmbientDisplayConfiguration;
21 import android.os.PowerManager;
22 import android.os.SystemProperties;
23 import android.os.UserHandle;
24 import android.provider.Settings;
25 import android.text.TextUtils;
26 
27 import androidx.preference.Preference;
28 
29 import com.android.settings.R;
30 import com.android.settings.core.TogglePreferenceController;
31 
32 public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreferenceController {
33 
34     private final int ON = 1;
35     private final int OFF = 0;
36 
37     private static final int MY_USER = UserHandle.myUserId();
38     private static final String PROP_AWARE_AVAILABLE = "ro.vendor.aware_available";
39     private static final String AOD_SUPPRESSED_TOKEN = "winddown";
40 
41     private AmbientDisplayConfiguration mConfig;
42 
AmbientDisplayAlwaysOnPreferenceController(Context context, String key)43     public AmbientDisplayAlwaysOnPreferenceController(Context context, String key) {
44         super(context, key);
45     }
46 
47     @Override
getAvailabilityStatus()48     public int getAvailabilityStatus() {
49         return isAvailable(getConfig())
50                 && !SystemProperties.getBoolean(PROP_AWARE_AVAILABLE, false) ?
51                 AVAILABLE : UNSUPPORTED_ON_DEVICE;
52     }
53 
54     @Override
updateState(Preference preference)55     public void updateState(Preference preference) {
56         super.updateState(preference);
57         refreshSummary(preference);
58     }
59 
60     @Override
isSliceable()61     public boolean isSliceable() {
62         return true;
63     }
64 
65     @Override
isPublicSlice()66     public boolean isPublicSlice() {
67         return TextUtils.equals(getPreferenceKey(), "ambient_display_always_on");
68     }
69 
70     @Override
getSliceHighlightMenuRes()71     public int getSliceHighlightMenuRes() {
72         return R.string.menu_key_display;
73     }
74 
75     @Override
isChecked()76     public boolean isChecked() {
77         return getConfig().alwaysOnEnabled(MY_USER);
78     }
79 
80     @Override
setChecked(boolean isChecked)81     public boolean setChecked(boolean isChecked) {
82         int enabled = isChecked ? ON : OFF;
83         Settings.Secure.putInt(
84                 mContext.getContentResolver(), Settings.Secure.DOZE_ALWAYS_ON, enabled);
85         return true;
86     }
87 
88     @Override
getSummary()89     public CharSequence getSummary() {
90         return mContext.getText(
91                 isAodSuppressedByBedtime(mContext) ? R.string.aware_summary_when_bedtime_on
92                         : R.string.doze_always_on_summary);
93     }
94 
setConfig( AmbientDisplayConfiguration config)95     public AmbientDisplayAlwaysOnPreferenceController setConfig(
96             AmbientDisplayConfiguration config) {
97         mConfig = config;
98         return this;
99     }
100 
isAvailable(AmbientDisplayConfiguration config)101     public static boolean isAvailable(AmbientDisplayConfiguration config) {
102         return config.alwaysOnAvailableForUser(MY_USER);
103     }
104 
getConfig()105     private AmbientDisplayConfiguration getConfig() {
106         if (mConfig == null) {
107             mConfig = new AmbientDisplayConfiguration(mContext);
108         }
109         return mConfig;
110     }
111 
112     /**
113      * Returns whether AOD is suppressed by Bedtime mode, a feature of Digital Wellbeing.
114      *
115      * We know that Bedtime mode suppresses AOD using {@link AOD_SUPPRESSED_TOKEN}. If the Digital
116      * Wellbeing app is suppressing AOD with {@link AOD_SUPPRESSED_TOKEN}, then we can infer that
117      * AOD is being suppressed by Bedtime mode.
118      */
isAodSuppressedByBedtime(Context context)119     public static boolean isAodSuppressedByBedtime(Context context) {
120         int uid;
121         final PowerManager powerManager = context.getSystemService(PowerManager.class);
122         final PackageManager packageManager = context.getPackageManager();
123         final String packageName = context.getString(
124                 com.android.internal.R.string.config_systemWellbeing);
125         try {
126             uid = packageManager.getApplicationInfo(packageName, /* flags= */ 0).uid;
127         } catch (PackageManager.NameNotFoundException e) {
128             return false;
129         }
130         return powerManager.isAmbientDisplaySuppressedForTokenByApp(AOD_SUPPRESSED_TOKEN, uid);
131     }
132 }
133