1 /*
2  * Copyright (C) 2015 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.nfc.cardemulation;
18 
19 import android.app.ActivityManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.nfc.cardemulation.NfcFServiceInfo;
23 import android.util.Log;
24 
25 import java.io.FileDescriptor;
26 import java.io.PrintWriter;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.HashMap;
32 
33 public class RegisteredT3tIdentifiersCache {
34     static final String TAG = "RegisteredT3tIdentifiersCache";
35 
36     static final boolean DBG = false;
37 
38     // All NFC-F services that have registered
39     List<NfcFServiceInfo> mServices = new ArrayList<NfcFServiceInfo>();
40 
41     final HashMap<String, NfcFServiceInfo> mForegroundT3tIdentifiersCache =
42             new HashMap<String, NfcFServiceInfo>();
43 
44     ComponentName mEnabledForegroundService;
45 
46     final class T3tIdentifier {
47         public final String systemCode;
48         public final String nfcid2;
49 
T3tIdentifier(String systemCode, String nfcid2)50         T3tIdentifier(String systemCode, String nfcid2) {
51             this.systemCode = systemCode;
52             this.nfcid2 = nfcid2;
53         }
54 
55         @Override
equals(Object o)56         public boolean equals(Object o) {
57             if (this == o) return true;
58             if (o == null || getClass() != o.getClass()) return false;
59 
60             T3tIdentifier that = (T3tIdentifier) o;
61             if (!systemCode.equalsIgnoreCase(that.systemCode)) return false;
62             if (!nfcid2.equalsIgnoreCase(that.nfcid2)) return false;
63 
64             return true;
65         }
66 
67         @Override
hashCode()68         public int hashCode() {
69             int result = systemCode.hashCode();
70             result = 31 * result + nfcid2.hashCode();
71             return result;
72         }
73     }
74 
75     final Context mContext;
76     final SystemCodeRoutingManager mRoutingManager;
77 
78     final Object mLock = new Object();
79 
80     boolean mNfcEnabled = false;
81 
RegisteredT3tIdentifiersCache(Context context)82     public RegisteredT3tIdentifiersCache(Context context) {
83         Log.d(TAG, "RegisteredT3tIdentifiersCache");
84         mContext = context;
85         mRoutingManager = new SystemCodeRoutingManager();
86     }
87 
resolveNfcid2(String nfcid2)88     public NfcFServiceInfo resolveNfcid2(String nfcid2) {
89         synchronized (mLock) {
90             if (DBG) Log.d(TAG, "resolveNfcid2: resolving NFCID " + nfcid2);
91             NfcFServiceInfo resolveInfo;
92             resolveInfo = mForegroundT3tIdentifiersCache.get(nfcid2);
93             Log.d(TAG,
94                     "Resolved to: " + (resolveInfo == null ? "null" : resolveInfo.toString()));
95             return resolveInfo;
96         }
97     }
98 
generateForegroundT3tIdentifiersCacheLocked()99     void generateForegroundT3tIdentifiersCacheLocked() {
100         if (DBG) Log.d(TAG, "generateForegroundT3tIdentifiersCacheLocked");
101         mForegroundT3tIdentifiersCache.clear();
102         if (mEnabledForegroundService != null) {
103             for (NfcFServiceInfo service : mServices) {
104                 if (mEnabledForegroundService.equals(service.getComponent())) {
105                     if (!service.getSystemCode().equalsIgnoreCase("NULL") &&
106                             !service.getNfcid2().equalsIgnoreCase("NULL")) {
107                         mForegroundT3tIdentifiersCache.put(service.getNfcid2(), service);
108                     }
109                     break;
110                 }
111             }
112         }
113 
114         if (DBG) {
115             Log.d(TAG, "mForegroundT3tIdentifiersCache: size=" +
116                     mForegroundT3tIdentifiersCache.size());
117             for (Map.Entry<String, NfcFServiceInfo> entry :
118                     mForegroundT3tIdentifiersCache.entrySet()) {
119                 Log.d(TAG, "    " + entry.getKey() +
120                         "/" + entry.getValue().getComponent().toString());
121             }
122         }
123 
124         updateRoutingLocked();
125     }
126 
updateRoutingLocked()127     void updateRoutingLocked() {
128         if (DBG) Log.d(TAG, "updateRoutingLocked");
129         if (!mNfcEnabled) {
130             Log.d(TAG, "Not updating routing table because NFC is off.");
131             return;
132         }
133         List<T3tIdentifier> t3tIdentifiers = new ArrayList<T3tIdentifier>();
134         Iterator<Map.Entry<String, NfcFServiceInfo>> it;
135         // Register foreground service
136         it = mForegroundT3tIdentifiersCache.entrySet().iterator();
137         while (it.hasNext()) {
138             Map.Entry<String, NfcFServiceInfo> entry =
139                     (Map.Entry<String, NfcFServiceInfo>) it.next();
140             t3tIdentifiers.add(new T3tIdentifier(
141                     entry.getValue().getSystemCode(), entry.getValue().getNfcid2()));
142         }
143         mRoutingManager.configureRouting(t3tIdentifiers);
144     }
145 
onServicesUpdated(int userId, List<NfcFServiceInfo> services)146     public void onServicesUpdated(int userId, List<NfcFServiceInfo> services) {
147         if (DBG) Log.d(TAG, "onServicesUpdated");
148         synchronized (mLock) {
149             if (ActivityManager.getCurrentUser() == userId) {
150                 // Rebuild our internal data-structures
151                 mServices = services;
152             } else {
153                 Log.d(TAG, "Ignoring update because it's not for the current user.");
154             }
155         }
156     }
157 
onEnabledForegroundNfcFServiceChanged(ComponentName component)158     public void onEnabledForegroundNfcFServiceChanged(ComponentName component) {
159         if (DBG) Log.d(TAG, "Enabled foreground service changed.");
160         synchronized (mLock) {
161             if (component != null) {
162                 if (mEnabledForegroundService != null) {
163                     return;
164                 }
165                 mEnabledForegroundService = component;
166             } else {
167                 if (mEnabledForegroundService == null) {
168                     return;
169                 }
170                 mEnabledForegroundService = null;
171             }
172             generateForegroundT3tIdentifiersCacheLocked();
173         }
174     }
175 
onNfcEnabled()176     public void onNfcEnabled() {
177         synchronized (mLock) {
178             mNfcEnabled = true;
179         }
180     }
181 
onNfcDisabled()182     public void onNfcDisabled() {
183         synchronized (mLock) {
184             mNfcEnabled = false;
185             mForegroundT3tIdentifiersCache.clear();
186             mEnabledForegroundService = null;
187         }
188         mRoutingManager.onNfccRoutingTableCleared();
189     }
190 
onUserSwitched()191     public void onUserSwitched() {
192         synchronized (mLock) {
193             mForegroundT3tIdentifiersCache.clear();
194             updateRoutingLocked();
195             mEnabledForegroundService = null;
196         }
197     }
198 
dump(FileDescriptor fd, PrintWriter pw, String[] args)199     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
200         pw.println("    T3T Identifier cache entries: ");
201         for (Map.Entry<String, NfcFServiceInfo> entry : mForegroundT3tIdentifiersCache.entrySet()) {
202             pw.println("    NFCID2: " + entry.getKey());
203             pw.println("    NfcFServiceInfo: ");
204             entry.getValue().dump(fd, pw, args);
205         }
206         pw.println("");
207         mRoutingManager.dump(fd, pw, args);
208         pw.println("");
209     }
210 }
211