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 package com.android.nfc.cardemulation; 17 18 import java.io.FileDescriptor; 19 import java.io.PrintWriter; 20 21 import com.android.nfc.ForegroundUtils; 22 23 import android.app.ActivityManager; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.nfc.cardemulation.NfcFServiceInfo; 27 import android.os.Handler; 28 import android.os.Looper; 29 import android.util.Log; 30 31 public class EnabledNfcFServices implements com.android.nfc.ForegroundUtils.Callback { 32 static final String TAG = "EnabledNfcFCardEmulationServices"; 33 static final boolean DBG = false; 34 35 final Context mContext; 36 final RegisteredNfcFServicesCache mNfcFServiceCache; 37 final RegisteredT3tIdentifiersCache mT3tIdentifiersCache; 38 final Callback mCallback; 39 final ForegroundUtils mForegroundUtils = ForegroundUtils.getInstance(); 40 final Handler mHandler = new Handler(Looper.getMainLooper()); 41 42 final Object mLock = new Object(); 43 // Variables below synchronized on mLock 44 ComponentName mForegroundComponent = null; // The computed enabled foreground component 45 ComponentName mForegroundRequested = null; // The component requested to be enabled by fg app 46 int mForegroundUid = -1; // The UID of the fg app, or -1 if fg app didn't request 47 48 boolean mComputeFgRequested = false; 49 boolean mActivated = false; 50 51 public interface Callback { onEnabledForegroundNfcFServiceChanged(ComponentName service)52 void onEnabledForegroundNfcFServiceChanged(ComponentName service); 53 } 54 EnabledNfcFServices(Context context, RegisteredNfcFServicesCache nfcFServiceCache, RegisteredT3tIdentifiersCache t3tIdentifiersCache, Callback callback)55 public EnabledNfcFServices(Context context, 56 RegisteredNfcFServicesCache nfcFServiceCache, 57 RegisteredT3tIdentifiersCache t3tIdentifiersCache, Callback callback) { 58 if (DBG) Log.d(TAG, "EnabledNfcFServices"); 59 mContext = context; 60 mNfcFServiceCache = nfcFServiceCache; 61 mT3tIdentifiersCache = t3tIdentifiersCache; 62 mCallback = callback; 63 } 64 computeEnabledForegroundService()65 void computeEnabledForegroundService() { 66 if (DBG) Log.d(TAG, "computeEnabledForegroundService"); 67 ComponentName foregroundRequested = null; 68 boolean changed = false; 69 synchronized (mLock) { 70 if (mActivated) { 71 Log.d(TAG, "configuration will be postponed until deactivation"); 72 mComputeFgRequested = true; 73 return; 74 } 75 mComputeFgRequested = false; 76 foregroundRequested = mForegroundRequested; 77 if (mForegroundRequested != null && 78 (mForegroundComponent == null || 79 !mForegroundRequested.equals(mForegroundComponent))) { 80 mForegroundComponent = mForegroundRequested; 81 changed = true; 82 } else if (mForegroundRequested == null && mForegroundComponent != null){ 83 mForegroundComponent = mForegroundRequested; 84 changed = true; 85 } 86 } 87 // Notify if anything changed 88 if (changed) { 89 mCallback.onEnabledForegroundNfcFServiceChanged(foregroundRequested); 90 } 91 } 92 onServicesUpdated()93 public void onServicesUpdated() { 94 if (DBG) Log.d(TAG, "onServicesUpdated"); 95 // If enabled foreground service is set, remove it 96 boolean changed = false; 97 synchronized (mLock) { 98 if (mForegroundComponent != null) { 99 Log.d(TAG, "Removing foreground enabled service because of service update."); 100 mForegroundRequested = null; 101 mForegroundUid = -1; 102 changed = true; 103 } 104 } 105 if (changed) { 106 computeEnabledForegroundService(); 107 } 108 } 109 registerEnabledForegroundService(ComponentName service, int callingUid)110 public boolean registerEnabledForegroundService(ComponentName service, int callingUid) { 111 if (DBG) Log.d(TAG, "registerEnabledForegroundService"); 112 boolean success = false; 113 synchronized (mLock) { 114 NfcFServiceInfo serviceInfo = mNfcFServiceCache.getService( 115 ActivityManager.getCurrentUser(), service); 116 if (serviceInfo == null) { 117 return false; 118 } else { 119 if (serviceInfo.getSystemCode().equalsIgnoreCase("NULL") || 120 serviceInfo.getNfcid2().equalsIgnoreCase("NULL")) { 121 return false; 122 } 123 } 124 if (service.equals(mForegroundRequested)) { 125 Log.e(TAG, "The servcie is already requested to the foreground service."); 126 return true; 127 } 128 if (mForegroundUtils.registerUidToBackgroundCallback(this, callingUid)) { 129 mForegroundRequested = service; 130 mForegroundUid = callingUid; 131 success = true; 132 } else { 133 Log.e(TAG, "Calling UID is not in the foreground, ignorning!"); 134 } 135 } 136 if (success) { 137 computeEnabledForegroundService(); 138 } 139 return success; 140 } 141 unregisterForegroundService(int uid)142 boolean unregisterForegroundService(int uid) { 143 if (DBG) Log.d(TAG, "unregisterForegroundService"); 144 boolean success = false; 145 synchronized (mLock) { 146 if (mForegroundUid == uid) { 147 mForegroundRequested = null; 148 mForegroundUid = -1; 149 success = true; 150 } // else, other UID in foreground 151 } 152 if (success) { 153 computeEnabledForegroundService(); 154 } 155 return success; 156 } 157 unregisteredEnabledForegroundService(int callingUid)158 public boolean unregisteredEnabledForegroundService(int callingUid) { 159 if (DBG) Log.d(TAG, "unregisterEnabledForegroundService"); 160 // Verify the calling UID is in the foreground 161 if (mForegroundUtils.isInForeground(callingUid)) { 162 return unregisterForegroundService(callingUid); 163 } else { 164 Log.e(TAG, "Calling UID is not in the foreground, ignorning!"); 165 return false; 166 } 167 } 168 169 @Override onUidToBackground(int uid)170 public void onUidToBackground(int uid) { 171 if (DBG) Log.d(TAG, "onUidToBackground"); 172 unregisterForegroundService(uid); 173 } 174 onHostEmulationActivated()175 public void onHostEmulationActivated() { 176 if (DBG) Log.d(TAG, "onHostEmulationActivated"); 177 synchronized (mLock) { 178 mActivated = true; 179 } 180 } 181 onHostEmulationDeactivated()182 public void onHostEmulationDeactivated() { 183 if (DBG) Log.d(TAG, "onHostEmulationDeactivated"); 184 boolean needComputeFg = false; 185 synchronized (mLock) { 186 mActivated = false; 187 if (mComputeFgRequested) { 188 needComputeFg = true; 189 } 190 } 191 if (needComputeFg) { 192 Log.d(TAG, "do postponed configuration"); 193 computeEnabledForegroundService(); 194 } 195 } 196 onNfcDisabled()197 public void onNfcDisabled() { 198 synchronized (mLock) { 199 mForegroundComponent = null; 200 mForegroundRequested = null; 201 mActivated = false; 202 mComputeFgRequested = false; 203 mForegroundUid = -1; 204 } 205 } 206 onUserSwitched(int userId)207 public void onUserSwitched(int userId) { 208 synchronized (mLock) { 209 mForegroundComponent = null; 210 mForegroundRequested = null; 211 mActivated = false; 212 mComputeFgRequested = false; 213 mForegroundUid = -1; 214 } 215 } 216 dump(FileDescriptor fd, PrintWriter pw, String[] args)217 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 218 } 219 } 220