1 /* 2 * Copyright (C) 2018 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.network.telephony; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.net.NetworkTemplate; 22 import android.provider.Settings; 23 import android.telephony.SubscriptionManager; 24 import android.text.TextUtils; 25 import android.util.Log; 26 27 import androidx.preference.Preference; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.settings.R; 31 import com.android.settings.datausage.DataUsageUtils; 32 import com.android.settings.datausage.lib.DataUsageLib; 33 import com.android.settingslib.net.DataUsageController; 34 import com.android.settingslib.utils.ThreadUtils; 35 36 import java.util.concurrent.ExecutionException; 37 import java.util.concurrent.Future; 38 import java.util.concurrent.atomic.AtomicReference; 39 40 /** 41 * Preference controller for "Data usage" 42 */ 43 public class DataUsagePreferenceController extends TelephonyBasePreferenceController { 44 45 private static final String LOG_TAG = "DataUsagePreferCtrl"; 46 47 private Future<NetworkTemplate> mTemplateFuture; 48 private AtomicReference<NetworkTemplate> mTemplate; 49 private Future<Long> mHistoricalUsageLevel; 50 DataUsagePreferenceController(Context context, String key)51 public DataUsagePreferenceController(Context context, String key) { 52 super(context, key); 53 mTemplate = new AtomicReference<NetworkTemplate>(); 54 } 55 56 @Override getAvailabilityStatus(int subId)57 public int getAvailabilityStatus(int subId) { 58 return (SubscriptionManager.isValidSubscriptionId(subId)) 59 ? AVAILABLE 60 : AVAILABLE_UNSEARCHABLE; 61 } 62 63 @Override handlePreferenceTreeClick(Preference preference)64 public boolean handlePreferenceTreeClick(Preference preference) { 65 if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { 66 return false; 67 } 68 final Intent intent = new Intent(Settings.ACTION_MOBILE_DATA_USAGE); 69 intent.putExtra(Settings.EXTRA_NETWORK_TEMPLATE, getNetworkTemplate()); 70 intent.putExtra(Settings.EXTRA_SUB_ID, mSubId); 71 72 mContext.startActivity(intent); 73 return true; 74 } 75 76 @Override updateState(Preference preference)77 public void updateState(Preference preference) { 78 super.updateState(preference); 79 if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { 80 preference.setEnabled(false); 81 return; 82 } 83 final CharSequence summary = getDataUsageSummary(mContext, mSubId); 84 if (summary == null) { 85 preference.setEnabled(false); 86 } else { 87 preference.setEnabled(true); 88 preference.setSummary(summary); 89 } 90 } 91 init(int subId)92 public void init(int subId) { 93 mSubId = subId; 94 mTemplate.set(null); 95 mTemplateFuture = ThreadUtils.postOnBackgroundThread(() 96 -> fetchMobileTemplate(mContext, mSubId)); 97 } 98 fetchMobileTemplate(Context context, int subId)99 private NetworkTemplate fetchMobileTemplate(Context context, int subId) { 100 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 101 return null; 102 } 103 return DataUsageLib.getMobileTemplate(context, subId); 104 } 105 getNetworkTemplate()106 private NetworkTemplate getNetworkTemplate() { 107 if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { 108 return null; 109 } 110 NetworkTemplate template = mTemplate.get(); 111 if (template != null) { 112 return template; 113 } 114 try { 115 template = mTemplateFuture.get(); 116 mTemplate.set(template); 117 } catch (ExecutionException | InterruptedException | NullPointerException exception) { 118 Log.e(LOG_TAG, "Fail to get data usage template", exception); 119 } 120 return template; 121 } 122 123 @VisibleForTesting getDataUsageInfo(DataUsageController controller)124 DataUsageController.DataUsageInfo getDataUsageInfo(DataUsageController controller) { 125 return controller.getDataUsageInfo(getNetworkTemplate()); 126 } 127 getDataUsageSummary(Context context, int subId)128 private CharSequence getDataUsageSummary(Context context, int subId) { 129 final DataUsageController controller = new DataUsageController(context); 130 controller.setSubscriptionId(subId); 131 132 mHistoricalUsageLevel = ThreadUtils.postOnBackgroundThread(() -> 133 controller.getHistoricalUsageLevel(getNetworkTemplate())); 134 135 final DataUsageController.DataUsageInfo usageInfo = getDataUsageInfo(controller); 136 137 long usageLevel = usageInfo.usageLevel; 138 if (usageLevel <= 0L) { 139 try { 140 usageLevel = mHistoricalUsageLevel.get(); 141 } catch (Exception exception) { 142 } 143 } 144 if (usageLevel <= 0L) { 145 return null; 146 } 147 return context.getString(R.string.data_usage_template, 148 DataUsageUtils.formatDataUsage(context, usageLevel), usageInfo.period); 149 } 150 } 151