Change scan downgrading to be app independent

Before this patch, every time an app started a new scan it would reset the
timer to downgrade apps down to opportunistic. Now each app is kept track
of individually so that another app doing frequent short scans doesn't cause
a long scanning app to avoid downgrading.

Fixes: 34224062
Test: Tested scanning multiple times with multiple apps / TestTracker:73279
Change-Id: Ibcae9115dcd0fb5325f7bc9fc5d6e0fe4bf6e062
(cherry picked from commit 65e839fa45222955a605f6270a240edc68b21617)
diff --git a/src/com/android/bluetooth/gatt/AppScanStats.java b/src/com/android/bluetooth/gatt/AppScanStats.java
index e73f415..7eed888 100644
--- a/src/com/android/bluetooth/gatt/AppScanStats.java
+++ b/src/com/android/bluetooth/gatt/AppScanStats.java
@@ -64,6 +64,9 @@
     // earliest recorded scan exits this window.
     static final long EXCESSIVE_SCANNING_PERIOD_MS = 30 * 1000;
 
+    // Maximum msec before scan gets downgraded to opportunistic
+    static final int SCAN_TIMEOUT_MS = 30 * 60 * 1000;
+
     String appName;
     int scansStarted = 0;
     int scansStopped = 0;
@@ -160,6 +163,14 @@
             EXCESSIVE_SCANNING_PERIOD_MS;
     }
 
+    synchronized boolean isScanningTooLong() {
+        if (lastScans.isEmpty() || !isScanning) {
+            return false;
+        }
+
+        return (System.currentTimeMillis() - startTime) > SCAN_TIMEOUT_MS;
+    }
+
     // This function truncates the app name for privacy reasons. Apps with
     // four part package names or more get truncated to three parts, and apps
     // with three part package names names get truncated to two. Apps with two
diff --git a/src/com/android/bluetooth/gatt/ScanManager.java b/src/com/android/bluetooth/gatt/ScanManager.java
index 7dceb28..8b2f6d9 100644
--- a/src/com/android/bluetooth/gatt/ScanManager.java
+++ b/src/com/android/bluetooth/gatt/ScanManager.java
@@ -70,9 +70,6 @@
     private static final int MSG_FLUSH_BATCH_RESULTS = 2;
     private static final int MSG_SCAN_TIMEOUT = 3;
 
-    // Maximum msec before scan gets downgraded to opportunistic
-    private static final int SCAN_TIMEOUT_MS = 30 * 60 * 1000;
-
     private static final String ACTION_REFRESH_BATCHED_SCAN =
             "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";
 
@@ -199,7 +196,7 @@
                     handleFlushBatchResults(client);
                     break;
                 case MSG_SCAN_TIMEOUT:
-                    mScanNative.regularScanTimeout();
+                    mScanNative.regularScanTimeout(client);
                     break;
                 default:
                     // Shouldn't happen.
@@ -234,8 +231,7 @@
                         Message msg = mHandler.obtainMessage(MSG_SCAN_TIMEOUT);
                         msg.obj = client;
                         // Only one timeout message should exist at any time
-                        mHandler.removeMessages(MSG_SCAN_TIMEOUT);
-                        mHandler.sendMessageDelayed(msg, SCAN_TIMEOUT_MS);
+                        mHandler.sendMessageDelayed(msg, AppScanStats.SCAN_TIMEOUT_MS);
                     }
                 }
 
@@ -679,14 +675,12 @@
             removeScanFilters(client.clientIf);
         }
 
-        void regularScanTimeout() {
-            for (ScanClient client : mRegularScanClients) {
-                if (!isExemptFromScanDowngrade(client)) {
-                    Log.w(TAG, "Moving scan client to opportunistic (clientIf "
-                          + client.clientIf + ")");
-                    setOpportunisticScanClient(client);
-                    client.stats.setScanTimeout();
-                }
+        void regularScanTimeout(ScanClient client) {
+            if (!isExemptFromScanDowngrade(client) && client.stats.isScanningTooLong()) {
+                Log.w(TAG,
+                        "Moving scan client to opportunistic (clientIf " + client.clientIf + ")");
+                setOpportunisticScanClient(client);
+                client.stats.setScanTimeout();
             }
 
             // The scan should continue for background scans