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.datausage;
18 
19 import android.content.Context;
20 import android.net.NetworkPolicyManager;
21 import android.net.NetworkTemplate;
22 import android.os.Bundle;
23 import android.telephony.SubscriptionManager;
24 import android.telephony.TelephonyManager;
25 
26 import androidx.annotation.StringRes;
27 import androidx.annotation.VisibleForTesting;
28 import androidx.annotation.XmlRes;
29 
30 import com.android.car.settings.R;
31 import com.android.car.settings.common.SettingsFragment;
32 import com.android.car.ui.toolbar.MenuItem;
33 import com.android.settingslib.NetworkPolicyEditor;
34 
35 import java.util.Collections;
36 import java.util.List;
37 
38 /** Screen used to pick the data usage warning threshold bytes. */
39 public abstract class DataUsageSetThresholdBaseFragment extends SettingsFragment {
40 
41     @VisibleForTesting
42     static final long MIB_IN_BYTES = 1024 * 1024;
43     @VisibleForTesting
44     static final long GIB_IN_BYTES = MIB_IN_BYTES * 1024;
45     @VisibleForTesting
46     static final long MAX_DATA_LIMIT_BYTES = 50000 * GIB_IN_BYTES;
47     @VisibleForTesting
48     static final float MB_GB_SUFFIX_THRESHOLD = 1.5f;
49 
50     @VisibleForTesting
51     DataUsageUnitPreferenceController mDataWarningUnitsPreferenceController;
52     @VisibleForTesting
53     DataUsageEditTextPreferenceController mDataUsageEditTextPreferenceController;
54     @VisibleForTesting
55     NetworkPolicyEditor mPolicyEditor;
56     @VisibleForTesting
57     NetworkTemplate mNetworkTemplate;
58 
59     private MenuItem mSaveButton;
60     private TelephonyManager mTelephonyManager;
61     private SubscriptionManager mSubscriptionManager;
62 
63     @Override
64     @XmlRes
getPreferenceScreenResId()65     protected int getPreferenceScreenResId() {
66         return R.xml.data_usage_set_threshold_fragment;
67     }
68 
69     @Override
getToolbarMenuItems()70     protected List<MenuItem> getToolbarMenuItems() {
71         return Collections.singletonList(mSaveButton);
72     }
73 
74     @Override
onAttach(Context context)75     public void onAttach(Context context) {
76         super.onAttach(context);
77 
78         if (mPolicyEditor == null) {
79             mPolicyEditor = new NetworkPolicyEditor(NetworkPolicyManager.from(context));
80 
81             // Loads the current policies to the policy editor cache.
82             mPolicyEditor.read();
83         }
84         mNetworkTemplate = getArguments().getParcelable(
85                 NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE);
86         if (mNetworkTemplate == null) {
87             mTelephonyManager = context.getSystemService(TelephonyManager.class);
88             mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
89             mNetworkTemplate = DataUsageUtils.getMobileNetworkTemplate(mTelephonyManager,
90                     DataUsageUtils.getDefaultSubscriptionId(mSubscriptionManager));
91         }
92 
93         mSaveButton = new MenuItem.Builder(context)
94                 .setTitle(R.string.data_usage_warning_save_title)
95                 .setOnClickListener(i -> {
96                     onSaveClicked();
97                 })
98                 .build();
99 
100         mDataUsageEditTextPreferenceController = use(
101                 DataUsageEditTextPreferenceController.class,
102                 R.string.pk_data_usage_edit_text);
103         mDataWarningUnitsPreferenceController = use(DataUsageUnitPreferenceController.class,
104                 R.string.pk_data_usage_radio_group);
105 
106         long currentWarningBytes = getInitialBytes();
107         String bytesText;
108         if (currentWarningBytes > MB_GB_SUFFIX_THRESHOLD * GIB_IN_BYTES) {
109             mDataWarningUnitsPreferenceController.setDefaultSelection(/* isGb= */ true);
110             bytesText = formatText(currentWarningBytes / (float) GIB_IN_BYTES);
111         } else {
112             mDataWarningUnitsPreferenceController.setDefaultSelection(/* isGb= */ false);
113             bytesText = formatText(currentWarningBytes / (float) MIB_IN_BYTES);
114         }
115 
116         mDataUsageEditTextPreferenceController.setDefaultText(bytesText);
117     }
118 
119     @Override
onCreate(Bundle savedInstanceState)120     public void onCreate(Bundle savedInstanceState) {
121         super.onCreate(savedInstanceState);
122 
123         getPreferenceScreen().setTitle(getTitleResId());
124     }
125 
126     @VisibleForTesting
onSaveClicked()127     void onSaveClicked() {
128         onSave(getCurrentThreshold());
129         goBack();
130     }
131 
132     @VisibleForTesting
getCurrentThreshold()133     long getCurrentThreshold() {
134         String bytesString = mDataUsageEditTextPreferenceController.getText();
135         if (bytesString.isEmpty() || bytesString.equals(".")) {
136             bytesString = "0";
137         }
138 
139         long bytes = (long) (Float.parseFloat(bytesString)
140                 * (mDataWarningUnitsPreferenceController.isGbSelected()
141                 ? GIB_IN_BYTES : MIB_IN_BYTES));
142 
143         // To fix the overflow problem.
144         return Math.min(MAX_DATA_LIMIT_BYTES, bytes);
145     }
146 
formatText(float v)147     private String formatText(float v) {
148         v = Math.round(v * 100) / 100f;
149         return String.valueOf(v);
150     }
151 
152     /**
153      * Callback when save button is clicked
154      *
155      * @param threshold number of bytes set
156      */
157     @VisibleForTesting
onSave(long threshold)158     abstract void onSave(long threshold);
159 
160     /** Returns the screen title res id */
161     @StringRes
getTitleResId()162     protected abstract int getTitleResId();
163 
164     /** Returns the initial bytes to be displayed */
getInitialBytes()165     protected abstract long getInitialBytes();
166 }
167