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
17package com.android.settings.nfc;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.pm.PackageManager;
22import android.content.res.Resources;
23import android.graphics.drawable.Drawable;
24import android.nfc.NfcAdapter;
25import android.nfc.cardemulation.ApduServiceInfo;
26import android.nfc.cardemulation.CardEmulation;
27import android.os.Handler;
28import android.os.Message;
29import android.provider.Settings;
30import android.provider.Settings.SettingNotFoundException;
31
32import com.android.internal.content.PackageMonitor;
33
34import java.util.ArrayList;
35import java.util.List;
36
37public class PaymentBackend {
38    public static final String TAG = "Settings.PaymentBackend";
39
40    public interface Callback {
41        void onPaymentAppsChanged();
42    }
43
44    public static class PaymentAppInfo {
45        public 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
62    public PaymentBackend(Context context) {
63        mContext = context;
64
65        mAdapter = NfcAdapter.getDefaultAdapter(context);
66        mCardEmuManager = CardEmulation.getInstance(mAdapter);
67        refresh();
68    }
69
70    public void onPause() {
71        mSettingsPackageMonitor.unregister();
72    }
73
74    public void onResume() {
75        mSettingsPackageMonitor.register(mContext, mContext.getMainLooper(), false);
76    }
77
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
118    public void registerCallback(Callback callback) {
119        mCallbacks.add(callback);
120    }
121
122    public void unregisterCallback(Callback callback) {
123        mCallbacks.remove(callback);
124    }
125
126    public List<PaymentAppInfo> getPaymentAppInfos() {
127        return mAppInfos;
128    }
129
130    public PaymentAppInfo getDefaultApp() {
131        return mDefaultAppInfo;
132    }
133
134    void makeCallbacks() {
135        for (Callback callback : mCallbacks) {
136            callback.onPaymentAppsChanged();
137        }
138    }
139
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
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
162    void setForegroundMode(boolean foreground) {
163        Settings.Secure.putInt(mContext.getContentResolver(),
164                Settings.Secure.NFC_PAYMENT_FOREGROUND, foreground ? 1 : 0) ;
165    }
166
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
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
193        public void onPackageAdded(String packageName, int uid) {
194            mHandler.obtainMessage().sendToTarget();
195        }
196
197        @Override
198        public void onPackageAppeared(String packageName, int reason) {
199            mHandler.obtainMessage().sendToTarget();
200        }
201
202        @Override
203        public void onPackageDisappeared(String packageName, int reason) {
204            mHandler.obtainMessage().sendToTarget();
205        }
206
207        @Override
208        public void onPackageRemoved(String packageName, int uid) {
209            mHandler.obtainMessage().sendToTarget();
210        }
211    }
212}
213