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.datasubscription.DataSubscription.DATA_SUBSCRIPTION_ACTION;
20 import static com.android.car.qc.QCItem.QC_ACTION_TOGGLE_STATE;
21 import static com.android.car.qc.QCItem.QC_TYPE_ACTION_SWITCH;
22 import static com.android.car.settings.qc.QCUtils.getActionDisabledDialogIntent;
23 import static com.android.car.settings.qc.QCUtils.getAvailabilityStatusForZoneFromXml;
24 import static com.android.car.settings.qc.SettingsQCRegistry.MOBILE_DATA_ROW_URI;
25 
26 import android.app.PendingIntent;
27 import android.car.drivingstate.CarUxRestrictions;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.graphics.drawable.Icon;
31 import android.net.Uri;
32 import android.os.UserManager;
33 
34 import androidx.annotation.VisibleForTesting;
35 
36 import com.android.car.datasubscription.DataSubscription;
37 import com.android.car.qc.QCActionItem;
38 import com.android.car.qc.QCCategory;
39 import com.android.car.qc.QCItem;
40 import com.android.car.qc.QCList;
41 import com.android.car.qc.QCRow;
42 import com.android.car.settings.R;
43 import com.android.car.settings.enterprise.EnterpriseUtils;
44 import com.android.settingslib.net.DataUsageController;
45 
46 /**
47  * QCItem for showing a mobile data row element.
48  * The row contains a data icon, the current default network name, and a switch
49  * to enable/disable mobile data.
50  */
51 public class MobileDataRow extends SettingsQCItem {
52     private final DataUsageController mDataUsageController;
53     private boolean mIsDistractionOptimizationRequired;
54     private DataSubscription mSubscription;
55 
MobileDataRow(Context context)56     public MobileDataRow(Context context) {
57         super(context);
58         setAvailabilityStatusForZone(getAvailabilityStatusForZoneFromXml(context,
59                 R.xml.network_and_internet_fragment, R.string.pk_mobile_network_settings_entry));
60         mDataUsageController = getDataUsageController(context);
61         mSubscription = new DataSubscription(context);
62     }
63     @Override
getQCItem()64     QCItem getQCItem() {
65         if (isHiddenForZone()) {
66             return null;
67         }
68         if (!isDataSubscriptionFlagEnable() && !mDataUsageController.isMobileDataSupported()) {
69             return null;
70         }
71         boolean dataEnabled = mDataUsageController.isMobileDataEnabled();
72         Icon icon = MobileNetworkQCUtils.getMobileNetworkSignalIcon(getContext());
73 
74         String userRestriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
75         boolean hasDpmRestrictions = EnterpriseUtils.hasUserRestrictionByDpm(getContext(),
76                 userRestriction);
77         boolean hasUmRestrictions = EnterpriseUtils.hasUserRestrictionByUm(getContext(),
78                 userRestriction);
79 
80         boolean isReadOnlyForZone = isReadOnlyForZone();
81         PendingIntent disabledPendingIntent = isReadOnlyForZone
82                 ? QCUtils.getDisabledToastBroadcastIntent(getContext())
83                 : getActionDisabledDialogIntent(getContext(), userRestriction);
84 
85         QCActionItem dataToggle = new QCActionItem.Builder(QC_TYPE_ACTION_SWITCH)
86                 .setChecked(dataEnabled)
87                 .setAction(getBroadcastIntent())
88                 .setEnabled(!hasUmRestrictions && !hasDpmRestrictions && isWritableForZone())
89                 .setClickableWhileDisabled(hasDpmRestrictions || isReadOnlyForZone)
90                 .setDisabledClickAction(disabledPendingIntent)
91                 .setContentDescription(getContext(), R.string.mobile_network_toggle_title)
92                 .build();
93 
94         QCRow dataRow = new QCRow.Builder()
95                 .setTitle(getContext().getString(R.string.mobile_network_settings))
96                 .setSubtitle(getSubtitle(dataEnabled))
97                 .setCategory(getCategory())
98                 .setActionText(getActionText(dataEnabled))
99                 .setIcon(icon)
100                 .setPrimaryAction(getPrimaryAction())
101                 .addEndItem(dataToggle)
102                 .build();
103 
104         return new QCList.Builder()
105                 .addRow(dataRow)
106                 .build();
107     }
108 
109     @Override
getUri()110     Uri getUri() {
111         return MOBILE_DATA_ROW_URI;
112     }
113 
114     @Override
onNotifyChange(Intent intent)115     void onNotifyChange(Intent intent) {
116         boolean newState = intent.getBooleanExtra(QC_ACTION_TOGGLE_STATE,
117                 !mDataUsageController.isMobileDataEnabled());
118         mDataUsageController.setMobileDataEnabled(newState);
119     }
120 
121     @Override
getBackgroundWorkerClass()122     Class getBackgroundWorkerClass() {
123         return MobileDataRowWorker.class;
124     }
125 
126     @VisibleForTesting
getDataUsageController(Context context)127     DataUsageController getDataUsageController(Context context) {
128         return new DataUsageController(context);
129     }
130 
getSubtitle(boolean dataEnabled)131     String getSubtitle(boolean dataEnabled) {
132         if (isDataSubscriptionFlagEnable()
133                 && dataEnabled
134                 && mSubscription.isDataSubscriptionInactive()) {
135             return getContext().getString(
136                     R.string.connectivity_inactive_prompt);
137         }
138         return MobileNetworkQCUtils.getMobileNetworkSummary(
139                 getContext(), dataEnabled);
140     }
141 
getActionText(boolean dataEnabled)142     String getActionText(boolean dataEnabled) {
143         if (isDataSubscriptionFlagEnable()
144                 && dataEnabled
145                 && mSubscription.isDataSubscriptionInactive()
146                 && !mIsDistractionOptimizationRequired) {
147             return getContext().getString(
148                     R.string.connectivity_inactive_action_text);
149         }
150         return "";
151     }
152 
getCategory()153     int getCategory() {
154         if (isDataSubscriptionFlagEnable()
155                 && mSubscription.isDataSubscriptionInactive()) {
156             return QCCategory.WARNING;
157         }
158         return QCCategory.NORMAL;
159     }
160 
setIsDistractionOptimizationRequired(CarUxRestrictions carUxRestrictions)161     void setIsDistractionOptimizationRequired(CarUxRestrictions carUxRestrictions) {
162         if (carUxRestrictions == null) {
163             mIsDistractionOptimizationRequired = false;
164         } else {
165             mIsDistractionOptimizationRequired = carUxRestrictions
166                     .isRequiresDistractionOptimization();
167         }
168     }
169 
setCarUxRestrictions(CarUxRestrictions carUxRestrictions)170     void setCarUxRestrictions(CarUxRestrictions carUxRestrictions) {
171         setIsDistractionOptimizationRequired(carUxRestrictions);
172     }
173 
getPrimaryAction()174     PendingIntent getPrimaryAction() {
175         if (!isDataSubscriptionFlagEnable()) {
176             return null;
177         }
178         if (!mSubscription.isDataSubscriptionInactive()
179                 || mIsDistractionOptimizationRequired) {
180             return null;
181         }
182         Intent dataSubscriptionIntent = new Intent(DATA_SUBSCRIPTION_ACTION);
183         dataSubscriptionIntent.setPackage(getContext().getString(
184                         R.string.connectivity_flow_app));
185         dataSubscriptionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
186         PendingIntent intent = PendingIntent.getActivity(getContext(), /* requestCode= */ 0,
187                 dataSubscriptionIntent, PendingIntent.FLAG_IMMUTABLE, null);
188         return intent;
189     }
190 
isDataSubscriptionFlagEnable()191     private boolean isDataSubscriptionFlagEnable() {
192         return com.android.car.datasubscription.Flags.dataSubscriptionPopUp();
193     }
194 
195     @VisibleForTesting
setSubscription(DataSubscription dataSubscription)196     public void setSubscription(DataSubscription dataSubscription) {
197         mSubscription = dataSubscription;
198     }
199 }
200