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.settings.gestures;
18 
19 import static com.android.settings.gestures.PowerMenuSettingsUtils.LONG_PRESS_POWER_ASSISTANT_VALUE;
20 import static com.android.settings.gestures.PowerMenuSettingsUtils.LONG_PRESS_POWER_GLOBAL_ACTIONS;
21 import static com.android.settings.gestures.PowerMenuSettingsUtils.POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE;
22 import static com.android.settings.gestures.PowerMenuSettingsUtils.POWER_BUTTON_LONG_PRESS_SETTING;
23 
24 import android.content.Context;
25 import android.provider.Settings;
26 
27 import androidx.preference.Preference;
28 import androidx.preference.PreferenceScreen;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 import com.android.settings.R;
32 import com.android.settings.core.TogglePreferenceController;
33 
34 import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
35 
36 /**
37  * Configures the behaviour of long press power button action.
38  */
39 public class LongPressPowerButtonPreferenceController extends TogglePreferenceController {
40 
41     private static final String KEY_CHORD_POWER_VOLUME_UP_SETTING =
42             Settings.Global.KEY_CHORD_POWER_VOLUME_UP;
43 
44     private static final String FOOTER_HINT_KEY = "power_menu_power_volume_up_hint";
45     private static final String ASSIST_SWITCH_KEY = "gesture_power_menu_long_press_for_assist";
46 
47     /**
48      * Values used for volume key chord behaviour when Assist setting is enabled.
49      *
50      * Values based on config_keyChordPowerVolumeUp in
51      * frameworks/base/core/res/res/values/config.xml
52      */
53     @VisibleForTesting
54     static final int KEY_CHORD_POWER_VOLUME_UP_NO_ACTION = 0;
55     @VisibleForTesting
56     static final int KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE = 1;
57     @VisibleForTesting
58     static final int KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS = 2;
59 
60     private static final int KEY_CHORD_POWER_VOLUME_UP_DEFAULT_VALUE_RESOURCE =
61             com.android.internal.R.integer.config_keyChordPowerVolumeUp;
62 
63     @MonotonicNonNull
64     @VisibleForTesting
65     Preference mFooterHint;
66 
67     @MonotonicNonNull
68     @VisibleForTesting
69     Preference mAssistSwitch;
70 
LongPressPowerButtonPreferenceController(Context context, String key)71     public LongPressPowerButtonPreferenceController(Context context, String key) {
72         super(context, key);
73     }
74 
75     @Override
displayPreference(PreferenceScreen screen)76     public void displayPreference(PreferenceScreen screen) {
77         super.displayPreference(screen);
78         mFooterHint = screen.findPreference(FOOTER_HINT_KEY);
79         mAssistSwitch = screen.findPreference(ASSIST_SWITCH_KEY);
80         refreshStateDisplay();
81     }
82 
83     @Override
getSummary()84     public CharSequence getSummary() {
85         final int powerButtonValue = PowerMenuSettingsUtils.getPowerButtonSettingValue(mContext);
86         if (powerButtonValue == LONG_PRESS_POWER_ASSISTANT_VALUE) {
87             return mContext.getString(R.string.power_menu_summary_long_press_for_assist_enabled);
88         } else if (powerButtonValue == LONG_PRESS_POWER_GLOBAL_ACTIONS) {
89             return mContext.getString(
90                     R.string.power_menu_summary_long_press_for_assist_disabled_with_power_menu);
91         } else {
92             return mContext.getString(
93                     R.string.power_menu_summary_long_press_for_assist_disabled_no_action);
94         }
95     }
96 
97     @Override
getAvailabilityStatus()98     public int getAvailabilityStatus() {
99         final boolean enabled = mContext.getResources().getBoolean(
100                 com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable);
101         return enabled ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
102     }
103 
104     @Override
isChecked()105     public boolean isChecked() {
106         return PowerMenuSettingsUtils.isLongPressPowerForAssistEnabled(mContext);
107     }
108 
109     @Override
setChecked(boolean isChecked)110     public boolean setChecked(boolean isChecked) {
111         if (setPowerLongPressValue(isChecked)) {
112             // The key chord value is dependant on the long press setting and it always
113             // toggled in tandem. POWER_BUTTON_LONG_PRESS_SETTING is always the source
114             // of truth for both.
115             setPowerVolumeChordValue(isChecked);
116             refreshStateDisplay();
117             return true;
118         }
119 
120         return false;
121     }
122 
123     @Override
getSliceHighlightMenuRes()124     public int getSliceHighlightMenuRes() {
125         return R.string.menu_key_system;
126     }
127 
refreshStateDisplay()128     private void refreshStateDisplay() {
129         if (mAssistSwitch != null) {
130             mAssistSwitch.setSummary(getSummary());
131         }
132 
133         if (mFooterHint != null) {
134             String footerHintText = mContext.getString(R.string.power_menu_power_volume_up_hint);
135             // If the device supports hush gesture, we need to notify the user where to find
136             // the setting.
137             if (mContext.getResources().getBoolean(
138                     com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
139                 footerHintText = footerHintText + "\n\n" + mContext.getString(
140                         R.string.power_menu_power_prevent_ringing_hint);
141             }
142 
143             mFooterHint.setSummary(footerHintText);
144             mFooterHint.setVisible(isPowerMenuKeyChordEnabled(mContext));
145         }
146     }
147 
isPowerMenuKeyChordEnabled(Context context)148     private static boolean isPowerMenuKeyChordEnabled(Context context) {
149         return Settings.Global.getInt(context.getContentResolver(),
150                 KEY_CHORD_POWER_VOLUME_UP_SETTING,
151                 context.getResources().getInteger(
152                         com.android.internal.R.integer.config_keyChordPowerVolumeUp))
153                 == KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS;
154     }
155 
setPowerLongPressValue(boolean isChecked)156     private boolean setPowerLongPressValue(boolean isChecked) {
157         if (isChecked) {
158             return Settings.Global.putInt(mContext.getContentResolver(),
159                     POWER_BUTTON_LONG_PRESS_SETTING, LONG_PRESS_POWER_ASSISTANT_VALUE);
160         }
161 
162         // We need to determine the right disabled value based on the device default
163         // for long-press power.
164 
165         // If the default is to start the assistant, then the fallback is GlobalActions.
166         final int defaultPowerButtonValue = mContext.getResources().getInteger(
167                 POWER_BUTTON_LONG_PRESS_DEFAULT_VALUE_RESOURCE);
168         if (defaultPowerButtonValue == LONG_PRESS_POWER_ASSISTANT_VALUE) {
169             return Settings.Global.putInt(mContext.getContentResolver(),
170                     POWER_BUTTON_LONG_PRESS_SETTING, LONG_PRESS_POWER_GLOBAL_ACTIONS);
171         }
172 
173         // If the default is something different than Assist, we use that default.
174         return Settings.Global.putInt(mContext.getContentResolver(),
175                 POWER_BUTTON_LONG_PRESS_SETTING, defaultPowerButtonValue);
176     }
177 
178     /**
179      * Updates {@link Settings.Global.KEY_CHORD_POWER_VOLUME_UP} based on the changed value of
180      * {@link #POWER_BUTTON_LONG_PRESS_SETTING}. If power button is used for Assist, key chord
181      * should show the power menu.
182      */
setPowerVolumeChordValue(boolean isPowerButtonLongPressChecked)183     private boolean setPowerVolumeChordValue(boolean isPowerButtonLongPressChecked) {
184         if (isPowerButtonLongPressChecked) {
185             return Settings.Global.putInt(mContext.getContentResolver(),
186                     KEY_CHORD_POWER_VOLUME_UP_SETTING, KEY_CHORD_POWER_VOLUME_UP_GLOBAL_ACTIONS);
187         }
188 
189         // We restore key chord to the default value.
190         int keyChordDefaultValue = mContext.getResources().getInteger(
191                 KEY_CHORD_POWER_VOLUME_UP_DEFAULT_VALUE_RESOURCE);
192         return Settings.Global.putInt(mContext.getContentResolver(),
193                 KEY_CHORD_POWER_VOLUME_UP_SETTING, keyChordDefaultValue);
194     }
195 
196 }
197