Adds functionality to detect live case NFC tags on lock screen.

Live case usecase at lock screen can be disabled by setting
enable_live_cases in the live_cases.xml to false.
live_case_tag_types contains technology types which will be polled for
at the lock screen. And live_case_mime_types contains the list of mime
records that will be allowed to be passed to the application. Currently
they are set to the Live Case application mime type, and can be
overriden for each of the device.

Bug: 34194910
Test: Manual; test with live case
Change-Id: I2534aeeaf550dee128c8963dfbada40574d5a4a5
Signed-off-by: Ruchi Kandoi<kandoiruchi@google.com>
diff --git a/res/values/live_cases.xml b/res/values/live_cases.xml
new file mode 100644
index 0000000..fc22b21
--- /dev/null
+++ b/res/values/live_cases.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<!-- NFC resources that may need to be customized
+     for different hardware or product builds. -->
+<resources>
+    <!-- Whether the device can receive NFC data in setup wizard -->
+    <bool name="enable_live_cases">true</bool>
+
+    <!-- The accepted mime-types when NFC is enabled at locked screen.
+         Mime-types must be lower case, wildcards are *not* accepted. -->
+    <string-array name="live_case_mime_types">
+        <item>application/vnd.google.android.apps.workshop</item>
+        <item>application/vnd.google.android.apps.live_case</item>
+    </string-array>
+
+    <!-- The accepted tag technology types which will be detected for live case
+         NFC at lock screen. Mime-types must be lower case, wildcards are *not*
+         accepted. -->
+    <string-array name="live_case_tag_types">
+        <item>TypeA</item>
+    </string-array>
+</resources>
diff --git a/src/com/android/nfc/NfcDispatcher.java b/src/com/android/nfc/NfcDispatcher.java
index ff86d6a..9f70b2e 100644
--- a/src/com/android/nfc/NfcDispatcher.java
+++ b/src/com/android/nfc/NfcDispatcher.java
@@ -75,6 +75,7 @@
     private final ContentResolver mContentResolver;
     private final HandoverDataParser mHandoverDataParser;
     private final String[] mProvisioningMimes;
+    private final String[] mLiveCaseMimes;
     private final ScreenStateHelper mScreenStateHelper;
     private final NfcUnlockManager mNfcUnlockManager;
     private final boolean mDeviceSupportsBluetooth;
@@ -112,6 +113,16 @@
             }
         }
         mProvisioningMimes = provisionMimes;
+
+        String[] liveCaseMimes = null;
+        try {
+            // Get accepted mime-types
+            liveCaseMimes = context.getResources().
+                    getStringArray(R.array.live_case_mime_types);
+        } catch (NotFoundException e) {
+           liveCaseMimes = null;
+        }
+        mLiveCaseMimes = liveCaseMimes;
     }
 
     public synchronized void setForegroundDispatch(PendingIntent intent,
@@ -231,6 +242,8 @@
         IntentFilter[] overrideFilters;
         String[][] overrideTechLists;
         String[] provisioningMimes;
+        String[] liveCaseMimes;
+        NdefMessage message = null;
         boolean provisioningOnly;
 
         synchronized (this) {
@@ -239,19 +252,31 @@
             overrideTechLists = mOverrideTechLists;
             provisioningOnly = mProvisioningOnly;
             provisioningMimes = mProvisioningMimes;
+            liveCaseMimes = mLiveCaseMimes;
         }
 
         boolean screenUnlocked = false;
+        boolean liveCaseDetected = false;
+        Ndef ndef = Ndef.get(tag);
         if (!provisioningOnly &&
                 mScreenStateHelper.checkScreenState() == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
             screenUnlocked = handleNfcUnlock(tag);
-            if (!screenUnlocked) {
-                return DISPATCH_FAIL;
+
+            if (ndef != null) {
+                message = ndef.getCachedNdefMessage();
+                if (message != null) {
+                    String ndefMimeType = message.getRecords()[0].toMimeType();
+                    if (liveCaseMimes != null &&
+                            Arrays.asList(liveCaseMimes).contains(ndefMimeType)) {
+                        liveCaseDetected = true;
+                    }
+                }
             }
+
+            if (!screenUnlocked && !liveCaseDetected)
+                return DISPATCH_FAIL;
         }
 
-        NdefMessage message = null;
-        Ndef ndef = Ndef.get(tag);
         if (ndef != null) {
             message = ndef.getCachedNdefMessage();
         } else {
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 6b671e8..0c36868 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -255,6 +255,9 @@
 
     private static NfcService sService;
 
+    boolean mIsLiveCaseEnabled; // whether live cases are enabled
+    int mLiveCaseTechnology; // Technology mask of accepted NFC tags
+
     public static NfcService getInstance() {
         return sService;
     }
@@ -355,6 +358,31 @@
         } catch (NotFoundException e) {
         }
 
+        try {
+            mIsLiveCaseEnabled = mContext.getResources().getBoolean(R.bool.enable_live_cases);
+        } catch (NotFoundException e) {
+            mIsLiveCaseEnabled = false;
+        }
+
+        mLiveCaseTechnology = 0;
+        String[] liveCaseTechList;
+        try {
+            liveCaseTechList = mContext.getResources().getStringArray(R.array.live_case_tag_types);
+            for (int i=0; i < liveCaseTechList.length; i++) {
+                if (liveCaseTechList[i].equals("TypeA")) {
+                    mLiveCaseTechnology |= NFC_POLL_A;
+                } else if (liveCaseTechList[i].equals("TypeB")) {
+                    mLiveCaseTechnology |= NFC_POLL_B;
+                } else if (liveCaseTechList[i].equals("TypeF")) {
+                    mLiveCaseTechnology |= NFC_POLL_F;
+                } else if (liveCaseTechList[i].equals("TypeV")) {
+                    mLiveCaseTechnology |= NFC_POLL_ISO15693;
+                }
+            }
+        } catch (NotFoundException e) {
+            mLiveCaseTechnology = 0;
+        }
+
         if (isNfcProvisioningEnabled) {
             mInProvisionMode = Settings.Secure.getInt(mContentResolver,
                     Settings.Global.DEVICE_PROVISIONED, 0) == 0;
@@ -1553,9 +1581,14 @@
             // enable P2P for MFM/EDU/Corp provisioning
             paramsBuilder.setEnableP2p(true);
         } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
-                mNfcUnlockManager.isLockscreenPollingEnabled()) {
-            // For lock-screen tags, no low-power polling
-            paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask());
+                (mIsLiveCaseEnabled || mNfcUnlockManager.isLockscreenPollingEnabled())) {
+            int techMask = 0;
+            // enable polling for Live Case technologies
+            if (mIsLiveCaseEnabled)
+                techMask |= mLiveCaseTechnology;
+            if (mNfcUnlockManager.isLockscreenPollingEnabled())
+                techMask |= mNfcUnlockManager.getLockscreenPollMask();
+            paramsBuilder.setTechMask(techMask);
             paramsBuilder.setEnableLowPowerDiscovery(false);
             paramsBuilder.setEnableP2p(false);
         }