1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.nfc;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.content.res.Resources;
23 import android.graphics.drawable.Drawable;
24 import android.nfc.NfcAdapter;
25 import android.nfc.cardemulation.ApduServiceInfo;
26 import android.nfc.cardemulation.CardEmulation;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.provider.Settings;
30 import android.provider.Settings.SettingNotFoundException;
31 
32 import com.android.internal.content.PackageMonitor;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 
37 public class PaymentBackend {
38     public static final String TAG = "Settings.PaymentBackend";
39 
40     public interface Callback {
onPaymentAppsChanged()41         void onPaymentAppsChanged();
42     }
43 
44     public static class PaymentAppInfo {
45         CharSequence label;
46         CharSequence description;
47         Drawable banner;
48         boolean isDefault;
49         public ComponentName componentName;
50         public ComponentName settingsComponent;
51     }
52 
53     private final Context mContext;
54     private final NfcAdapter mAdapter;
55     private final CardEmulation mCardEmuManager;
56     private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
57     // Fields below only modified on UI thread
58     private ArrayList<PaymentAppInfo> mAppInfos;
59     private PaymentAppInfo mDefaultAppInfo;
60     private ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
61 
PaymentBackend(Context context)62     public PaymentBackend(Context context) {
63         mContext = context;
64 
65         mAdapter = NfcAdapter.getDefaultAdapter(context);
66         mCardEmuManager = CardEmulation.getInstance(mAdapter);
67         refresh();
68     }
69 
onPause()70     public void onPause() {
71         mSettingsPackageMonitor.unregister();
72     }
73 
onResume()74     public void onResume() {
75         mSettingsPackageMonitor.register(mContext, mContext.getMainLooper(), false);
76     }
77 
refresh()78     public void refresh() {
79         PackageManager pm = mContext.getPackageManager();
80         List<ApduServiceInfo> serviceInfos =
81                 mCardEmuManager.getServices(CardEmulation.CATEGORY_PAYMENT);
82         ArrayList<PaymentAppInfo> appInfos = new ArrayList<PaymentAppInfo>();
83 
84         if (serviceInfos == null) {
85             makeCallbacks();
86             return;
87         }
88 
89         ComponentName defaultAppName = getDefaultPaymentApp();
90         PaymentAppInfo foundDefaultApp = null;
91         for (ApduServiceInfo service : serviceInfos) {
92             PaymentAppInfo appInfo = new PaymentAppInfo();
93             appInfo.label = service.loadLabel(pm);
94             if (appInfo.label == null) {
95                 appInfo.label = service.loadAppLabel(pm);
96             }
97             appInfo.isDefault = service.getComponent().equals(defaultAppName);
98             if (appInfo.isDefault) {
99                 foundDefaultApp = appInfo;
100             }
101             appInfo.componentName = service.getComponent();
102             String settingsActivity = service.getSettingsActivityName();
103             if (settingsActivity != null) {
104                 appInfo.settingsComponent = new ComponentName(appInfo.componentName.getPackageName(),
105                         settingsActivity);
106             } else {
107                 appInfo.settingsComponent = null;
108             }
109             appInfo.description = service.getDescription();
110             appInfo.banner = service.loadBanner(pm);
111             appInfos.add(appInfo);
112         }
113         mAppInfos = appInfos;
114         mDefaultAppInfo = foundDefaultApp;
115         makeCallbacks();
116     }
117 
registerCallback(Callback callback)118     public void registerCallback(Callback callback) {
119         mCallbacks.add(callback);
120     }
121 
unregisterCallback(Callback callback)122     public void unregisterCallback(Callback callback) {
123         mCallbacks.remove(callback);
124     }
125 
getPaymentAppInfos()126     public List<PaymentAppInfo> getPaymentAppInfos() {
127         return mAppInfos;
128     }
129 
getDefaultApp()130     public PaymentAppInfo getDefaultApp() {
131         return mDefaultAppInfo;
132     }
133 
makeCallbacks()134     void makeCallbacks() {
135         for (Callback callback : mCallbacks) {
136             callback.onPaymentAppsChanged();
137         }
138     }
139 
loadDrawableForPackage(String pkgName, int drawableResId)140     Drawable loadDrawableForPackage(String pkgName, int drawableResId) {
141         PackageManager pm = mContext.getPackageManager();
142         try {
143             Resources res = pm.getResourcesForApplication(pkgName);
144             Drawable banner = res.getDrawable(drawableResId);
145             return banner;
146         } catch (Resources.NotFoundException e) {
147             return null;
148         } catch (PackageManager.NameNotFoundException e) {
149             return null;
150         }
151     }
152 
isForegroundMode()153     boolean isForegroundMode() {
154         try {
155             return Settings.Secure.getInt(mContext.getContentResolver(),
156                     Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
157         } catch (SettingNotFoundException e) {
158             return false;
159         }
160     }
161 
setForegroundMode(boolean foreground)162     void setForegroundMode(boolean foreground) {
163         Settings.Secure.putInt(mContext.getContentResolver(),
164                 Settings.Secure.NFC_PAYMENT_FOREGROUND, foreground ? 1 : 0) ;
165     }
166 
getDefaultPaymentApp()167     ComponentName getDefaultPaymentApp() {
168         String componentString = Settings.Secure.getString(mContext.getContentResolver(),
169                 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
170         if (componentString != null) {
171             return ComponentName.unflattenFromString(componentString);
172         } else {
173             return null;
174         }
175     }
176 
setDefaultPaymentApp(ComponentName app)177     public void setDefaultPaymentApp(ComponentName app) {
178         Settings.Secure.putString(mContext.getContentResolver(),
179                 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
180                 app != null ? app.flattenToString() : null);
181         refresh();
182     }
183 
184     private final Handler mHandler = new Handler() {
185         @Override
186         public void dispatchMessage(Message msg) {
187             refresh();
188         }
189     };
190 
191     private class SettingsPackageMonitor extends PackageMonitor {
192         @Override
onPackageAdded(String packageName, int uid)193         public void onPackageAdded(String packageName, int uid) {
194             mHandler.obtainMessage().sendToTarget();
195         }
196 
197         @Override
onPackageAppeared(String packageName, int reason)198         public void onPackageAppeared(String packageName, int reason) {
199             mHandler.obtainMessage().sendToTarget();
200         }
201 
202         @Override
onPackageDisappeared(String packageName, int reason)203         public void onPackageDisappeared(String packageName, int reason) {
204             mHandler.obtainMessage().sendToTarget();
205         }
206 
207         @Override
onPackageRemoved(String packageName, int uid)208         public void onPackageRemoved(String packageName, int uid) {
209             mHandler.obtainMessage().sendToTarget();
210         }
211     }
212 }
213