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.wifi.tether;
18 
19 import android.content.Context;
20 import android.net.wifi.SoftApConfiguration;
21 import android.util.Log;
22 
23 import androidx.annotation.VisibleForTesting;
24 import androidx.preference.Preference;
25 import androidx.preference.SwitchPreference;
26 
27 import com.android.settings.R;
28 
29 /**
30  * This controller helps to manage the state of maximize compatibility switch preference.
31  */
32 public class WifiTetherMaximizeCompatibilityPreferenceController extends
33         WifiTetherBasePreferenceController {
34 
35     private static final String TAG = "WifiTetherMaximizeCompatibilityPref";
36     public static final String PREF_KEY = "wifi_tether_maximize_compatibility";
37 
38     private boolean mIsChecked;
39 
WifiTetherMaximizeCompatibilityPreferenceController(Context context, WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener)40     public WifiTetherMaximizeCompatibilityPreferenceController(Context context,
41             WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
42         super(context, listener);
43         mIsChecked = isMaximizeCompatibilityEnabled();
44     }
45 
46     @Override
getPreferenceKey()47     public String getPreferenceKey() {
48         return PREF_KEY;
49     }
50 
51     @Override
updateDisplay()52     public void updateDisplay() {
53         if (mPreference == null) {
54             return;
55         }
56         mPreference.setEnabled(is5GhzBandSupported());
57         ((SwitchPreference) mPreference).setChecked(mIsChecked);
58         mPreference.setSummary(mWifiManager.isBridgedApConcurrencySupported()
59                 ? R.string.wifi_hotspot_maximize_compatibility_dual_ap_summary
60                 : R.string.wifi_hotspot_maximize_compatibility_single_ap_summary);
61     }
62 
63     @Override
onPreferenceChange(Preference preference, Object newValue)64     public boolean onPreferenceChange(Preference preference, Object newValue) {
65         mIsChecked = (Boolean) newValue;
66         if (mListener != null) {
67             mListener.onTetherConfigUpdated(this);
68         }
69         return true;
70     }
71 
is5GhzBandSupported()72     private boolean is5GhzBandSupported() {
73         if (mWifiManager == null) {
74             return false;
75         }
76         if (!mWifiManager.is5GHzBandSupported() || mWifiManager.getCountryCode() == null) {
77             return false;
78         }
79         return true;
80     }
81 
82     @VisibleForTesting
isMaximizeCompatibilityEnabled()83     boolean isMaximizeCompatibilityEnabled() {
84         if (mWifiManager == null) {
85             return false;
86         }
87         final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
88         if (config == null) {
89             return false;
90         }
91         if (mWifiManager.isBridgedApConcurrencySupported()) {
92             final boolean isEnabled = config.isBridgedModeOpportunisticShutdownEnabled();
93             Log.d(TAG, "isBridgedModeOpportunisticShutdownEnabled:" + isEnabled);
94             // Because the return value defined by the Wi-Fi framework API is opposite to the UI.
95             //   Compatibility on:  isBridgedModeOpportunisticShutdownEnabled() = false
96             //   Compatibility off: isBridgedModeOpportunisticShutdownEnabled() = true
97             // Need to return the reverse value.
98             return !isEnabled;
99         }
100 
101         // If the BridgedAp Concurrency is not supported in early Pixel devices (e.g. Pixel 2~5),
102         // show toggle on when band is 2.4G only.
103         final int band = config.getBand();
104         Log.d(TAG, "getBand:" + band);
105         return band == SoftApConfiguration.BAND_2GHZ;
106     }
107 
108     /**
109      * Setup the Maximize Compatibility setting to the SoftAp Configuration
110      *
111      * @param builder The builder to build the SoftApConfiguration.
112      */
setupMaximizeCompatibility(SoftApConfiguration.Builder builder)113     public void setupMaximizeCompatibility(SoftApConfiguration.Builder builder) {
114         if (builder == null) {
115             return;
116         }
117         final boolean enabled = mIsChecked;
118         if (mWifiManager.isBridgedApConcurrencySupported()) {
119             int[] bands = {
120                     SoftApConfiguration.BAND_2GHZ,
121                     SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ};
122             builder.setBands(bands);
123             Log.d(TAG, "setBridgedModeOpportunisticShutdownEnabled:" + enabled);
124             // Because the defined value by the Wi-Fi framework API is opposite to the UI.
125             //   Compatibility on:  setBridgedModeOpportunisticShutdownEnabled(false)
126             //   Compatibility off: setBridgedModeOpportunisticShutdownEnabled(true)
127             // Need to set the reverse value.
128             builder.setBridgedModeOpportunisticShutdownEnabled(!enabled);
129         } else {
130             int band = enabled
131                     ? SoftApConfiguration.BAND_2GHZ
132                     : SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
133             Log.d(TAG, "setBand:" + band);
134             builder.setBand(band);
135         }
136     }
137 }
138