blob: 0d15dac1570d14c442bd1c75adc401638af09864 [file] [log] [blame]
Jeff Sharkey4dfa6602011-06-13 00:42:03 -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
19import static android.net.NetworkPolicyManager.POLICY_NONE;
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -070020import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070021import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
22import static com.android.settings.DataUsageSummary.getHistoryBounds;
23
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070024import android.app.AlertDialog;
25import android.app.Dialog;
26import android.app.DialogFragment;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070027import android.app.Fragment;
28import android.content.Context;
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070029import android.content.DialogInterface;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070030import android.content.Intent;
31import android.content.pm.PackageManager;
32import android.graphics.Color;
33import android.net.INetworkPolicyManager;
34import android.net.INetworkStatsService;
Jeff Sharkey8e911d72011-06-14 22:41:21 -070035import android.net.NetworkPolicyManager;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070036import android.net.NetworkStatsHistory;
37import android.os.Bundle;
38import android.os.RemoteException;
39import android.os.ServiceManager;
40import android.preference.CheckBoxPreference;
41import android.preference.Preference;
42import android.text.format.DateUtils;
43import android.text.format.Formatter;
44import android.util.Log;
45import android.view.LayoutInflater;
46import android.view.View;
47import android.view.View.OnClickListener;
48import android.view.ViewGroup;
49import android.widget.Button;
50import android.widget.FrameLayout;
51import android.widget.LinearLayout;
52import android.widget.TextView;
53
54import com.android.settings.widget.DataUsageChartView;
55import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
56
57public class DataUsageAppDetail extends Fragment {
58 private static final String TAG = "DataUsage";
59 private static final boolean LOGD = true;
60
61 private int mUid;
Jeff Sharkey8e911d72011-06-14 22:41:21 -070062 private Intent mAppSettingsIntent;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070063
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070064 private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict";
65
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070066 private INetworkStatsService mStatsService;
67 private INetworkPolicyManager mPolicyService;
68
69 private CheckBoxPreference mRestrictBackground;
70 private View mRestrictBackgroundView;
71
72 private FrameLayout mChartContainer;
73 private TextView mTitle;
74 private TextView mText1;
75 private Button mAppSettings;
76 private LinearLayout mSwitches;
77
78 private DataUsageChartView mChart;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070079 private NetworkStatsHistory mHistory;
80
81 @Override
82 public void onCreate(Bundle savedInstanceState) {
83 super.onCreate(savedInstanceState);
84
85 mStatsService = INetworkStatsService.Stub.asInterface(
86 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
87 mPolicyService = INetworkPolicyManager.Stub.asInterface(
88 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
89 }
90
91 @Override
92 public View onCreateView(LayoutInflater inflater, ViewGroup container,
93 Bundle savedInstanceState) {
94
95 final Context context = inflater.getContext();
96 final View view = inflater.inflate(R.layout.data_usage_detail, container, false);
97
98 mChartContainer = (FrameLayout) view.findViewById(R.id.chart_container);
99 mTitle = (TextView) view.findViewById(android.R.id.title);
100 mText1 = (TextView) view.findViewById(android.R.id.text1);
101 mAppSettings = (Button) view.findViewById(R.id.data_usage_app_settings);
102 mSwitches = (LinearLayout) view.findViewById(R.id.switches);
103
104 mRestrictBackground = new CheckBoxPreference(context);
105 mRestrictBackground.setTitle(R.string.data_usage_app_restrict_background);
106 mRestrictBackground.setSummary(R.string.data_usage_app_restrict_background_summary);
107
108 // kick refresh once to force-create views
109 refreshPreferenceViews();
110
111 mSwitches.addView(mRestrictBackgroundView);
112 mRestrictBackgroundView.setOnClickListener(mRestrictBackgroundListener);
113
114 mAppSettings.setOnClickListener(mAppSettingsListener);
115
116 mChart = new DataUsageChartView(context);
117 mChartContainer.addView(mChart);
118
119 mChart.setListener(mChartListener);
120 mChart.setChartColor(Color.parseColor("#d88d3a"), Color.parseColor("#c0ba7f3e"),
121 Color.parseColor("#88566abc"));
122
123 return view;
124 }
125
126 @Override
127 public void onResume() {
128 super.onResume();
129
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700130 updateBody();
131 }
132
133 private void updateBody() {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700134 final PackageManager pm = getActivity().getPackageManager();
135
136 mUid = getArguments().getInt(Intent.EXTRA_UID);
137 mTitle.setText(pm.getNameForUid(mUid));
138
139 // enable settings button when package provides it
140 // TODO: target torwards entire UID instead of just first package
141 final String[] packageNames = pm.getPackagesForUid(mUid);
142 if (packageNames != null && packageNames.length > 0) {
143 mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
144 mAppSettingsIntent.setPackage(packageNames[0]);
145 mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
146
147 final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null;
148 mAppSettings.setEnabled(matchFound);
149
150 } else {
151 mAppSettingsIntent = null;
152 mAppSettings.setEnabled(false);
153 }
154
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700155 try {
156 // load stats for current uid and template
157 // TODO: read template from extras
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700158 mHistory = mStatsService.getHistoryForUid(mUid, TEMPLATE_MOBILE_ALL);
159 } catch (RemoteException e) {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700160 // since we can't do much without history, and we don't want to
161 // leave with half-baked UI, we bail hard.
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700162 throw new RuntimeException("problem reading network stats", e);
163 }
164
165 // bind chart to historical stats
166 mChart.bindNetworkStats(mHistory);
167
168 // show entire history known
169 final long[] bounds = getHistoryBounds(mHistory);
170 mChart.setVisibleRange(bounds[0], bounds[1] + DateUtils.WEEK_IN_MILLIS, bounds[1]);
171 updateDetailData();
172
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700173 final Context context = getActivity();
174 if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) {
175 mRestrictBackgroundView.setVisibility(View.VISIBLE);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700176
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700177 final int uidPolicy;
178 try {
179 uidPolicy = mPolicyService.getUidPolicy(mUid);
180 } catch (RemoteException e) {
181 // since we can't do much without policy, we bail hard.
182 throw new RuntimeException("problem reading network policy", e);
183 }
184
185 // update policy checkbox
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700186 final boolean restrictBackground = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700187 mRestrictBackground.setChecked(restrictBackground);
188
189 // kick preference views so they rebind from changes above
190 refreshPreferenceViews();
191
192 } else {
193 mRestrictBackgroundView.setVisibility(View.GONE);
194 }
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700195 }
196
197 private void updateDetailData() {
198 if (LOGD) Log.d(TAG, "updateDetailData()");
199
200 final Context context = mChart.getContext();
201 final long[] range = mChart.getInspectRange();
202 final long[] total = mHistory.getTotalData(range[0], range[1], null);
203 final long totalCombined = total[0] + total[1];
204 mText1.setText(Formatter.formatFileSize(context, totalCombined));
205 }
206
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700207 private void setRestrictBackground(boolean restrictBackground) {
208 if (LOGD) Log.d(TAG, "setRestrictBackground()");
209 try {
210 mPolicyService.setUidPolicy(
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700211 mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700212 } catch (RemoteException e) {
213 throw new RuntimeException("unable to save policy", e);
214 }
215
216 mRestrictBackground.setChecked(restrictBackground);
217 refreshPreferenceViews();
218 }
219
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700220 /**
221 * Force rebind of hijacked {@link Preference} views.
222 */
223 private void refreshPreferenceViews() {
224 mRestrictBackgroundView = mRestrictBackground.getView(mRestrictBackgroundView, mSwitches);
225 }
226
227 private DataUsageChartListener mChartListener = new DataUsageChartListener() {
228 /** {@inheritDoc} */
229 public void onInspectRangeChanged() {
230 if (LOGD) Log.d(TAG, "onInspectRangeChanged()");
231 updateDetailData();
232 }
233
234 /** {@inheritDoc} */
235 public void onWarningChanged() {
236 // ignored
237 }
238
239 /** {@inheritDoc} */
240 public void onLimitChanged() {
241 // ignored
242 }
243 };
244
245 private OnClickListener mAppSettingsListener = new OnClickListener() {
246 /** {@inheritDoc} */
247 public void onClick(View v) {
248 // TODO: target torwards entire UID instead of just first package
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700249 startActivity(mAppSettingsIntent);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700250 }
251 };
252
253 private OnClickListener mRestrictBackgroundListener = new OnClickListener() {
254 /** {@inheritDoc} */
255 public void onClick(View v) {
256 final boolean restrictBackground = !mRestrictBackground.isChecked();
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700257
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700258 if (restrictBackground) {
259 // enabling restriction; show confirmation dialog which
260 // eventually calls setRestrictBackground() once user confirms.
261 ConfirmRestrictFragment.show(DataUsageAppDetail.this);
262 } else {
263 setRestrictBackground(false);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700264 }
265 }
266 };
267
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700268 /**
269 * Dialog to request user confirmation before setting
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700270 * {@link #POLICY_REJECT_METERED_BACKGROUND}.
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700271 */
272 public static class ConfirmRestrictFragment extends DialogFragment {
273 public static void show(DataUsageAppDetail parent) {
274 final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
275 dialog.setTargetFragment(parent, 0);
276 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
277 }
278
279 @Override
280 public Dialog onCreateDialog(Bundle savedInstanceState) {
281 final Context context = getActivity();
282
283 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
284 builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
285 builder.setMessage(R.string.data_usage_app_restrict_dialog);
286
287 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
288 public void onClick(DialogInterface dialog, int which) {
289 final DataUsageAppDetail target = (DataUsageAppDetail) getTargetFragment();
290 if (target != null) {
291 target.setRestrictBackground(true);
292 }
293 }
294 });
295 builder.setNegativeButton(android.R.string.cancel, null);
296
297 return builder.create();
298 }
299 }
300
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700301}