blob: 45793b130b08e362b6afcbcfe16eacef948fb2d4 [file] [log] [blame]
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001/*
2 * Copyright (C) 2011 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
17package com.android.settings;
18
Jeff Sharkey9549e9f2011-07-14 20:01:13 -070019import static android.net.ConnectivityManager.TYPE_ETHERNET;
Jeff Sharkey29d56b32011-06-20 17:06:52 -070020import static android.net.ConnectivityManager.TYPE_MOBILE;
21import static android.net.ConnectivityManager.TYPE_WIMAX;
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -070022import static android.net.NetworkPolicy.LIMIT_DISABLED;
Jeff Sharkeydd6efe12011-06-15 10:31:41 -070023import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -070024import static android.net.NetworkPolicyManager.POLICY_NONE;
25import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
Jeff Sharkey8a503642011-06-10 13:31:21 -070026import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
27import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
Jeff Sharkey1ae43f92011-08-03 17:16:09 -070028import static android.net.NetworkStats.TAG_NONE;
29import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
30import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
Jeff Sharkeya662e492011-06-18 21:57:06 -070031import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
32import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
33import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
34import static android.net.NetworkTemplate.MATCH_WIFI;
Jeff Sharkey9549e9f2011-07-14 20:01:13 -070035import static android.net.NetworkTemplate.buildTemplateEthernet;
36import static android.net.NetworkTemplate.buildTemplateMobile3gLower;
37import static android.net.NetworkTemplate.buildTemplateMobile4g;
38import static android.net.NetworkTemplate.buildTemplateMobileAll;
39import static android.net.NetworkTemplate.buildTemplateWifi;
Jeff Sharkey29d56b32011-06-20 17:06:52 -070040import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070041
Jeff Sharkeyf54f4352011-06-23 22:15:54 -070042import android.animation.LayoutTransition;
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070043import android.app.AlertDialog;
44import android.app.Dialog;
45import android.app.DialogFragment;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070046import android.app.Fragment;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -070047import android.app.FragmentTransaction;
Jeff Sharkey398b18f2011-07-10 18:56:30 -070048import android.app.LoaderManager.LoaderCallbacks;
Jeff Sharkey9fab0da2011-07-09 17:52:31 -070049import android.content.ContentResolver;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070050import android.content.Context;
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070051import android.content.DialogInterface;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070052import android.content.Intent;
Jeff Sharkey398b18f2011-07-10 18:56:30 -070053import android.content.Loader;
Jeff Sharkey29d56b32011-06-20 17:06:52 -070054import android.content.SharedPreferences;
Jeff Sharkey8e911d72011-06-14 22:41:21 -070055import android.content.pm.ApplicationInfo;
56import android.content.pm.PackageInfo;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070057import android.content.pm.PackageManager;
Jeff Sharkey8e911d72011-06-14 22:41:21 -070058import android.content.pm.PackageManager.NameNotFoundException;
Jeff Sharkey518bc9d2011-07-12 20:20:46 -070059import android.content.res.Resources;
Jeff Sharkey29d56b32011-06-20 17:06:52 -070060import android.net.ConnectivityManager;
Jeff Sharkey8a503642011-06-10 13:31:21 -070061import android.net.INetworkPolicyManager;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070062import android.net.INetworkStatsService;
Jeff Sharkey8a503642011-06-10 13:31:21 -070063import android.net.NetworkPolicy;
Jeff Sharkeydd6efe12011-06-15 10:31:41 -070064import android.net.NetworkPolicyManager;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070065import android.net.NetworkStats;
66import android.net.NetworkStatsHistory;
Jeff Sharkeya662e492011-06-18 21:57:06 -070067import android.net.NetworkTemplate;
Jeff Sharkey518bc9d2011-07-12 20:20:46 -070068import android.net.TrafficStats;
Jeff Sharkeyaa5260e2011-06-14 23:21:59 -070069import android.os.AsyncTask;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070070import android.os.Bundle;
Jeff Sharkey1ae43f92011-08-03 17:16:09 -070071import android.os.INetworkManagementService;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070072import android.os.RemoteException;
73import android.os.ServiceManager;
Jeff Sharkey9549e9f2011-07-14 20:01:13 -070074import android.os.SystemProperties;
Jeff Sharkey8a503642011-06-10 13:31:21 -070075import android.preference.Preference;
Jeff Sharkey9fab0da2011-07-09 17:52:31 -070076import android.provider.Settings;
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -070077import android.telephony.TelephonyManager;
Jeff Sharkey8e911d72011-06-14 22:41:21 -070078import android.text.TextUtils;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070079import android.text.format.DateUtils;
80import android.text.format.Formatter;
Jeff Sharkey8a503642011-06-10 13:31:21 -070081import android.text.format.Time;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070082import android.util.Log;
83import android.view.LayoutInflater;
Jeff Sharkey8a503642011-06-10 13:31:21 -070084import android.view.Menu;
85import android.view.MenuInflater;
86import android.view.MenuItem;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070087import android.view.View;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -070088import android.view.View.OnClickListener;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070089import android.view.ViewGroup;
Jeff Sharkey2af35fb2011-06-24 17:30:27 -070090import android.view.ViewTreeObserver.OnGlobalLayoutListener;
Jeff Sharkey8a503642011-06-10 13:31:21 -070091import android.widget.AdapterView;
92import android.widget.AdapterView.OnItemClickListener;
93import android.widget.AdapterView.OnItemSelectedListener;
94import android.widget.ArrayAdapter;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -070095import android.widget.BaseAdapter;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -070096import android.widget.Button;
Jeff Sharkey29d56b32011-06-20 17:06:52 -070097import android.widget.CheckBox;
98import android.widget.CompoundButton;
99import android.widget.CompoundButton.OnCheckedChangeListener;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700100import android.widget.LinearLayout;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700101import android.widget.ListView;
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700102import android.widget.NumberPicker;
Jeff Sharkey2412b0f2011-07-17 20:31:40 -0700103import android.widget.ProgressBar;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700104import android.widget.Spinner;
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700105import android.widget.Switch;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700106import android.widget.TabHost;
107import android.widget.TabHost.OnTabChangeListener;
108import android.widget.TabHost.TabContentFactory;
109import android.widget.TabHost.TabSpec;
110import android.widget.TabWidget;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700111import android.widget.TextView;
112
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700113import com.android.internal.telephony.Phone;
Jeff Sharkeya662e492011-06-18 21:57:06 -0700114import com.android.settings.net.NetworkPolicyEditor;
Jeff Sharkey398b18f2011-07-10 18:56:30 -0700115import com.android.settings.net.SummaryForAllUidLoader;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700116import com.android.settings.widget.DataUsageChartView;
117import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700118import com.google.android.collect.Lists;
119
120import java.util.ArrayList;
121import java.util.Collections;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700122import java.util.Locale;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700123
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700124import libcore.util.Objects;
125
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700126/**
127 * Panel show data usage history across various networks, including options to
128 * inspect based on usage cycle and control through {@link NetworkPolicy}.
129 */
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700130public class DataUsageSummary extends Fragment {
131 private static final String TAG = "DataUsage";
Jeff Sharkey8a503642011-06-10 13:31:21 -0700132 private static final boolean LOGD = true;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700133
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700134 // TODO: remove this testing code
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700135 private static final boolean TEST_ANIM = false;
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700136 private static final boolean TEST_RADIOS = false;
137 private static final String TEST_RADIOS_PROP = "test.radios";
138
Jeff Sharkey8a503642011-06-10 13:31:21 -0700139 private static final String TAB_3G = "3g";
140 private static final String TAB_4G = "4g";
141 private static final String TAB_MOBILE = "mobile";
142 private static final String TAB_WIFI = "wifi";
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700143 private static final String TAB_ETHERNET = "ethernet";
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700144
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700145 private static final String TAG_CONFIRM_ROAMING = "confirmRoaming";
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700146 private static final String TAG_CONFIRM_LIMIT = "confirmLimit";
147 private static final String TAG_CYCLE_EDITOR = "cycleEditor";
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700148 private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700149 private static final String TAG_CONFIRM_APP_RESTRICT = "confirmAppRestrict";
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700150 private static final String TAG_APP_DETAILS = "appDetails";
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700151
Jeff Sharkey398b18f2011-07-10 18:56:30 -0700152 private static final int LOADER_SUMMARY = 2;
153
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700154 private static final long KB_IN_BYTES = 1024;
155 private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
156 private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
157
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700158 private INetworkManagementService mNetworkService;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700159 private INetworkStatsService mStatsService;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700160 private INetworkPolicyManager mPolicyService;
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700161 private ConnectivityManager mConnService;
162
163 private static final String PREF_FILE = "data_usage";
164 private static final String PREF_SHOW_WIFI = "show_wifi";
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700165 private static final String PREF_SHOW_ETHERNET = "show_ethernet";
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700166
167 private SharedPreferences mPrefs;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700168
Jeff Sharkey8a503642011-06-10 13:31:21 -0700169 private TabHost mTabHost;
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700170 private ViewGroup mTabsContainer;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700171 private TabWidget mTabWidget;
172 private ListView mListView;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700173 private DataUsageAdapter mAdapter;
174
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700175 private ViewGroup mHeader;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700176
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700177 private ViewGroup mNetworkSwitchesContainer;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700178 private LinearLayout mNetworkSwitches;
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700179 private Switch mDataEnabled;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700180 private View mDataEnabledView;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700181 private CheckBox mDisableAtLimit;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700182 private View mDisableAtLimitView;
183
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700184 private View mCycleView;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700185 private Spinner mCycleSpinner;
186 private CycleAdapter mCycleAdapter;
187
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700188 private DataUsageChartView mChart;
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700189 private TextView mUsageSummary;
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -0700190 private TextView mEmpty;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700191
192 private View mAppDetail;
193 private TextView mAppTitle;
194 private TextView mAppSubtitle;
195 private Button mAppSettings;
196
197 private LinearLayout mAppSwitches;
198 private CheckBox mAppRestrict;
199 private View mAppRestrictView;
200
Jeff Sharkey8a503642011-06-10 13:31:21 -0700201 private boolean mShowWifi = false;
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700202 private boolean mShowEthernet = false;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700203
Jeff Sharkeya662e492011-06-18 21:57:06 -0700204 private NetworkTemplate mTemplate = null;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700205
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700206 private static final int UID_NONE = -1;
207 private int mUid = UID_NONE;
208
209 private Intent mAppSettingsIntent;
210
Jeff Sharkeya662e492011-06-18 21:57:06 -0700211 private NetworkPolicyEditor mPolicyEditor;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700212
Jeff Sharkey8a503642011-06-10 13:31:21 -0700213 private NetworkStatsHistory mHistory;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700214 private NetworkStatsHistory mDetailHistory;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700215
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700216 private String mCurrentTab = null;
Jeff Sharkeydd6efe12011-06-15 10:31:41 -0700217 private String mIntentTab = null;
218
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700219 private MenuItem mMenuDataRoaming;
220 private MenuItem mMenuRestrictBackground;
221
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700222 /** Flag used to ignore listeners during binding. */
223 private boolean mBinding;
224
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700225 @Override
Jeff Sharkey8a503642011-06-10 13:31:21 -0700226 public void onCreate(Bundle savedInstanceState) {
227 super.onCreate(savedInstanceState);
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700228
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700229 mNetworkService = INetworkManagementService.Stub.asInterface(
230 ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700231 mStatsService = INetworkStatsService.Stub.asInterface(
232 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
Jeff Sharkey8a503642011-06-10 13:31:21 -0700233 mPolicyService = INetworkPolicyManager.Stub.asInterface(
234 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700235 mConnService = (ConnectivityManager) getActivity().getSystemService(
236 Context.CONNECTIVITY_SERVICE);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700237
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700238 mPrefs = getActivity().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700239
Jeff Sharkeya662e492011-06-18 21:57:06 -0700240 mPolicyEditor = new NetworkPolicyEditor(mPolicyService);
241 mPolicyEditor.read();
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700242
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700243 mShowWifi = mPrefs.getBoolean(PREF_SHOW_WIFI, false);
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700244 mShowEthernet = mPrefs.getBoolean(PREF_SHOW_ETHERNET, false);
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700245
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700246 setHasOptionsMenu(true);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700247 }
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700248
Jeff Sharkey8a503642011-06-10 13:31:21 -0700249 @Override
250 public View onCreateView(LayoutInflater inflater, ViewGroup container,
251 Bundle savedInstanceState) {
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700252
Jeff Sharkey8a503642011-06-10 13:31:21 -0700253 final Context context = inflater.getContext();
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700254 final View view = inflater.inflate(R.layout.data_usage_summary, container, false);
255
Jeff Sharkey8a503642011-06-10 13:31:21 -0700256 mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700257 mTabsContainer = (ViewGroup) view.findViewById(R.id.tabs_container);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700258 mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs);
259 mListView = (ListView) view.findViewById(android.R.id.list);
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700260
Jeff Sharkey8a503642011-06-10 13:31:21 -0700261 mTabHost.setup();
262 mTabHost.setOnTabChangedListener(mTabListener);
263
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700264 mHeader = (ViewGroup) inflater.inflate(R.layout.data_usage_header, mListView, false);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700265 mListView.addHeaderView(mHeader, null, false);
266
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700267 {
268 // bind network switches
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700269 mNetworkSwitchesContainer = (ViewGroup) mHeader.findViewById(
270 R.id.network_switches_container);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700271 mNetworkSwitches = (LinearLayout) mHeader.findViewById(R.id.network_switches);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700272
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700273 mDataEnabled = new Switch(inflater.getContext());
274 mDataEnabledView = inflatePreference(inflater, mNetworkSwitches, mDataEnabled);
275 mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener);
276 mNetworkSwitches.addView(mDataEnabledView);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700277
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700278 mDisableAtLimit = new CheckBox(inflater.getContext());
279 mDisableAtLimit.setClickable(false);
280 mDisableAtLimitView = inflatePreference(inflater, mNetworkSwitches, mDisableAtLimit);
281 mDisableAtLimitView.setOnClickListener(mDisableAtLimitListener);
282 mNetworkSwitches.addView(mDisableAtLimitView);
283 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700284
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700285 // bind cycle dropdown
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700286 mCycleView = mHeader.findViewById(R.id.cycles);
287 mCycleSpinner = (Spinner) mCycleView.findViewById(R.id.cycles_spinner);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700288 mCycleAdapter = new CycleAdapter(context);
289 mCycleSpinner.setAdapter(mCycleAdapter);
290 mCycleSpinner.setOnItemSelectedListener(mCycleListener);
291
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700292 mChart = (DataUsageChartView) mHeader.findViewById(R.id.chart);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700293 mChart.setListener(mChartListener);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700294
295 {
296 // bind app detail controls
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700297 mAppDetail = mHeader.findViewById(R.id.app_detail);
298 mAppTitle = (TextView) mAppDetail.findViewById(R.id.app_title);
299 mAppSubtitle = (TextView) mAppDetail.findViewById(R.id.app_subtitle);
300 mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700301
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700302 mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700303 mAppSettings.setOnClickListener(mAppSettingsListener);
304
305 mAppRestrict = new CheckBox(inflater.getContext());
306 mAppRestrict.setClickable(false);
307 mAppRestrictView = inflatePreference(inflater, mAppSwitches, mAppRestrict);
308 setPreferenceTitle(mAppRestrictView, R.string.data_usage_app_restrict_background);
309 setPreferenceSummary(
310 mAppRestrictView, R.string.data_usage_app_restrict_background_summary);
311 mAppRestrictView.setOnClickListener(mAppRestrictListener);
312 mAppSwitches.addView(mAppRestrictView);
313 }
314
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700315 mUsageSummary = (TextView) mHeader.findViewById(R.id.usage_summary);
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -0700316 mEmpty = (TextView) mHeader.findViewById(android.R.id.empty);
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700317
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700318 // only assign layout transitions once first layout is finished
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700319 mListView.getViewTreeObserver().addOnGlobalLayoutListener(mFirstLayoutListener);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700320
321 mAdapter = new DataUsageAdapter();
322 mListView.setOnItemClickListener(mListListener);
323 mListView.setAdapter(mAdapter);
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700324
325 return view;
326 }
327
328 @Override
329 public void onResume() {
330 super.onResume();
331
Jeff Sharkeydd6efe12011-06-15 10:31:41 -0700332 // pick default tab based on incoming intent
333 final Intent intent = getActivity().getIntent();
334 mIntentTab = computeTabFromIntent(intent);
335
Jeff Sharkey8a503642011-06-10 13:31:21 -0700336 // this kicks off chain reaction which creates tabs, binds the body to
337 // selected network, and binds chart, cycles and detail list.
338 updateTabs();
Jeff Sharkeydd6efe12011-06-15 10:31:41 -0700339
Jeff Sharkey398b18f2011-07-10 18:56:30 -0700340 // kick off background task to update stats
341 new AsyncTask<Void, Void, Void>() {
342 @Override
343 protected Void doInBackground(Void... params) {
344 try {
345 mStatsService.forceUpdate();
346 } catch (RemoteException e) {
347 }
348 return null;
349 }
350
351 @Override
352 protected void onPostExecute(Void result) {
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700353 if (isAdded()) {
354 updateBody();
355 }
Jeff Sharkey398b18f2011-07-10 18:56:30 -0700356 }
357 }.execute();
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700358 }
359
Jeff Sharkey8a503642011-06-10 13:31:21 -0700360 @Override
361 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
362 inflater.inflate(R.menu.data_usage, menu);
363 }
364
365 @Override
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700366 public void onPrepareOptionsMenu(Menu menu) {
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700367 final Context context = getActivity();
368
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700369 mMenuDataRoaming = menu.findItem(R.id.data_usage_menu_roaming);
370 mMenuDataRoaming.setVisible(hasMobileRadio(context));
371 mMenuDataRoaming.setChecked(getDataRoaming());
372
373 mMenuRestrictBackground = menu.findItem(R.id.data_usage_menu_restrict_background);
374 mMenuRestrictBackground.setChecked(getRestrictBackground());
375
376 final MenuItem split4g = menu.findItem(R.id.data_usage_menu_split_4g);
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700377 split4g.setVisible(hasMobile4gRadio(context));
Jeff Sharkeya662e492011-06-18 21:57:06 -0700378 split4g.setChecked(isMobilePolicySplit());
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700379
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700380 final MenuItem showWifi = menu.findItem(R.id.data_usage_menu_show_wifi);
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700381 if (hasWifiRadio(context) && hasMobileRadio(context)) {
382 showWifi.setVisible(true);
383 showWifi.setChecked(mShowWifi);
384 } else {
385 showWifi.setVisible(false);
386 mShowWifi = true;
387 }
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700388
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700389 final MenuItem showEthernet = menu.findItem(R.id.data_usage_menu_show_ethernet);
390 if (hasEthernet(context) && hasMobileRadio(context)) {
391 showEthernet.setVisible(true);
392 showEthernet.setChecked(mShowEthernet);
393 } else {
394 showEthernet.setVisible(false);
395 mShowEthernet = true;
396 }
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700397 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700398
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700399 @Override
400 public boolean onOptionsItemSelected(MenuItem item) {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700401 switch (item.getItemId()) {
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700402 case R.id.data_usage_menu_roaming: {
403 final boolean dataRoaming = !item.isChecked();
404 if (dataRoaming) {
405 ConfirmDataRoamingFragment.show(this);
406 } else {
407 // no confirmation to disable roaming
408 setDataRoaming(false);
409 }
410 return true;
411 }
412 case R.id.data_usage_menu_restrict_background: {
413 final boolean restrictBackground = !item.isChecked();
414 if (restrictBackground) {
415 ConfirmRestrictFragment.show(this);
416 } else {
417 // no confirmation to drop restriction
418 setRestrictBackground(false);
419 }
420 return true;
421 }
422 case R.id.data_usage_menu_split_4g: {
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700423 final boolean mobileSplit = !item.isChecked();
Jeff Sharkeya662e492011-06-18 21:57:06 -0700424 setMobilePolicySplit(mobileSplit);
425 item.setChecked(isMobilePolicySplit());
Jeff Sharkey8a503642011-06-10 13:31:21 -0700426 updateTabs();
427 return true;
428 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700429 case R.id.data_usage_menu_show_wifi: {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700430 mShowWifi = !item.isChecked();
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700431 mPrefs.edit().putBoolean(PREF_SHOW_WIFI, mShowWifi).apply();
Jeff Sharkey8a503642011-06-10 13:31:21 -0700432 item.setChecked(mShowWifi);
433 updateTabs();
434 return true;
435 }
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700436 case R.id.data_usage_menu_show_ethernet: {
437 mShowEthernet = !item.isChecked();
438 mPrefs.edit().putBoolean(PREF_SHOW_ETHERNET, mShowEthernet).apply();
439 item.setChecked(mShowEthernet);
440 updateTabs();
441 return true;
442 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700443 }
444 return false;
445 }
446
Jeff Sharkey94a90952011-06-13 22:31:09 -0700447 @Override
448 public void onDestroyView() {
449 super.onDestroyView();
450
451 mDataEnabledView = null;
452 mDisableAtLimitView = null;
453 }
454
Jeff Sharkey8a503642011-06-10 13:31:21 -0700455 /**
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700456 * Listener to setup {@link LayoutTransition} after first layout pass.
457 */
458 private OnGlobalLayoutListener mFirstLayoutListener = new OnGlobalLayoutListener() {
459 /** {@inheritDoc} */
460 public void onGlobalLayout() {
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700461 mListView.getViewTreeObserver().removeGlobalOnLayoutListener(mFirstLayoutListener);
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700462
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700463 mTabsContainer.setLayoutTransition(buildLayoutTransition());
464 mHeader.setLayoutTransition(buildLayoutTransition());
465 mNetworkSwitchesContainer.setLayoutTransition(buildLayoutTransition());
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700466
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700467 final LayoutTransition chartTransition = buildLayoutTransition();
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700468 chartTransition.setStartDelay(LayoutTransition.APPEARING, 0);
469 chartTransition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
470 mChart.setLayoutTransition(chartTransition);
471 }
472 };
473
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700474 private static LayoutTransition buildLayoutTransition() {
475 final LayoutTransition transition = new LayoutTransition();
476 if (TEST_ANIM) {
477 transition.setDuration(1500);
478 }
479 transition.setAnimateParentHierarchy(false);
480 return transition;
481 }
482
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700483 /**
Jeff Sharkeya662e492011-06-18 21:57:06 -0700484 * Rebuild all tabs based on {@link NetworkPolicyEditor} and
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700485 * {@link #mShowWifi}, hiding the tabs entirely when applicable. Selects
486 * first tab, and kicks off a full rebind of body contents.
Jeff Sharkey8a503642011-06-10 13:31:21 -0700487 */
488 private void updateTabs() {
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700489 final Context context = getActivity();
Jeff Sharkey8a503642011-06-10 13:31:21 -0700490 mTabHost.clearAllTabs();
491
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700492 final boolean mobileSplit = isMobilePolicySplit();
493 if (mobileSplit && hasMobile4gRadio(context)) {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700494 mTabHost.addTab(buildTabSpec(TAB_3G, R.string.data_usage_tab_3g));
495 mTabHost.addTab(buildTabSpec(TAB_4G, R.string.data_usage_tab_4g));
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700496 } else if (hasMobileRadio(context)) {
497 mTabHost.addTab(buildTabSpec(TAB_MOBILE, R.string.data_usage_tab_mobile));
Jeff Sharkey8a503642011-06-10 13:31:21 -0700498 }
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700499 if (mShowWifi && hasWifiRadio(context)) {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700500 mTabHost.addTab(buildTabSpec(TAB_WIFI, R.string.data_usage_tab_wifi));
501 }
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700502 if (mShowEthernet && hasEthernet(context)) {
503 mTabHost.addTab(buildTabSpec(TAB_ETHERNET, R.string.data_usage_tab_ethernet));
504 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700505
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700506 final boolean multipleTabs = mTabWidget.getTabCount() > 1;
507 mTabWidget.setVisibility(multipleTabs ? View.VISIBLE : View.GONE);
508 if (mIntentTab != null) {
509 if (Objects.equal(mIntentTab, mTabHost.getCurrentTabTag())) {
510 updateBody();
Jeff Sharkeydd6efe12011-06-15 10:31:41 -0700511 } else {
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700512 mTabHost.setCurrentTabByTag(mIntentTab);
513 }
514 mIntentTab = null;
515 } else {
516 if (mTabHost.getCurrentTab() == 0) {
517 updateBody();
518 } else {
Jeff Sharkeydd6efe12011-06-15 10:31:41 -0700519 mTabHost.setCurrentTab(0);
520 }
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700521 }
522 }
523
Jeff Sharkey8a503642011-06-10 13:31:21 -0700524 /**
525 * Factory that provide empty {@link View} to make {@link TabHost} happy.
526 */
527 private TabContentFactory mEmptyTabContent = new TabContentFactory() {
528 /** {@inheritDoc} */
529 public View createTabContent(String tag) {
530 return new View(mTabHost.getContext());
531 }
532 };
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700533
Jeff Sharkey8a503642011-06-10 13:31:21 -0700534 /**
535 * Build {@link TabSpec} with thin indicator, and empty content.
536 */
537 private TabSpec buildTabSpec(String tag, int titleRes) {
538 final LayoutInflater inflater = LayoutInflater.from(mTabWidget.getContext());
539 final View indicator = inflater.inflate(
540 R.layout.tab_indicator_thin_holo, mTabWidget, false);
541 final TextView title = (TextView) indicator.findViewById(android.R.id.title);
542 title.setText(titleRes);
543 return mTabHost.newTabSpec(tag).setIndicator(indicator).setContent(mEmptyTabContent);
544 }
545
546 private OnTabChangeListener mTabListener = new OnTabChangeListener() {
547 /** {@inheritDoc} */
548 public void onTabChanged(String tabId) {
549 // user changed tab; update body
550 updateBody();
551 }
552 };
553
554 /**
555 * Update body content based on current tab. Loads
556 * {@link NetworkStatsHistory} and {@link NetworkPolicy} from system, and
557 * binds them to visible controls.
558 */
559 private void updateBody() {
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700560 mBinding = true;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700561
Jeff Sharkeya662e492011-06-18 21:57:06 -0700562 final Context context = getActivity();
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700563 final String currentTab = mTabHost.getCurrentTabTag();
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700564
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700565 if (currentTab == null) {
566 Log.w(TAG, "no tab selected; hiding body");
567 mListView.setVisibility(View.GONE);
568 return;
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700569 } else {
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700570 mListView.setVisibility(View.VISIBLE);
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700571 }
Jeff Sharkeya662e492011-06-18 21:57:06 -0700572
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700573 final boolean tabChanged = !currentTab.equals(mCurrentTab);
574 mCurrentTab = currentTab;
575
Jeff Sharkey8a503642011-06-10 13:31:21 -0700576 if (LOGD) Log.d(TAG, "updateBody() with currentTab=" + currentTab);
577
578 if (TAB_WIFI.equals(currentTab)) {
579 // wifi doesn't have any controls
580 mDataEnabledView.setVisibility(View.GONE);
581 mDisableAtLimitView.setVisibility(View.GONE);
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700582 mTemplate = buildTemplateWifi();
583
584 } else if (TAB_ETHERNET.equals(currentTab)) {
585 // ethernet doesn't have any controls
586 mDataEnabledView.setVisibility(View.GONE);
587 mDisableAtLimitView.setVisibility(View.GONE);
588 mTemplate = buildTemplateEthernet();
Jeff Sharkey8a503642011-06-10 13:31:21 -0700589
590 } else {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700591 mDataEnabledView.setVisibility(View.VISIBLE);
592 mDisableAtLimitView.setVisibility(View.VISIBLE);
593 }
594
595 if (TAB_MOBILE.equals(currentTab)) {
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700596 setPreferenceTitle(mDataEnabledView, R.string.data_usage_enable_mobile);
597 setPreferenceTitle(mDisableAtLimitView, R.string.data_usage_disable_mobile_limit);
598 mDataEnabled.setChecked(mConnService.getMobileDataEnabled());
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700599 mTemplate = buildTemplateMobileAll(getActiveSubscriberId(context));
Jeff Sharkey8a503642011-06-10 13:31:21 -0700600
601 } else if (TAB_3G.equals(currentTab)) {
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700602 setPreferenceTitle(mDataEnabledView, R.string.data_usage_enable_3g);
603 setPreferenceTitle(mDisableAtLimitView, R.string.data_usage_disable_3g_limit);
604 // TODO: bind mDataEnabled to 3G radio state
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700605 mTemplate = buildTemplateMobile3gLower(getActiveSubscriberId(context));
Jeff Sharkey8a503642011-06-10 13:31:21 -0700606
607 } else if (TAB_4G.equals(currentTab)) {
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700608 setPreferenceTitle(mDataEnabledView, R.string.data_usage_enable_4g);
609 setPreferenceTitle(mDisableAtLimitView, R.string.data_usage_disable_4g_limit);
610 // TODO: bind mDataEnabled to 4G radio state
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700611 mTemplate = buildTemplateMobile4g(getActiveSubscriberId(context));
Jeff Sharkey8a503642011-06-10 13:31:21 -0700612 }
613
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -0700614 try {
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700615 // load stats for current template
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700616 mHistory = mStatsService.getHistoryForNetwork(
617 mTemplate, FIELD_RX_BYTES | FIELD_TX_BYTES);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700618 } catch (RemoteException e) {
619 // since we can't do much without policy or history, and we don't
620 // want to leave with half-baked UI, we bail hard.
621 throw new RuntimeException("problem reading network policy or stats", e);
622 }
623
Jeff Sharkey8a503642011-06-10 13:31:21 -0700624 // bind chart to historical stats
Jeff Sharkey8a503642011-06-10 13:31:21 -0700625 mChart.bindNetworkStats(mHistory);
626
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700627 // only update policy when switching tabs
628 updatePolicy(tabChanged);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700629 updateAppDetail();
Jeff Sharkey8a503642011-06-10 13:31:21 -0700630
631 // force scroll to top of body
632 mListView.smoothScrollToPosition(0);
633
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700634 mBinding = false;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700635 }
636
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700637 private boolean isAppDetailMode() {
638 return mUid != UID_NONE;
639 }
640
641 /**
642 * Update UID details panels to match {@link #mUid}, showing or hiding them
643 * depending on {@link #isAppDetailMode()}.
644 */
645 private void updateAppDetail() {
646 if (isAppDetailMode()) {
647 mAppDetail.setVisibility(View.VISIBLE);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700648 mCycleAdapter.setChangeVisible(false);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700649 } else {
650 mAppDetail.setVisibility(View.GONE);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700651 mCycleAdapter.setChangeVisible(true);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700652
653 // hide detail stats when not in detail mode
654 mChart.bindDetailNetworkStats(null);
655 return;
656 }
657
658 // remove warning/limit sweeps while in detail mode
659 mChart.bindNetworkPolicy(null);
660
661 final PackageManager pm = getActivity().getPackageManager();
662 mAppTitle.setText(pm.getNameForUid(mUid));
663
664 // enable settings button when package provides it
665 // TODO: target torwards entire UID instead of just first package
666 final String[] packageNames = pm.getPackagesForUid(mUid);
667 if (packageNames != null && packageNames.length > 0) {
668 mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
669 mAppSettingsIntent.setPackage(packageNames[0]);
670 mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
671
672 final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null;
673 mAppSettings.setEnabled(matchFound);
674
675 } else {
676 mAppSettingsIntent = null;
677 mAppSettings.setEnabled(false);
678 }
679
680 try {
681 // load stats for current uid and template
682 // TODO: read template from extras
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700683 mDetailHistory = mStatsService.getHistoryForUid(
684 mTemplate, mUid, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700685 } catch (RemoteException e) {
686 // since we can't do much without history, and we don't want to
687 // leave with half-baked UI, we bail hard.
688 throw new RuntimeException("problem reading network stats", e);
689 }
690
691 // bind chart to historical stats
692 mChart.bindDetailNetworkStats(mDetailHistory);
693
694 updateDetailData();
695
696 final Context context = getActivity();
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700697 if (NetworkPolicyManager.isUidValidForPolicy(context, mUid) && !getRestrictBackground()
698 && isBandwidthControlEnabled()) {
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700699 mAppRestrictView.setVisibility(View.VISIBLE);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700700 mAppRestrict.setChecked(getAppRestrictBackground());
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700701
702 } else {
703 mAppRestrictView.setVisibility(View.GONE);
704 }
705
706 }
707
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700708 private void setPolicyCycleDay(int cycleDay) {
709 if (LOGD) Log.d(TAG, "setPolicyCycleDay()");
Jeff Sharkeya662e492011-06-18 21:57:06 -0700710 mPolicyEditor.setPolicyCycleDay(mTemplate, cycleDay);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700711 updatePolicy(true);
712 }
713
714 private void setPolicyWarningBytes(long warningBytes) {
715 if (LOGD) Log.d(TAG, "setPolicyWarningBytes()");
Jeff Sharkeya662e492011-06-18 21:57:06 -0700716 mPolicyEditor.setPolicyWarningBytes(mTemplate, warningBytes);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700717 updatePolicy(false);
718 }
719
720 private void setPolicyLimitBytes(long limitBytes) {
721 if (LOGD) Log.d(TAG, "setPolicyLimitBytes()");
Jeff Sharkeya662e492011-06-18 21:57:06 -0700722 mPolicyEditor.setPolicyLimitBytes(mTemplate, limitBytes);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700723 updatePolicy(false);
724 }
725
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700726 private boolean isNetworkPolicyModifiable() {
727 return isBandwidthControlEnabled() && mDataEnabled.isChecked();
728 }
729
730 private boolean isBandwidthControlEnabled() {
731 try {
732 return mNetworkService.isBandwidthControlEnabled();
733 } catch (RemoteException e) {
734 Log.w(TAG, "problem talking with INetworkManagementService: " + e);
735 return false;
736 }
737 }
738
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700739 private boolean getDataRoaming() {
740 final ContentResolver resolver = getActivity().getContentResolver();
741 return Settings.Secure.getInt(resolver, Settings.Secure.DATA_ROAMING, 0) != 0;
742 }
743
744 private void setDataRoaming(boolean enabled) {
745 // TODO: teach telephony DataConnectionTracker to watch and apply
746 // updates when changed.
747 final ContentResolver resolver = getActivity().getContentResolver();
748 Settings.Secure.putInt(resolver, Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
749 mMenuDataRoaming.setChecked(enabled);
750 }
751
752 private boolean getRestrictBackground() {
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700753 try {
754 return mPolicyService.getRestrictBackground();
755 } catch (RemoteException e) {
756 Log.w(TAG, "problem talking with policy service: " + e);
757 return false;
758 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700759 }
760
761 private void setRestrictBackground(boolean restrictBackground) {
762 if (LOGD) Log.d(TAG, "setRestrictBackground()");
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700763 try {
764 mPolicyService.setRestrictBackground(restrictBackground);
765 mMenuRestrictBackground.setChecked(restrictBackground);
766 } catch (RemoteException e) {
767 Log.w(TAG, "problem talking with policy service: " + e);
768 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700769 }
770
771 private boolean getAppRestrictBackground() {
772 final int uidPolicy;
773 try {
774 uidPolicy = mPolicyService.getUidPolicy(mUid);
775 } catch (RemoteException e) {
776 // since we can't do much without policy, we bail hard.
777 throw new RuntimeException("problem reading network policy", e);
778 }
779
780 return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
781 }
782
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700783 private void setAppRestrictBackground(boolean restrictBackground) {
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700784 if (LOGD) Log.d(TAG, "setAppRestrictBackground()");
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700785 try {
786 mPolicyService.setUidPolicy(
787 mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
788 } catch (RemoteException e) {
789 throw new RuntimeException("unable to save policy", e);
790 }
791
792 mAppRestrict.setChecked(restrictBackground);
793 }
794
Jeff Sharkey8a503642011-06-10 13:31:21 -0700795 /**
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700796 * Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
797 * current {@link #mTemplate}.
798 */
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700799 private void updatePolicy(boolean refreshCycle) {
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700800 if (isAppDetailMode()) {
801 mNetworkSwitches.setVisibility(View.GONE);
802 // we fall through to update cycle list for detail mode
803 } else {
804 mNetworkSwitches.setVisibility(View.VISIBLE);
Jeff Sharkey2af35fb2011-06-24 17:30:27 -0700805
806 // when heading back to summary without cycle refresh, kick details
807 // update to repopulate list.
808 if (!refreshCycle) {
809 updateDetailData();
810 }
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700811 }
812
Jeff Sharkeya662e492011-06-18 21:57:06 -0700813 final NetworkPolicy policy = mPolicyEditor.getPolicy(mTemplate);
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700814 if (isNetworkPolicyModifiable()) {
815 mDisableAtLimitView.setVisibility(View.VISIBLE);
816 mDisableAtLimit.setChecked(policy != null && policy.limitBytes != LIMIT_DISABLED);
817 mChart.bindNetworkPolicy(policy);
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700818
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700819 } else {
820 // controls are disabled; don't bind warning/limit sweeps
821 mDisableAtLimitView.setVisibility(View.GONE);
822 mChart.bindNetworkPolicy(null);
823 }
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700824
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700825 if (refreshCycle) {
826 // generate cycle list based on policy and available history
827 updateCycleList(policy);
828 }
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700829 }
830
831 /**
Jeff Sharkey8a503642011-06-10 13:31:21 -0700832 * Rebuild {@link #mCycleAdapter} based on {@link NetworkPolicy#cycleDay}
833 * and available {@link NetworkStatsHistory} data. Always selects the newest
834 * item, updating the inspection range on {@link #mChart}.
835 */
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700836 private void updateCycleList(NetworkPolicy policy) {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700837 mCycleAdapter.clear();
838
839 final Context context = mCycleSpinner.getContext();
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700840 long historyStart = mHistory.getStart();
841 long historyEnd = mHistory.getEnd();
Jeff Sharkey8a503642011-06-10 13:31:21 -0700842
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700843 if (historyStart == Long.MAX_VALUE || historyEnd == Long.MIN_VALUE) {
844 historyStart = System.currentTimeMillis();
845 historyEnd = System.currentTimeMillis();
846 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700847
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700848 boolean hasCycles = false;
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700849 if (policy != null) {
850 // find the next cycle boundary
851 long cycleEnd = computeNextCycleBoundary(historyEnd, policy);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700852
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700853 int guardCount = 0;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700854
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700855 // walk backwards, generating all valid cycle ranges
856 while (cycleEnd > historyStart) {
857 final long cycleStart = computeLastCycleBoundary(cycleEnd, policy);
858 Log.d(TAG, "generating cs=" + cycleStart + " to ce=" + cycleEnd + " waiting for hs="
859 + historyStart);
860 mCycleAdapter.add(new CycleItem(context, cycleStart, cycleEnd));
861 cycleEnd = cycleStart;
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700862 hasCycles = true;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700863
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700864 // TODO: remove this guard once we have better testing
865 if (guardCount++ > 50) {
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700866 Log.wtf(TAG, "stuck generating ranges for historyStart=" + historyStart
867 + ", historyEnd=" + historyEnd + " and policy=" + policy);
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700868 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700869 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700870
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700871 // one last cycle entry to modify policy cycle day
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700872 mCycleAdapter.setChangePossible(isNetworkPolicyModifiable());
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700873 }
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700874
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700875 if (!hasCycles) {
876 // no valid cycles; show all data
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700877 // TODO: offer simple ranges like "last week" etc
878 mCycleAdapter.add(new CycleItem(context, historyStart, historyEnd));
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700879 mCycleAdapter.setChangePossible(false);
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -0700880 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700881
882 // force pick the current cycle (first item)
883 mCycleSpinner.setSelection(0);
884 mCycleListener.onItemSelected(mCycleSpinner, null, 0, 0);
885 }
886
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700887 private OnCheckedChangeListener mDataEnabledListener = new OnCheckedChangeListener() {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700888 /** {@inheritDoc} */
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700889 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
890 if (mBinding) return;
Jeff Sharkey8a503642011-06-10 13:31:21 -0700891
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700892 final boolean dataEnabled = isChecked;
893 mDataEnabled.setChecked(dataEnabled);
894
Jeff Sharkey9549e9f2011-07-14 20:01:13 -0700895 final String currentTab = mCurrentTab;
896 if (TAB_MOBILE.equals(currentTab)) {
897 mConnService.setMobileDataEnabled(dataEnabled);
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700898 }
Jeff Sharkey1ae43f92011-08-03 17:16:09 -0700899
900 // rebind policy to match radio state
901 updatePolicy(true);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700902 }
903 };
904
Jeff Sharkey29d56b32011-06-20 17:06:52 -0700905 private View.OnClickListener mDisableAtLimitListener = new View.OnClickListener() {
Jeff Sharkey8a503642011-06-10 13:31:21 -0700906 /** {@inheritDoc} */
907 public void onClick(View v) {
908 final boolean disableAtLimit = !mDisableAtLimit.isChecked();
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700909 if (disableAtLimit) {
910 // enabling limit; show confirmation dialog which eventually
911 // calls setPolicyLimitBytes() once user confirms.
912 ConfirmLimitFragment.show(DataUsageSummary.this);
913 } else {
914 setPolicyLimitBytes(LIMIT_DISABLED);
915 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700916 }
917 };
918
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700919 private View.OnClickListener mAppRestrictListener = new View.OnClickListener() {
920 /** {@inheritDoc} */
921 public void onClick(View v) {
922 final boolean restrictBackground = !mAppRestrict.isChecked();
923
924 if (restrictBackground) {
925 // enabling restriction; show confirmation dialog which
926 // eventually calls setRestrictBackground() once user confirms.
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700927 ConfirmAppRestrictFragment.show(DataUsageSummary.this);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700928 } else {
929 setAppRestrictBackground(false);
930 }
931 }
932 };
933
934 private OnClickListener mAppSettingsListener = new OnClickListener() {
935 /** {@inheritDoc} */
936 public void onClick(View v) {
937 // TODO: target torwards entire UID instead of just first package
938 startActivity(mAppSettingsIntent);
939 }
940 };
941
Jeff Sharkey8a503642011-06-10 13:31:21 -0700942 private OnItemClickListener mListListener = new OnItemClickListener() {
943 /** {@inheritDoc} */
944 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700945 final AppUsageItem app = (AppUsageItem) parent.getItemAtPosition(position);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700946 AppDetailsFragment.show(DataUsageSummary.this, app.uid);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700947 }
948 };
949
950 private OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
951 /** {@inheritDoc} */
952 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
953 final CycleItem cycle = (CycleItem) parent.getItemAtPosition(position);
954 if (cycle instanceof CycleChangeItem) {
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700955 // show cycle editor; will eventually call setPolicyCycleDay()
956 // when user finishes editing.
957 CycleEditorFragment.show(DataUsageSummary.this);
958
959 // reset spinner to something other than "change cycle..."
960 mCycleSpinner.setSelection(0);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700961
962 } else {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700963 if (LOGD) {
964 Log.d(TAG, "showing cycle " + cycle + ", start=" + cycle.start + ", end="
965 + cycle.end + "]");
966 }
Jeff Sharkey8a503642011-06-10 13:31:21 -0700967
968 // update chart to show selected cycle, and update detail data
969 // to match updated sweep bounds.
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700970 mChart.setVisibleRange(cycle.start, cycle.end);
Jeff Sharkey8a503642011-06-10 13:31:21 -0700971
972 updateDetailData();
973 }
974 }
975
976 /** {@inheritDoc} */
977 public void onNothingSelected(AdapterView<?> parent) {
978 // ignored
979 }
980 };
981
982 /**
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700983 * Update details based on {@link #mChart} inspection range depending on
984 * current mode. In network mode, updates {@link #mAdapter} with sorted list
985 * of applications data usage, and when {@link #isAppDetailMode()} update
986 * app details.
Jeff Sharkey8a503642011-06-10 13:31:21 -0700987 */
988 private void updateDetailData() {
989 if (LOGD) Log.d(TAG, "updateDetailData()");
990
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700991 final long start = mChart.getInspectStart();
992 final long end = mChart.getInspectEnd();
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -0700993 final long now = System.currentTimeMillis();
994
995 final Context context = getActivity();
996 final NetworkStatsHistory.Entry entry;
Jeff Sharkey518bc9d2011-07-12 20:20:46 -0700997
Jeff Sharkeyf54f4352011-06-23 22:15:54 -0700998 if (isAppDetailMode()) {
999 if (mDetailHistory != null) {
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001000 entry = mDetailHistory.getValues(start, end, now, null);
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001001
1002 mAppSubtitle.setText(
1003 getString(R.string.data_usage_received_sent,
1004 Formatter.formatFileSize(context, entry.rxBytes),
1005 Formatter.formatFileSize(context, entry.txBytes)));
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001006 } else {
1007 entry = null;
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001008 }
1009
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001010 getLoaderManager().destroyLoader(LOADER_SUMMARY);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001011
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001012 } else {
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001013 entry = mHistory.getValues(start, end, now, null);
1014
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001015 // kick off loader for detailed stats
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001016 getLoaderManager().restartLoader(LOADER_SUMMARY,
Jeff Sharkey518bc9d2011-07-12 20:20:46 -07001017 SummaryForAllUidLoader.buildArgs(mTemplate, start, end), mSummaryForAllUid);
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001018
1019 }
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001020
1021 final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0;
1022 final String totalPhrase = Formatter.formatFileSize(context, totalBytes);
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -07001023 final String rangePhrase = formatDateRange(context, start, end, null);
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001024
1025 mUsageSummary.setText(
1026 getString(R.string.data_usage_total_during_range, totalPhrase, rangePhrase));
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001027 }
1028
1029 private final LoaderCallbacks<NetworkStats> mSummaryForAllUid = new LoaderCallbacks<
1030 NetworkStats>() {
1031 /** {@inheritDoc} */
1032 public Loader<NetworkStats> onCreateLoader(int id, Bundle args) {
1033 return new SummaryForAllUidLoader(getActivity(), mStatsService, args);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001034 }
1035
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001036 /** {@inheritDoc} */
1037 public void onLoadFinished(Loader<NetworkStats> loader, NetworkStats data) {
1038 mAdapter.bindStats(data);
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -07001039 updateEmptyVisible();
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001040 }
Jeff Sharkeyaa5260e2011-06-14 23:21:59 -07001041
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001042 /** {@inheritDoc} */
1043 public void onLoaderReset(Loader<NetworkStats> loader) {
1044 mAdapter.bindStats(null);
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -07001045 updateEmptyVisible();
1046 }
1047
1048 private void updateEmptyVisible() {
1049 final boolean isEmpty = mAdapter.isEmpty() && !isAppDetailMode();
1050 mEmpty.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
Jeff Sharkey398b18f2011-07-10 18:56:30 -07001051 }
1052 };
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001053
Jeff Sharkeya662e492011-06-18 21:57:06 -07001054 private boolean isMobilePolicySplit() {
Jeff Sharkey9549e9f2011-07-14 20:01:13 -07001055 final Context context = getActivity();
1056 if (hasMobileRadio(context)) {
1057 final String subscriberId = getActiveSubscriberId(context);
1058 return mPolicyEditor.isMobilePolicySplit(subscriberId);
1059 } else {
1060 return false;
1061 }
Jeff Sharkeya662e492011-06-18 21:57:06 -07001062 }
1063
1064 private void setMobilePolicySplit(boolean split) {
1065 final String subscriberId = getActiveSubscriberId(getActivity());
1066 mPolicyEditor.setMobilePolicySplit(subscriberId, split);
1067 }
1068
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -07001069 private static String getActiveSubscriberId(Context context) {
1070 final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
1071 Context.TELEPHONY_SERVICE);
1072 return telephony.getSubscriberId();
1073 }
1074
Jeff Sharkey8a503642011-06-10 13:31:21 -07001075 private DataUsageChartListener mChartListener = new DataUsageChartListener() {
1076 /** {@inheritDoc} */
1077 public void onInspectRangeChanged() {
1078 if (LOGD) Log.d(TAG, "onInspectRangeChanged()");
1079 updateDetailData();
1080 }
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001081
Jeff Sharkey8a503642011-06-10 13:31:21 -07001082 /** {@inheritDoc} */
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -07001083 public void onWarningChanged() {
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001084 setPolicyWarningBytes(mChart.getWarningBytes());
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -07001085 }
Jeff Sharkey8a503642011-06-10 13:31:21 -07001086
Jeff Sharkey05cc0cc2011-06-12 23:11:24 -07001087 /** {@inheritDoc} */
1088 public void onLimitChanged() {
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001089 setPolicyLimitBytes(mChart.getLimitBytes());
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001090 }
1091 };
1092
1093
1094 /**
Jeff Sharkey8a503642011-06-10 13:31:21 -07001095 * List item that reflects a specific data usage cycle.
1096 */
1097 public static class CycleItem {
1098 public CharSequence label;
1099 public long start;
1100 public long end;
1101
Jeff Sharkey8a503642011-06-10 13:31:21 -07001102 CycleItem(CharSequence label) {
1103 this.label = label;
1104 }
1105
1106 public CycleItem(Context context, long start, long end) {
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -07001107 this.label = formatDateRange(context, start, end, Time.TIMEZONE_UTC);
Jeff Sharkey8a503642011-06-10 13:31:21 -07001108 this.start = start;
1109 this.end = end;
1110 }
1111
Jeff Sharkey8a503642011-06-10 13:31:21 -07001112 @Override
1113 public String toString() {
1114 return label.toString();
1115 }
1116 }
1117
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001118 private static final StringBuilder sBuilder = new StringBuilder(50);
1119 private static final java.util.Formatter sFormatter = new java.util.Formatter(
1120 sBuilder, Locale.getDefault());
1121
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -07001122 private static String formatDateRange(Context context, long start, long end, String timezone) {
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001123 synchronized (sBuilder) {
1124 int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
1125 if (Time.getJulianDay(start, 0) == Time.getJulianDay(end, 0)) {
1126 // when times are on same day, include time detail
1127 flags |= DateUtils.FORMAT_SHOW_TIME;
1128 }
1129
1130 sBuilder.setLength(0);
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -07001131 return DateUtils
1132 .formatDateRange(context, sFormatter, start, end, flags, timezone).toString();
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001133 }
1134 }
1135
Jeff Sharkey8a503642011-06-10 13:31:21 -07001136 /**
1137 * Special-case data usage cycle that triggers dialog to change
1138 * {@link NetworkPolicy#cycleDay}.
1139 */
1140 public static class CycleChangeItem extends CycleItem {
1141 public CycleChangeItem(Context context) {
1142 super(context.getString(R.string.data_usage_change_cycle));
1143 }
1144 }
1145
1146 public static class CycleAdapter extends ArrayAdapter<CycleItem> {
Jeff Sharkey9fab0da2011-07-09 17:52:31 -07001147 private boolean mChangePossible = false;
1148 private boolean mChangeVisible = false;
1149
1150 private final CycleChangeItem mChangeItem;
1151
Jeff Sharkey8a503642011-06-10 13:31:21 -07001152 public CycleAdapter(Context context) {
1153 super(context, android.R.layout.simple_spinner_item);
1154 setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -07001155 mChangeItem = new CycleChangeItem(context);
1156 }
1157
1158 public void setChangePossible(boolean possible) {
1159 mChangePossible = possible;
1160 updateChange();
1161 }
1162
1163 public void setChangeVisible(boolean visible) {
1164 mChangeVisible = visible;
1165 updateChange();
1166 }
1167
1168 private void updateChange() {
1169 remove(mChangeItem);
1170 if (mChangePossible && mChangeVisible) {
1171 add(mChangeItem);
1172 }
Jeff Sharkey8a503642011-06-10 13:31:21 -07001173 }
1174 }
1175
Jeff Sharkey4dfa6602011-06-13 00:42:03 -07001176 private static class AppUsageItem implements Comparable<AppUsageItem> {
1177 public int uid;
1178 public long total;
1179
1180 /** {@inheritDoc} */
1181 public int compareTo(AppUsageItem another) {
1182 return Long.compare(another.total, total);
1183 }
1184 }
1185
Jeff Sharkey8a503642011-06-10 13:31:21 -07001186 /**
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001187 * Adapter of applications, sorted by total usage descending.
1188 */
1189 public static class DataUsageAdapter extends BaseAdapter {
Jeff Sharkey8a503642011-06-10 13:31:21 -07001190 private ArrayList<AppUsageItem> mItems = Lists.newArrayList();
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001191 private long mLargest;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001192
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001193 /**
1194 * Bind the given {@link NetworkStats}, or {@code null} to clear list.
1195 */
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001196 public void bindStats(NetworkStats stats) {
Jeff Sharkey8a503642011-06-10 13:31:21 -07001197 mItems.clear();
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001198
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001199 if (stats != null) {
Jeff Sharkey518bc9d2011-07-12 20:20:46 -07001200 final AppUsageItem systemItem = new AppUsageItem();
1201 systemItem.uid = android.os.Process.SYSTEM_UID;
1202
Jeff Sharkeyebae6592011-07-12 13:53:11 -07001203 NetworkStats.Entry entry = null;
1204 for (int i = 0; i < stats.size(); i++) {
1205 entry = stats.getValues(i, entry);
Jeff Sharkey518bc9d2011-07-12 20:20:46 -07001206
1207 final boolean isApp = entry.uid >= android.os.Process.FIRST_APPLICATION_UID
1208 && entry.uid <= android.os.Process.LAST_APPLICATION_UID;
1209 if (isApp || entry.uid == TrafficStats.UID_REMOVED) {
1210 final AppUsageItem item = new AppUsageItem();
1211 item.uid = entry.uid;
1212 item.total = entry.rxBytes + entry.txBytes;
1213 mItems.add(item);
1214 } else {
1215 systemItem.total += entry.rxBytes + entry.txBytes;
1216 }
1217 }
1218
1219 if (systemItem.total > 0) {
1220 mItems.add(systemItem);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001221 }
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001222 }
1223
Jeff Sharkey8a503642011-06-10 13:31:21 -07001224 Collections.sort(mItems);
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001225 mLargest = (mItems.size() > 0) ? mItems.get(0).total : 0;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001226 notifyDataSetChanged();
1227 }
1228
1229 @Override
1230 public int getCount() {
Jeff Sharkey8a503642011-06-10 13:31:21 -07001231 return mItems.size();
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001232 }
1233
1234 @Override
1235 public Object getItem(int position) {
Jeff Sharkey8a503642011-06-10 13:31:21 -07001236 return mItems.get(position);
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001237 }
1238
1239 @Override
1240 public long getItemId(int position) {
Jeff Sharkeye2afc0f2011-08-01 15:29:30 -07001241 return mItems.get(position).uid;
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001242 }
1243
1244 @Override
1245 public View getView(int position, View convertView, ViewGroup parent) {
1246 if (convertView == null) {
1247 convertView = LayoutInflater.from(parent.getContext()).inflate(
Jeff Sharkey52c3f442011-06-23 00:39:38 -07001248 R.layout.data_usage_item, parent, false);
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001249 }
1250
1251 final Context context = parent.getContext();
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001252
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001253 final TextView title = (TextView) convertView.findViewById(android.R.id.title);
1254 final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
1255 final ProgressBar progress = (ProgressBar) convertView.findViewById(
1256 android.R.id.progress);
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001257
Jeff Sharkey8a503642011-06-10 13:31:21 -07001258 final AppUsageItem item = mItems.get(position);
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001259 title.setText(resolveLabelForUid(context, item.uid));
1260 summary.setText(Formatter.formatFileSize(context, item.total));
1261
1262 final int percentTotal = mLargest != 0 ? (int) (item.total * 100 / mLargest) : 0;
1263 progress.setProgress(percentTotal);
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001264
1265 return convertView;
1266 }
1267
1268 }
1269
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001270 /**
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001271 * Empty {@link Fragment} that controls display of UID details in
1272 * {@link DataUsageSummary}.
1273 */
1274 public static class AppDetailsFragment extends Fragment {
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001275 private static final String EXTRA_UID = "uid";
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001276
1277 public static void show(DataUsageSummary parent, int uid) {
1278 final Bundle args = new Bundle();
1279 args.putInt(EXTRA_UID, uid);
1280
1281 final AppDetailsFragment fragment = new AppDetailsFragment();
1282 fragment.setArguments(args);
1283 fragment.setTargetFragment(parent, 0);
1284
1285 final FragmentTransaction ft = parent.getFragmentManager().beginTransaction();
1286 ft.add(fragment, TAG_APP_DETAILS);
1287 ft.addToBackStack(TAG_APP_DETAILS);
1288 ft.commit();
1289 }
1290
1291 @Override
1292 public void onStart() {
1293 super.onStart();
1294 final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
1295 target.mUid = getArguments().getInt(EXTRA_UID);
1296 target.updateBody();
1297 }
1298
1299 @Override
1300 public void onStop() {
1301 super.onStop();
1302 final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
1303 target.mUid = UID_NONE;
1304 target.updateBody();
1305 }
1306 }
1307
1308 /**
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001309 * Dialog to request user confirmation before setting
1310 * {@link NetworkPolicy#limitBytes}.
1311 */
1312 public static class ConfirmLimitFragment extends DialogFragment {
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001313 private static final String EXTRA_MESSAGE_ID = "messageId";
1314 private static final String EXTRA_LIMIT_BYTES = "limitBytes";
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001315
1316 public static void show(DataUsageSummary parent) {
1317 final Bundle args = new Bundle();
1318
1319 // TODO: customize default limits based on network template
Jeff Sharkey9549e9f2011-07-14 20:01:13 -07001320 final String currentTab = parent.mCurrentTab;
1321 if (TAB_3G.equals(currentTab)) {
1322 args.putInt(EXTRA_MESSAGE_ID, R.string.data_usage_limit_dialog_3g);
1323 args.putLong(EXTRA_LIMIT_BYTES, 5 * GB_IN_BYTES);
1324 } else if (TAB_4G.equals(currentTab)) {
1325 args.putInt(EXTRA_MESSAGE_ID, R.string.data_usage_limit_dialog_4g);
1326 args.putLong(EXTRA_LIMIT_BYTES, 5 * GB_IN_BYTES);
1327 } else if (TAB_MOBILE.equals(currentTab)) {
1328 args.putInt(EXTRA_MESSAGE_ID, R.string.data_usage_limit_dialog_mobile);
1329 args.putLong(EXTRA_LIMIT_BYTES, 5 * GB_IN_BYTES);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001330 }
1331
1332 final ConfirmLimitFragment dialog = new ConfirmLimitFragment();
1333 dialog.setArguments(args);
1334 dialog.setTargetFragment(parent, 0);
1335 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_LIMIT);
1336 }
1337
1338 @Override
1339 public Dialog onCreateDialog(Bundle savedInstanceState) {
1340 final Context context = getActivity();
1341
1342 final int messageId = getArguments().getInt(EXTRA_MESSAGE_ID);
1343 final long limitBytes = getArguments().getLong(EXTRA_LIMIT_BYTES);
1344
1345 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
1346 builder.setTitle(R.string.data_usage_limit_dialog_title);
1347 builder.setMessage(messageId);
1348
1349 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
1350 public void onClick(DialogInterface dialog, int which) {
1351 final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
1352 if (target != null) {
1353 target.setPolicyLimitBytes(limitBytes);
1354 }
1355 }
1356 });
1357
1358 return builder.create();
1359 }
1360 }
1361
1362 /**
1363 * Dialog to edit {@link NetworkPolicy#cycleDay}.
1364 */
1365 public static class CycleEditorFragment extends DialogFragment {
Jeff Sharkey2412b0f2011-07-17 20:31:40 -07001366 private static final String EXTRA_CYCLE_DAY = "cycleDay";
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001367
1368 public static void show(DataUsageSummary parent) {
Jeff Sharkeya662e492011-06-18 21:57:06 -07001369 final NetworkPolicy policy = parent.mPolicyEditor.getPolicy(parent.mTemplate);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -07001370 final Bundle args = new Bundle();
1371 args.putInt(CycleEditorFragment.EXTRA_CYCLE_DAY, policy.cycleDay);
1372
1373 final CycleEditorFragment dialog = new CycleEditorFragment();
1374 dialog.setArguments(args);
1375 dialog.setTargetFragment(parent, 0);
1376 dialog.show(parent.getFragmentManager(), TAG_CYCLE_EDITOR);
1377 }
1378
1379 @Override
1380 public Dialog onCreateDialog(Bundle savedInstanceState) {
1381 final Context context = getActivity();
1382
1383 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
1384 final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
1385
1386 final View view = dialogInflater.inflate(R.layout.data_usage_cycle_editor, null, false);
1387 final NumberPicker cycleDayPicker = (NumberPicker) view.findViewById(R.id.cycle_day);
1388
1389 final int oldCycleDay = getArguments().getInt(EXTRA_CYCLE_DAY, 1);
1390
1391 cycleDayPicker.setMinValue(1);
1392 cycleDayPicker.setMaxValue(31);
1393 cycleDayPicker.setValue(oldCycleDay);
1394 cycleDayPicker.setWrapSelectorWheel(true);
1395
1396 builder.setTitle(R.string.data_usage_cycle_editor_title);
1397 builder.setView(view);
1398
1399 builder.setPositiveButton(R.string.data_usage_cycle_editor_positive,
1400 new DialogInterface.OnClickListener() {
1401 public void onClick(DialogInterface dialog, int which) {
1402 final int cycleDay = cycleDayPicker.getValue();
1403 final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
1404 if (target != null) {
1405 target.setPolicyCycleDay(cycleDay);
1406 }
1407 }
1408 });
1409
1410 return builder.create();
1411 }
1412 }
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001413
Jeff Sharkey8e911d72011-06-14 22:41:21 -07001414 /**
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001415 * Dialog to request user confirmation before setting
Jeff Sharkey9fab0da2011-07-09 17:52:31 -07001416 * {@link Settings.Secure#DATA_ROAMING}.
1417 */
1418 public static class ConfirmDataRoamingFragment extends DialogFragment {
1419 public static void show(DataUsageSummary parent) {
1420 final Bundle args = new Bundle();
1421
1422 final ConfirmDataRoamingFragment dialog = new ConfirmDataRoamingFragment();
1423 dialog.setTargetFragment(parent, 0);
1424 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_ROAMING);
1425 }
1426
1427 @Override
1428 public Dialog onCreateDialog(Bundle savedInstanceState) {
1429 final Context context = getActivity();
1430
1431 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
1432 builder.setTitle(R.string.roaming_reenable_title);
1433 builder.setMessage(R.string.roaming_warning);
1434
1435 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
1436 public void onClick(DialogInterface dialog, int which) {
1437 final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
1438 if (target != null) {
1439 target.setDataRoaming(true);
1440 }
1441 }
1442 });
1443 builder.setNegativeButton(android.R.string.cancel, null);
1444
1445 return builder.create();
1446 }
1447 }
1448
1449 /**
1450 * Dialog to request user confirmation before setting
Jeff Sharkeyd360e5e2011-07-26 19:30:26 -07001451 * {@link INetworkPolicyManager#setRestrictBackground(boolean)}.
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001452 */
1453 public static class ConfirmRestrictFragment extends DialogFragment {
1454 public static void show(DataUsageSummary parent) {
Jeff Sharkey9fab0da2011-07-09 17:52:31 -07001455 final Bundle args = new Bundle();
1456
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001457 final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
1458 dialog.setTargetFragment(parent, 0);
1459 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
1460 }
1461
1462 @Override
1463 public Dialog onCreateDialog(Bundle savedInstanceState) {
1464 final Context context = getActivity();
1465
1466 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -07001467 builder.setTitle(R.string.data_usage_restrict_background_title);
1468 builder.setMessage(R.string.data_usage_restrict_background);
1469
1470 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
1471 public void onClick(DialogInterface dialog, int which) {
1472 final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
1473 if (target != null) {
1474 target.setRestrictBackground(true);
1475 }
1476 }
1477 });
1478 builder.setNegativeButton(android.R.string.cancel, null);
1479
1480 return builder.create();
1481 }
1482 }
1483
1484 /**
1485 * Dialog to request user confirmation before setting
1486 * {@link #POLICY_REJECT_METERED_BACKGROUND}.
1487 */
1488 public static class ConfirmAppRestrictFragment extends DialogFragment {
1489 public static void show(DataUsageSummary parent) {
1490 final ConfirmAppRestrictFragment dialog = new ConfirmAppRestrictFragment();
1491 dialog.setTargetFragment(parent, 0);
1492 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_APP_RESTRICT);
1493 }
1494
1495 @Override
1496 public Dialog onCreateDialog(Bundle savedInstanceState) {
1497 final Context context = getActivity();
1498
1499 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001500 builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
1501 builder.setMessage(R.string.data_usage_app_restrict_dialog);
1502
1503 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
1504 public void onClick(DialogInterface dialog, int which) {
1505 final DataUsageSummary target = (DataUsageSummary) getTargetFragment();
1506 if (target != null) {
1507 target.setAppRestrictBackground(true);
1508 }
1509 }
1510 });
1511 builder.setNegativeButton(android.R.string.cancel, null);
1512
1513 return builder.create();
1514 }
1515 }
1516
1517 /**
Jeff Sharkeydd6efe12011-06-15 10:31:41 -07001518 * Compute default tab that should be selected, based on
1519 * {@link NetworkPolicyManager#EXTRA_NETWORK_TEMPLATE} extra.
1520 */
1521 private static String computeTabFromIntent(Intent intent) {
Jeff Sharkey271ec8a2011-07-20 16:59:16 -07001522 final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE);
1523 if (template == null) return null;
1524
1525 switch (template.getMatchRule()) {
Jeff Sharkeya662e492011-06-18 21:57:06 -07001526 case MATCH_MOBILE_3G_LOWER:
Jeff Sharkeydd6efe12011-06-15 10:31:41 -07001527 return TAB_3G;
Jeff Sharkeya662e492011-06-18 21:57:06 -07001528 case MATCH_MOBILE_4G:
Jeff Sharkeydd6efe12011-06-15 10:31:41 -07001529 return TAB_4G;
Jeff Sharkeya662e492011-06-18 21:57:06 -07001530 case MATCH_MOBILE_ALL:
Jeff Sharkeydd6efe12011-06-15 10:31:41 -07001531 return TAB_MOBILE;
Jeff Sharkeya662e492011-06-18 21:57:06 -07001532 case MATCH_WIFI:
Jeff Sharkeydd6efe12011-06-15 10:31:41 -07001533 return TAB_WIFI;
1534 default:
1535 return null;
1536 }
1537 }
1538
1539 /**
Jeff Sharkey8e911d72011-06-14 22:41:21 -07001540 * Resolve best descriptive label for the given UID.
1541 */
Jeff Sharkey518bc9d2011-07-12 20:20:46 -07001542 public static CharSequence resolveLabelForUid(Context context, int uid) {
1543 final Resources res = context.getResources();
1544 final PackageManager pm = context.getPackageManager();
1545
1546 // handle special case labels
1547 switch (uid) {
1548 case android.os.Process.SYSTEM_UID:
1549 return res.getText(R.string.process_kernel_label);
1550 case TrafficStats.UID_REMOVED:
1551 return res.getText(R.string.data_usage_uninstalled_apps);
1552 }
1553
1554 // otherwise fall back to using packagemanager labels
Jeff Sharkey8e911d72011-06-14 22:41:21 -07001555 final String[] packageNames = pm.getPackagesForUid(uid);
1556 final int length = packageNames != null ? packageNames.length : 0;
1557
1558 CharSequence label = pm.getNameForUid(uid);
1559 try {
1560 if (length == 1) {
1561 final ApplicationInfo info = pm.getApplicationInfo(packageNames[0], 0);
1562 label = info.loadLabel(pm);
1563 } else if (length > 1) {
1564 for (String packageName : packageNames) {
1565 final PackageInfo info = pm.getPackageInfo(packageName, 0);
1566 if (info.sharedUserLabel != 0) {
1567 label = pm.getText(packageName, info.sharedUserLabel, info.applicationInfo);
1568 if (!TextUtils.isEmpty(label)) {
1569 break;
1570 }
1571 }
1572 }
1573 }
1574 } catch (NameNotFoundException e) {
1575 }
1576
1577 if (TextUtils.isEmpty(label)) {
1578 label = Integer.toString(uid);
1579 }
1580 return label;
1581 }
1582
Jeff Sharkey29d56b32011-06-20 17:06:52 -07001583 /**
1584 * Test if device has a mobile data radio.
1585 */
1586 private static boolean hasMobileRadio(Context context) {
Jeff Sharkey9549e9f2011-07-14 20:01:13 -07001587 if (TEST_RADIOS) {
1588 return SystemProperties.get(TEST_RADIOS_PROP).contains("mobile");
1589 }
1590
Jeff Sharkey29d56b32011-06-20 17:06:52 -07001591 final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(
1592 Context.CONNECTIVITY_SERVICE);
1593
1594 // mobile devices should have MOBILE network tracker regardless of
1595 // connection status.
1596 return conn.getNetworkInfo(TYPE_MOBILE) != null;
1597 }
1598
1599 /**
1600 * Test if device has a mobile 4G data radio.
1601 */
1602 private static boolean hasMobile4gRadio(Context context) {
Jeff Sharkey9549e9f2011-07-14 20:01:13 -07001603 if (TEST_RADIOS) {
1604 return SystemProperties.get(TEST_RADIOS_PROP).contains("4g");
1605 }
1606
Jeff Sharkey29d56b32011-06-20 17:06:52 -07001607 final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(
1608 Context.CONNECTIVITY_SERVICE);
1609 final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
1610 Context.TELEPHONY_SERVICE);
1611
1612 // WiMAX devices should have WiMAX network tracker regardless of
1613 // connection status.
1614 final boolean hasWimax = conn.getNetworkInfo(TYPE_WIMAX) != null;
1615 final boolean hasLte = telephony.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE;
1616 return hasWimax || hasLte;
1617 }
1618
1619 /**
1620 * Test if device has a Wi-Fi data radio.
1621 */
1622 private static boolean hasWifiRadio(Context context) {
Jeff Sharkey9549e9f2011-07-14 20:01:13 -07001623 if (TEST_RADIOS) {
1624 return SystemProperties.get(TEST_RADIOS_PROP).contains("wifi");
1625 }
1626
Jeff Sharkey29d56b32011-06-20 17:06:52 -07001627 return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
1628 }
1629
1630 /**
Jeff Sharkey9549e9f2011-07-14 20:01:13 -07001631 * Test if device has an ethernet network connection.
1632 */
1633 private static boolean hasEthernet(Context context) {
1634 if (TEST_RADIOS) {
1635 return SystemProperties.get(TEST_RADIOS_PROP).contains("ethernet");
1636 }
1637
1638 final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(
1639 Context.CONNECTIVITY_SERVICE);
1640 return conn.getNetworkInfo(TYPE_ETHERNET) != null;
1641 }
1642
1643 /**
Jeff Sharkey29d56b32011-06-20 17:06:52 -07001644 * Inflate a {@link Preference} style layout, adding the given {@link View}
1645 * widget into {@link android.R.id#widget_frame}.
1646 */
1647 private static View inflatePreference(LayoutInflater inflater, ViewGroup root, View widget) {
1648 final View view = inflater.inflate(R.layout.preference, root, false);
1649 final LinearLayout widgetFrame = (LinearLayout) view.findViewById(
1650 android.R.id.widget_frame);
1651 widgetFrame.addView(widget, new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
1652 return view;
1653 }
1654
1655 /**
1656 * Set {@link android.R.id#title} for a preference view inflated with
Jeff Sharkey52c3f442011-06-23 00:39:38 -07001657 * {@link #inflatePreference(LayoutInflater, ViewGroup, View)}.
Jeff Sharkey29d56b32011-06-20 17:06:52 -07001658 */
1659 private static void setPreferenceTitle(View parent, int resId) {
1660 final TextView title = (TextView) parent.findViewById(android.R.id.title);
1661 title.setText(resId);
1662 }
1663
Jeff Sharkeyf54f4352011-06-23 22:15:54 -07001664 /**
1665 * Set {@link android.R.id#summary} for a preference view inflated with
1666 * {@link #inflatePreference(LayoutInflater, ViewGroup, View)}.
1667 */
1668 private static void setPreferenceSummary(View parent, int resId) {
1669 final TextView summary = (TextView) parent.findViewById(android.R.id.summary);
1670 summary.setVisibility(View.VISIBLE);
1671 summary.setText(resId);
1672 }
Jeff Sharkeyab2d8d32011-05-30 16:19:56 -07001673}