blob: 6294ad348debfa5553d3637b9ffb4b9b64724de0 [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 Sharkey827fde32011-06-19 20:56:31 -070035import android.net.NetworkStats;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070036import android.net.NetworkStatsHistory;
Jeff Sharkeya662e492011-06-18 21:57:06 -070037import android.net.NetworkTemplate;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070038import android.os.Bundle;
39import android.os.RemoteException;
40import android.os.ServiceManager;
41import android.preference.CheckBoxPreference;
42import android.preference.Preference;
43import android.text.format.DateUtils;
44import android.text.format.Formatter;
45import android.util.Log;
46import android.view.LayoutInflater;
47import android.view.View;
48import android.view.View.OnClickListener;
49import android.view.ViewGroup;
50import android.widget.Button;
51import android.widget.FrameLayout;
52import android.widget.LinearLayout;
53import android.widget.TextView;
54
55import com.android.settings.widget.DataUsageChartView;
56import com.android.settings.widget.DataUsageChartView.DataUsageChartListener;
57
58public class DataUsageAppDetail extends Fragment {
59 private static final String TAG = "DataUsage";
60 private static final boolean LOGD = true;
61
Jeff Sharkeya662e492011-06-18 21:57:06 -070062 public static final String EXTRA_UID = "uid";
63 public static final String EXTRA_NETWORK_TEMPLATE = "networkTemplate";
64
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070065 private int mUid;
Jeff Sharkeya662e492011-06-18 21:57:06 -070066 private NetworkTemplate mTemplate;
67
Jeff Sharkey8e911d72011-06-14 22:41:21 -070068 private Intent mAppSettingsIntent;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070069
Jeff Sharkey4c72ae52011-06-14 15:01:18 -070070 private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict";
71
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070072 private INetworkStatsService mStatsService;
73 private INetworkPolicyManager mPolicyService;
74
75 private CheckBoxPreference mRestrictBackground;
76 private View mRestrictBackgroundView;
77
78 private FrameLayout mChartContainer;
79 private TextView mTitle;
80 private TextView mText1;
81 private Button mAppSettings;
82 private LinearLayout mSwitches;
83
84 private DataUsageChartView mChart;
Jeff Sharkey4dfa6602011-06-13 00:42:03 -070085 private NetworkStatsHistory mHistory;
86
87 @Override
88 public void onCreate(Bundle savedInstanceState) {
89 super.onCreate(savedInstanceState);
90
91 mStatsService = INetworkStatsService.Stub.asInterface(
92 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
93 mPolicyService = INetworkPolicyManager.Stub.asInterface(
94 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
95 }
96
97 @Override
98 public View onCreateView(LayoutInflater inflater, ViewGroup container,
99 Bundle savedInstanceState) {
100
101 final Context context = inflater.getContext();
102 final View view = inflater.inflate(R.layout.data_usage_detail, container, false);
103
104 mChartContainer = (FrameLayout) view.findViewById(R.id.chart_container);
105 mTitle = (TextView) view.findViewById(android.R.id.title);
106 mText1 = (TextView) view.findViewById(android.R.id.text1);
107 mAppSettings = (Button) view.findViewById(R.id.data_usage_app_settings);
108 mSwitches = (LinearLayout) view.findViewById(R.id.switches);
109
110 mRestrictBackground = new CheckBoxPreference(context);
111 mRestrictBackground.setTitle(R.string.data_usage_app_restrict_background);
112 mRestrictBackground.setSummary(R.string.data_usage_app_restrict_background_summary);
113
114 // kick refresh once to force-create views
115 refreshPreferenceViews();
116
117 mSwitches.addView(mRestrictBackgroundView);
118 mRestrictBackgroundView.setOnClickListener(mRestrictBackgroundListener);
119
120 mAppSettings.setOnClickListener(mAppSettingsListener);
121
122 mChart = new DataUsageChartView(context);
123 mChartContainer.addView(mChart);
124
125 mChart.setListener(mChartListener);
126 mChart.setChartColor(Color.parseColor("#d88d3a"), Color.parseColor("#c0ba7f3e"),
127 Color.parseColor("#88566abc"));
128
129 return view;
130 }
131
132 @Override
133 public void onResume() {
134 super.onResume();
135
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700136 updateBody();
137 }
138
139 private void updateBody() {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700140 final PackageManager pm = getActivity().getPackageManager();
141
Jeff Sharkeya662e492011-06-18 21:57:06 -0700142 mUid = getArguments().getInt(EXTRA_UID);
143 mTemplate = getArguments().getParcelable(EXTRA_NETWORK_TEMPLATE);
144
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700145 mTitle.setText(pm.getNameForUid(mUid));
146
147 // enable settings button when package provides it
148 // TODO: target torwards entire UID instead of just first package
149 final String[] packageNames = pm.getPackagesForUid(mUid);
150 if (packageNames != null && packageNames.length > 0) {
151 mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
152 mAppSettingsIntent.setPackage(packageNames[0]);
153 mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
154
155 final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null;
156 mAppSettings.setEnabled(matchFound);
157
158 } else {
159 mAppSettingsIntent = null;
160 mAppSettings.setEnabled(false);
161 }
162
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700163 try {
164 // load stats for current uid and template
165 // TODO: read template from extras
Jeff Sharkey827fde32011-06-19 20:56:31 -0700166 mHistory = mStatsService.getHistoryForUid(mTemplate, mUid, NetworkStats.TAG_NONE);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700167 } catch (RemoteException e) {
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700168 // since we can't do much without history, and we don't want to
169 // leave with half-baked UI, we bail hard.
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700170 throw new RuntimeException("problem reading network stats", e);
171 }
172
173 // bind chart to historical stats
174 mChart.bindNetworkStats(mHistory);
175
176 // show entire history known
177 final long[] bounds = getHistoryBounds(mHistory);
178 mChart.setVisibleRange(bounds[0], bounds[1] + DateUtils.WEEK_IN_MILLIS, bounds[1]);
179 updateDetailData();
180
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700181 final Context context = getActivity();
182 if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) {
183 mRestrictBackgroundView.setVisibility(View.VISIBLE);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700184
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700185 final int uidPolicy;
186 try {
187 uidPolicy = mPolicyService.getUidPolicy(mUid);
188 } catch (RemoteException e) {
189 // since we can't do much without policy, we bail hard.
190 throw new RuntimeException("problem reading network policy", e);
191 }
192
193 // update policy checkbox
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700194 final boolean restrictBackground = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700195 mRestrictBackground.setChecked(restrictBackground);
196
197 // kick preference views so they rebind from changes above
198 refreshPreferenceViews();
199
200 } else {
201 mRestrictBackgroundView.setVisibility(View.GONE);
202 }
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700203 }
204
205 private void updateDetailData() {
206 if (LOGD) Log.d(TAG, "updateDetailData()");
207
208 final Context context = mChart.getContext();
209 final long[] range = mChart.getInspectRange();
210 final long[] total = mHistory.getTotalData(range[0], range[1], null);
211 final long totalCombined = total[0] + total[1];
212 mText1.setText(Formatter.formatFileSize(context, totalCombined));
213 }
214
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700215 private void setRestrictBackground(boolean restrictBackground) {
216 if (LOGD) Log.d(TAG, "setRestrictBackground()");
217 try {
218 mPolicyService.setUidPolicy(
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700219 mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700220 } catch (RemoteException e) {
221 throw new RuntimeException("unable to save policy", e);
222 }
223
224 mRestrictBackground.setChecked(restrictBackground);
225 refreshPreferenceViews();
226 }
227
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700228 /**
229 * Force rebind of hijacked {@link Preference} views.
230 */
231 private void refreshPreferenceViews() {
232 mRestrictBackgroundView = mRestrictBackground.getView(mRestrictBackgroundView, mSwitches);
233 }
234
235 private DataUsageChartListener mChartListener = new DataUsageChartListener() {
236 /** {@inheritDoc} */
237 public void onInspectRangeChanged() {
238 if (LOGD) Log.d(TAG, "onInspectRangeChanged()");
239 updateDetailData();
240 }
241
242 /** {@inheritDoc} */
243 public void onWarningChanged() {
244 // ignored
245 }
246
247 /** {@inheritDoc} */
248 public void onLimitChanged() {
249 // ignored
250 }
251 };
252
253 private OnClickListener mAppSettingsListener = new OnClickListener() {
254 /** {@inheritDoc} */
255 public void onClick(View v) {
256 // TODO: target torwards entire UID instead of just first package
Jeff Sharkey8e911d72011-06-14 22:41:21 -0700257 startActivity(mAppSettingsIntent);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700258 }
259 };
260
261 private OnClickListener mRestrictBackgroundListener = new OnClickListener() {
262 /** {@inheritDoc} */
263 public void onClick(View v) {
264 final boolean restrictBackground = !mRestrictBackground.isChecked();
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700265
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700266 if (restrictBackground) {
267 // enabling restriction; show confirmation dialog which
268 // eventually calls setRestrictBackground() once user confirms.
269 ConfirmRestrictFragment.show(DataUsageAppDetail.this);
270 } else {
271 setRestrictBackground(false);
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700272 }
273 }
274 };
275
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700276 /**
277 * Dialog to request user confirmation before setting
Jeff Sharkey1a3e41d2011-06-16 15:08:08 -0700278 * {@link #POLICY_REJECT_METERED_BACKGROUND}.
Jeff Sharkey4c72ae52011-06-14 15:01:18 -0700279 */
280 public static class ConfirmRestrictFragment extends DialogFragment {
281 public static void show(DataUsageAppDetail parent) {
282 final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment();
283 dialog.setTargetFragment(parent, 0);
284 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT);
285 }
286
287 @Override
288 public Dialog onCreateDialog(Bundle savedInstanceState) {
289 final Context context = getActivity();
290
291 final AlertDialog.Builder builder = new AlertDialog.Builder(context);
292 builder.setTitle(R.string.data_usage_app_restrict_dialog_title);
293 builder.setMessage(R.string.data_usage_app_restrict_dialog);
294
295 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
296 public void onClick(DialogInterface dialog, int which) {
297 final DataUsageAppDetail target = (DataUsageAppDetail) getTargetFragment();
298 if (target != null) {
299 target.setRestrictBackground(true);
300 }
301 }
302 });
303 builder.setNegativeButton(android.R.string.cancel, null);
304
305 return builder.create();
306 }
307 }
308
Jeff Sharkey4dfa6602011-06-13 00:42:03 -0700309}