diff options
author | Jeff Sharkey <jsharkey@android.com> | 2014-07-22 23:40:05 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-07-22 20:40:07 +0000 |
commit | e65bb4927faf8e353c73b58648e51a8081615dcf (patch) | |
tree | 0d0a2f20cc881e9f4f1fb1df8ee8213c5947df2e /src/com/android | |
parent | 0da1f8515a6af368a923cc99e5435795a031692a (diff) | |
parent | b654846300f79e9e4c605ce62d09f9a05d232fee (diff) | |
download | packages_apps_Settings-e65bb4927faf8e353c73b58648e51a8081615dcf.zip packages_apps_Settings-e65bb4927faf8e353c73b58648e51a8081615dcf.tar.gz packages_apps_Settings-e65bb4927faf8e353c73b58648e51a8081615dcf.tar.bz2 |
Merge "Data Usage, materialized!" into lmp-dev
Diffstat (limited to 'src/com/android')
8 files changed, 339 insertions, 599 deletions
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java index bdae072..f8f285f 100644 --- a/src/com/android/settings/DataUsageSummary.java +++ b/src/com/android/settings/DataUsageSummary.java @@ -55,6 +55,7 @@ import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; import android.app.LoaderManager.LoaderCallbacks; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; @@ -63,6 +64,7 @@ import android.content.Loader; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -107,9 +109,6 @@ import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; @@ -138,7 +137,6 @@ import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; import com.android.settings.widget.ChartDataUsageView; import com.android.settings.widget.ChartDataUsageView.DataUsageChartListener; -import com.android.settings.widget.PieChartView; import com.google.android.collect.Lists; import libcore.util.Objects; @@ -170,7 +168,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private static final String TAB_ETHERNET = "ethernet"; private static final String TAG_CONFIRM_DATA_DISABLE = "confirmDataDisable"; - private static final String TAG_CONFIRM_DATA_ROAMING = "confirmDataRoaming"; private static final String TAG_CONFIRM_LIMIT = "confirmLimit"; private static final String TAG_CYCLE_EDITOR = "cycleEditor"; private static final String TAG_WARNING_EDITOR = "warningEditor"; @@ -189,15 +186,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private static final int LOADER_CHART_DATA = 2; private static final int LOADER_SUMMARY = 3; - private static final int FOREGROUND_BYTES_COLOR = 0xff009688; - private static final int DEFAULT_BYTES_COLOR = 0xffced7db; - private INetworkManagementService mNetworkService; private INetworkStatsService mStatsService; private NetworkPolicyManager mPolicyManager; private TelephonyManager mTelephonyManager; - private INetworkStatsSession mStatsSession; private static final String PREF_FILE = "data_usage"; @@ -219,29 +212,33 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private ViewGroup mNetworkSwitchesContainer; private LinearLayout mNetworkSwitches; + private boolean mDataEnabledSupported; private Switch mDataEnabled; private View mDataEnabledView; - private CheckBox mDisableAtLimit; + private boolean mDisableAtLimitSupported; + private Switch mDisableAtLimit; private View mDisableAtLimitView; private View mCycleView; private Spinner mCycleSpinner; private CycleAdapter mCycleAdapter; + private TextView mCycleSummary; private ChartDataUsageView mChart; - private TextView mUsageSummary; + private View mDisclaimer; private TextView mEmpty; + private View mStupidPadding; private View mAppDetail; private ImageView mAppIcon; private ViewGroup mAppTitles; - private PieChartView mAppPieChart; + private TextView mAppTotal; private TextView mAppForeground; private TextView mAppBackground; private Button mAppSettings; private LinearLayout mAppSwitches; - private CheckBox mAppRestrict; + private Switch mAppRestrict; private View mAppRestrictView; private boolean mShowWifi = false; @@ -259,9 +256,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private String mCurrentTab = null; private String mIntentTab = null; - private MenuItem mMenuDataRoaming; private MenuItem mMenuRestrictBackground; - private MenuItem mMenuAutoSync; + private MenuItem mMenuShowWifi; + private MenuItem mMenuShowEthernet; + private MenuItem mMenuSimCards; + private MenuItem mMenuCellularNetworks; /** Flag used to ignore listeners during binding. */ private boolean mBinding; @@ -359,13 +358,17 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mNetworkSwitches = (LinearLayout) mHeader.findViewById(R.id.network_switches); mDataEnabled = new Switch(inflater.getContext()); + mDataEnabled.setClickable(false); + mDataEnabled.setFocusable(false); mDataEnabledView = inflatePreference(inflater, mNetworkSwitches, mDataEnabled); mDataEnabledView.setTag(R.id.preference_highlight_key, DATA_USAGE_ENABLE_MOBILE_KEY); - mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener); + mDataEnabledView.setClickable(true); + mDataEnabledView.setFocusable(true); + mDataEnabledView.setOnClickListener(mDataEnabledListener); mNetworkSwitches.addView(mDataEnabledView); - mDisableAtLimit = new CheckBox(inflater.getContext()); + mDisableAtLimit = new Switch(inflater.getContext()); mDisableAtLimit.setClickable(false); mDisableAtLimit.setFocusable(false); mDisableAtLimitView = inflatePreference(inflater, mNetworkSwitches, mDisableAtLimit); @@ -375,15 +378,16 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mDisableAtLimitView.setFocusable(true); mDisableAtLimitView.setOnClickListener(mDisableAtLimitListener); mNetworkSwitches.addView(mDisableAtLimitView); - } - // bind cycle dropdown - mCycleView = mHeader.findViewById(R.id.cycles); - mCycleView.setTag(R.id.preference_highlight_key, DATA_USAGE_CYCLE_KEY); - mCycleSpinner = (Spinner) mCycleView.findViewById(R.id.cycles_spinner); - mCycleAdapter = new CycleAdapter(context); - mCycleSpinner.setAdapter(mCycleAdapter); - mCycleSpinner.setOnItemSelectedListener(mCycleListener); + mCycleView = inflater.inflate(R.layout.data_usage_cycles, mNetworkSwitches, false); + mCycleView.setTag(R.id.preference_highlight_key, DATA_USAGE_CYCLE_KEY); + mCycleSpinner = (Spinner) mCycleView.findViewById(R.id.cycles_spinner); + mCycleAdapter = new CycleAdapter(context); + mCycleSpinner.setAdapter(mCycleAdapter); + mCycleSpinner.setOnItemSelectedListener(mCycleListener); + mCycleSummary = (TextView) mCycleView.findViewById(R.id.cycle_summary); + mNetworkSwitches.addView(mCycleView); + } mChart = (ChartDataUsageView) mHeader.findViewById(R.id.chart); mChart.setListener(mChartListener); @@ -394,7 +398,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mAppDetail = mHeader.findViewById(R.id.app_detail); mAppIcon = (ImageView) mAppDetail.findViewById(R.id.app_icon); mAppTitles = (ViewGroup) mAppDetail.findViewById(R.id.app_titles); - mAppPieChart = (PieChartView) mAppDetail.findViewById(R.id.app_pie_chart); mAppForeground = (TextView) mAppDetail.findViewById(R.id.app_foreground); mAppBackground = (TextView) mAppDetail.findViewById(R.id.app_background); mAppSwitches = (LinearLayout) mAppDetail.findViewById(R.id.app_switches); @@ -402,7 +405,7 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mAppSettings = (Button) mAppDetail.findViewById(R.id.app_settings); mAppSettings.setOnClickListener(mAppSettingsListener); - mAppRestrict = new CheckBox(inflater.getContext()); + mAppRestrict = new Switch(inflater.getContext()); mAppRestrict.setClickable(false); mAppRestrict.setFocusable(false); mAppRestrictView = inflatePreference(inflater, mAppSwitches, mAppRestrict); @@ -412,8 +415,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mAppSwitches.addView(mAppRestrictView); } - mUsageSummary = (TextView) mHeader.findViewById(R.id.usage_summary); + mDisclaimer = mHeader.findViewById(R.id.disclaimer); mEmpty = (TextView) mHeader.findViewById(android.R.id.empty); + mStupidPadding = mHeader.findViewById(R.id.stupid_padding); mAdapter = new DataUsageAdapter(mUidDetailProvider, mInsetSide); mListView.setOnItemClickListener(mListListener); @@ -480,40 +484,25 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final boolean appDetailMode = isAppDetailMode(); final boolean isOwner = ActivityManager.getCurrentUser() == UserHandle.USER_OWNER; - mMenuDataRoaming = menu.findItem(R.id.data_usage_menu_roaming); - mMenuDataRoaming.setVisible(hasReadyMobileRadio(context) && !appDetailMode); - mMenuDataRoaming.setChecked(getDataRoaming()); - - mMenuRestrictBackground = menu.findItem(R.id.data_usage_menu_restrict_background); - mMenuRestrictBackground.setVisible( - hasReadyMobileRadio(context) && isOwner && !appDetailMode); - mMenuRestrictBackground.setChecked(mPolicyManager.getRestrictBackground()); - + mMenuShowWifi = menu.findItem(R.id.data_usage_menu_show_wifi); // TODO: Define behavior of this sync button. See: http://b/16076571 - mMenuAutoSync = menu.findItem(R.id.data_usage_menu_auto_sync); - mMenuAutoSync.setChecked(ContentResolver.getMasterSyncAutomatically()); - mMenuAutoSync.setVisible(!appDetailMode); - - final MenuItem split4g = menu.findItem(R.id.data_usage_menu_split_4g); - split4g.setVisible(hasReadyMobile4gRadio(context) && isOwner && !appDetailMode); - split4g.setChecked(isMobilePolicySplit()); - - final MenuItem showWifi = menu.findItem(R.id.data_usage_menu_show_wifi); if (hasWifiRadio(context) && hasReadyMobileRadio(context)) { - showWifi.setVisible(!appDetailMode); - showWifi.setChecked(mShowWifi); + mMenuShowWifi.setVisible(!appDetailMode); } else { - showWifi.setVisible(false); + mMenuShowWifi.setVisible(false); } - final MenuItem showEthernet = menu.findItem(R.id.data_usage_menu_show_ethernet); + mMenuShowEthernet = menu.findItem(R.id.data_usage_menu_show_ethernet); if (hasEthernet(context) && hasReadyMobileRadio(context)) { - showEthernet.setVisible(!appDetailMode); - showEthernet.setChecked(mShowEthernet); + mMenuShowEthernet.setVisible(!appDetailMode); } else { - showEthernet.setVisible(false); + mMenuShowEthernet.setVisible(false); } + mMenuRestrictBackground = menu.findItem(R.id.data_usage_menu_restrict_background); + mMenuRestrictBackground.setVisible( + hasReadyMobileRadio(context) && isOwner && !appDetailMode); + final MenuItem metered = menu.findItem(R.id.data_usage_menu_metered); if (hasReadyMobileRadio(context) || hasWifiRadio(context)) { metered.setVisible(!appDetailMode); @@ -521,6 +510,17 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable metered.setVisible(false); } + // TODO: show when multiple sims available + mMenuSimCards = menu.findItem(R.id.data_usage_menu_sim_cards); + mMenuSimCards.setVisible(false); + + mMenuCellularNetworks = menu.findItem(R.id.data_usage_menu_cellular_networks); + if (hasReadyMobileRadio(context)) { + mMenuCellularNetworks.setVisible(!appDetailMode); + } else { + mMenuCellularNetworks.setVisible(false); + } + final MenuItem help = menu.findItem(R.id.data_usage_menu_help); String helpUrl; if (!TextUtils.isEmpty(helpUrl = getResources().getString(R.string.help_url_data_usage))) { @@ -528,23 +528,35 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } else { help.setVisible(false); } + + updateMenuTitles(); + } + + private void updateMenuTitles() { + if (mPolicyManager.getRestrictBackground()) { + mMenuRestrictBackground.setTitle(R.string.data_usage_menu_allow_background); + } else { + mMenuRestrictBackground.setTitle(R.string.data_usage_menu_restrict_background); + } + + if (mShowWifi) { + mMenuShowWifi.setTitle(R.string.data_usage_menu_hide_wifi); + } else { + mMenuShowWifi.setTitle(R.string.data_usage_menu_show_wifi); + } + + if (mShowEthernet) { + mMenuShowEthernet.setTitle(R.string.data_usage_menu_hide_ethernet); + } else { + mMenuShowEthernet.setTitle(R.string.data_usage_menu_show_ethernet); + } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.data_usage_menu_roaming: { - final boolean dataRoaming = !item.isChecked(); - if (dataRoaming) { - ConfirmDataRoamingFragment.show(this); - } else { - // no confirmation to disable roaming - setDataRoaming(false); - } - return true; - } case R.id.data_usage_menu_restrict_background: { - final boolean restrictBackground = !item.isChecked(); + final boolean restrictBackground = !mPolicyManager.getRestrictBackground(); if (restrictBackground) { ConfirmRestrictFragment.show(this); } else { @@ -553,41 +565,37 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } return true; } - case R.id.data_usage_menu_split_4g: { - final boolean mobileSplit = !item.isChecked(); - setMobilePolicySplit(mobileSplit); - item.setChecked(isMobilePolicySplit()); - updateTabs(); - return true; - } case R.id.data_usage_menu_show_wifi: { - mShowWifi = !item.isChecked(); + mShowWifi = !mShowWifi; mPrefs.edit().putBoolean(PREF_SHOW_WIFI, mShowWifi).apply(); - item.setChecked(mShowWifi); + updateMenuTitles(); updateTabs(); return true; } case R.id.data_usage_menu_show_ethernet: { - mShowEthernet = !item.isChecked(); + mShowEthernet = !mShowEthernet; mPrefs.edit().putBoolean(PREF_SHOW_ETHERNET, mShowEthernet).apply(); - item.setChecked(mShowEthernet); + updateMenuTitles(); updateTabs(); return true; } + case R.id.data_usage_menu_sim_cards: { + // TODO: hook up to sim cards + return true; + } + case R.id.data_usage_menu_cellular_networks: { + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setComponent(new ComponentName("com.android.phone", + "com.android.phone.MobileNetworkSettings")); + startActivity(intent); + return true; + } case R.id.data_usage_menu_metered: { final SettingsActivity sa = (SettingsActivity) getActivity(); sa.startPreferencePanel(DataUsageMeteredSettings.class.getCanonicalName(), null, R.string.data_usage_metered_title, null, this, 0); return true; } - case R.id.data_usage_menu_auto_sync: { - if (ActivityManager.isUserAMonkey()) { - Log.d("SyncState", "ignoring monkey's attempt to flip global sync state"); - } else { - ConfirmAutoSyncChangeFragment.show(this, !item.isChecked()); - } - return true; - } } return false; } @@ -725,7 +733,8 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable if (LOGD) Log.d(TAG, "updateBody() with currentTab=" + currentTab); - mDataEnabledView.setVisibility(isOwner ? View.VISIBLE : View.GONE); + mDataEnabledSupported = isOwner; + mDisableAtLimitSupported = true; // TODO: remove mobile tabs when SIM isn't ready @@ -748,14 +757,14 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } else if (TAB_WIFI.equals(currentTab)) { // wifi doesn't have any controls - mDataEnabledView.setVisibility(View.GONE); - mDisableAtLimitView.setVisibility(View.GONE); + mDataEnabledSupported = false; + mDisableAtLimitSupported = false; mTemplate = buildTemplateWifiWildcard(); } else if (TAB_ETHERNET.equals(currentTab)) { // ethernet doesn't have any controls - mDataEnabledView.setVisibility(View.GONE); - mDisableAtLimitView.setVisibility(View.GONE); + mDataEnabledSupported = false; + mDisableAtLimitSupported = false; mTemplate = buildTemplateEthernet(); } else { @@ -808,12 +817,25 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mAppIcon.setImageDrawable(detail.icon); mAppTitles.removeAllViews(); + + View title = null; if (detail.detailLabels != null) { for (CharSequence label : detail.detailLabels) { - mAppTitles.addView(inflateAppTitle(inflater, mAppTitles, label)); + title = inflater.inflate(R.layout.data_usage_app_title, mAppTitles, false); + ((TextView) title.findViewById(R.id.app_title)).setText(label); + mAppTitles.addView(title); } } else { - mAppTitles.addView(inflateAppTitle(inflater, mAppTitles, detail.label)); + title = inflater.inflate(R.layout.data_usage_app_title, mAppTitles, false); + ((TextView) title.findViewById(R.id.app_title)).setText(detail.label); + mAppTitles.addView(title); + } + + // Remember last slot for summary + if (title != null) { + mAppTotal = (TextView) title.findViewById(R.id.app_summary); + } else { + mAppTotal = null; } // enable settings button when package provides it @@ -904,24 +926,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } } - private boolean getDataRoaming() { - final ContentResolver resolver = getActivity().getContentResolver(); - return android.provider.Settings.Global.getInt(resolver, - android.provider.Settings.Global.DATA_ROAMING, 0) != 0; - } - - private void setDataRoaming(boolean enabled) { - // TODO: teach telephony DataConnectionTracker to watch and apply - // updates when changed. - final ContentResolver resolver = getActivity().getContentResolver(); - android.provider.Settings.Global.putInt(resolver, - android.provider.Settings.Global.DATA_ROAMING, enabled ? 1 : 0); - mMenuDataRoaming.setChecked(enabled); - } - public void setRestrictBackground(boolean restrictBackground) { mPolicyManager.setRestrictBackground(restrictBackground); - mMenuRestrictBackground.setChecked(restrictBackground); + updateMenuTitles(); } private boolean getAppRestrictBackground() { @@ -943,10 +950,12 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable * current {@link #mTemplate}. */ private void updatePolicy(boolean refreshCycle) { + boolean dataEnabledVisible = mDataEnabledSupported; + boolean disableAtLimitVisible = mDisableAtLimitSupported; + if (isAppDetailMode()) { - mNetworkSwitches.setVisibility(View.GONE); - } else { - mNetworkSwitches.setVisibility(View.VISIBLE); + dataEnabledVisible = false; + disableAtLimitVisible = false; } // TODO: move enabled state directly into policy @@ -958,7 +967,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final NetworkPolicy policy = mPolicyEditor.getPolicy(mTemplate); if (isNetworkPolicyModifiable(policy)) { - mDisableAtLimitView.setVisibility(View.VISIBLE); mDisableAtLimit.setChecked(policy != null && policy.limitBytes != LIMIT_DISABLED); if (!isAppDetailMode()) { mChart.bindNetworkPolicy(policy); @@ -966,10 +974,13 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } else { // controls are disabled; don't bind warning/limit sweeps - mDisableAtLimitView.setVisibility(View.GONE); + disableAtLimitVisible = false; mChart.bindNetworkPolicy(null); } + mDataEnabledView.setVisibility(dataEnabledVisible ? View.VISIBLE : View.GONE); + mDisableAtLimitView.setVisibility(disableAtLimitVisible ? View.VISIBLE : View.GONE); + if (refreshCycle) { // generate cycle list based on policy and available history updateCycleList(policy); @@ -1049,12 +1060,12 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } } - private OnCheckedChangeListener mDataEnabledListener = new OnCheckedChangeListener() { + private View.OnClickListener mDataEnabledListener = new View.OnClickListener() { @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + public void onClick(View v) { if (mBinding) return; - final boolean dataEnabled = isChecked; + final boolean dataEnabled = !mDataEnabled.isChecked(); final String currentTab = mCurrentTab; if (TAB_MOBILE.equals(currentTab)) { if (dataEnabled) { @@ -1178,15 +1189,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final long defaultBytes = entry.rxBytes + entry.txBytes; entry = mChartData.detailForeground.getValues(start, end, now, entry); final long foregroundBytes = entry.rxBytes + entry.txBytes; + final long totalBytes = defaultBytes + foregroundBytes; - mAppPieChart.setOriginAngle(175); - - mAppPieChart.removeAllSlices(); - mAppPieChart.addSlice(foregroundBytes, FOREGROUND_BYTES_COLOR); - mAppPieChart.addSlice(defaultBytes, DEFAULT_BYTES_COLOR); - - mAppPieChart.generatePath(); - + if (mAppTotal != null) { + mAppTotal.setText(Formatter.formatFileSize(context, totalBytes)); + } mAppBackground.setText(Formatter.formatFileSize(context, defaultBytes)); mAppForeground.setText(Formatter.formatFileSize(context, foregroundBytes)); @@ -1195,11 +1202,15 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable getLoaderManager().destroyLoader(LOADER_SUMMARY); + mCycleSummary.setVisibility(View.GONE); + } else { if (mChartData != null) { entry = mChartData.network.getValues(start, end, now, null); } + mCycleSummary.setVisibility(View.VISIBLE); + // kick off loader for detailed stats getLoaderManager().restartLoader(LOADER_SUMMARY, SummaryForAllUidLoader.buildArgs(mTemplate, start, end), mSummaryCallbacks); @@ -1207,18 +1218,19 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0; final String totalPhrase = Formatter.formatFileSize(context, totalBytes); - final String rangePhrase = formatDateRange(context, start, end); + mCycleSummary.setText(totalPhrase); - final int summaryRes; if (TAB_MOBILE.equals(mCurrentTab) || TAB_3G.equals(mCurrentTab) || TAB_4G.equals(mCurrentTab)) { - summaryRes = R.string.data_usage_total_during_range_mobile; + if (isAppDetailMode()) { + mDisclaimer.setVisibility(View.GONE); + } else { + mDisclaimer.setVisibility(View.VISIBLE); + } } else { - summaryRes = R.string.data_usage_total_during_range; + mDisclaimer.setVisibility(View.GONE); } - mUsageSummary.setText(getString(summaryRes, totalPhrase, rangePhrase)); - // initial layout is finished above, ensure we have transitions ensureLayoutTransitions(); } @@ -1278,6 +1290,7 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private void updateEmptyVisible() { final boolean isEmpty = mAdapter.isEmpty() && !isAppDetailMode(); mEmpty.setVisibility(isEmpty ? View.VISIBLE : View.GONE); + mStupidPadding.setVisibility(isEmpty ? View.VISIBLE : View.GONE); } }; @@ -1309,12 +1322,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private DataUsageChartListener mChartListener = new DataUsageChartListener() { @Override - public void onInspectRangeChanged() { - if (LOGD) Log.d(TAG, "onInspectRangeChanged()"); - updateDetailData(); - } - - @Override public void onWarningChanged() { setPolicyWarningBytes(mChart.getWarningBytes()); } @@ -1404,8 +1411,8 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private final CycleChangeItem mChangeItem; public CycleAdapter(Context context) { - super(context, android.R.layout.simple_spinner_item); - setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + super(context, R.layout.data_usage_cycle_item); + setDropDownViewResource(R.layout.data_usage_cycle_item_dropdown); mChangeItem = new CycleChangeItem(context); } @@ -1447,11 +1454,21 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } public static class AppItem implements Comparable<AppItem>, Parcelable { + public static final int CATEGORY_USER = 0; + public static final int CATEGORY_APP_TITLE = 1; + public static final int CATEGORY_APP = 2; + public final int key; public boolean restricted; + public int category; + public SparseBooleanArray uids = new SparseBooleanArray(); public long total; + public AppItem() { + this.key = 0; + } + public AppItem(int key) { this.key = key; } @@ -1480,7 +1497,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable @Override public int compareTo(AppItem another) { - return Long.compare(another.total, total); + int comparison = Integer.compare(another.category, category); + if (comparison == 0) { + comparison = Long.compare(another.total, total); + } + return comparison; } public static final Creator<AppItem> CREATOR = new Creator<AppItem>() { @@ -1516,9 +1537,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable */ public void bindStats(NetworkStats stats, int[] restrictedUids) { mItems.clear(); + mLargest = 0; final int currentUserId = ActivityManager.getCurrentUser(); final SparseArray<AppItem> knownItems = new SparseArray<AppItem>(); + boolean hasApps = false; NetworkStats.Entry entry = null; final int size = stats != null ? stats.size() : 0; @@ -1548,6 +1571,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } item.addUid(uid); item.total += entry.rxBytes + entry.txBytes; + if (item.total > mLargest) { + mLargest = item.total; + } } for (int uid : restrictedUids) { @@ -1564,8 +1590,14 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable item.restricted = true; } + hasApps = !mItems.isEmpty(); + if (hasApps) { + final AppItem title = new AppItem(); + title.category = AppItem.CATEGORY_APP_TITLE; + mItems.add(title); + } + Collections.sort(mItems); - mLargest = (mItems.size() > 0) ? mItems.get(0).total : 0; notifyDataSetChanged(); } @@ -1585,36 +1617,72 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable } @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(parent.getContext()).inflate( - R.layout.data_usage_item, parent, false); + public int getViewTypeCount() { + return 2; + } - if (mInsetSide > 0) { - convertView.setPaddingRelative(mInsetSide, 0, mInsetSide, 0); - } + @Override + public int getItemViewType(int position) { + final AppItem item = mItems.get(position); + if (item.category == AppItem.CATEGORY_APP_TITLE) { + return 1; + } else { + return 0; } + } - final Context context = parent.getContext(); + @Override + public boolean areAllItemsEnabled() { + return false; + } - final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1); - final ProgressBar progress = (ProgressBar) convertView.findViewById( - android.R.id.progress); + @Override + public boolean isEnabled(int position) { + return getItemViewType(position) == 0; + } - // kick off async load of app details + @Override + public View getView(int position, View convertView, ViewGroup parent) { final AppItem item = mItems.get(position); - UidDetailTask.bindView(mProvider, item, convertView); + if (getItemViewType(position) == 1) { + if (convertView == null) { + convertView = inflateCategoryHeader(LayoutInflater.from(parent.getContext()), + parent); + } + + final TextView title = (TextView) convertView.findViewById(android.R.id.title); + title.setText(R.string.data_usage_app); - if (item.restricted && item.total <= 0) { - text1.setText(R.string.data_usage_app_restricted); - progress.setVisibility(View.GONE); } else { - text1.setText(Formatter.formatFileSize(context, item.total)); - progress.setVisibility(View.VISIBLE); - } + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()).inflate( + R.layout.data_usage_item, parent, false); - final int percentTotal = mLargest != 0 ? (int) (item.total * 100 / mLargest) : 0; - progress.setProgress(percentTotal); + if (mInsetSide > 0) { + convertView.setPaddingRelative(mInsetSide, 0, mInsetSide, 0); + } + } + + final Context context = parent.getContext(); + + final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1); + final ProgressBar progress = (ProgressBar) convertView.findViewById( + android.R.id.progress); + + // kick off async load of app details + UidDetailTask.bindView(mProvider, item, convertView); + + if (item.restricted && item.total <= 0) { + text1.setText(R.string.data_usage_app_restricted); + progress.setVisibility(View.GONE); + } else { + text1.setText(Formatter.formatFileSize(context, item.total)); + progress.setVisibility(View.VISIBLE); + } + + final int percentTotal = mLargest != 0 ? (int) (item.total * 100 / mLargest) : 0; + progress.setProgress(percentTotal); + } return convertView; } @@ -1639,7 +1707,8 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final FragmentTransaction ft = parent.getFragmentManager().beginTransaction(); ft.add(fragment, TAG_APP_DETAILS); ft.addToBackStack(TAG_APP_DETAILS); - ft.setBreadCrumbTitle(label); + ft.setBreadCrumbTitle( + parent.getResources().getString(R.string.data_usage_app_summary_title)); ft.commitAllowingStateLoss(); } @@ -1948,46 +2017,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable /** * Dialog to request user confirmation before setting - * {@link android.provider.Settings.Global#DATA_ROAMING}. - */ - public static class ConfirmDataRoamingFragment extends DialogFragment { - public static void show(DataUsageSummary parent) { - if (!parent.isAdded()) return; - - final ConfirmDataRoamingFragment dialog = new ConfirmDataRoamingFragment(); - dialog.setTargetFragment(parent, 0); - dialog.show(parent.getFragmentManager(), TAG_CONFIRM_DATA_ROAMING); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Context context = getActivity(); - - final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.roaming_reenable_title); - if (Utils.hasMultipleUsers(context)) { - builder.setMessage(R.string.roaming_warning_multiuser); - } else { - builder.setMessage(R.string.roaming_warning); - } - - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - final DataUsageSummary target = (DataUsageSummary) getTargetFragment(); - if (target != null) { - target.setDataRoaming(true); - } - } - }); - builder.setNegativeButton(android.R.string.cancel, null); - - return builder.create(); - } - } - - /** - * Dialog to request user confirmation before setting * {@link INetworkPolicyManager#setRestrictBackground(boolean)}. */ public static class ConfirmRestrictFragment extends DialogFragment { @@ -2308,12 +2337,12 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable return view; } - private static View inflateAppTitle( - LayoutInflater inflater, ViewGroup root, CharSequence label) { - final TextView view = (TextView) inflater.inflate( - R.layout.data_usage_app_title, root, false); - view.setText(label); - return view; + private static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup root) { + final TypedArray a = inflater.getContext().obtainStyledAttributes(null, + com.android.internal.R.styleable.Preference, + com.android.internal.R.attr.preferenceCategoryStyle, 0); + final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, 0); + return inflater.inflate(resId, root, false); } /** diff --git a/src/com/android/settings/net/DataUsageMeteredSettings.java b/src/com/android/settings/net/DataUsageMeteredSettings.java index 87358f6..d567c7e 100644 --- a/src/com/android/settings/net/DataUsageMeteredSettings.java +++ b/src/com/android/settings/net/DataUsageMeteredSettings.java @@ -29,10 +29,9 @@ import android.net.NetworkTemplate; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.Bundle; -import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceCategory; -import android.provider.SearchIndexableResource; +import android.preference.SwitchPreference; import android.telephony.TelephonyManager; import com.android.settings.R; @@ -42,7 +41,6 @@ import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -117,7 +115,7 @@ public class DataUsageMeteredSettings extends SettingsPreferenceFragment impleme return pref; } - private class MeteredPreference extends CheckBoxPreference { + private class MeteredPreference extends SwitchPreference { private final NetworkTemplate mTemplate; private boolean mBinding; diff --git a/src/com/android/settings/widget/ChartDataUsageView.java b/src/com/android/settings/widget/ChartDataUsageView.java index 4e16bfc..c20a8db 100644 --- a/src/com/android/settings/widget/ChartDataUsageView.java +++ b/src/com/android/settings/widget/ChartDataUsageView.java @@ -50,26 +50,24 @@ public class ChartDataUsageView extends ChartView { private static final int MSG_UPDATE_AXIS = 100; private static final long DELAY_MILLIS = 250; - private static final boolean LIMIT_SWEEPS_TO_VALID_DATA = false; - private ChartGridView mGrid; private ChartNetworkSeriesView mSeries; private ChartNetworkSeriesView mDetailSeries; private NetworkStatsHistory mHistory; - private ChartSweepView mSweepLeft; - private ChartSweepView mSweepRight; private ChartSweepView mSweepWarning; private ChartSweepView mSweepLimit; + private long mInspectStart; + private long mInspectEnd; + private Handler mHandler; /** Current maximum value of {@link #mVert}. */ private long mVertMax; public interface DataUsageChartListener { - public void onInspectRangeChanged(); public void onWarningChanged(); public void onLimitChanged(); public void requestWarningEdit(); @@ -112,43 +110,27 @@ public class ChartDataUsageView extends ChartView { mDetailSeries = (ChartNetworkSeriesView) findViewById(R.id.detail_series); mDetailSeries.setVisibility(View.GONE); - mSweepLeft = (ChartSweepView) findViewById(R.id.sweep_left); - mSweepRight = (ChartSweepView) findViewById(R.id.sweep_right); mSweepLimit = (ChartSweepView) findViewById(R.id.sweep_limit); mSweepWarning = (ChartSweepView) findViewById(R.id.sweep_warning); // prevent sweeps from crossing each other - mSweepLeft.setValidRangeDynamic(null, mSweepRight); - mSweepRight.setValidRangeDynamic(mSweepLeft, null); mSweepWarning.setValidRangeDynamic(null, mSweepLimit); mSweepLimit.setValidRangeDynamic(mSweepWarning, null); // mark neighbors for checking touch events against - mSweepLeft.setNeighbors(mSweepRight); - mSweepRight.setNeighbors(mSweepLeft); - mSweepLimit.setNeighbors(mSweepWarning, mSweepLeft, mSweepRight); - mSweepWarning.setNeighbors(mSweepLimit, mSweepLeft, mSweepRight); + mSweepLimit.setNeighbors(mSweepWarning); + mSweepWarning.setNeighbors(mSweepLimit); - mSweepLeft.addOnSweepListener(mHorizListener); - mSweepRight.addOnSweepListener(mHorizListener); mSweepWarning.addOnSweepListener(mVertListener); mSweepLimit.addOnSweepListener(mVertListener); mSweepWarning.setDragInterval(5 * MB_IN_BYTES); mSweepLimit.setDragInterval(5 * MB_IN_BYTES); - // TODO: make time sweeps adjustable through dpad - mSweepLeft.setClickable(false); - mSweepLeft.setFocusable(false); - mSweepRight.setClickable(false); - mSweepRight.setFocusable(false); - // tell everyone about our axis mGrid.init(mHoriz, mVert); mSeries.init(mHoriz, mVert); mDetailSeries.init(mHoriz, mVert); - mSweepLeft.init(mHoriz); - mSweepRight.init(mHoriz); mSweepWarning.init(mVert); mSweepLimit.init(mVert); @@ -194,7 +176,7 @@ public class ChartDataUsageView extends ChartView { mSweepLimit.setEnabled(true); mSweepLimit.setValue(policy.limitBytes); } else { - mSweepLimit.setVisibility(View.VISIBLE); + mSweepLimit.setVisibility(View.INVISIBLE); mSweepLimit.setEnabled(false); mSweepLimit.setValue(-1); } @@ -295,23 +277,6 @@ public class ChartDataUsageView extends ChartView { mSeries.setEstimateVisible(estimateVisible); } - private OnSweepListener mHorizListener = new OnSweepListener() { - @Override - public void onSweep(ChartSweepView sweep, boolean sweepDone) { - updatePrimaryRange(); - - // update detail list only when done sweeping - if (sweepDone && mListener != null) { - mListener.onInspectRangeChanged(); - } - } - - @Override - public void requestEdit(ChartSweepView sweep) { - // ignored - } - }; - private void sendUpdateAxisDelayed(ChartSweepView sweep, boolean force) { if (force || !mHandler.hasMessages(MSG_UPDATE_AXIS, sweep)) { mHandler.sendMessageDelayed( @@ -369,11 +334,11 @@ public class ChartDataUsageView extends ChartView { } public long getInspectStart() { - return mSweepLeft.getValue(); + return mInspectStart; } public long getInspectEnd() { - return mSweepRight.getValue(); + return mInspectEnd; } public long getWarningBytes() { @@ -384,14 +349,6 @@ public class ChartDataUsageView extends ChartView { return mSweepLimit.getLabelValue(); } - private long getHistoryStart() { - return mHistory != null ? mHistory.getStart() : Long.MAX_VALUE; - } - - private long getHistoryEnd() { - return mHistory != null ? mHistory.getEnd() : Long.MIN_VALUE; - } - /** * Set the exact time range that should be displayed, updating how * {@link ChartNetworkSeriesView} paints. Moves inspection ranges to be the @@ -403,30 +360,8 @@ public class ChartDataUsageView extends ChartView { mSeries.setBounds(visibleStart, visibleEnd); mDetailSeries.setBounds(visibleStart, visibleEnd); - final long historyStart = getHistoryStart(); - final long historyEnd = getHistoryEnd(); - - final long validStart = historyStart == Long.MAX_VALUE ? visibleStart - : Math.max(visibleStart, historyStart); - final long validEnd = historyEnd == Long.MIN_VALUE ? visibleEnd - : Math.min(visibleEnd, historyEnd); - - if (LIMIT_SWEEPS_TO_VALID_DATA) { - // prevent time sweeps from leaving valid data - mSweepLeft.setValidRange(validStart, validEnd); - mSweepRight.setValidRange(validStart, validEnd); - } else { - mSweepLeft.setValidRange(visibleStart, visibleEnd); - mSweepRight.setValidRange(visibleStart, visibleEnd); - } - - // default sweeps to last week of data - final long halfRange = (visibleEnd + visibleStart) / 2; - final long sweepMax = validEnd; - final long sweepMin = Math.max(visibleStart, (sweepMax - DateUtils.WEEK_IN_MILLIS)); - - mSweepLeft.setValue(sweepMin); - mSweepRight.setValue(sweepMax); + mInspectStart = visibleStart; + mInspectEnd = visibleEnd; requestLayout(); if (changed) { @@ -440,15 +375,11 @@ public class ChartDataUsageView extends ChartView { } private void updatePrimaryRange() { - final long left = mSweepLeft.getValue(); - final long right = mSweepRight.getValue(); - // prefer showing primary range on detail series, when available if (mDetailSeries.getVisibility() == View.VISIBLE) { - mDetailSeries.setPrimaryRange(left, right); - mSeries.setPrimaryRange(0, 0); + mSeries.setSecondary(true); } else { - mSeries.setPrimaryRange(left, right); + mSeries.setSecondary(false); } } diff --git a/src/com/android/settings/widget/ChartGridView.java b/src/com/android/settings/widget/ChartGridView.java index ec5882c..4cd6f5f 100644 --- a/src/com/android/settings/widget/ChartGridView.java +++ b/src/com/android/settings/widget/ChartGridView.java @@ -19,22 +19,25 @@ package com.android.settings.widget; import static com.android.settings.DataUsageSummary.formatDateRange; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; +import android.util.Log; import android.util.TypedValue; import android.view.View; import com.android.internal.util.Preconditions; import com.android.settings.R; +import java.util.Locale; + /** * Background of {@link ChartView} that renders grid lines as requested by * {@link ChartAxis#getTickPoints()}. @@ -47,10 +50,13 @@ public class ChartGridView extends View { private Drawable mPrimary; private Drawable mSecondary; private Drawable mBorder; + + private int mLabelSize; private int mLabelColor; - private Layout mLayoutStart; - private Layout mLayoutEnd; + private Layout mLabelStart; + private Layout mLabelMid; + private Layout mLabelEnd; public ChartGridView(Context context) { this(context, null, 0); @@ -71,7 +77,17 @@ public class ChartGridView extends View { mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable); mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable); mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable); - mLabelColor = a.getColor(R.styleable.ChartGridView_labelColor, Color.RED); + + final int taId = a.getResourceId(R.styleable.ChartGridView_android_textAppearance, -1); + final TypedArray ta = context.obtainStyledAttributes(taId, + com.android.internal.R.styleable.TextAppearance); + mLabelSize = ta.getDimensionPixelSize( + com.android.internal.R.styleable.TextAppearance_textSize, 0); + ta.recycle(); + + final ColorStateList labelColor = a.getColorStateList( + R.styleable.ChartGridView_android_textColor); + mLabelColor = labelColor.getDefaultColor(); a.recycle(); } @@ -83,71 +99,83 @@ public class ChartGridView extends View { void setBounds(long start, long end) { final Context context = getContext(); - mLayoutStart = makeLayout(formatDateRange(context, start, start)); - mLayoutEnd = makeLayout(formatDateRange(context, end, end)); + final long mid = (start + end) / 2; + mLabelStart = makeLabel(formatDateRange(context, start, start)); + mLabelMid = makeLabel(formatDateRange(context, mid, mid)); + mLabelEnd = makeLabel(formatDateRange(context, end, end)); invalidate(); } @Override protected void onDraw(Canvas canvas) { final int width = getWidth(); - final int height = getHeight(); + final int height = getHeight() - getPaddingBottom(); final Drawable secondary = mSecondary; - final int secondaryHeight = mSecondary.getIntrinsicHeight(); - - final float[] vertTicks = mVert.getTickPoints(); - for (float y : vertTicks) { - final int bottom = (int) Math.min(y + secondaryHeight, height); - secondary.setBounds(0, (int) y, width, bottom); - secondary.draw(canvas); + if (secondary != null) { + final int secondaryHeight = secondary.getIntrinsicHeight(); + + final float[] vertTicks = mVert.getTickPoints(); + for (float y : vertTicks) { + final int bottom = (int) Math.min(y + secondaryHeight, height); + secondary.setBounds(0, (int) y, width, bottom); + secondary.draw(canvas); + } } final Drawable primary = mPrimary; - final int primaryWidth = mPrimary.getIntrinsicWidth(); - final int primaryHeight = mPrimary.getIntrinsicHeight(); - - final float[] horizTicks = mHoriz.getTickPoints(); - for (float x : horizTicks) { - final int right = (int) Math.min(x + primaryWidth, width); - primary.setBounds((int) x, 0, right, height); - primary.draw(canvas); + if (primary != null) { + final int primaryWidth = primary.getIntrinsicWidth(); + final int primaryHeight = primary.getIntrinsicHeight(); + + final float[] horizTicks = mHoriz.getTickPoints(); + for (float x : horizTicks) { + final int right = (int) Math.min(x + primaryWidth, width); + primary.setBounds((int) x, 0, right, height); + primary.draw(canvas); + } } mBorder.setBounds(0, 0, width, height); mBorder.draw(canvas); - final int padding = mLayoutStart != null ? mLayoutStart.getHeight() / 8 : 0; + final int padding = mLabelStart != null ? mLabelStart.getHeight() / 8 : 0; - final Layout start = mLayoutStart; + final Layout start = mLabelStart; if (start != null) { - canvas.save(); + final int saveCount = canvas.save(); canvas.translate(0, height + padding); start.draw(canvas); - canvas.restore(); + canvas.restoreToCount(saveCount); + } + + final Layout mid = mLabelMid; + if (mid != null) { + final int saveCount = canvas.save(); + canvas.translate((width - mid.getWidth()) / 2, height + padding); + mid.draw(canvas); + canvas.restoreToCount(saveCount); } - final Layout end = mLayoutEnd; + final Layout end = mLabelEnd; if (end != null) { - canvas.save(); + final int saveCount = canvas.save(); canvas.translate(width - end.getWidth(), height + padding); end.draw(canvas); - canvas.restore(); + canvas.restoreToCount(saveCount); } } - private Layout makeLayout(CharSequence text) { + private Layout makeLabel(CharSequence text) { final Resources res = getResources(); final TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG); paint.density = res.getDisplayMetrics().density; paint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale); paint.setColor(mLabelColor); - paint.setTextSize( - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, res.getDisplayMetrics())); + paint.setTextSize(mLabelSize); return new StaticLayout(text, paint, (int) Math.ceil(Layout.getDesiredWidth(text, paint)), Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); } - } diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java index 6250a25..7aaba66 100644 --- a/src/com/android/settings/widget/ChartNetworkSeriesView.java +++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java @@ -60,17 +60,17 @@ public class ChartNetworkSeriesView extends View { private Path mPathFill; private Path mPathEstimate; + private int mSafeRegion; + private long mStart; private long mEnd; - private long mPrimaryLeft; - private long mPrimaryRight; - /** Series will be extended to reach this end time. */ private long mEndTime = Long.MIN_VALUE; private boolean mPathValid = false; private boolean mEstimateVisible = false; + private boolean mSecondary = false; private long mMax; private long mMaxEstimate; @@ -93,8 +93,11 @@ public class ChartNetworkSeriesView extends View { final int fill = a.getColor(R.styleable.ChartNetworkSeriesView_fillColor, Color.RED); final int fillSecondary = a.getColor( R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED); + final int safeRegion = a.getDimensionPixelSize( + R.styleable.ChartNetworkSeriesView_safeRegion, 0); setChartColor(stroke, fill, fillSecondary); + setSafeRegion(safeRegion); setWillNotDraw(false); a.recycle(); @@ -134,6 +137,10 @@ public class ChartNetworkSeriesView extends View { mPaintEstimate.setPathEffect(new DashPathEffect(new float[] { 10, 10 }, 1)); } + public void setSafeRegion(int safeRegion) { + mSafeRegion = safeRegion; + } + public void bindNetworkStats(NetworkStatsHistory stats) { mStats = stats; invalidatePath(); @@ -145,14 +152,8 @@ public class ChartNetworkSeriesView extends View { mEnd = end; } - /** - * Set the range to paint with {@link #mPaintFill}, leaving the remaining - * area to be painted with {@link #mPaintFillSecondary}. - */ - public void setPrimaryRange(long left, long right) { - mPrimaryLeft = left; - mPrimaryRight = right; - invalidate(); + public void setSecondary(boolean secondary) { + mSecondary = secondary; } public void invalidatePath() { @@ -322,9 +323,6 @@ public class ChartNetworkSeriesView extends View { generatePath(); } - final float primaryLeftPoint = mHoriz.convertToPoint(mPrimaryLeft); - final float primaryRightPoint = mHoriz.convertToPoint(mPrimaryRight); - if (mEstimateVisible) { save = canvas.save(); canvas.clipRect(0, 0, getWidth(), getHeight()); @@ -332,21 +330,11 @@ public class ChartNetworkSeriesView extends View { canvas.restoreToCount(save); } - save = canvas.save(); - canvas.clipRect(0, 0, primaryLeftPoint, getHeight()); - canvas.drawPath(mPathFill, mPaintFillSecondary); - canvas.restoreToCount(save); + final Paint paintFill = mSecondary ? mPaintFillSecondary : mPaintFill; save = canvas.save(); - canvas.clipRect(primaryRightPoint, 0, getWidth(), getHeight()); - canvas.drawPath(mPathFill, mPaintFillSecondary); + canvas.clipRect(mSafeRegion, 0, getWidth(), getHeight() - mSafeRegion); + canvas.drawPath(mPathFill, paintFill); canvas.restoreToCount(save); - - save = canvas.save(); - canvas.clipRect(primaryLeftPoint, 0, primaryRightPoint, getHeight()); - canvas.drawPath(mPathFill, mPaintFill); - canvas.drawPath(mPathStroke, mPaintStroke); - canvas.restoreToCount(save); - } } diff --git a/src/com/android/settings/widget/ChartSweepView.java b/src/com/android/settings/widget/ChartSweepView.java index 774e5d8..04fc862 100644 --- a/src/com/android/settings/widget/ChartSweepView.java +++ b/src/com/android/settings/widget/ChartSweepView.java @@ -58,6 +58,7 @@ public class ChartSweepView extends View { private Rect mMargins = new Rect(); private float mNeighborMargin; + private int mSafeRegion; private int mFollowAxis; @@ -125,6 +126,7 @@ public class ChartSweepView extends View { setSweepDrawable(a.getDrawable(R.styleable.ChartSweepView_sweepDrawable)); setFollowAxis(a.getInt(R.styleable.ChartSweepView_followAxis, -1)); setNeighborMargin(a.getDimensionPixelSize(R.styleable.ChartSweepView_neighborMargin, 0)); + setSafeRegion(a.getDimensionPixelSize(R.styleable.ChartSweepView_safeRegion, 0)); setLabelMinSize(a.getDimensionPixelSize(R.styleable.ChartSweepView_labelSize, 0)); setLabelTemplate(a.getResourceId(R.styleable.ChartSweepView_labelTemplate, 0)); @@ -259,7 +261,6 @@ public class ChartSweepView extends View { paint.density = getResources().getDisplayMetrics().density; paint.setCompatibilityScaling(getResources().getCompatibilityInfo().applicationScale); paint.setColor(mLabelColor); - paint.setShadowLayer(4 * paint.density, 0, 0, Color.BLACK); mLabelTemplate = new SpannableStringBuilder(template); mLabelLayout = new DynamicLayout( @@ -383,6 +384,10 @@ public class ChartSweepView extends View { mNeighborMargin = neighborMargin; } + public void setSafeRegion(int safeRegion) { + mSafeRegion = safeRegion; + } + /** * Set valid range this sweep can move within, defined by the given * {@link ChartSweepView}. The most restrictive combination of all valid @@ -709,7 +714,7 @@ public class ChartSweepView extends View { mLabelLayout.draw(canvas); } canvas.restoreToCount(count); - labelSize = (int) mLabelSize; + labelSize = (int) mLabelSize + mSafeRegion; } else { labelSize = 0; } diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java index 69e6e94..30284bc 100644 --- a/src/com/android/settings/widget/ChartView.java +++ b/src/com/android/settings/widget/ChartView.java @@ -112,12 +112,18 @@ public class ChartView extends FrameLayout { parentRect.set(mContent); - if (child instanceof ChartNetworkSeriesView || child instanceof ChartGridView) { + if (child instanceof ChartNetworkSeriesView) { // series are always laid out to fill entire graph area // TODO: handle scrolling for series larger than content area Gravity.apply(params.gravity, width, height, parentRect, childRect); child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom); + } else if (child instanceof ChartGridView) { + // Grid uses some extra room for labels + Gravity.apply(params.gravity, width, height, parentRect, childRect); + child.layout(childRect.left, childRect.top, childRect.right, + childRect.bottom + child.getPaddingBottom()); + } else if (child instanceof ChartSweepView) { layoutSweep((ChartSweepView) child, parentRect, childRect); child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom); @@ -154,5 +160,4 @@ public class ChartView extends FrameLayout { parentRect, childRect); } } - } diff --git a/src/com/android/settings/widget/PieChartView.java b/src/com/android/settings/widget/PieChartView.java deleted file mode 100644 index 6070190..0000000 --- a/src/com/android/settings/widget/PieChartView.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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.widget; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Paint.Style; -import android.graphics.Path; -import android.graphics.Path.Direction; -import android.graphics.RadialGradient; -import android.graphics.RectF; -import android.graphics.Shader.TileMode; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; - -import com.google.android.collect.Lists; - -import java.util.ArrayList; - -/** - * Pie chart with multiple items. - */ -public class PieChartView extends View { - public static final String TAG = "PieChartView"; - public static final boolean LOGD = false; - - private static final boolean FILL_GRADIENT = false; - - private ArrayList<Slice> mSlices = Lists.newArrayList(); - - private int mOriginAngle; - private Matrix mMatrix = new Matrix(); - - private Paint mPaintOutline = new Paint(); - - private Path mPathSide = new Path(); - private Path mPathSideOutline = new Path(); - - private Path mPathOutline = new Path(); - - private int mSideWidth; - - public class Slice { - public long value; - - public Path path = new Path(); - public Path pathSide = new Path(); - public Path pathOutline = new Path(); - - public Paint paint; - - public Slice(long value, int color) { - this.value = value; - this.paint = buildFillPaint(color, getResources()); - } - } - - public PieChartView(Context context) { - this(context, null); - } - - public PieChartView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PieChartView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mPaintOutline.setColor(Color.BLACK); - mPaintOutline.setStyle(Style.STROKE); - mPaintOutline.setStrokeWidth(3f * getResources().getDisplayMetrics().density); - mPaintOutline.setAntiAlias(true); - - mSideWidth = (int) (20 * getResources().getDisplayMetrics().density); - - setWillNotDraw(false); - } - - private static Paint buildFillPaint(int color, Resources res) { - final Paint paint = new Paint(); - - paint.setColor(color); - paint.setStyle(Style.FILL_AND_STROKE); - paint.setAntiAlias(true); - - if (FILL_GRADIENT) { - final int width = (int) (280 * res.getDisplayMetrics().density); - paint.setShader(new RadialGradient(0, 0, width, color, darken(color), TileMode.MIRROR)); - } - - return paint; - } - - public void setOriginAngle(int originAngle) { - mOriginAngle = originAngle; - } - - public void addSlice(long value, int color) { - mSlices.add(new Slice(value, color)); - } - - public void removeAllSlices() { - mSlices.clear(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - final float centerX = getWidth() / 2; - final float centerY = getHeight() / 2; - - mMatrix.reset(); - mMatrix.postScale(0.665f, 0.95f, centerX, centerY); - mMatrix.postRotate(-40, centerX, centerY); - - generatePath(); - } - - public void generatePath() { - if (LOGD) Log.d(TAG, "generatePath()"); - - long total = 0; - for (Slice slice : mSlices) { - slice.path.reset(); - slice.pathSide.reset(); - slice.pathOutline.reset(); - total += slice.value; - } - - mPathSide.reset(); - mPathSideOutline.reset(); - mPathOutline.reset(); - - // bail when not enough stats to render - if (total == 0) { - invalidate(); - return; - } - - final int width = getWidth(); - final int height = getHeight(); - - final RectF rect = new RectF(0, 0, width, height); - final RectF rectSide = new RectF(); - rectSide.set(rect); - rectSide.offset(-mSideWidth, 0); - - mPathSide.addOval(rectSide, Direction.CW); - mPathSideOutline.addOval(rectSide, Direction.CW); - mPathOutline.addOval(rect, Direction.CW); - - int startAngle = mOriginAngle; - for (Slice slice : mSlices) { - final int sweepAngle = (int) (slice.value * 360 / total); - final int endAngle = startAngle + sweepAngle; - - final float startAngleMod = startAngle % 360; - final float endAngleMod = endAngle % 360; - final boolean startSideVisible = startAngleMod > 90 && startAngleMod < 270; - final boolean endSideVisible = endAngleMod > 90 && endAngleMod < 270; - - // draw slice - slice.path.moveTo(rect.centerX(), rect.centerY()); - slice.path.arcTo(rect, startAngle, sweepAngle); - slice.path.lineTo(rect.centerX(), rect.centerY()); - - if (startSideVisible || endSideVisible) { - - // when start is beyond horizon, push until visible - final float startAngleSide = startSideVisible ? startAngle : 450; - final float endAngleSide = endSideVisible ? endAngle : 270; - final float sweepAngleSide = endAngleSide - startAngleSide; - - // draw slice side - slice.pathSide.moveTo(rect.centerX(), rect.centerY()); - slice.pathSide.arcTo(rect, startAngleSide, 0); - slice.pathSide.rLineTo(-mSideWidth, 0); - slice.pathSide.arcTo(rectSide, startAngleSide, sweepAngleSide); - slice.pathSide.rLineTo(mSideWidth, 0); - slice.pathSide.arcTo(rect, endAngleSide, -sweepAngleSide); - } - - // draw slice outline - slice.pathOutline.moveTo(rect.centerX(), rect.centerY()); - slice.pathOutline.arcTo(rect, startAngle, 0); - if (startSideVisible) { - slice.pathOutline.rLineTo(-mSideWidth, 0); - } - slice.pathOutline.moveTo(rect.centerX(), rect.centerY()); - slice.pathOutline.arcTo(rect, startAngle + sweepAngle, 0); - if (endSideVisible) { - slice.pathOutline.rLineTo(-mSideWidth, 0); - } - - startAngle += sweepAngle; - } - - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - - canvas.concat(mMatrix); - - for (Slice slice : mSlices) { - canvas.drawPath(slice.pathSide, slice.paint); - } - canvas.drawPath(mPathSideOutline, mPaintOutline); - - for (Slice slice : mSlices) { - canvas.drawPath(slice.path, slice.paint); - canvas.drawPath(slice.pathOutline, mPaintOutline); - } - canvas.drawPath(mPathOutline, mPaintOutline); - } - - public static int darken(int color) { - float[] hsv = new float[3]; - Color.colorToHSV(color, hsv); - hsv[2] /= 2; - hsv[1] /= 2; - return Color.HSVToColor(hsv); - } - -} |