diff options
Diffstat (limited to 'src/com/android/settings/DataUsageAppDetail.java')
-rw-r--r-- | src/com/android/settings/DataUsageAppDetail.java | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/com/android/settings/DataUsageAppDetail.java b/src/com/android/settings/DataUsageAppDetail.java new file mode 100644 index 0000000..6294ad3 --- /dev/null +++ b/src/com/android/settings/DataUsageAppDetail.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings; + +import static android.net.NetworkPolicyManager.POLICY_NONE; +import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; +import static com.android.settings.DataUsageSummary.getHistoryBounds; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.Fragment; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.net.INetworkPolicyManager; +import android.net.INetworkStatsService; +import android.net.NetworkPolicyManager; +import android.net.NetworkStats; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.text.format.DateUtils; +import android.text.format.Formatter; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.settings.widget.DataUsageChartView; +import com.android.settings.widget.DataUsageChartView.DataUsageChartListener; + +public class DataUsageAppDetail extends Fragment { + private static final String TAG = "DataUsage"; + private static final boolean LOGD = true; + + public static final String EXTRA_UID = "uid"; + public static final String EXTRA_NETWORK_TEMPLATE = "networkTemplate"; + + private int mUid; + private NetworkTemplate mTemplate; + + private Intent mAppSettingsIntent; + + private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict"; + + private INetworkStatsService mStatsService; + private INetworkPolicyManager mPolicyService; + + private CheckBoxPreference mRestrictBackground; + private View mRestrictBackgroundView; + + private FrameLayout mChartContainer; + private TextView mTitle; + private TextView mText1; + private Button mAppSettings; + private LinearLayout mSwitches; + + private DataUsageChartView mChart; + private NetworkStatsHistory mHistory; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mStatsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + mPolicyService = INetworkPolicyManager.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + final Context context = inflater.getContext(); + final View view = inflater.inflate(R.layout.data_usage_detail, container, false); + + mChartContainer = (FrameLayout) view.findViewById(R.id.chart_container); + mTitle = (TextView) view.findViewById(android.R.id.title); + mText1 = (TextView) view.findViewById(android.R.id.text1); + mAppSettings = (Button) view.findViewById(R.id.data_usage_app_settings); + mSwitches = (LinearLayout) view.findViewById(R.id.switches); + + mRestrictBackground = new CheckBoxPreference(context); + mRestrictBackground.setTitle(R.string.data_usage_app_restrict_background); + mRestrictBackground.setSummary(R.string.data_usage_app_restrict_background_summary); + + // kick refresh once to force-create views + refreshPreferenceViews(); + + mSwitches.addView(mRestrictBackgroundView); + mRestrictBackgroundView.setOnClickListener(mRestrictBackgroundListener); + + mAppSettings.setOnClickListener(mAppSettingsListener); + + mChart = new DataUsageChartView(context); + mChartContainer.addView(mChart); + + mChart.setListener(mChartListener); + mChart.setChartColor(Color.parseColor("#d88d3a"), Color.parseColor("#c0ba7f3e"), + Color.parseColor("#88566abc")); + + return view; + } + + @Override + public void onResume() { + super.onResume(); + + updateBody(); + } + + private void updateBody() { + final PackageManager pm = getActivity().getPackageManager(); + + mUid = getArguments().getInt(EXTRA_UID); + mTemplate = getArguments().getParcelable(EXTRA_NETWORK_TEMPLATE); + + mTitle.setText(pm.getNameForUid(mUid)); + + // enable settings button when package provides it + // TODO: target torwards entire UID instead of just first package + final String[] packageNames = pm.getPackagesForUid(mUid); + if (packageNames != null && packageNames.length > 0) { + mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE); + mAppSettingsIntent.setPackage(packageNames[0]); + mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT); + + final boolean matchFound = pm.resolveActivity(mAppSettingsIntent, 0) != null; + mAppSettings.setEnabled(matchFound); + + } else { + mAppSettingsIntent = null; + mAppSettings.setEnabled(false); + } + + try { + // load stats for current uid and template + // TODO: read template from extras + mHistory = mStatsService.getHistoryForUid(mTemplate, mUid, NetworkStats.TAG_NONE); + } catch (RemoteException e) { + // since we can't do much without history, and we don't want to + // leave with half-baked UI, we bail hard. + throw new RuntimeException("problem reading network stats", e); + } + + // bind chart to historical stats + mChart.bindNetworkStats(mHistory); + + // show entire history known + final long[] bounds = getHistoryBounds(mHistory); + mChart.setVisibleRange(bounds[0], bounds[1] + DateUtils.WEEK_IN_MILLIS, bounds[1]); + updateDetailData(); + + final Context context = getActivity(); + if (NetworkPolicyManager.isUidValidForPolicy(context, mUid)) { + mRestrictBackgroundView.setVisibility(View.VISIBLE); + + final int uidPolicy; + try { + uidPolicy = mPolicyService.getUidPolicy(mUid); + } catch (RemoteException e) { + // since we can't do much without policy, we bail hard. + throw new RuntimeException("problem reading network policy", e); + } + + // update policy checkbox + final boolean restrictBackground = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; + mRestrictBackground.setChecked(restrictBackground); + + // kick preference views so they rebind from changes above + refreshPreferenceViews(); + + } else { + mRestrictBackgroundView.setVisibility(View.GONE); + } + } + + private void updateDetailData() { + if (LOGD) Log.d(TAG, "updateDetailData()"); + + final Context context = mChart.getContext(); + final long[] range = mChart.getInspectRange(); + final long[] total = mHistory.getTotalData(range[0], range[1], null); + final long totalCombined = total[0] + total[1]; + mText1.setText(Formatter.formatFileSize(context, totalCombined)); + } + + private void setRestrictBackground(boolean restrictBackground) { + if (LOGD) Log.d(TAG, "setRestrictBackground()"); + try { + mPolicyService.setUidPolicy( + mUid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE); + } catch (RemoteException e) { + throw new RuntimeException("unable to save policy", e); + } + + mRestrictBackground.setChecked(restrictBackground); + refreshPreferenceViews(); + } + + /** + * Force rebind of hijacked {@link Preference} views. + */ + private void refreshPreferenceViews() { + mRestrictBackgroundView = mRestrictBackground.getView(mRestrictBackgroundView, mSwitches); + } + + private DataUsageChartListener mChartListener = new DataUsageChartListener() { + /** {@inheritDoc} */ + public void onInspectRangeChanged() { + if (LOGD) Log.d(TAG, "onInspectRangeChanged()"); + updateDetailData(); + } + + /** {@inheritDoc} */ + public void onWarningChanged() { + // ignored + } + + /** {@inheritDoc} */ + public void onLimitChanged() { + // ignored + } + }; + + private OnClickListener mAppSettingsListener = new OnClickListener() { + /** {@inheritDoc} */ + public void onClick(View v) { + // TODO: target torwards entire UID instead of just first package + startActivity(mAppSettingsIntent); + } + }; + + private OnClickListener mRestrictBackgroundListener = new OnClickListener() { + /** {@inheritDoc} */ + public void onClick(View v) { + final boolean restrictBackground = !mRestrictBackground.isChecked(); + + if (restrictBackground) { + // enabling restriction; show confirmation dialog which + // eventually calls setRestrictBackground() once user confirms. + ConfirmRestrictFragment.show(DataUsageAppDetail.this); + } else { + setRestrictBackground(false); + } + } + }; + + /** + * Dialog to request user confirmation before setting + * {@link #POLICY_REJECT_METERED_BACKGROUND}. + */ + public static class ConfirmRestrictFragment extends DialogFragment { + public static void show(DataUsageAppDetail parent) { + final ConfirmRestrictFragment dialog = new ConfirmRestrictFragment(); + dialog.setTargetFragment(parent, 0); + dialog.show(parent.getFragmentManager(), TAG_CONFIRM_RESTRICT); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Context context = getActivity(); + + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.data_usage_app_restrict_dialog_title); + builder.setMessage(R.string.data_usage_app_restrict_dialog); + + builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + final DataUsageAppDetail target = (DataUsageAppDetail) getTargetFragment(); + if (target != null) { + target.setRestrictBackground(true); + } + } + }); + builder.setNegativeButton(android.R.string.cancel, null); + + return builder.create(); + } + } + +} |