blob: a683561eade552e767d63e93c645258375f569eb [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 com.android.settings.DataUsageSummary.getHistoryBounds;
22
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070023import android.app.AlertDialog;
24import android.app.Dialog;
25import android.app.DialogFragment;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070026import android.app.Fragment;
27import android.content.Context;
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070028import android.content.DialogInterface;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070029import android.content.Intent;
30import android.content.pm.PackageManager;
31import android.graphics.Color;
32import android.net.INetworkPolicyManager;
33import android.net.INetworkStatsService;
Jeff Sharkey8e911d72011-06-14 22:41:21 -070034import android.net.NetworkPolicyManager;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070035import android.net.NetworkStatsHistory;
Jeff Sharkeya662e492011-06-18 21:57:06 -070036import android.net.NetworkTemplate;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070037import 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
Jeff Sharkeya662e492011-06-18 21:57:06 -070061 public static final String EXTRA_UID = "uid";
62 public static final String EXTRA_NETWORK_TEMPLATE = "networkTemplate";
63
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070064 private int mUid;
Jeff Sharkeya662e492011-06-18 21:57:06 -070065 private NetworkTemplate mTemplate;
66
Jeff Sharkey8e911d72011-06-14 22:41:21 -070067 private Intent mAppSettingsIntent;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070068
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070069 private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict";
70
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070071 private INetworkStatsService mStatsService;
72 private INetworkPolicyManager mPolicyService;
73
74 private CheckBoxPreference mRestrictBackground;
75 private View mRestrictBackgroundView;
76
77 private FrameLayout mChartContainer;
78 private TextView mTitle;
79 private TextView mText1;
80 private Button mAppSettings;
81 private LinearLayout mSwitches;
82
83 private DataUsageChartView mChart;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070084 private NetworkStatsHistory mHistory;
85
86 @Override
87 public void onCreate(Bundle savedInstanceState) {
88 super.onCreate(savedInstanceState);
89
90 mStatsService = INetworkStatsService.Stub.asInterface(
91 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
92 mPolicyService = INetworkPolicyManager.Stub.asInterface(
93 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
94 }
95
96 @Override
97 public View onCreateView(LayoutInflater inflater, ViewGroup container,
98 Bundle savedInstanceState) {
99
100 final Context context = inflater.getContext();
101 final View view = inflater.inflate(R.layout.data_usage_detail, container, false);
102
103 mChartContainer = (FrameLayout) view.findViewById(R.id.chart_container);
104 mTitle = (TextView) view.findViewById(android.R.id.title);
105 mText1 = (TextView) view.findViewById(android.R.id.text1);
106 mAppSettings = (Button) view.findViewById(R.id.data_usage_app_settings);
107 mSwitches = (LinearLayout) view.findViewById(R.id.switches);
108
109 mRestrictBackground = new CheckBoxPreference(context);
110 mRestrictBackground.setTitle(R.string.data_usage_app_restrict_background);
111 mRestrictBackground.setSummary(R.string.data_usage_app_restrict_background_summary);
112
113 // kick refresh once to force-create views
114 refreshPreferenceViews();
115
116 mSwitches.addView(mRestrictBackgroundView);
117 mRestrictBackgroundView.setOnClickListener(mRestrictBackgroundListener);
118
119 mAppSettings.setOnClickListener(mAppSettingsListener);
120
121 mChart = new DataUsageChartView(context);
122 mChartContainer.addView(mChart);
123
124 mChart.setListener(mChartListener);
125 mChart.setChartColor(Color.parseColor("#d88d3a"), Color.parseColor("#c0ba7f3e"),
126 Color.parseColor("#88566abc"));
127
128 return view;
129 }
130
131 @Override
132 public void onResume() {
133 super.onResume();
134
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700135 updateBody();
136 }
137
138 private void updateBody() {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700139 final PackageManager pm = getActivity().getPackageManager();
140
Jeff Sharkeya662e492011-06-18 21:57:06 -0700141 mUid = getArguments().getInt(EXTRA_UID);
142 mTemplate = getArguments().getParcelable(EXTRA_NETWORK_TEMPLATE);
143
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700144 mTitle.setText(pm.getNameForUid(mUid));
145
146 // enable settings button when package provides it
147 // TODO: target torwards entire UID instead of just first package
148 final String[] packageNames = pm.getPackagesForUid(mUid);
149 if (packageNames != null && packageNames.length > 0) {
150 mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
151 mAppSettingsIntent.setPackage(packageNames[0]);
152 mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
153
154 final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null;
155 mAppSettings.setEnabled(matchFound);
156
157 } else {
158 mAppSettingsIntent = null;
159 mAppSettings.setEnabled(false);
160 }
161
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700162 try {
163 // load stats for current uid and template
164 // TODO: read template from extras
Jeff Sharkeya662e492011-06-18 21:57:06 -0700165 mHistory = mStatsService.getHistoryForUid(mTemplate, mUid);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700166 } catch (RemoteException e) {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700167 // since we can't do much without history, and we don't want to
168 // leave with half-baked UI, we bail hard.
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700169 throw new RuntimeException("problem reading network stats", e);
170 }
171
172 // bind chart to historical stats
173 mChart.bindNetworkStats(mHistory);
174
175 // show entire history known
176 final long[] bounds = getHistoryBounds(mHistory);
177 mChart.setVisibleRange(bounds[0], bounds[1] + DateUtils.WEEK_IN_MILLIS, bounds[1]);
178 updateDetailData();
179
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700180 final Context context = getActivity();
181 if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) {
182 mRestrictBackgroundView.setVisibility(View.VISIBLE);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700183
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700184 final int uidPolicy;
185 try {
186 uidPolicy = mPolicyService.getUidPolicy(mUid);
187 } catch (RemoteException e) {
188 // since we can't do much without policy, we bail hard.
189 throw new RuntimeException("problem reading network policy", e);
190 }
191
192 // update policy checkbox
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700193 final boolean restrictBackground = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700194 mRestrictBackground.setChecked(restrictBackground);
195
196 // kick preference views so they rebind from changes above
197 refreshPreferenceViews();
198
199 } else {
200 mRestrictBackgroundView.setVisibility(View.GONE);
201 }
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700202 }
203
204 private void updateDetailData() {
205 if (LOGD) Log.d(TAG, "updateDetailData()");
206
207 final Context context = mChart.getContext();
208 final long[] range = mChart.getInspectRange();
209 final long[] total = mHistory.getTotalData(range[0], range[1], null);
210 final long totalCombined = total[0] + total[1];
211 mText1.setText(Formatter.formatFileSize(context, totalCombined));
212 }
213
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700214 private void setRestrictBackground(boolean restrictBackground) {
215 if (LOGD) Log.d(TAG, "setRestrictBackground()");
216 try {
217 mPolicyService.setUidPolicy(
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700218 mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700219 } catch (RemoteException e) {
220 throw new RuntimeException("unable to save policy", e);
221 }
222
223 mRestrictBackground.setChecked(restrictBackground);
224 refreshPreferenceViews();
225 }
226
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700227 /**
228 * Force rebind of hijacked {@link Preference} views.
229 */
230 private void refreshPreferenceViews() {
231 mRestrictBackgroundView = mRestrictBackground.getView(mRestrictBackgroundView, mSwitches);
232 }
233
234 private DataUsageChartListener mChartListener = new DataUsageChartListener() {
235 /** {@inheritDoc} */
236 public void onInspectRangeChanged() {
237 if (LOGD) Log.d(TAG, "onInspectRangeChanged()");
238 updateDetailData();
239 }
240
241 /** {@inheritDoc} */
242 public void onWarningChanged() {
243 // ignored
244 }
245
246 /** {@inheritDoc} */
247 public void onLimitChanged() {
248 // ignored
249 }
250 };
251
252 private OnClickListener mAppSettingsListener = new OnClickListener() {
253 /** {@inheritDoc} */
254 public void onClick(View v) {
255 // TODO: target torwards entire UID instead of just first package
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700256 startActivity(mAppSettingsIntent);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700257 }
258 };
259
260 private OnClickListener mRestrictBackgroundListener = new OnClickListener() {
261 /** {@inheritDoc} */
262 public void onClick(View v) {
263 final boolean restrictBackground = !mRestrictBackground.isChecked();
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700264
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700265 if (restrictBackground) {
266 // enabling restriction; show confirmation dialog which
267 // eventually calls setRestrictBackground() once user confirms.
268 ConfirmRestrictFragment.show(DataUsageAppDetail.this);
269 } else {
270 setRestrictBackground(false);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700271 }
272 }
273 };
274
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700275 /**
276 * Dialog to request user confirmation before setting
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700277 * {@link #POLICY_REJECT_METERED_BACKGROUND}.
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700278 */
279 public static class ConfirmRestrictFragment extends DialogFragment {
280 public static void show(DataUsageAppDetail parent) {
281 final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
282 dialog.setTargetFragment(parent, 0);
283 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
284 }
285
286 @Override
287 public Dialog onCreateDialog(Bundle savedInstanceState) {
288 final Context context = getActivity();
289
290 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
291 builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
292 builder.setMessage(R.string.data_usage_app_restrict_dialog);
293
294 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
295 public void onClick(DialogInterface dialog, int which) {
296 final DataUsageAppDetail target = (DataUsageAppDetail) getTargetFragment();
297 if (target != null) {
298 target.setRestrictBackground(true);
299 }
300 }
301 });
302 builder.setNegativeButton(android.R.string.cancel, null);
303
304 return builder.create();
305 }
306 }
307
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700308}