blob: cee54ee26690121f53297fa04d32f6a2183c6afb [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;
20import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
21import 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;
79
80 private int mUidPolicy;
81 private NetworkStatsHistory mHistory;
82
83 @Override
84 public void onCreate(Bundle savedInstanceState) {
85 super.onCreate(savedInstanceState);
86
87 mStatsService = INetworkStatsService.Stub.asInterface(
88 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
89 mPolicyService = INetworkPolicyManager.Stub.asInterface(
90 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
91 }
92
93 @Override
94 public View onCreateView(LayoutInflater inflater, ViewGroup container,
95 Bundle savedInstanceState) {
96
97 final Context context = inflater.getContext();
98 final View view = inflater.inflate(R.layout.data_usage_detail, container, false);
99
100 mChartContainer = (FrameLayout) view.findViewById(R.id.chart_container);
101 mTitle = (TextView) view.findViewById(android.R.id.title);
102 mText1 = (TextView) view.findViewById(android.R.id.text1);
103 mAppSettings = (Button) view.findViewById(R.id.data_usage_app_settings);
104 mSwitches = (LinearLayout) view.findViewById(R.id.switches);
105
106 mRestrictBackground = new CheckBoxPreference(context);
107 mRestrictBackground.setTitle(R.string.data_usage_app_restrict_background);
108 mRestrictBackground.setSummary(R.string.data_usage_app_restrict_background_summary);
109
110 // kick refresh once to force-create views
111 refreshPreferenceViews();
112
113 mSwitches.addView(mRestrictBackgroundView);
114 mRestrictBackgroundView.setOnClickListener(mRestrictBackgroundListener);
115
116 mAppSettings.setOnClickListener(mAppSettingsListener);
117
118 mChart = new DataUsageChartView(context);
119 mChartContainer.addView(mChart);
120
121 mChart.setListener(mChartListener);
122 mChart.setChartColor(Color.parseColor("#d88d3a"), Color.parseColor("#c0ba7f3e"),
123 Color.parseColor("#88566abc"));
124
125 return view;
126 }
127
128 @Override
129 public void onResume() {
130 super.onResume();
131
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700132 updateBody();
133 }
134
135 private void updateBody() {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700136 final PackageManager pm = getActivity().getPackageManager();
137
138 mUid = getArguments().getInt(Intent.EXTRA_UID);
139 mTitle.setText(pm.getNameForUid(mUid));
140
141 // enable settings button when package provides it
142 // TODO: target torwards entire UID instead of just first package
143 final String[] packageNames = pm.getPackagesForUid(mUid);
144 if (packageNames != null && packageNames.length > 0) {
145 mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
146 mAppSettingsIntent.setPackage(packageNames[0]);
147 mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
148
149 final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null;
150 mAppSettings.setEnabled(matchFound);
151
152 } else {
153 mAppSettingsIntent = null;
154 mAppSettings.setEnabled(false);
155 }
156
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700157 try {
158 // load stats for current uid and template
159 // TODO: read template from extras
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700160 mHistory = mStatsService.getHistoryForUid(mUid, TEMPLATE_MOBILE_ALL);
161 } catch (RemoteException e) {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700162 // since we can't do much without history, and we don't want to
163 // leave with half-baked UI, we bail hard.
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700164 throw new RuntimeException("problem reading network stats", e);
165 }
166
167 // bind chart to historical stats
168 mChart.bindNetworkStats(mHistory);
169
170 // show entire history known
171 final long[] bounds = getHistoryBounds(mHistory);
172 mChart.setVisibleRange(bounds[0], bounds[1] + DateUtils.WEEK_IN_MILLIS, bounds[1]);
173 updateDetailData();
174
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700175 final Context context = getActivity();
176 if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) {
177 mRestrictBackgroundView.setVisibility(View.VISIBLE);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700178
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700179 final int uidPolicy;
180 try {
181 uidPolicy = mPolicyService.getUidPolicy(mUid);
182 } catch (RemoteException e) {
183 // since we can't do much without policy, we bail hard.
184 throw new RuntimeException("problem reading network policy", e);
185 }
186
187 // update policy checkbox
188 final boolean restrictBackground = (mUidPolicy & POLICY_REJECT_PAID_BACKGROUND) != 0;
189 mRestrictBackground.setChecked(restrictBackground);
190
191 // kick preference views so they rebind from changes above
192 refreshPreferenceViews();
193
194 } else {
195 mRestrictBackgroundView.setVisibility(View.GONE);
196 }
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700197 }
198
199 private void updateDetailData() {
200 if (LOGD) Log.d(TAG, "updateDetailData()");
201
202 final Context context = mChart.getContext();
203 final long[] range = mChart.getInspectRange();
204 final long[] total = mHistory.getTotalData(range[0], range[1], null);
205 final long totalCombined = total[0] + total[1];
206 mText1.setText(Formatter.formatFileSize(context, totalCombined));
207 }
208
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700209 private void setRestrictBackground(boolean restrictBackground) {
210 if (LOGD) Log.d(TAG, "setRestrictBackground()");
211 try {
212 mPolicyService.setUidPolicy(
213 mUid, restrictBackground ? POLICY_REJECT_PAID_BACKGROUND : POLICY_NONE);
214 } catch (RemoteException e) {
215 throw new RuntimeException("unable to save policy", e);
216 }
217
218 mRestrictBackground.setChecked(restrictBackground);
219 refreshPreferenceViews();
220 }
221
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700222 /**
223 * Force rebind of hijacked {@link Preference} views.
224 */
225 private void refreshPreferenceViews() {
226 mRestrictBackgroundView = mRestrictBackground.getView(mRestrictBackgroundView, mSwitches);
227 }
228
229 private DataUsageChartListener mChartListener = new DataUsageChartListener() {
230 /** {@inheritDoc} */
231 public void onInspectRangeChanged() {
232 if (LOGD) Log.d(TAG, "onInspectRangeChanged()");
233 updateDetailData();
234 }
235
236 /** {@inheritDoc} */
237 public void onWarningChanged() {
238 // ignored
239 }
240
241 /** {@inheritDoc} */
242 public void onLimitChanged() {
243 // ignored
244 }
245 };
246
247 private OnClickListener mAppSettingsListener = new OnClickListener() {
248 /** {@inheritDoc} */
249 public void onClick(View v) {
250 // TODO: target torwards entire UID instead of just first package
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700251 startActivity(mAppSettingsIntent);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700252 }
253 };
254
255 private OnClickListener mRestrictBackgroundListener = new OnClickListener() {
256 /** {@inheritDoc} */
257 public void onClick(View v) {
258 final boolean restrictBackground = !mRestrictBackground.isChecked();
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700259
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700260 if (restrictBackground) {
261 // enabling restriction; show confirmation dialog which
262 // eventually calls setRestrictBackground() once user confirms.
263 ConfirmRestrictFragment.show(DataUsageAppDetail.this);
264 } else {
265 setRestrictBackground(false);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700266 }
267 }
268 };
269
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700270 /**
271 * Dialog to request user confirmation before setting
272 * {@link #POLICY_REJECT_PAID_BACKGROUND}.
273 */
274 public static class ConfirmRestrictFragment extends DialogFragment {
275 public static void show(DataUsageAppDetail parent) {
276 final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
277 dialog.setTargetFragment(parent, 0);
278 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
279 }
280
281 @Override
282 public Dialog onCreateDialog(Bundle savedInstanceState) {
283 final Context context = getActivity();
284
285 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
286 builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
287 builder.setMessage(R.string.data_usage_app_restrict_dialog);
288
289 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
290 public void onClick(DialogInterface dialog, int which) {
291 final DataUsageAppDetail target = (DataUsageAppDetail) getTargetFragment();
292 if (target != null) {
293 target.setRestrictBackground(true);
294 }
295 }
296 });
297 builder.setNegativeButton(android.R.string.cancel, null);
298
299 return builder.create();
300 }
301 }
302
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700303}