blob: f24ee69bc7589c16c86ab5d47e98465f5e3c2de8 [file] [log] [blame]
/*
* Copyright (C) 2015 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.nfc.cardemulation;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.nfc.cardemulation.NfcFServiceInfo;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class RegisteredT3tIdentifiersCache {
static final String TAG = "RegisteredT3tIdentifiersCache";
static final boolean DBG = false;
// All NFC-F services that have registered
List<NfcFServiceInfo> mServices = new ArrayList<NfcFServiceInfo>();
final HashMap<String, NfcFServiceInfo> mForegroundT3tIdentifiersCache =
new HashMap<String, NfcFServiceInfo>();
ComponentName mEnabledForegroundService;
final class T3tIdentifier {
public final String systemCode;
public final String nfcid2;
public final String t3tPmm;
T3tIdentifier(String systemCode, String nfcid2, String t3tPmm) {
this.systemCode = systemCode;
this.nfcid2 = nfcid2;
this.t3tPmm = t3tPmm;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
T3tIdentifier that = (T3tIdentifier) o;
if (!systemCode.equalsIgnoreCase(that.systemCode)) return false;
if (!nfcid2.equalsIgnoreCase(that.nfcid2)) return false;
return true;
}
@Override
public int hashCode() {
int result = systemCode.hashCode();
result = 31 * result + nfcid2.hashCode();
return result;
}
}
final Context mContext;
final SystemCodeRoutingManager mRoutingManager;
final Object mLock = new Object();
boolean mNfcEnabled = false;
public RegisteredT3tIdentifiersCache(Context context) {
Log.d(TAG, "RegisteredT3tIdentifiersCache");
mContext = context;
mRoutingManager = new SystemCodeRoutingManager();
}
public NfcFServiceInfo resolveNfcid2(String nfcid2) {
synchronized (mLock) {
if (DBG) Log.d(TAG, "resolveNfcid2: resolving NFCID " + nfcid2);
NfcFServiceInfo resolveInfo;
resolveInfo = mForegroundT3tIdentifiersCache.get(nfcid2);
Log.d(TAG,
"Resolved to: " + (resolveInfo == null ? "null" : resolveInfo.toString()));
return resolveInfo;
}
}
void generateForegroundT3tIdentifiersCacheLocked() {
if (DBG) Log.d(TAG, "generateForegroundT3tIdentifiersCacheLocked");
mForegroundT3tIdentifiersCache.clear();
if (mEnabledForegroundService != null) {
for (NfcFServiceInfo service : mServices) {
if (mEnabledForegroundService.equals(service.getComponent())) {
if (!service.getSystemCode().equalsIgnoreCase("NULL") &&
!service.getNfcid2().equalsIgnoreCase("NULL")) {
mForegroundT3tIdentifiersCache.put(service.getNfcid2(), service);
}
break;
}
}
}
if (DBG) {
Log.d(TAG, "mForegroundT3tIdentifiersCache: size=" +
mForegroundT3tIdentifiersCache.size());
for (Map.Entry<String, NfcFServiceInfo> entry :
mForegroundT3tIdentifiersCache.entrySet()) {
Log.d(TAG, " " + entry.getKey() +
"/" + entry.getValue().getComponent().toString());
}
}
updateRoutingLocked(false);
}
void updateRoutingLocked(boolean force) {
if (DBG) Log.d(TAG, "updateRoutingLocked");
if (!mNfcEnabled) {
Log.d(TAG, "Not updating routing table because NFC is off.");
return;
}
List<T3tIdentifier> t3tIdentifiers = new ArrayList<T3tIdentifier>();
// Sending an empty table will de-register all entries
if (force) {
mRoutingManager.configureRouting(t3tIdentifiers);
}
Iterator<Map.Entry<String, NfcFServiceInfo>> it;
// Register foreground service
it = mForegroundT3tIdentifiersCache.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, NfcFServiceInfo> entry =
(Map.Entry<String, NfcFServiceInfo>) it.next();
t3tIdentifiers.add(new T3tIdentifier(
entry.getValue().getSystemCode(), entry.getValue().getNfcid2(), entry.getValue().getT3tPmm()));
}
mRoutingManager.configureRouting(t3tIdentifiers);
}
public void onSecureNfcToggled() {
synchronized(mLock) {
updateRoutingLocked(true);
}
}
public void onServicesUpdated(int userId, List<NfcFServiceInfo> services) {
if (DBG) Log.d(TAG, "onServicesUpdated");
synchronized (mLock) {
if (ActivityManager.getCurrentUser() == userId) {
// Rebuild our internal data-structures
mServices = services;
} else {
Log.d(TAG, "Ignoring update because it's not for the current user.");
}
}
}
public void onEnabledForegroundNfcFServiceChanged(ComponentName component) {
if (DBG) Log.d(TAG, "Enabled foreground service changed.");
synchronized (mLock) {
if (component != null) {
if (mEnabledForegroundService != null) {
return;
}
mEnabledForegroundService = component;
} else {
if (mEnabledForegroundService == null) {
return;
}
mEnabledForegroundService = null;
}
generateForegroundT3tIdentifiersCacheLocked();
}
}
public void onNfcEnabled() {
synchronized (mLock) {
mNfcEnabled = true;
}
}
public void onNfcDisabled() {
synchronized (mLock) {
mNfcEnabled = false;
mForegroundT3tIdentifiersCache.clear();
mEnabledForegroundService = null;
}
mRoutingManager.onNfccRoutingTableCleared();
}
public void onUserSwitched() {
synchronized (mLock) {
mForegroundT3tIdentifiersCache.clear();
updateRoutingLocked(false);
mEnabledForegroundService = null;
}
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("T3T Identifier cache entries: ");
for (Map.Entry<String, NfcFServiceInfo> entry : mForegroundT3tIdentifiersCache.entrySet()) {
pw.println(" NFCID2: " + entry.getKey());
pw.println(" NfcFServiceInfo: ");
entry.getValue().dump(fd, pw, args);
}
pw.println("");
mRoutingManager.dump(fd, pw, args);
pw.println("");
}
/**
* Dump debugging information as a RegisteredT3tIdentifiersCacheProto
*
* Note:
* See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto
* When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
* {@link ProtoOutputStream#end(long)} after.
* Never reuse a proto field number. When removing a field, mark it as reserved.
*/
void dumpDebug(ProtoOutputStream proto) {
for (NfcFServiceInfo serviceInfo : mForegroundT3tIdentifiersCache.values()) {
long token = proto.start(
RegisteredT3tIdentifiersCacheProto.T3T_IDENTIFIER_CACHE_ENTRIES);
serviceInfo.dumpDebug(proto);
proto.end(token);
}
long token = proto.start(RegisteredT3tIdentifiersCacheProto.ROUTING_MANAGER);
mRoutingManager.dumpDebug(proto);
proto.end(token);
}
}