From 26515da08707b6f8182cc8b0ed5e01e97aa92a96 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 1 Aug 2013 18:13:33 -0700 Subject: [PATCH] NFC payment settings. First version, pending final UX. Change-Id: I357e900c3f2012b35814ae197c49a8c9b97b7148 --- AndroidManifest.xml | 25 +++ proguard.flags | 1 + .../ic_settings_nfc_payment.png | Bin 0 -> 7154 bytes res/layout/nfc_payment_option.xml | 80 ++++++++++ res/values/strings.xml | 9 ++ res/xml/nfc_payment_settings.xml | 18 +++ res/xml/settings_headers.xml | 7 + src/com/android/settings/Settings.java | 8 +- .../android/settings/nfc/PaymentBackend.java | 102 +++++++++++++ .../settings/nfc/PaymentDefaultDialog.java | 144 ++++++++++++++++++ .../android/settings/nfc/PaymentSettings.java | 126 +++++++++++++++ 11 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 res/drawable-xhdpi/ic_settings_nfc_payment.png create mode 100644 res/layout/nfc_payment_option.xml create mode 100644 res/xml/nfc_payment_settings.xml create mode 100644 src/com/android/settings/nfc/PaymentBackend.java create mode 100644 src/com/android/settings/nfc/PaymentDefaultDialog.java create mode 100644 src/com/android/settings/nfc/PaymentSettings.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 10c66d43ae9..5769305036b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1571,6 +1571,31 @@ android:resource="@id/user_settings" /> + + + + + + + + + + + + + + + + 50H76FNlL1ySUR{mxL7(kQprh5QaL(1m|NMJ0f6UXX|jh(f(=pc*p1(QXfh0z zI4(4aO7(qQ5;rgS+xHN%uNbH_zkWHNqv@kF(-=##|Hr5eX&~wjI{r0Zu|`Eq=+>fL zky8~=(Y=zfBIa&BHY@~B=N=P26+C?yLlj>cNs;gQjVzui#TJE$Y5cA*uPP!I24G|( zqDJ_BY)yQFkB|CNBf1Ph0@e!d8Oj(O`rK0JlpJ3j~%X+93qMn4)4ak=kPrzFYdXvf{%QUjZcu9}CD~ ze~qW^e2jS4B=8xzjoJ?yYoq6m4r|3cTf(Xr) zU}${y1;ItIh6DOX9E>;|R8}ZJ?1*UL7$1eU0|0^W{3z3fG#zK6&&-5TM>@ih?Gu?h zo7+cd158CFk*D4s#5jPsD^$#zw+RSRhkU=J6se_b_os&Ooy(4GionQ-*SmEBCA2su zx*))MAi_aAk_ZO^cLnlmM+o*A1Pe)0KuS_LuU#KUoM<}`gGhptHJs}=%&h{|`isy} zP>UmgB`Ne1#_b3xYj>;1#1==DJj0V&M~tRMk&ya_f;b@=jf>um<@9krf)X!Uil!2Z z79VCxgC`Y8K+6(`mWNg(?M|cEPrWVRjNA}%NqzGjVoKr_<@=E{F^o%9avCoqtV)%Q zEU-7%Wn94(q8pO@%VwPHFJvXQHpgO|<)58KWUG`cXZ!C|Eb|~iV_R07s9v>7427`w zJ%g3jB@mmA50w;0^ab69U$UH#$PxQG1=oEYztkiB1nPh~g3pn~J;yyY8>1Wco5+r| z^{1X6Rso0bn_l?Yz^%fggfD3;*;<5Hm{@GvH_FZcDjbv#NGw4N)Y0E1`l(szHSlWj zbWsgLL_4XzBtq#9aE~KeyDe$57#Wgr>u_%HmGK>L!XvVv8u6S1p#&20@8qB?(3w2H zJoUUcc@}w`RmclLM~X4@=mSyxHUmuq8QV77)E6Yu316kp^SjlZ8Hbp76Nv`B1|Fv zWS@8scw%fWZKAEYcrti%dEq=Pyf;>clfGrr(^b=Gvv}4?*2j|{ih29nNz9|g!(f&1 zmFZ5IoZWOBrK!T^Sk*yZu!SM=iP=f_DWz$)>9Q%&qSEOOS5`OA4_`BCK7_lS{PRuw zDiA6p&0}_zn9Rgq;5(i1XJ~?OKl!lsV0HHCSKlQ1?9hx}`CQozl(NvFSWG=2=b7&b zeqUa|Rd}yJsPI0^+w;H=ak_n$YSy^2gDtoiIX6ruEGJB@>wTC7rV;5riBq(5G#^<8 z7a5;9$pfjy8wVayyT_pXkv`>>R@1NfW+p; zR;RyTMqM_fFQmU#zt9l5T-&hXW>GKOQ0{!{{<6EVPYt&`C%NXiQGl1+99eKLa30BD zOS3nBhRt!6;~QqRh&1o4hPS+2IGqh#E$qR48)sZ6E?1^r`ziX}wF>zq`Lnk1w7vD0 z55Ny-4G4b0k0F)qx7rroT6A=&e`qL2{E1)+=|d1j_I}NVdW6;)BoRCq>>XSagdb!R zOc|aUW*Wv59v#vc&W3f2))g)tQi^@JM|y$OOuq`Px44ZzbHV)^Q6I4w!4Ov)SJgkt z$ipmbEjisqO2kday_ie=gSdtIUNu^CI4E_^9M8OWxFr3KXI8LQpq3#9m!I9Ye60ri8+G>~gK~zp~;pCgbE46cy|g-ewRA+f0?@ zESyvinXjdp@D@6b<~Q8C^tdRGs%Q0OdC*~IB`4OhAG3)4SZk+L+{>RUj733smHvu7 zlzc;GqoV(_#yjuijdazdbKxm|7s*}6@%jS|cQSDFy&JjXJTtW&gwt2)MA7{;rr++M&p#ir1l8G+j5M`b{M9fB zZV9IeeRWgo&!9QxIeBLXG)vOO#3C$cO!sb__Las?9+h(E7n_0amfs1b(0rOoacAe& z(`vN+P50OI)Oqk?d8e)1QCGEQ^Jy?IDI-5D|6P8tSm^V#et{M}%c0Ruwe`bTeO7hA ziNSHB_t3%VPUpoCp%UQ?p%Kfgq?7=s=ltE2b6!##?>X<1mD-pJrK*!r@0Tl|VxHpv z{vh*9*;y|2FKV}*KNWbTvuQSII;<%yl+2fuM3(H&e{D5eNiMI^si`|eIM6-BJor2p zu*|&dZSuxKZ^*stm~g4>sDIVT!{Xm)E%H#mUw$_Ul6%KaXizSv6t71McSBM{9f6yh@b+0}6t3@6X{9iCTR{q;Y7lBR3 z8{F%-cynDOmF@Ax?(*%?p-M!M$YR*7!;JIGp0owt_gND z_KVJ^qzh%6@(jvHO*2W4GUuMwZ7&w|_RKR6MJSz~H$%UpTlmzA6tdqN3OfxvOr8%N z4IO_LF8gcX*5-ZWakCbC<$YOe0B@dkS~>K#Si5Xh=YMqg*+A+F?|i>n%2H>seA1NQ zxM%-z`W{s1^?q0xNPyHq?a?5<@!NFJp(rK zt6=t*;TQO!%D(#j)PY6s*pJL6VKGi}F5jn~5@JdAeD*%Wq$fqV!&P~y5#>`9d~POg zJ1&R6ihs+2Wo^G@3BG#lcVjvHZwuRtvR5=YVDjPb4flh~SV|uISTB+PJO9!(tu-1O07!srQc}R-1{hZdNai4n*7#n;0PsCB8jB>i&L+g)7G9#8TEIZIv~kXnLyPP0l=OC09?ue z$m<#a@G1oWMGFA(Y7YQ7PXGXqSd(VW6aa9#n6dbIop%Ky(MJ!2$({9UWa`|uK zPiksvn-F=773&ZJ?0mB)3jgcZuY(d25*(J}RIYArB95iu*p$ytP=FdqtC$cRf`H2| zhW%=DySJI3h@-VnpU>}|0+X@f!xV~fkKUa^h5(`b9E6QuUI;E6d?ci z@1MB8zbGJ{J3&Q9*B!bguoru7Q2Di|jhL8t&C=SsQ)Ix?llkn^ac$QIxR3Dk6wgs< zpPM5-K0ZFXyp)1MQG|ts#}^hB7~`O$`H7zalBk9w0X_uvn@q6Z!?oh;?}|*CcoG#Zd!y$d8bunGGvvyA`vsPS-lQ+) z$>Ey}zS|h`vI8PAhW5=MOL?=Nwlb$S4x5jfM1N3CZ?dx)@tMOfShjYLwNN8#jM$6C=v1-F`X=T~$fNY?jo~(ZP{Ea=AT_&=?aF<4e)io0pe&OD^Odt)Zp$tFiIk=P73akZ1C4q{YU@ z?wH7x#ZQ#qkp*NR+Mo&siP;U042+CoOQ*4^>u{m6AeY%tt{-SBK_L zjwq=lX|wv#%Y3#MIj6&X4S6nJD4td$l#Y`OK|{j?sig)@LCLGEwcRh zD8*4>a!PRTGW~{lMJ1&$ajM%@acgVq7ddfR+1COwh(lF4ky8D`!&2VfAKXutBR9Ij zxg~N`HXox^7=3wpcw8qVaA|+b=l^BV}(HykjS$duRIOy1;iTELf% z85$buaXZUpHkjCVy4(=l+uM73<*yoOZ$yEI7ZehLG?xDlx-? z4Q6S5eSKMb`;#G6Rn=F3uTP_Nj*5UDTgs`Z^L9UPkp^0Z(jGXw73}p_7VLvnM~FI}`eCo#d99CI}M@NzK z2~bf{vlCCY1j>ld?ynBjkuk|aE-zgP2noMD-Cu1ass(eG{rPk7w7zb9dw(DQhTq=5?l=$s6ih&LOxbfAWcgfHPe?$p4psz|EeVG) zEbUb2$B!QrEbQ#z^7#mWcIoUhXHb*-apz%q+w&;mv|P38{$!d=ZXEKfR}-C`64P^Y zdY(rS#wW`SwLgB4S@MwKk&|NpM6H6wfBvMNWSbACa<+6g%bvaCC;JA52*dmL?@>@u z_bCy=uqk6euc~>25mw_{8Q|%8>l^l^89Xcv4Jp9x#>;R*2!t85`rh@L4JGH)))Lvw zmQcUOBA-Xjo+NGZxv}@s&>&d#yD@Neb%m)dUI7=r8On$zfLjK4KC9WygmLaoAb<#Vykeh++)Pfru`^AWYRe26e5i|n?x7d1*s zN>y!b60K6*SC!h!Snb=#=STS1OJTKP>+NRL#>mLX zT!;kqkM#6NnOxj6)2Pnf-Q5T4ot>SYht{$(HY;iASL*8O!Rm!d6K7|RK46TNb2vOd z-UUq+DktRS(UFmpM_*iAP)dtuX=WD}qk~nesj0EFvs=N+Zb;eJV%`HKmYtV}bW
0w)TW-ps$~;!g$|@+}+dj zk(FqxGZcN=x&}|Qj*cj5X>)Tkd&YWVVPW9xSbGfnpzKua_jzKkSL6X(HKJ#>{F5!} z85|z0KriX+%=Oj8gdcL|+MB9S&@AF}?fPH`0nV{A(6w2K=56^5DV0%jAP|TKI0rSf z+zFIc8hNlsR=|Z4T3K0%Y-$n$Rq!B-P*qh$l`@1nRK>%`=Z>=W>*jPVK!l&4nA?09 zR#?c;QfC~f4z;_vyhQ5a`2G90xVk$23l^tBcwHTT(ts)G_O$-~{sgc|QjdS*)F)sL z`L&)-Ss+;3*x(WnNWFRUCJTup4qIJKt+VFuUn*W+LUdxb?VkqgEmgJeX=o5Iy4JfR z@z({ge6`Ze7Q*J|wbK`D!;}hhIwlHsvh>3_50 zaSMv-OZ7tY-Lw)Fj^o!#61Ad4XucYlSI=<(*aD3nr>kO3_4T&fZ^Rte#aG$`5#Ms9 zMGHUQZmBRQkqVbhx4Iq9wwYO2m|Pz%T+Vzp>iH!d^^9Pg%FV~gIiUgaV{@~xLMq2b z>w~L(W@cv0`1tt4fJ&QOJJ=N)hlfp>4kds8{(Y<-6CD~D9Ha@sxftdi6ED?b@xsWu zI$Eec0w3wL(fLY4Q!~)v24ehgJckD)nP6nhpbleT>g|W?7?RUfmaxfI0_g{Z_B;5V z)6I!N>un}zUoY@)Z}`dT9M+WH6QNu1rQ-vZo)sz6)^2;mM!tbe>IK>L^{G4Dwt#}N z=v^L2Qe-r7C}8+7kzQa8Lz6HzUVmC;C(P*xeof2GJr%5`yI9SfJ7djl z31|;Vami$YX%t2hRH#0uiE%KOxMVa^|tqp=hb>bvj>whYspCBPXNQFH) z=#?{BD|Jixy_h95u}f*D=jWlxtU8mI3PU&;RS)yHuU@`jhqnuo%W&d|- zR-%nAU#YQ~<6EnD z3VysQ56CYoD}#RegbwOTRrpTIPg1gL&5Vl_%;cP;q$HIh4ZXXs|JBykVlOW*pLM*Z z6xK)R{(Ao8n`x%w>Fph4rbEZTu;#ZBO8g8l&Ph;KHfZzrn;TB!9ss8)2ihSf8k+79 z!}HbERp0gLnzA$vZe(mM1AKQR7oT3?Y)7vTq-G^vK0dIP#h(wJRYs9@l6$}beosjW z2TfD5aLSFIfuYZZJf+J?pSaJ-z{<+12rOUnCpx^4@bD>+?NtNC&lmy%UKX(XacjY8 z(=swfc>DNFEiNwZL83PT`7F%Movmxgz+!`-xMN!(R5P>h`j5>KXx|-4F9nwmPDVyX zU}$IvBCH*Fe|zw#_r792I6Qo(qoc#FDsSM$)iPB4xqLPyDQP1=#V`nri~_}U38s8z zi;@Y;$8;$gtAkM%ia%%qp}*EA6q}R^ZSbRdaH4uZqnvt;jNA!s(nfy@(n`@xIA<1> z%#|Aj*z69c(Sytcf?9lXG9S1AO6whqb+!v?bE~ULF3!&0m<4%x!omm?Qt}>q0$8Ul zHx!^QsqrE!+>dovk3aZa+dhNv$G+S|Ck^_!rLAoVSqr-?(B1$74o#`n(hY58_(zz_ zD(EP&AU$c9YLS0%{Z}mLvilfiw$LDQrBggJI=AoY0d7FR^o!6fEg*_AtJ7a)0rL7{ z-VT))7jqZpNzwH5-^c@OSlV-Pru8k~0mK$Hg-?rNxsjTh+T>+7zOs1v+)FbF za$B4XN(VSNYN9A`0N+3&BTMJA8x-?AGkyz$Q4GxAz1OStT^=77|5IEX;CLwZc-FOs z4Z-MYH?Q89E>gcaCDHo)*=8(5h~H|t-suiNhA=)~FFAZpNlunvOPTUX+Rl=F%oS65 p?pUHlpuj!*|Eq(?oTV2`V17)XS$9hF8GQ8t$Vn?nl}Q)}{SN>dx26C9 literal 0 HcmV?d00001 diff --git a/res/layout/nfc_payment_option.xml b/res/layout/nfc_payment_option.xml new file mode 100644 index 00000000000..122e04154ff --- /dev/null +++ b/res/layout/nfc_payment_option.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index a4a3aec688b..9d20fabca74 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4589,6 +4589,15 @@ Change font size + + Tap and Pay + + Ask every time + + Set as your preference? + diff --git a/res/xml/nfc_payment_settings.xml b/res/xml/nfc_payment_settings.xml new file mode 100644 index 00000000000..9b47dda1c08 --- /dev/null +++ b/res/xml/nfc_payment_settings.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/res/xml/settings_headers.xml b/res/xml/settings_headers.xml index 867fc191832..65c42efbbbb 100644 --- a/res/xml/settings_headers.xml +++ b/res/xml/settings_headers.xml @@ -104,6 +104,13 @@ android:title="@string/user_settings_title" android:id="@+id/user_settings" /> + +
+
getPaymentAppInfos() { + PackageManager pm = mContext.getPackageManager(); + List serviceInfos = + mCardEmuManager.getServices(CardEmulationManager.CATEGORY_PAYMENT); + List appInfos = new ArrayList(); + + if (serviceInfos == null) return appInfos; + + ComponentName defaultApp = getDefaultPaymentApp(); + + for (ApduServiceInfo service : serviceInfos) { + PaymentAppInfo appInfo = new PaymentAppInfo(); + appInfo.caption = service.loadLabel(pm); + appInfo.icon = service.loadIcon(pm); + appInfo.isDefault = service.getComponent().equals(defaultApp); + appInfo.componentName = service.getComponent(); + appInfos.add(appInfo); + } + + return appInfos; + } + + ComponentName getDefaultPaymentApp() { + String componentString = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT); + if (componentString != null) { + return ComponentName.unflattenFromString(componentString); + } else { + return null; + } + } + + public void setDefaultPaymentApp(ComponentName app) { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT, + app != null ? app.flattenToString() : null); + } + + public boolean isAutoPaymentMode() { + String mode = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.NFC_PAYMENT_MODE); + return (!CardEmulationManager.PAYMENT_MODE_MANUAL.equals(mode)); + } + + public void setAutoPaymentMode(boolean enable) { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.NFC_PAYMENT_MODE, + enable ? CardEmulationManager.PAYMENT_MODE_AUTO + : CardEmulationManager.PAYMENT_MODE_MANUAL); + } +} \ No newline at end of file diff --git a/src/com/android/settings/nfc/PaymentDefaultDialog.java b/src/com/android/settings/nfc/PaymentDefaultDialog.java new file mode 100644 index 00000000000..f3217dd5179 --- /dev/null +++ b/src/com/android/settings/nfc/PaymentDefaultDialog.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 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.nfc; + +import android.content.ComponentName; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.nfc.cardemulation.CardEmulationManager; +import android.os.Bundle; +import android.util.Log; + +import com.android.internal.app.AlertActivity; +import com.android.internal.app.AlertController; +import com.android.settings.R; +import com.android.settings.nfc.PaymentBackend.PaymentAppInfo; + +import java.util.List; + +public final class PaymentDefaultDialog extends AlertActivity implements + DialogInterface.OnClickListener { + + public static final String TAG = "PaymentDefaultDialog"; + + private PaymentBackend mBackend; + private ComponentName mNewDefault; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mBackend = new PaymentBackend(this); + Intent intent = getIntent(); + ComponentName component = intent.getParcelableExtra( + CardEmulationManager.EXTRA_SERVICE_COMPONENT); + String category = intent.getStringExtra(CardEmulationManager.EXTRA_CATEGORY); + + if (!buildDialog(component, category)) { + finish(); + } + + } + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case BUTTON_POSITIVE: + mBackend.setDefaultPaymentApp(mNewDefault); + mBackend.setAutoPaymentMode(true); + break; + case BUTTON_NEGATIVE: + break; + } + } + + private boolean buildDialog(ComponentName component, String category) { + if (component == null || category == null) { + Log.e(TAG, "Component or category are null"); + return false; + } + + if (!CardEmulationManager.CATEGORY_PAYMENT.equals(category)) { + Log.e(TAG, "Don't support defaults for category " + category); + return false; + } + + // Check if passed in service exists + boolean found = false; + + List services = mBackend.getPaymentAppInfos(); + for (PaymentAppInfo service : services) { + if (component.equals(service.componentName)) { + found = true; + break; + } + } + + if (!found) { + Log.e(TAG, "Component " + component + " is not a registered payment service."); + return false; + } + + // Get current mode and default component + boolean isAuto = mBackend.isAutoPaymentMode(); + ComponentName defaultComponent = mBackend.getDefaultPaymentApp(); + if (defaultComponent != null && defaultComponent.equals(component)) { + Log.e(TAG, "Component " + component + " is already default."); + return false; + } + + PackageManager pm = getPackageManager(); + ApplicationInfo newAppInfo; + try { + newAppInfo = pm.getApplicationInfo(component.getPackageName(), 0); + } catch (NameNotFoundException e) { + Log.e(TAG, "PM could not load app info for " + component); + return false; + } + ApplicationInfo defaultAppInfo = null; + try { + if (defaultComponent != null) { + defaultAppInfo = pm.getApplicationInfo(defaultComponent.getPackageName(), 0); + } + } catch (NameNotFoundException e) { + Log.e(TAG, "PM could not load app info for " + defaultComponent); + // Continue intentionally + } + + mNewDefault = component; + + // Compose dialog; get + final AlertController.AlertParams p = mAlertParams; + p.mTitle = getString(R.string.nfc_payment_set_default); + if (defaultAppInfo == null || !isAuto) { + p.mMessage = "Always use " + newAppInfo.loadLabel(pm) + " when you tap and pay?"; + } else { + p.mMessage = "Always use " + newAppInfo.loadLabel(pm) + " instead of " + + defaultAppInfo.loadLabel(pm) + " when you tap and pay?"; + } + p.mPositiveButtonText = getString(R.string.yes); + p.mNegativeButtonText = getString(R.string.no); + p.mPositiveButtonListener = this; + p.mNegativeButtonListener = this; + setupAlert(); + + return true; + } + +} diff --git a/src/com/android/settings/nfc/PaymentSettings.java b/src/com/android/settings/nfc/PaymentSettings.java new file mode 100644 index 00000000000..a1ed883f132 --- /dev/null +++ b/src/com/android/settings/nfc/PaymentSettings.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2013 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.nfc; + +import android.content.Context; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceManager; +import android.preference.PreferenceScreen; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.RadioButton; + +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.nfc.PaymentBackend.PaymentAppInfo; + +import java.util.List; + +public class PaymentSettings extends SettingsPreferenceFragment implements + OnClickListener { + public static final String TAG = "PaymentSettings"; + private PaymentBackend mPaymentBackend; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + setHasOptionsMenu(false); + mPaymentBackend = new PaymentBackend(getActivity()); + } + + public void refresh() { + PreferenceManager manager = getPreferenceManager(); + PreferenceScreen screen = manager.createPreferenceScreen(getActivity()); + + boolean isAuto = mPaymentBackend.isAutoPaymentMode(); + + // Get all payment services + List appInfos = mPaymentBackend.getPaymentAppInfos(); + if (appInfos != null && appInfos.size() > 0) { + // Add all payment apps + for (PaymentAppInfo appInfo : appInfos) { + PaymentAppPreference preference = + new PaymentAppPreference(getActivity(), appInfo, this); + // If for some reason isAuto gets out of sync, clear out app default + appInfo.isDefault &= isAuto; + preference.setIcon(appInfo.icon); + preference.setTitle(appInfo.caption); + screen.addPreference(preference); + } + if (appInfos.size() > 1) { + PaymentAppInfo appInfo = new PaymentAppInfo(); + appInfo.icon = null; + appInfo.componentName = null; + appInfo.isDefault = !isAuto; + // Add "Ask every time" option + PaymentAppPreference preference = + new PaymentAppPreference(getActivity(), appInfo, this); + preference.setIcon(null); + preference.setTitle(R.string.nfc_payment_ask); + screen.addPreference(preference); + } + } + setPreferenceScreen(screen); + } + + @Override + public void onClick(View v) { + if (v.getTag() instanceof PaymentAppInfo) { + PaymentAppInfo appInfo = (PaymentAppInfo) v.getTag(); + if (appInfo.componentName != null) { + mPaymentBackend.setDefaultPaymentApp(appInfo.componentName); + mPaymentBackend.setAutoPaymentMode(true); + } else { + mPaymentBackend.setDefaultPaymentApp(null); + mPaymentBackend.setAutoPaymentMode(false); + } + refresh(); + } + } + + @Override + public void onResume() { + super.onResume(); + refresh(); + } + + public static class PaymentAppPreference extends Preference { + private final OnClickListener listener; + private final PaymentAppInfo appInfo; + + public PaymentAppPreference(Context context, PaymentAppInfo appInfo, + OnClickListener listener) { + super(context); + setLayoutResource(R.layout.nfc_payment_option); + this.appInfo = appInfo; + this.listener = listener; + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + + view.setOnClickListener(listener); + view.setTag(appInfo); + + RadioButton radioButton = (RadioButton) view.findViewById(android.R.id.button1); + radioButton.setChecked(appInfo.isDefault); + } + } +} \ No newline at end of file