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_TOGGLE_STATE;
20 import static com.android.car.qc.QCItem.QC_TYPE_ACTION_SWITCH;
21 import static com.android.car.settings.qc.SettingsQCRegistry.HOTSPOT_ROW_URI;
22 
23 import android.content.Context;
24 import android.content.Intent;
25 import android.graphics.drawable.Icon;
26 import android.net.TetheringManager;
27 import android.net.Uri;
28 import android.net.wifi.SoftApConfiguration;
29 import android.net.wifi.WifiManager;
30 import android.text.TextUtils;
31 
32 import com.android.car.qc.QCActionItem;
33 import com.android.car.qc.QCItem;
34 import com.android.car.qc.QCList;
35 import com.android.car.qc.QCRow;
36 import com.android.car.settings.R;
37 
38 /**
39  * QCItem for showing a hotspot row element.
40  * The row contains an icon, the status, and a switch to enable/disable hotspot.
41  */
42 public class HotspotRow extends SettingsQCItem {
43     private final TetheringManager mTetheringManager;
44     private final WifiManager mWifiManager;
45     // Assume hotspot is available until notified otherwise.
46     private boolean mIsSupported = true;
47     private int mConnectedDevicesCount;
48 
HotspotRow(Context context)49     public HotspotRow(Context context) {
50         super(context);
51         mTetheringManager = context.getSystemService(TetheringManager.class);
52         mWifiManager = context.getSystemService(WifiManager.class);
53     }
54 
55     @Override
getQCItem()56     QCItem getQCItem() {
57         Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_qc_hotspot);
58 
59         QCActionItem hotpotToggle = new QCActionItem.Builder(QC_TYPE_ACTION_SWITCH)
60                 .setChecked(HotspotQCUtils.isHotspotEnabled(mWifiManager))
61                 .setEnabled(!HotspotQCUtils.isHotspotBusy(mWifiManager))
62                 .setAvailable(mIsSupported)
63                 .setAction(getBroadcastIntent())
64                 .build();
65 
66         QCRow hotspotRow = new QCRow.Builder()
67                 .setIcon(icon)
68                 .setTitle(getContext().getString(R.string.hotspot_settings_title))
69                 .setSubtitle(getSubtitle())
70                 .addEndItem(hotpotToggle)
71                 .build();
72 
73         return new QCList.Builder()
74                 .addRow(hotspotRow)
75                 .build();
76     }
77 
78     @Override
getUri()79     Uri getUri() {
80         return HOTSPOT_ROW_URI;
81     }
82 
getHotspotSupported()83     boolean getHotspotSupported() {
84         return mIsSupported;
85     }
86 
setHotspotSupported(boolean supported)87     void setHotspotSupported(boolean supported) {
88         mIsSupported = supported;
89     }
90 
setConnectedDevicesCount(int devicesCount)91     void setConnectedDevicesCount(int devicesCount) {
92         mConnectedDevicesCount = devicesCount;
93     }
94 
95     @Override
onNotifyChange(Intent intent)96     void onNotifyChange(Intent intent) {
97         boolean newState = intent.getBooleanExtra(QC_ACTION_TOGGLE_STATE,
98                 !mWifiManager.isWifiApEnabled());
99         if (newState) {
100             HotspotQCUtils.enableHotspot(mTetheringManager,
101                     HotspotQCUtils.getDefaultStartTetheringCallback(getContext(), getUri()));
102         } else {
103             HotspotQCUtils.disableHotspot(mTetheringManager);
104         }
105     }
106 
107     @Override
getBackgroundWorkerClass()108     Class getBackgroundWorkerClass() {
109         return HotspotRowWorker.class;
110     }
111 
112     /** Returns the subtitle to be shown for the hotspot quick controls item.
113      * There are three different states that can be shown:
114      * - If tethering is disabled, return the off string.
115      * - If tethering is enabled but no devices are connected, return the ssid + password string.
116      * - If tethering is enabled and devices are connected, return the devices connected string.
117      */
getSubtitle()118     private String getSubtitle() {
119         if (!HotspotQCUtils.isHotspotEnabled(mWifiManager)) {
120             return getContext().getString(R.string.wifi_hotspot_state_off);
121         }
122         if (mConnectedDevicesCount > 0) {
123             return getContext().getResources().getQuantityString(
124                     R.plurals.wifi_tether_connected_summary, mConnectedDevicesCount,
125                     mConnectedDevicesCount);
126         }
127         String subtitle = getHotspotSSID();
128         if (TextUtils.isEmpty(subtitle)) {
129             // If there currently is no SSID to show, use a default "On" string
130             return getContext().getString(R.string.car_ui_preference_switch_on);
131         }
132         String password = getHotspotPassword();
133         if (!TextUtils.isEmpty(password)) {
134             subtitle += " / " + password;
135         }
136         return subtitle;
137     }
138 
getHotspotSSID()139     private String getHotspotSSID() {
140         return mWifiManager.getSoftApConfiguration().getSsid();
141     }
142 
getHotspotPassword()143     private String getHotspotPassword() {
144         int securityType = mWifiManager.getSoftApConfiguration().getSecurityType();
145         if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
146             return null;
147         }
148         return mWifiManager.getSoftApConfiguration().getPassphrase();
149     }
150 }
151