From 52c3f4461b806e4f1ce48455ee2ba0ac05dfdab4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 23 Jun 2011 00:39:38 -0700 Subject: [PATCH] Iterate on data usage chart UI. Switched to inflating chart views from XML, using attributes for configuration. Start using drawable assets for chart components instead of manually painting. Include hand-cut assets, and animate between states when touched to invoke. Clamp sweeps to valid chart ranges and prepare for sweep labels. Bug: 4768483, 4598460 Change-Id: Ic660c35bec826eb5e3f6a1dde3cc04d8c437ef2b --- res/drawable-hdpi/data_grid_border.9.png | Bin 0 -> 229 bytes res/drawable-hdpi/data_grid_primary.9.png | Bin 0 -> 203 bytes res/drawable-hdpi/data_grid_secondary.9.png | Bin 0 -> 193 bytes .../data_sweep_left_activated.9.png | Bin 0 -> 851 bytes .../data_sweep_left_default.9.png | Bin 0 -> 790 bytes .../data_sweep_limit_activated.9.png | Bin 0 -> 711 bytes .../data_sweep_limit_default.9.png | Bin 0 -> 833 bytes .../data_sweep_right_activated.9.png | Bin 0 -> 766 bytes .../data_sweep_right_default.9.png | Bin 0 -> 799 bytes .../data_sweep_warning_activated.9.png | Bin 0 -> 813 bytes .../data_sweep_warning_default.9.png | Bin 0 -> 847 bytes res/drawable/data_sweep_left.xml | 22 +++ res/drawable/data_sweep_limit.xml | 22 +++ res/drawable/data_sweep_right.xml | 22 +++ res/drawable/data_sweep_warning.xml | 22 +++ res/layout/data_usage_chart.xml | 79 ++++++++ res/layout/data_usage_item.xml | 39 ++++ res/values/attrs.xml | 22 +++ res/values/strings.xml | 7 +- .../android/settings/DataUsageSummary.java | 12 +- .../android/settings/widget/ChartAxis.java | 1 + .../settings/widget/ChartGridView.java | 73 ++++--- .../widget/ChartNetworkSeriesView.java | 81 ++++---- .../settings/widget/ChartSweepView.java | 183 +++++++++++------ .../android/settings/widget/ChartView.java | 54 +++-- .../settings/widget/DataUsageChartView.java | 187 ++++++++++++------ .../settings/widget/InvertedChartAxis.java | 5 + 27 files changed, 608 insertions(+), 223 deletions(-) create mode 100644 res/drawable-hdpi/data_grid_border.9.png create mode 100644 res/drawable-hdpi/data_grid_primary.9.png create mode 100644 res/drawable-hdpi/data_grid_secondary.9.png create mode 100644 res/drawable-hdpi/data_sweep_left_activated.9.png create mode 100644 res/drawable-hdpi/data_sweep_left_default.9.png create mode 100644 res/drawable-hdpi/data_sweep_limit_activated.9.png create mode 100644 res/drawable-hdpi/data_sweep_limit_default.9.png create mode 100644 res/drawable-hdpi/data_sweep_right_activated.9.png create mode 100644 res/drawable-hdpi/data_sweep_right_default.9.png create mode 100644 res/drawable-hdpi/data_sweep_warning_activated.9.png create mode 100644 res/drawable-hdpi/data_sweep_warning_default.9.png create mode 100644 res/drawable/data_sweep_left.xml create mode 100644 res/drawable/data_sweep_limit.xml create mode 100644 res/drawable/data_sweep_right.xml create mode 100644 res/drawable/data_sweep_warning.xml create mode 100644 res/layout/data_usage_chart.xml create mode 100644 res/layout/data_usage_item.xml diff --git a/res/drawable-hdpi/data_grid_border.9.png b/res/drawable-hdpi/data_grid_border.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e0110b699aa9b4fd0a6c6a8dfa0734f4c12b0663 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)HgQG~BS8rR4WN)@iEBiObAE1a zYF-J0b5UwyNotBhd1gt5g1e`0KzJjcI8c#;r;B5V#O34!2iE@!CHN#HB_t#+t=j%C z{Qy(i)+%EoLjeY#6K?0SzNXE&`s!>)j;f<@#DaG}`VZ^2+&$oMVm3p;ae)#Qfh(JV PW-)lW`njxgN@xNAm!m{- literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/data_grid_primary.9.png b/res/drawable-hdpi/data_grid_primary.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b7b82b623d6486f93554a5331998ca20db71ed GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1|(O0oL2{=7>k44ofy`glX(f`uqAoByDx`7I;J!Gca%qgD@k*tT_@uLG}_)Usv|qY~l>oOe*q0_kco@C9V-A&iT2y zsd*&~&PAz-C8;S2<(VZJ3hti10pX2&;y^`eo-U3d9M_W*8XEowoH=mfz=03;Ypb-G mf#C3(uzWT(HW`L>tPDCQ+5a=-xYYu6FnGH9xvXQL70(Y)*K0-AbW|YuPgg)HgN`N^XD3y;(|2Mr-@_?y; ZjUjM4OXbvb_m4nz44$rjF6*2UngALWGLirQ literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/data_sweep_left_activated.9.png b/res/drawable-hdpi/data_sweep_left_activated.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e91ccf5fb1ac02c6a6c03250e74d66a090cc4ec4 GIT binary patch literal 851 zcmV-Z1FZasP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01lu401lu52jA`V00007bV*G`2ipb~ z7Bm@&^*>qw00PrVL_t(|+U?xUP8v}Z!14ce&U|fMcTHFN3MPV}f>>09G)?VC`T{;h zAD~IoG>r`bgdz?|H@-!auH5-1(}hTkQN!mj*mIM+;A8ImayT>ho*Te~VaTY>7{fTn z-5Vne!_bU;+@vRtx-GF_ZQ;NY)rpKTUw{{P0(IL>zc<4$Jc$h$NC7XOc>PbTA`FB8 z$H&Jc5{bc+K@f0xc^SWyxNZ4-p0%~L!Q<=e>!HEMm{9K$3ce3E#)MH`bQ6Qena?#P z6db1<)(9(Db68VC!FthYgcYngtPxhQ=CG!Of;EQ~{G7qY7z6kV0q$eJ0tw5qSYBS9 zXgrAk`wjSHSr(N_g_V_+c!K-b@4!dPvZz+8l*{Fb$CVjjm-^TbmSs_^)hLxpQyE)k zg#7`$6A@~)8i$96QyX7qfIR`;iU{?3ono;#)quzpu@>+Xcq1a5o}O}Wa4_|BlPO{= zz-tkq(P*&0zdw_US*C=o0%hB_X*3$_?d{F%Rw)x=rH?JywoS9yq);f#bRv=ov2~zm z+cvFMi{0JbnNRaF0k#3`JB~xE)gqtIN3!^lF|an!1PYGhaCUaa&dyF`t2G$|`wMvG zI1cT0n_Mmz>GD!Wz&bz+$h)pfyWJ+6%|^Z+mJzURAm_R+=jZ2aZ*R|K0WU*f-99$! zx-LNwu(h={w~9lCzy`pU=XnG{z~<)WTuUT*0_y=CAme!+olb{LCNuY%PM*Mafwbp& zbh};B>2xfLPbYEh1b@l(=`BAWf6|7(dKM!yihDIZ-UwZwzY=q!dAa|_pa}r>cgbU%9%kcOAPHSEI4?@1h>W>Ixzj9l2O=Fy~4>=dDB}O zd2wD|1+0UAJWxH)-m_mE^Fn({aZ(!TvKWBe~ z>;!k^dgo}DX${*Q!dzy|oqP0qZP8AdvuTsv7CUagUD}?{d_H7rvFo}M;bmMucwd}3 z)AR1_+m}yYeE%J_GQ?!2Pu!Z43taA3Apw9P81sd=-@p6v=xr_ddS8~5+a=LIc(xa(|$ zw(JL{3p;mOzWrLYFmKn|wYuep=Q4h0f7UB7hcT*Q+Ucj+8}H_YtE;Qa{`fkzQh8lT z_kl>Ii5I?pEq(j_H}gh!clRg_5t(nd7uep|YB5h$>wvd|&H3ci)Yhbp9%i$je)uq< zYVWyY$JmxHU(R6PczjjV{Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01lu401lu52jA`V00007bV*G`2ipb~ z7BLO(SRY~l00KuzL_t(|+U?uRYt=v$$MNr(BsU56D!I7xCW3-41>ahH)uM;BX1CIcYjmyzva;A#fxT;j&{8K4ApF1K?;R!bn!I z#W4t9FiMEyp$M0VbA%GvG#go_vg+y;iq8Q}|rYZxWOaDZ?jYqKNu2f`%` z0d4_j48r-W&CYZQzQs5KaT7ROLhSMoqWpv~GdF-i{=9pzJJ0b#&Y3w*fmJ2MfTs|% zVYGqOc1>U5T(-<>h}kdzIM%n+nzz}e1gxlFJBzS!m>M&%WBCIrr+H^9wv9b7@|{KtBKg002ovPDHLkV1mMID4+lU literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/data_sweep_limit_default.9.png b/res/drawable-hdpi/data_sweep_limit_default.9.png new file mode 100644 index 0000000000000000000000000000000000000000..dea3a0b153ca01ec6e8506449cafdbb9f215e3a9 GIT binary patch literal 833 zcmV-H1HSx;P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01lu401lu52jA`V00007bV*G`2ipb~ z7BLS1R(?(Z00O~DL_t(|+U?uTOH@%9$MNr(=FJ%=%}h)wD+`PadqE05Mbixij;$u(4u%8@xB9d48)q z%()!qeD1mTJcm0*L|AH!F(M)cjVCe1U}!vqFh+bj3@ay!p%@y)Pz;S?D27Hc6hosJ zilI>q#n32*MllpaqZo>zQ4Gbf0d& z5Dmap;LrliJ_4sjdKoPaSLj#SV+X#?!@6l49WAlrjwC4uqC zo&cb!$ltpyFx$S>m7>oWQ}R!6E9(HT))y%1yei-9wOr>4hQ8ttTLNJKJ~*kO&ijK z)>?tj7F`B-0JQlq951h?BUV#z%X(tRxis;Ov1|t5JFr7UMs+*HeULh!2WSTf86R5% zVHyKrtgOS^bc*p@Cf|GrI3*(eF7>S#^9;-x;3BYkj;{r{44f5_q>Ftj#sY&A0d@g< zfM#a)pk4wmM8xu-KgC!<`1)_xl@!HL3{BB>hHfJMv4r{udw4$qXr1=Kv_YR)00000 LNkvXXu0mjfsz6{d literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/data_sweep_right_activated.9.png b/res/drawable-hdpi/data_sweep_right_activated.9.png new file mode 100644 index 0000000000000000000000000000000000000000..afb15d63618501c0b7653b69a9091e5d8301497c GIT binary patch literal 766 zcmVPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01lu401lu52jA`V00007bV*G`2ipb~ z7Be3&*9@ot00MqVL_t(|+U?xQjuKH6fZ-pRxBU>hY92y{VrtrA4l%|d#*GiqkI<{$ z8l%QYfTm;yAAm<-r?U1P*jaA+wzV)VLsj)9IVT~cLQ#Ah-jt9Um;H@9v(3a;t0*pIe|LIqTL%W=87zUlYp$-YwEWh%1ni58 z3)>mXggJT#!#(=T?1P7!f1nfT8mJAD6YFIKXU;)dZ6R^~Cd1+iit@1HAVdeQ-&%S}i)A zjzYf%K6r_CrG}f$Cf#mVp^~6!FR_XWq3jGvlyM^{_rmIvcSe8XN90q6s9XHUPPR-?V z*@`?fY87G))GBfkHQc-XUmT7C-0b=M0BKB9RC{4e0NS_HDIRDwUk*3h)&O zYrVWYJ3C`E8Y#5758C(jaIsiqJRTE`Mgg7xLm;B{0=`fvIMF3wv@QDHI*xok&tx)D z=prx%qFT2|xm=FvbV@8111JEK|Do@_r^{xuPIL~K0WqzcP{S~o&1MR1+=bSrYtCdc z%;$6B@i;&RSll$X`nLJ$blQnd{R^$#zCR|t*2%I3s}Gc7O;wdWLUrg7O;Q?EMNf(Sik}nuz+u4r@N7sWwBbVe1UB?n}gne w$={#3-^XL;3=e=GNbJ$)-#j17KXL^A06QYIV?c9UC;$Ke07*qoM6N<$f8!j(_}a&gRO@w@^2Nqm{2oz(;3EOOw~}zPny?t(KIQ?Dn)0S>nCI-m??AG?D%DB4y)eZ^XbVxdy9F+lU|t3 zDW3FXhl|DY9T&>upE!q0YW~vs#W$y~a<47>Jhwed6=3hiA;2 zmzJ0J?#tJA@AOWeK7BGyc#@UefozA*pFjVyHZwP8<+#y*`FtwBgPFI)51kv9*TcPI zUu~*p+O5KqlfW!};{co4hDKgunC`COOMBSa*>!YvH*VePsy98kq{O7Mu;-H_`9tfSI5?QavElviH*emw%r$LDpJew{Yv;M0 zefu+b1FYs=d-P~g)Y@t1jvYJJcI^1^!#@96-hDAT9H_3{z{bY5W#7JaD=aK6FP=H$ z)A7$|_cl920|TZ%3{NWOJ#yI_7p^v$^J4#GHhTsW8=Ez0n^*4GxM71p(|wg#`x^cQ z5jsXDCL+}VQ@oa5PP@eIF1H{+qvUF&-F*JptxFF6W@vA3k1Z8ralCQo^~G5a&oS4t zeyH8Qns4>htQ%j1V_!DRKA`WgdiCm!Y%!Z}UO95a#o|TWmmIx5iHZ4)y}i9JU%XhM zeB<*TfoOK4a7H=CeT-US-M8-D`=`F;YSzimHcNvvxBj1cGwz+b)mzn52izYVd+J-=3sNS-&c(1C`tGl;GA86;>y>)L~x>;D;`IO&*)z{1R z+xoM=z4?IqL)@i8q1%bo3>T0i?Ehchw{?{v5tDxN>R9Xj;Z``A228ySp00i_>zopr E0OH7IwEzGB literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/data_sweep_warning_activated.9.png b/res/drawable-hdpi/data_sweep_warning_activated.9.png new file mode 100644 index 0000000000000000000000000000000000000000..81a7aa87506b643c59a81e5c55778a7a627a96d5 GIT binary patch literal 813 zcmV+|1JeA7P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01lu401lu52jA`V00007bV*G`2ipb~ z7BMzoQ}#vx00ON^L_t(|+U?xCPZUuU$MNr7(Fn0IbjDg^q9IW`OEp%$!efz_tZ0ad ze+`XMo`NwNM39FF>RMQfh@ucJEVMB*70J%-&f{3XHn1AeEHk@ve%%zC+?>zO%$+;u zju8?5HpUnc5rd{AG26k=ln}xgNoX0O6U9&rjbbQGoHMPiWqYZ4qiusfC*0Q98S=t-|dVvxHM z(BEE5@?=fyFunt;g&TRXoBKA7|K&HEkE{KFLtP^_2?LEMYT|<-BDbP6Kx2#nZu?npuYg}{eW9h#=2;nn zR7^vHh30tM6$-1 zi@=oQ%9;8*79-bcITk`2kdxo~ND<53uEv;ZUPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01lu401lu52jA`V00007bV*G`2ipb~ z7BUF6AGj_600PfRL_t(|+U=T6NK{c2fWJFBGx^hmBB3T(=1N5?RH6|=1QXl145CGU zu4>WFA_{UiOH*CXKdh|Z~M;W zy?4KN&%5Vvjfk*bj4>i21|=q#NMtB66k&`wbQ%pD)cUjf?eulFx;|vEZfH9y@L`GvG z!x&Q!QxlrTb@{w(8 z#`*jq4qh7}XbC{Ah_r1~M%W*?caNKbET=65431m0`({W>cF<7cS=X4tEGH+uDcpJa z6QB}k+vszIm2tEznbY1>TgbTnG(fv=hSFRYu7vfs-pY5m7iE-3rRX!p*!~ax?rR8u zk{nk=3s=6;K5(bqRNM|XeF7BW0r7P>+`Um|X@RbW6D-5~^mi8?=On-Ae^{SFB_V0|Pe9Rv99s)Hna2 zt09vl=jz$}YHI+WKLiUss|VT+iEag+4)}n~ihMVBkEN5B@$a`fJ0~7M4pa0ozvD7c#Wy(=?^143(j%43(j%43(j%43(j%43(k$CssX>peNLq*^C3? ZzX74e{+}mflHC9R002ovPDHLkV1lvwa4G-* literal 0 HcmV?d00001 diff --git a/res/drawable/data_sweep_left.xml b/res/drawable/data_sweep_left.xml new file mode 100644 index 00000000000..739a74ecb95 --- /dev/null +++ b/res/drawable/data_sweep_left.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/res/drawable/data_sweep_limit.xml b/res/drawable/data_sweep_limit.xml new file mode 100644 index 00000000000..29ecec8c939 --- /dev/null +++ b/res/drawable/data_sweep_limit.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/res/drawable/data_sweep_right.xml b/res/drawable/data_sweep_right.xml new file mode 100644 index 00000000000..1a114699bc4 --- /dev/null +++ b/res/drawable/data_sweep_right.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/res/drawable/data_sweep_warning.xml b/res/drawable/data_sweep_warning.xml new file mode 100644 index 00000000000..5cafe068bb2 --- /dev/null +++ b/res/drawable/data_sweep_warning.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/res/layout/data_usage_chart.xml b/res/layout/data_usage_chart.xml new file mode 100644 index 00000000000..5fd640f51a2 --- /dev/null +++ b/res/layout/data_usage_chart.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/layout/data_usage_item.xml b/res/layout/data_usage_item.xml new file mode 100644 index 00000000000..6451e214f44 --- /dev/null +++ b/res/layout/data_usage_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + + diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 7cff69c2e3d..06d26508658 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -49,4 +49,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 986d86789d2..5839934d518 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3456,7 +3456,7 @@ found in the list of installed applications. Date of each month: - set + Set Limiting data usage @@ -3476,6 +3476,9 @@ found in the list of installed applications. The specified data usage limit has been reached.\n\nAdditional data use may incur carrier charges. - re-enable data + Re-enable data + + + %1$s %2$s\nwarning diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java index ef2282aef97..692c75382ef 100644 --- a/src/com/android/settings/DataUsageSummary.java +++ b/src/com/android/settings/DataUsageSummary.java @@ -27,7 +27,6 @@ import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; import static android.net.NetworkTemplate.MATCH_MOBILE_4G; import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; import static android.net.NetworkTemplate.MATCH_WIFI; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.app.AlertDialog; @@ -68,7 +67,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; @@ -204,6 +202,7 @@ public class DataUsageSummary extends Fragment { mDataEnabled.setOnCheckedChangeListener(mDataEnabledListener); mDisableAtLimit = new CheckBox(inflater.getContext()); + mDisableAtLimit.setClickable(false); mDisableAtLimitView = inflatePreference(inflater, mSwitches, mDisableAtLimit); mDisableAtLimitView.setOnClickListener(mDisableAtLimitListener); @@ -216,11 +215,8 @@ public class DataUsageSummary extends Fragment { mCycleSpinner.setAdapter(mCycleAdapter); mCycleSpinner.setOnItemSelectedListener(mCycleListener); - final int chartHeight = getResources().getDimensionPixelSize( - R.dimen.data_usage_chart_height); - mChart = new DataUsageChartView(context); + mChart = (DataUsageChartView) inflater.inflate(R.layout.data_usage_chart, mListView, false); mChart.setListener(mChartListener); - mChart.setLayoutParams(new AbsListView.LayoutParams(MATCH_PARENT, chartHeight)); mListView.addHeaderView(mChart, null, false); mAdapter = new DataUsageAdapter(); @@ -791,7 +787,7 @@ public class DataUsageSummary extends Fragment { public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()).inflate( - android.R.layout.simple_list_item_2, parent, false); + R.layout.data_usage_item, parent, false); } final Context context = parent.getContext(); @@ -1080,7 +1076,7 @@ public class DataUsageSummary extends Fragment { /** * Set {@link android.R.id#title} for a preference view inflated with - * {@link #inflatePreference(LayoutInflater, View, View)}. + * {@link #inflatePreference(LayoutInflater, ViewGroup, View)}. */ private static void setPreferenceTitle(View parent, int resId) { final TextView title = (TextView) parent.findViewById(android.R.id.title); diff --git a/src/com/android/settings/widget/ChartAxis.java b/src/com/android/settings/widget/ChartAxis.java index 2b21d285616..e761202d679 100644 --- a/src/com/android/settings/widget/ChartAxis.java +++ b/src/com/android/settings/widget/ChartAxis.java @@ -29,6 +29,7 @@ public interface ChartAxis { public long convertToValue(float point); public CharSequence getLabel(long value); + public CharSequence getShortLabel(long value); public float[] getTickPoints(); diff --git a/src/com/android/settings/widget/ChartGridView.java b/src/com/android/settings/widget/ChartGridView.java index be71890b969..7a83fbfbe36 100644 --- a/src/com/android/settings/widget/ChartGridView.java +++ b/src/com/android/settings/widget/ChartGridView.java @@ -17,12 +17,13 @@ package com.android.settings.widget; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Style; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; import android.view.View; +import com.android.settings.R; import com.google.common.base.Preconditions; /** @@ -31,32 +32,42 @@ import com.google.common.base.Preconditions; */ public class ChartGridView extends View { - private final ChartAxis mHoriz; - private final ChartAxis mVert; + // TODO: eventually teach about drawing chart labels - private final Paint mPaintHoriz; - private final Paint mPaintVert; + private ChartAxis mHoriz; + private ChartAxis mVert; - public ChartGridView(Context context, ChartAxis horiz, ChartAxis vert) { - super(context); + private Drawable mPrimary; + private Drawable mSecondary; + private Drawable mBorder; - mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); - mVert = Preconditions.checkNotNull(vert, "missing vert"); + public ChartGridView(Context context) { + this(context, null, 0); + } + + public ChartGridView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ChartGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); setWillNotDraw(false); - // TODO: convert these colors to resources - mPaintHoriz = new Paint(); - mPaintHoriz.setColor(Color.parseColor("#667bb5")); - mPaintHoriz.setStrokeWidth(2.0f); - mPaintHoriz.setStyle(Style.STROKE); - mPaintHoriz.setAntiAlias(true); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ChartGridView, defStyle, 0); - mPaintVert = new Paint(); - mPaintVert.setColor(Color.parseColor("#28262c")); - mPaintVert.setStrokeWidth(1.0f); - mPaintVert.setStyle(Style.STROKE); - mPaintVert.setAntiAlias(true); + mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable); + mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable); + mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable); + // TODO: eventually read labelColor + + a.recycle(); + } + + void init(ChartAxis horiz, ChartAxis vert) { + mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); + mVert = Preconditions.checkNotNull(vert, "missing vert"); } @Override @@ -64,16 +75,28 @@ public class ChartGridView extends View { final int width = getWidth(); final int height = getHeight(); + final Drawable secondary = mSecondary; + final int secondaryHeight = mSecondary.getIntrinsicHeight(); + final float[] vertTicks = mVert.getTickPoints(); for (float y : vertTicks) { - canvas.drawLine(0, y, width, y, mPaintVert); + 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) { - canvas.drawLine(x, 0, x, height, mPaintHoriz); + final int right = (int) Math.min(x + primaryWidth, width); + primary.setBounds((int) x, 0, right, height); + primary.draw(canvas); } - canvas.drawRect(0, 0, width, height, mPaintHoriz); + mBorder.setBounds(0, 0, width, height); + mBorder.draw(canvas); } } diff --git a/src/com/android/settings/widget/ChartNetworkSeriesView.java b/src/com/android/settings/widget/ChartNetworkSeriesView.java index 780ca46583f..0a34565faca 100644 --- a/src/com/android/settings/widget/ChartNetworkSeriesView.java +++ b/src/com/android/settings/widget/ChartNetworkSeriesView.java @@ -17,6 +17,7 @@ package com.android.settings.widget; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -24,9 +25,11 @@ import android.graphics.Paint.Style; import android.graphics.Path; import android.graphics.RectF; import android.net.NetworkStatsHistory; +import android.util.AttributeSet; import android.util.Log; import android.view.View; +import com.android.settings.R; import com.google.common.base.Preconditions; /** @@ -37,35 +40,54 @@ public class ChartNetworkSeriesView extends View { private static final String TAG = "ChartNetworkSeriesView"; private static final boolean LOGD = true; - private final ChartAxis mHoriz; - private final ChartAxis mVert; + private ChartAxis mHoriz; + private ChartAxis mVert; private Paint mPaintStroke; private Paint mPaintFill; - private Paint mPaintFillDisabled; + private Paint mPaintFillSecondary; private NetworkStatsHistory mStats; private Path mPathStroke; private Path mPathFill; - private ChartSweepView mSweep1; - private ChartSweepView mSweep2; + private long mPrimaryLeft; + private long mPrimaryRight; - public ChartNetworkSeriesView(Context context, ChartAxis horiz, ChartAxis vert) { - super(context); + public ChartNetworkSeriesView(Context context) { + this(context, null, 0); + } - mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); - mVert = Preconditions.checkNotNull(vert, "missing vert"); + public ChartNetworkSeriesView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } - setChartColor(Color.parseColor("#24aae1"), Color.parseColor("#c050ade5"), - Color.parseColor("#88566abc")); + public ChartNetworkSeriesView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ChartNetworkSeriesView, defStyle, 0); + + final int stroke = a.getColor(R.styleable.ChartNetworkSeriesView_strokeColor, Color.RED); + final int fill = a.getColor(R.styleable.ChartNetworkSeriesView_fillColor, Color.RED); + final int fillSecondary = a.getColor( + R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED); + + setChartColor(stroke, fill, fillSecondary); + + a.recycle(); mPathStroke = new Path(); mPathFill = new Path(); } - public void setChartColor(int stroke, int fill, int disabled) { + void init(ChartAxis horiz, ChartAxis vert) { + mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); + mVert = Preconditions.checkNotNull(vert, "missing vert"); + } + + public void setChartColor(int stroke, int fill, int fillSecondary) { mPaintStroke = new Paint(); mPaintStroke.setStrokeWidth(6.0f); mPaintStroke.setColor(stroke); @@ -77,10 +99,10 @@ public class ChartNetworkSeriesView extends View { mPaintFill.setStyle(Style.FILL); mPaintFill.setAntiAlias(true); - mPaintFillDisabled = new Paint(); - mPaintFillDisabled.setColor(disabled); - mPaintFillDisabled.setStyle(Style.FILL); - mPaintFillDisabled.setAntiAlias(true); + mPaintFillSecondary = new Paint(); + mPaintFillSecondary.setColor(fillSecondary); + mPaintFillSecondary.setStyle(Style.FILL); + mPaintFillSecondary.setAntiAlias(true); } public void bindNetworkStats(NetworkStatsHistory stats) { @@ -90,12 +112,10 @@ public class ChartNetworkSeriesView extends View { mPathFill.reset(); } - public void bindSweepRange(ChartSweepView sweep1, ChartSweepView sweep2) { - // TODO: generalize to support vertical sweeps - // TODO: enforce that both sweeps are along same dimension - - mSweep1 = Preconditions.checkNotNull(sweep1, "missing sweep1"); - mSweep2 = Preconditions.checkNotNull(sweep2, "missing sweep2"); + public void setPrimaryRange(long left, long right) { + mPrimaryLeft = left; + mPrimaryRight = right; + invalidate(); } @Override @@ -168,27 +188,20 @@ public class ChartNetworkSeriesView extends View { @Override protected void onDraw(Canvas canvas) { - - // clip to sweep area - final float sweep1 = mSweep1.getPoint(); - final float sweep2 = mSweep2.getPoint(); - final float sweepLeft = Math.min(sweep1, sweep2); - final float sweepRight = Math.max(sweep1, sweep2); - int save; save = canvas.save(); - canvas.clipRect(0, 0, sweepLeft, getHeight()); - canvas.drawPath(mPathFill, mPaintFillDisabled); + canvas.clipRect(0, 0, mPrimaryLeft, getHeight()); + canvas.drawPath(mPathFill, mPaintFillSecondary); canvas.restoreToCount(save); save = canvas.save(); - canvas.clipRect(sweepRight, 0, getWidth(), getHeight()); - canvas.drawPath(mPathFill, mPaintFillDisabled); + canvas.clipRect(mPrimaryRight, 0, getWidth(), getHeight()); + canvas.drawPath(mPathFill, mPaintFillSecondary); canvas.restoreToCount(save); save = canvas.save(); - canvas.clipRect(sweepLeft, 0, sweepRight, getHeight()); + canvas.clipRect(mPrimaryLeft, 0, mPrimaryRight, 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 788caad4f9a..881fde41bca 100644 --- a/src/com/android/settings/widget/ChartSweepView.java +++ b/src/com/android/settings/widget/ChartSweepView.java @@ -17,63 +17,79 @@ package com.android.settings.widget; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.DashPathEffect; -import android.graphics.Paint; -import android.graphics.Paint.Style; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.MathUtils; import android.view.MotionEvent; import android.view.View; +import android.widget.FrameLayout; +import com.android.settings.R; import com.google.common.base.Preconditions; /** * Sweep across a {@link ChartView} at a specific {@link ChartAxis} value, which * a user can drag. */ -public class ChartSweepView extends View { +public class ChartSweepView extends FrameLayout { - private final Paint mPaintSweep; - private final Paint mPaintSweepDisabled; - private final Paint mPaintShadow; + // TODO: paint label when requested - private final ChartAxis mAxis; + private Drawable mSweep; + private int mFollowAxis; + private boolean mShowLabel; + + private ChartAxis mAxis; private long mValue; + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + public interface OnSweepListener { public void onSweep(ChartSweepView sweep, boolean sweepDone); } private OnSweepListener mListener; - - private boolean mHorizontal; private MotionEvent mTracking; - public ChartSweepView(Context context, ChartAxis axis, long value, int color) { - super(context); + public ChartSweepView(Context context) { + this(context, null, 0); + } + public ChartSweepView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ChartSweepView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ChartSweepView, defStyle, 0); + + setSweepDrawable(a.getDrawable(R.styleable.ChartSweepView_sweepDrawable)); + setFollowAxis(a.getInt(R.styleable.ChartSweepView_followAxis, -1)); + setShowLabel(a.getBoolean(R.styleable.ChartSweepView_showLabel, false)); + + a.recycle(); + + setClipToPadding(false); + setClipChildren(false); + setWillNotDraw(false); + } + + void init(ChartAxis axis) { mAxis = Preconditions.checkNotNull(axis, "missing axis"); - mValue = value; + } - mPaintSweep = new Paint(); - mPaintSweep.setColor(color); - mPaintSweep.setStrokeWidth(3.0f); - mPaintSweep.setStyle(Style.FILL_AND_STROKE); - mPaintSweep.setAntiAlias(true); - - mPaintSweepDisabled = new Paint(); - mPaintSweepDisabled.setColor(color); - mPaintSweepDisabled.setStrokeWidth(1.5f); - mPaintSweepDisabled.setStyle(Style.FILL_AND_STROKE); - mPaintSweepDisabled.setPathEffect(new DashPathEffect(new float[] { 5, 5 }, 0)); - mPaintSweepDisabled.setAntiAlias(true); - - mPaintShadow = new Paint(); - mPaintShadow.setColor(Color.BLACK); - mPaintShadow.setStrokeWidth(6.0f); - mPaintShadow.setStyle(Style.FILL_AND_STROKE); - mPaintShadow.setAntiAlias(true); + public int getFollowAxis() { + return mFollowAxis; + } + public void getExtraMargins(Rect rect) { + mSweep.getPadding(rect); } public void addOnSweepListener(OnSweepListener listener) { @@ -86,6 +102,56 @@ public class ChartSweepView extends View { } } + public void setSweepDrawable(Drawable sweep) { + if (mSweep != null) { + mSweep.setCallback(null); + unscheduleDrawable(mSweep); + } + + if (sweep != null) { + sweep.setCallback(this); + if (sweep.isStateful()) { + sweep.setState(getDrawableState()); + } + sweep.setVisible(getVisibility() == VISIBLE, false); + mSweep = sweep; + } else { + mSweep = null; + } + + invalidate(); + } + + public void setFollowAxis(int followAxis) { + mFollowAxis = followAxis; + } + + public void setShowLabel(boolean showLabel) { + mShowLabel = showLabel; + invalidate(); + } + + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + if (mSweep != null) { + mSweep.jumpToCurrentState(); + } + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (mSweep != null) { + mSweep.setVisible(visibility == VISIBLE, false); + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mSweep || super.verifyDrawable(who); + } + public ChartAxis getAxis() { return mAxis; } @@ -115,14 +181,24 @@ public class ChartSweepView extends View { case MotionEvent.ACTION_MOVE: { getParent().requestDisallowInterceptTouchEvent(true); - if (mHorizontal) { - setTranslationY(event.getRawY() - mTracking.getRawY()); + if (mFollowAxis == VERTICAL) { + final float chartHeight = parent.getHeight() - parent.getPaddingTop() + - parent.getPaddingBottom(); + final float translationY = MathUtils.constrain( + event.getRawY() - mTracking.getRawY(), -getTop(), + chartHeight - getTop()); + setTranslationY(translationY); final float point = (getTop() + getTranslationY() + (getHeight() / 2)) - parent.getPaddingTop(); mValue = mAxis.convertToValue(point); dispatchOnSweep(false); } else { - setTranslationX(event.getRawX() - mTracking.getRawX()); + final float chartWidth = parent.getWidth() - parent.getPaddingLeft() + - parent.getPaddingRight(); + final float translationX = MathUtils.constrain( + event.getRawX() - mTracking.getRawX(), -getLeft(), + chartWidth - getLeft()); + setTranslationX(translationX); final float point = (getLeft() + getTranslationX() + (getWidth() / 2)) - parent.getPaddingLeft(); mValue = mAxis.convertToValue(point); @@ -144,41 +220,26 @@ public class ChartSweepView extends View { } } + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + if (mSweep.isStateful()) { + mSweep.setState(getDrawableState()); + } + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // need at least 50px in each direction for grippies - // TODO: provide this value through params - setMeasuredDimension(50, 50); + setMeasuredDimension(mSweep.getIntrinsicWidth(), mSweep.getIntrinsicHeight()); } @Override protected void onDraw(Canvas canvas) { - - // draw line across larger dimension final int width = getWidth(); final int height = getHeight(); - mHorizontal = width > height; - - final Paint linePaint = isEnabled() ? mPaintSweep : mPaintSweepDisabled; - - if (mHorizontal) { - final int centerY = height / 2; - final int endX = width - height; - - canvas.drawLine(0, centerY, endX, centerY, mPaintShadow); - canvas.drawLine(0, centerY, endX, centerY, linePaint); - canvas.drawCircle(endX, centerY, 4.0f, mPaintShadow); - canvas.drawCircle(endX, centerY, 4.0f, mPaintSweep); - } else { - final int centerX = width / 2; - final int endY = height - width; - - canvas.drawLine(centerX, 0, centerX, endY, mPaintShadow); - canvas.drawLine(centerX, 0, centerX, endY, linePaint); - canvas.drawCircle(centerX, endY, 4.0f, mPaintShadow); - canvas.drawCircle(centerX, endY, 4.0f, mPaintSweep); - } + mSweep.setBounds(0, 0, width, height); + mSweep.draw(canvas); } } diff --git a/src/com/android/settings/widget/ChartView.java b/src/com/android/settings/widget/ChartView.java index 3e5fc5051b1..d762631c851 100644 --- a/src/com/android/settings/widget/ChartView.java +++ b/src/com/android/settings/widget/ChartView.java @@ -16,13 +16,11 @@ package com.android.settings.widget; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.google.common.base.Preconditions.checkNotNull; import android.content.Context; import android.graphics.Rect; -import android.util.Log; +import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; @@ -38,21 +36,31 @@ public class ChartView extends FrameLayout { // TODO: extend something that supports two-dimensional scrolling - final ChartAxis mHoriz; - final ChartAxis mVert; + ChartAxis mHoriz; + ChartAxis mVert; private Rect mContent = new Rect(); - public ChartView(Context context, ChartAxis horiz, ChartAxis vert) { - super(context); + public ChartView(Context context) { + this(context, null, 0); + } - mHoriz = checkNotNull(horiz, "missing horiz"); - mVert = checkNotNull(vert, "missing vert"); + public ChartView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ChartView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); setClipToPadding(false); setClipChildren(false); } + void init(ChartAxis horiz, ChartAxis vert) { + mHoriz = checkNotNull(horiz, "missing horiz"); + mVert = checkNotNull(vert, "missing vert"); + } + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(), @@ -66,6 +74,7 @@ public class ChartView extends FrameLayout { final Rect parentRect = new Rect(); final Rect childRect = new Rect(); + final Rect extraMargins = new Rect(); for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); @@ -82,23 +91,22 @@ public class ChartView extends FrameLayout { } else if (child instanceof ChartSweepView) { // sweep is always placed along specific dimension final ChartSweepView sweep = (ChartSweepView) child; - final ChartAxis axis = sweep.getAxis(); final float point = sweep.getPoint(); + sweep.getExtraMargins(extraMargins); - if (axis == mHoriz) { + if (sweep.getFollowAxis() == ChartSweepView.HORIZONTAL) { parentRect.left = parentRect.right = (int) point + getPaddingLeft(); - parentRect.bottom += child.getMeasuredWidth(); + parentRect.top -= extraMargins.top; + parentRect.bottom += extraMargins.bottom; Gravity.apply(params.gravity, child.getMeasuredWidth(), parentRect.height(), parentRect, childRect); - } else if (axis == mVert) { + } else { parentRect.top = parentRect.bottom = (int) point + getPaddingTop(); - parentRect.right += child.getMeasuredHeight(); + parentRect.left -= extraMargins.left; + parentRect.right += extraMargins.right; Gravity.apply(params.gravity, parentRect.width(), child.getMeasuredHeight(), parentRect, childRect); - - } else { - throw new IllegalStateException("unexpected axis"); } } @@ -106,16 +114,4 @@ public class ChartView extends FrameLayout { } } - public static LayoutParams buildChartParams() { - final LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - params.gravity = Gravity.LEFT | Gravity.BOTTOM; - return params; - } - - public static LayoutParams buildSweepParams() { - final LayoutParams params = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - params.gravity = Gravity.CENTER; - return params; - } - } diff --git a/src/com/android/settings/widget/DataUsageChartView.java b/src/com/android/settings/widget/DataUsageChartView.java index 6c62fa810ef..1c76291b46a 100644 --- a/src/com/android/settings/widget/DataUsageChartView.java +++ b/src/com/android/settings/widget/DataUsageChartView.java @@ -17,12 +17,14 @@ package com.android.settings.widget; import android.content.Context; -import android.graphics.Color; import android.net.NetworkPolicy; import android.net.NetworkStatsHistory; import android.text.format.DateUtils; +import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; +import com.android.settings.R; import com.android.settings.widget.ChartSweepView.OnSweepListener; /** @@ -35,13 +37,16 @@ public class DataUsageChartView extends ChartView { private static final long MB_IN_BYTES = KB_IN_BYTES * 1024; private static final long GB_IN_BYTES = MB_IN_BYTES * 1024; + // TODO: enforce that sweeps cant cross each other + // TODO: limit sweeps at graph boundaries + + private ChartGridView mGrid; private ChartNetworkSeriesView mSeries; - // TODO: limit sweeps at graph boundaries - private ChartSweepView mSweepTime1; - private ChartSweepView mSweepTime2; - private ChartSweepView mSweepDataWarn; - private ChartSweepView mSweepDataLimit; + private ChartSweepView mSweepLeft; + private ChartSweepView mSweepRight; + private ChartSweepView mSweepWarning; + private ChartSweepView mSweepLimit; public interface DataUsageChartListener { public void onInspectRangeChanged(); @@ -51,46 +56,58 @@ public class DataUsageChartView extends ChartView { private DataUsageChartListener mListener; - private static ChartAxis buildTimeAxis() { - return new TimeAxis(); - } - - private static ChartAxis buildDataAxis() { - return new InvertedChartAxis(new DataAxis()); - } - public DataUsageChartView(Context context) { - super(context, buildTimeAxis(), buildDataAxis()); - setPadding(20, 20, 20, 20); - - addView(new ChartGridView(context, mHoriz, mVert), buildChartParams()); - - mSeries = new ChartNetworkSeriesView(context, mHoriz, mVert); - addView(mSeries, buildChartParams()); - - mSweepTime1 = new ChartSweepView(context, mHoriz, 0L, Color.parseColor("#ffffff")); - mSweepTime2 = new ChartSweepView(context, mHoriz, 0L, Color.parseColor("#ffffff")); - mSweepDataWarn = new ChartSweepView(context, mVert, 0L, Color.parseColor("#f7931d")); - mSweepDataLimit = new ChartSweepView(context, mVert, 0L, Color.parseColor("#be1d2c")); - - addView(mSweepTime1, buildSweepParams()); - addView(mSweepTime2, buildSweepParams()); - addView(mSweepDataWarn, buildSweepParams()); - addView(mSweepDataLimit, buildSweepParams()); - - mSeries.bindSweepRange(mSweepTime1, mSweepTime2); - - mSweepDataWarn.addOnSweepListener(mWarningListener); - mSweepDataLimit.addOnSweepListener(mLimitListener); - - mSweepTime1.addOnSweepListener(mSweepListener); - mSweepTime2.addOnSweepListener(mSweepListener); - - mSweepDataWarn.setVisibility(View.INVISIBLE); - mSweepDataLimit.setVisibility(View.INVISIBLE); - + this(context, null, 0); } + public DataUsageChartView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DataUsageChartView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(new TimeAxis(), new InvertedChartAxis(new DataAxis())); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mGrid = (ChartGridView) findViewById(R.id.grid); + mSeries = (ChartNetworkSeriesView) findViewById(R.id.series); + + 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); + + mSweepLeft.addOnSweepListener(mSweepListener); + mSweepRight.addOnSweepListener(mSweepListener); + mSweepWarning.addOnSweepListener(mWarningListener); + mSweepLimit.addOnSweepListener(mLimitListener); + + // tell everyone about our axis + mGrid.init(mHoriz, mVert); + mSeries.init(mHoriz, mVert); + mSweepLeft.init(mHoriz); + mSweepRight.init(mHoriz); + mSweepWarning.init(mVert); + mSweepLimit.init(mVert); + + setActivated(false); + } + + @Override + public void setActivated(boolean activated) { + super.setActivated(activated); + + mSweepLeft.setEnabled(activated); + mSweepRight.setEnabled(activated); + mSweepWarning.setEnabled(activated); + mSweepLimit.setEnabled(activated); + } + + @Deprecated public void setChartColor(int stroke, int fill, int disabled) { mSeries.setChartColor(stroke, fill, disabled); } @@ -105,36 +122,46 @@ public class DataUsageChartView extends ChartView { public void bindNetworkPolicy(NetworkPolicy policy) { if (policy == null) { - mSweepDataLimit.setVisibility(View.INVISIBLE); - mSweepDataWarn.setVisibility(View.INVISIBLE); + mSweepLimit.setVisibility(View.INVISIBLE); + mSweepWarning.setVisibility(View.INVISIBLE); return; } if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) { - mSweepDataLimit.setVisibility(View.VISIBLE); - mSweepDataLimit.setValue(policy.limitBytes); - mSweepDataLimit.setEnabled(true); + mSweepLimit.setVisibility(View.VISIBLE); + mSweepLimit.setValue(policy.limitBytes); + mSweepLimit.setEnabled(true); } else { // TODO: set limit default based on axis maximum - mSweepDataLimit.setVisibility(View.VISIBLE); - mSweepDataLimit.setValue(5 * GB_IN_BYTES); - mSweepDataLimit.setEnabled(false); + mSweepLimit.setVisibility(View.VISIBLE); + mSweepLimit.setValue(5 * GB_IN_BYTES); + mSweepLimit.setEnabled(false); } if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) { - mSweepDataWarn.setVisibility(View.VISIBLE); - mSweepDataWarn.setValue(policy.warningBytes); + mSweepWarning.setVisibility(View.VISIBLE); + mSweepWarning.setValue(policy.warningBytes); } else { - mSweepDataWarn.setVisibility(View.INVISIBLE); + mSweepWarning.setVisibility(View.INVISIBLE); } requestLayout(); + + // TODO: eventually remove this; was to work around lack of sweep clamping + if (policy.limitBytes < -1 || policy.limitBytes > 5 * GB_IN_BYTES) { + policy.limitBytes = 5 * GB_IN_BYTES; + mLimitListener.onSweep(mSweepLimit, true); + } + if (policy.warningBytes < -1 || policy.warningBytes > 5 * GB_IN_BYTES) { + policy.warningBytes = 4 * GB_IN_BYTES; + mWarningListener.onSweep(mSweepWarning, true); + } + } private OnSweepListener mSweepListener = new OnSweepListener() { public void onSweep(ChartSweepView sweep, boolean sweepDone) { - // always update graph clip region - mSeries.invalidate(); + mSeries.setPrimaryRange(mSweepLeft.getValue(), mSweepRight.getValue()); // update detail list only when done sweeping if (sweepDone && mListener != null) { @@ -159,24 +186,39 @@ public class DataUsageChartView extends ChartView { } }; + @Override + public boolean onTouchEvent(MotionEvent event) { + if (isActivated()) return false; + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: { + return true; + } + case MotionEvent.ACTION_UP: { + setActivated(true); + return true; + } + default: { + return false; + } + } + } + /** * Return current inspection range (start and end time) based on internal * {@link ChartSweepView} positions. */ public long[] getInspectRange() { - final long sweep1 = mSweepTime1.getValue(); - final long sweep2 = mSweepTime2.getValue(); - final long start = Math.min(sweep1, sweep2); - final long end = Math.max(sweep1, sweep2); + final long start = mSweepLeft.getValue(); + final long end = mSweepRight.getValue(); return new long[] { start, end }; } public long getWarningBytes() { - return mSweepDataWarn.getValue(); + return mSweepWarning.getValue(); } public long getLimitBytes() { - return mSweepDataLimit.getValue(); + return mSweepLimit.getValue(); } /** @@ -192,8 +234,9 @@ public class DataUsageChartView extends ChartView { final long sweepMax = Math.min(end, dataBoundary); final long sweepMin = Math.max(start, (sweepMax - DateUtils.WEEK_IN_MILLIS)); - mSweepTime1.setValue(sweepMin); - mSweepTime2.setValue(sweepMax); + mSweepLeft.setValue(sweepMin); + mSweepRight.setValue(sweepMax); + mSeries.setPrimaryRange(sweepMin, sweepMax); requestLayout(); mSeries.generatePath(); @@ -239,6 +282,12 @@ public class DataUsageChartView extends ChartView { return Long.toString(value); } + /** {@inheritDoc} */ + public CharSequence getShortLabel(long value) { + // TODO: convert to string + return Long.toString(value); + } + /** {@inheritDoc} */ public float[] getTickPoints() { // tick mark for every week @@ -299,6 +348,16 @@ public class DataUsageChartView extends ChartView { /** {@inheritDoc} */ public CharSequence getLabel(long value) { + + // TODO: use exploded string here + + + // TODO: convert to string + return Long.toString(value); + } + + /** {@inheritDoc} */ + public CharSequence getShortLabel(long value) { // TODO: convert to string return Long.toString(value); } diff --git a/src/com/android/settings/widget/InvertedChartAxis.java b/src/com/android/settings/widget/InvertedChartAxis.java index e7e7893eabe..a30d24cfa39 100644 --- a/src/com/android/settings/widget/InvertedChartAxis.java +++ b/src/com/android/settings/widget/InvertedChartAxis.java @@ -53,6 +53,11 @@ public class InvertedChartAxis implements ChartAxis { return mWrapped.getLabel(value); } + /** {@inheritDoc} */ + public CharSequence getShortLabel(long value) { + return mWrapped.getShortLabel(value); + } + /** {@inheritDoc} */ public float[] getTickPoints() { final float[] points = mWrapped.getTickPoints();