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.QCUtils.getActionDisabledDialogIntent;
22 import static com.android.car.settings.qc.QCUtils.getAvailabilityStatusForZoneFromXml;
23 import static com.android.car.settings.qc.SettingsQCRegistry.HOTSPOT_ROW_URI;
24 
25 import android.app.PendingIntent;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.graphics.drawable.Icon;
29 import android.net.TetheringManager;
30 import android.net.Uri;
31 import android.net.wifi.WifiManager;
32 import android.os.UserManager;
33 
34 import androidx.annotation.Nullable;
35 
36 import com.android.car.qc.QCActionItem;
37 import com.android.car.qc.QCItem;
38 import com.android.car.qc.QCList;
39 import com.android.car.qc.QCRow;
40 import com.android.car.settings.R;
41 import com.android.car.settings.enterprise.EnterpriseUtils;
42 import com.android.car.settings.wifi.WifiTetherUtil;
43 
44 /**
45  * QCItem for showing a hotspot row element.
46  * The row contains an icon, the status, and a switch to enable/disable hotspot.
47  */
48 public class HotspotRow extends SettingsQCItem {
49     private final TetheringManager mTetheringManager;
50     private final WifiManager mWifiManager;
51     // Assume hotspot is available until notified otherwise.
52     private boolean mIsSupported = true;
53     private int mConnectedDevicesCount;
54 
HotspotRow(Context context)55     public HotspotRow(Context context) {
56         super(context);
57         setAvailabilityStatusForZone(getAvailabilityStatusForZoneFromXml(context,
58                 R.xml.network_and_internet_fragment, R.string.pk_wifi_tether_settings_entry));
59         mTetheringManager = context.getSystemService(TetheringManager.class);
60         mWifiManager = context.getSystemService(WifiManager.class);
61     }
62 
63     @Override
getQCItem()64     QCItem getQCItem() {
65         if (isHiddenForZone()) {
66             return null;
67         }
68         Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_qc_hotspot);
69 
70         String userRestriction = UserManager.DISALLOW_CONFIG_TETHERING;
71         boolean hasDpmRestrictions = EnterpriseUtils.hasUserRestrictionByDpm(getContext(),
72                 userRestriction);
73         boolean hasUmRestrictions = EnterpriseUtils.hasUserRestrictionByUm(getContext(),
74                 userRestriction);
75 
76         boolean isReadOnlyForZone = isReadOnlyForZone();
77         PendingIntent disabledPendingIntent = isReadOnlyForZone
78                 ? QCUtils.getDisabledToastBroadcastIntent(getContext())
79                 : getActionDisabledDialogIntent(getContext(), userRestriction);
80 
81         QCActionItem hotpotToggle = new QCActionItem.Builder(QC_TYPE_ACTION_SWITCH)
82                 .setChecked(HotspotQCUtils.isHotspotEnabled(mWifiManager))
83                 .setEnabled(!HotspotQCUtils.isHotspotBusy(mWifiManager) && !hasUmRestrictions
84                         && !hasDpmRestrictions && isWritableForZone())
85                 .setAvailable(mIsSupported)
86                 .setAction(getBroadcastIntent())
87                 .setClickableWhileDisabled(hasDpmRestrictions || isReadOnlyForZone)
88                 .setDisabledClickAction(disabledPendingIntent)
89                 .setContentDescription(getContext(), R.string.hotspot_settings_title)
90                 .build();
91 
92         QCRow hotspotRow = new QCRow.Builder()
93                 .setIcon(icon)
94                 .setTitle(getContext().getString(R.string.hotspot_settings_title))
95                 .setSubtitle(getSubtitle())
96                 .addEndItem(hotpotToggle)
97                 .setPrimaryAction(getPrimaryAction())
98                 .build();
99 
100         return new QCList.Builder()
101                 .addRow(hotspotRow)
102                 .build();
103     }
104 
105     @Override
getUri()106     Uri getUri() {
107         return HOTSPOT_ROW_URI;
108     }
109 
getHotspotSupported()110     boolean getHotspotSupported() {
111         return mIsSupported;
112     }
113 
setHotspotSupported(boolean supported)114     void setHotspotSupported(boolean supported) {
115         mIsSupported = supported;
116     }
117 
setConnectedDevicesCount(int devicesCount)118     void setConnectedDevicesCount(int devicesCount) {
119         mConnectedDevicesCount = devicesCount;
120     }
121 
122     @Override
onNotifyChange(Intent intent)123     void onNotifyChange(Intent intent) {
124         boolean newState = intent.getBooleanExtra(QC_ACTION_TOGGLE_STATE,
125                 !mWifiManager.isWifiApEnabled());
126         if (newState) {
127             WifiTetherUtil.startTethering(mTetheringManager,
128                     HotspotQCUtils.getDefaultStartTetheringCallback(getContext(), getUri()));
129         } else {
130             WifiTetherUtil.stopTethering(mTetheringManager);
131         }
132     }
133 
134     @Override
getBackgroundWorkerClass()135     Class getBackgroundWorkerClass() {
136         return HotspotRowWorker.class;
137     }
138 
getSubtitle()139     private String getSubtitle() {
140         // Early exit in case Wi-Fi is not ready, otherwise it may cause an ANR.
141         if (!HotspotQCUtils.isHotspotEnabled(mWifiManager)) {
142             return getContext().getString(R.string.wifi_hotspot_state_off);
143         }
144         return WifiTetherUtil.getHotspotSubtitle(getContext(),
145                 mWifiManager.getSoftApConfiguration(),
146                 HotspotQCUtils.isHotspotEnabled(mWifiManager), mConnectedDevicesCount);
147     }
148 
149     @Nullable
getPrimaryAction()150     protected PendingIntent getPrimaryAction() {
151         return null;
152     }
153 }
154