Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd6eb673 authored by Jayden Kim's avatar Jayden Kim Committed by Automerger Merge Worker
Browse files

Merge "Extend scan timeout logic to downgrade regular scan" into tm-dev-plus-aosp am: 58dea7f8

parents 63b9741c 58dea7f8
Loading
Loading
Loading
Loading
+18 −21
Original line number Original line Diff line number Diff line
@@ -5181,33 +5181,30 @@ public class AdapterService extends Service {
        }
        }
    }
    }


    public static int getScanQuotaCount() {
    /**
        if (sAdapterService == null) {
     * Returns scan quota count.
            return DeviceConfigListener.DEFAULT_SCAN_QUOTA_COUNT;
     */
        }
    public int getScanQuotaCount() {

        synchronized (mDeviceConfigLock) {
        synchronized (sAdapterService.mDeviceConfigLock) {
            return mScanQuotaCount;
            return sAdapterService.mScanQuotaCount;
        }
        }
        }

    public static long getScanQuotaWindowMillis() {
        if (sAdapterService == null) {
            return DeviceConfigListener.DEFAULT_SCAN_QUOTA_WINDOW_MILLIS;
    }
    }


        synchronized (sAdapterService.mDeviceConfigLock) {
    /**
            return sAdapterService.mScanQuotaWindowMillis;
     * Returns scan quota window in millis.
        }
     */
    public long getScanQuotaWindowMillis() {
        synchronized (mDeviceConfigLock) {
            return mScanQuotaWindowMillis;
        }
        }

    public static long getScanTimeoutMillis() {
        if (sAdapterService == null) {
            return DeviceConfigListener.DEFAULT_SCAN_TIMEOUT_MILLIS;
    }
    }


        synchronized (sAdapterService.mDeviceConfigLock) {
    /**
            return sAdapterService.mScanTimeoutMillis;
     * Returns scan timeout in millis.
     */
    public long getScanTimeoutMillis() {
        synchronized (mDeviceConfigLock) {
            return mScanTimeoutMillis;
        }
        }
    }
    }


+75 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2022 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.bluetooth.btservice;

import android.bluetooth.BluetoothAdapter;
import android.util.Log;

import com.android.bluetooth.Utils;
import com.android.internal.annotations.VisibleForTesting;

/**
 * A proxy class that facilitates testing of the ScanManager.
 *
 * This is necessary due to the "final" attribute of the BluetoothAdapter class. In order to
 * test the correct functioning of the ScanManager class, the final class must be put
 * into a container that can be mocked correctly.
 */
public class BluetoothAdapterProxy {
    private static final String TAG = BluetoothAdapterProxy.class.getSimpleName();
    private static BluetoothAdapterProxy sInstance;
    private static final Object INSTANCE_LOCK = new Object();

    private BluetoothAdapterProxy() {}

    /**
     * Get the singleton instance of proxy.
     *
     * @return the singleton instance, guaranteed not null
     */
    public static BluetoothAdapterProxy getInstance() {
        synchronized (INSTANCE_LOCK) {
            if (sInstance == null) {
                sInstance = new BluetoothAdapterProxy();
            }
            return sInstance;
        }
    }

    /**
     * Proxy function that calls {@link BluetoothAdapter#isOffloadedFilteringSupported()}.
     *
     * @return whether the offloaded scan filtering is supported
     */
    public boolean isOffloadedScanFilteringSupported() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        return adapter.isOffloadedFilteringSupported();
    }

    /**
     * Allow unit tests to substitute BluetoothAdapterProxy with a test instance
     *
     * @param proxy a test instance of the BluetoothAdapterProxy
     */
    @VisibleForTesting
    public static void setInstanceForTesting(BluetoothAdapterProxy proxy) {
        Utils.enforceInstrumentationTestMode();
        synchronized (INSTANCE_LOCK) {
            Log.d(TAG, "setInstanceForTesting(), set to " + proxy);
            sInstance = proxy;
        }
    }
}
+0 −23
Original line number Original line Diff line number Diff line
@@ -105,29 +105,6 @@ import java.util.Objects;
            this.filterString = "";
            this.filterString = "";
        }
        }
    }
    }

    static int getNumScanDurationsKept() {
        return AdapterService.getScanQuotaCount();
    }

    // This constant defines the time window an app can scan multiple times.
    // Any single app can scan up to |NUM_SCAN_DURATIONS_KEPT| times during
    // this window. Once they reach this limit, they must wait until their
    // earliest recorded scan exits this window.
    static long getExcessiveScanningPeriodMillis() {
        return AdapterService.getScanQuotaWindowMillis();
    }

    // Maximum msec before scan gets downgraded to opportunistic
    static long getScanTimeoutMillis() {
        return AdapterService.getScanTimeoutMillis();
    }

    // Scan mode upgrade duration after scanStart()
    static long getScanUpgradeDurationMillis() {
        return AdapterService.getAdapterService().getScanUpgradeDurationMillis();
    }

    public String appName;
    public String appName;
    public WorkSource mWorkSource; // Used for BatteryStatsManager
    public WorkSource mWorkSource; // Used for BatteryStatsManager
    public final WorkSourceUtil mWorkSourceUtil; // Used for BluetoothStatsLog
    public final WorkSourceUtil mWorkSourceUtil; // Used for BluetoothStatsLog
+13 −1
Original line number Original line Diff line number Diff line
@@ -75,6 +75,7 @@ import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AbstractionLayer;
import com.android.bluetooth.btservice.AbstractionLayer;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.util.NumberUtils;
import com.android.bluetooth.util.NumberUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
@@ -262,6 +263,7 @@ public class GattService extends ProfileService {
    private final HashMap<String, AtomicBoolean> mPermits = new HashMap<>();
    private final HashMap<String, AtomicBoolean> mPermits = new HashMap<>();


    private AdapterService mAdapterService;
    private AdapterService mAdapterService;
    private BluetoothAdapterProxy mBluetoothAdapterProxy;
    private AdvertiseManager mAdvertiseManager;
    private AdvertiseManager mAdvertiseManager;
    private PeriodicScanManager mPeriodicScanManager;
    private PeriodicScanManager mPeriodicScanManager;
    private ScanManager mScanManager;
    private ScanManager mScanManager;
@@ -319,12 +321,13 @@ public class GattService extends ProfileService {


        initializeNative();
        initializeNative();
        mAdapterService = AdapterService.getAdapterService();
        mAdapterService = AdapterService.getAdapterService();
        mBluetoothAdapterProxy = BluetoothAdapterProxy.getInstance();
        mCompanionManager = getSystemService(CompanionDeviceManager.class);
        mCompanionManager = getSystemService(CompanionDeviceManager.class);
        mAppOps = getSystemService(AppOpsManager.class);
        mAppOps = getSystemService(AppOpsManager.class);
        mAdvertiseManager = new AdvertiseManager(this, mAdapterService);
        mAdvertiseManager = new AdvertiseManager(this, mAdapterService);
        mAdvertiseManager.start();
        mAdvertiseManager.start();


        mScanManager = new ScanManager(this, mAdapterService);
        mScanManager = new ScanManager(this, mAdapterService, mBluetoothAdapterProxy);
        mScanManager.start();
        mScanManager.start();


        mPeriodicScanManager = new PeriodicScanManager(mAdapterService);
        mPeriodicScanManager = new PeriodicScanManager(mAdapterService);
@@ -426,6 +429,15 @@ public class GattService extends ProfileService {
        return sGattService;
        return sGattService;
    }
    }


    @VisibleForTesting
    ScanManager getScanManager() {
        if (mScanManager == null) {
            Log.w(TAG, "getScanManager(): scan manager is null");
            return null;
        }
        return mScanManager;
    }

    private static synchronized void setGattService(GattService instance) {
    private static synchronized void setGattService(GattService instance) {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "setGattService(): set to: " + instance);
            Log.d(TAG, "setGattService(): set to: " + instance);
+80 −32
Original line number Original line Diff line number Diff line
@@ -20,7 +20,6 @@ import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
import android.bluetooth.le.ScanSettings;
@@ -45,6 +44,8 @@ import android.view.Display;


import com.android.bluetooth.Utils;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.internal.annotations.VisibleForTesting;


import java.util.ArrayDeque;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Collections;
@@ -86,17 +87,18 @@ public class ScanManager {
    static final int SCAN_RESULT_TYPE_FULL = 2;
    static final int SCAN_RESULT_TYPE_FULL = 2;
    static final int SCAN_RESULT_TYPE_BOTH = 3;
    static final int SCAN_RESULT_TYPE_BOTH = 3;


    // Internal messages for handling BLE scan operations.
    // Messages for handling BLE scan operations.
    private static final int MSG_START_BLE_SCAN = 0;
    @VisibleForTesting
    private static final int MSG_STOP_BLE_SCAN = 1;
    static final int MSG_START_BLE_SCAN = 0;
    private static final int MSG_FLUSH_BATCH_RESULTS = 2;
    static final int MSG_STOP_BLE_SCAN = 1;
    private static final int MSG_SCAN_TIMEOUT = 3;
    static final int MSG_FLUSH_BATCH_RESULTS = 2;
    private static final int MSG_SUSPEND_SCANS = 4;
    static final int MSG_SCAN_TIMEOUT = 3;
    private static final int MSG_RESUME_SCANS = 5;
    static final int MSG_SUSPEND_SCANS = 4;
    private static final int MSG_IMPORTANCE_CHANGE = 6;
    static final int MSG_RESUME_SCANS = 5;
    private static final int MSG_SCREEN_ON = 7;
    static final int MSG_IMPORTANCE_CHANGE = 6;
    private static final int MSG_SCREEN_OFF = 8;
    static final int MSG_SCREEN_ON = 7;
    private static final int MSG_REVERT_SCAN_MODE_UPGRADE = 9;
    static final int MSG_SCREEN_OFF = 8;
    static final int MSG_REVERT_SCAN_MODE_UPGRADE = 9;
    private static final String ACTION_REFRESH_BATCHED_SCAN =
    private static final String ACTION_REFRESH_BATCHED_SCAN =
            "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";
            "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN";


@@ -115,6 +117,7 @@ public class ScanManager {
    private boolean mBatchAlarmReceiverRegistered;
    private boolean mBatchAlarmReceiverRegistered;
    private ScanNative mScanNative;
    private ScanNative mScanNative;
    private volatile ClientHandler mHandler;
    private volatile ClientHandler mHandler;
    private BluetoothAdapterProxy mBluetoothAdapterProxy;


    private Set<ScanClient> mRegularScanClients;
    private Set<ScanClient> mRegularScanClients;
    private Set<ScanClient> mBatchClients;
    private Set<ScanClient> mBatchClients;
@@ -134,7 +137,8 @@ public class ScanManager {
    private final SparseBooleanArray mIsUidForegroundMap = new SparseBooleanArray();
    private final SparseBooleanArray mIsUidForegroundMap = new SparseBooleanArray();
    private boolean mScreenOn = false;
    private boolean mScreenOn = false;


    private class UidImportance {
    @VisibleForTesting
    static class UidImportance {
        public int uid;
        public int uid;
        public int importance;
        public int importance;


@@ -144,7 +148,8 @@ public class ScanManager {
        }
        }
    }
    }


    ScanManager(GattService service, AdapterService adapterService) {
    ScanManager(GattService service, AdapterService adapterService,
            BluetoothAdapterProxy bluetoothAdapterProxy) {
        mRegularScanClients =
        mRegularScanClients =
                Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
                Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
        mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
        mBatchClients = Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>());
@@ -157,6 +162,7 @@ public class ScanManager {
        mActivityManager = mService.getSystemService(ActivityManager.class);
        mActivityManager = mService.getSystemService(ActivityManager.class);
        mLocationManager = mService.getSystemService(LocationManager.class);
        mLocationManager = mService.getSystemService(LocationManager.class);
        mAdapterService = adapterService;
        mAdapterService = adapterService;
        mBluetoothAdapterProxy = bluetoothAdapterProxy;


        mPriorityMap.put(ScanSettings.SCAN_MODE_OPPORTUNISTIC, 0);
        mPriorityMap.put(ScanSettings.SCAN_MODE_OPPORTUNISTIC, 0);
        mPriorityMap.put(ScanSettings.SCAN_MODE_SCREEN_OFF, 1);
        mPriorityMap.put(ScanSettings.SCAN_MODE_SCREEN_OFF, 1);
@@ -175,6 +181,7 @@ public class ScanManager {
        if (mDm != null) {
        if (mDm != null) {
            mDm.registerDisplayListener(mDisplayListener, null);
            mDm.registerDisplayListener(mDisplayListener, null);
        }
        }
        mScreenOn = isScreenOn();
        if (mActivityManager != null) {
        if (mActivityManager != null) {
            mActivityManager.addOnUidImportanceListener(mUidImportanceListener,
            mActivityManager.addOnUidImportanceListener(mUidImportanceListener,
                    FOREGROUND_IMPORTANCE_CUTOFF);
                    FOREGROUND_IMPORTANCE_CUTOFF);
@@ -234,6 +241,13 @@ public class ScanManager {
        return mRegularScanClients;
        return mRegularScanClients;
    }
    }


    /**
     * Returns the suspended scan queue.
     */
    Set<ScanClient> getSuspendedScanQueue() {
        return mSuspendedScanClients;
    }

    /**
    /**
     * Returns batch scan queue.
     * Returns batch scan queue.
     */
     */
@@ -298,8 +312,11 @@ public class ScanManager {
    }
    }


    private boolean isFilteringSupported() {
    private boolean isFilteringSupported() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapterProxy == null) {
        return adapter.isOffloadedFilteringSupported();
            Log.e(TAG, "mBluetoothAdapterProxy is null");
            return false;
        }
        return mBluetoothAdapterProxy.isOffloadedScanFilteringSupported();
    }
    }


    // Handler class that handles BLE scan operations.
    // Handler class that handles BLE scan operations.
@@ -363,7 +380,7 @@ public class ScanManager {
                return;
                return;
            }
            }


            if (requiresScreenOn(client) && !isScreenOn()) {
            if (requiresScreenOn(client) && !mScreenOn) {
                Log.w(TAG, "Cannot start unfiltered scan in screen-off. This scan will be resumed "
                Log.w(TAG, "Cannot start unfiltered scan in screen-off. This scan will be resumed "
                        + "later: " + client.scannerId);
                        + "later: " + client.scannerId);
                mSuspendedScanClients.add(client);
                mSuspendedScanClients.add(client);
@@ -400,6 +417,11 @@ public class ScanManager {
                        msg.obj = client;
                        msg.obj = client;
                        // Only one timeout message should exist at any time
                        // Only one timeout message should exist at any time
                        sendMessageDelayed(msg, mAdapterService.getScanTimeoutMillis());
                        sendMessageDelayed(msg, mAdapterService.getScanTimeoutMillis());
                        if (DBG) {
                            Log.d(TAG,
                                    "apply scan timeout (" + mAdapterService.getScanTimeoutMillis()
                                            + ")" + "to scannerId " + client.scannerId);
                        }
                    }
                    }
                }
                }
            }
            }
@@ -429,13 +451,10 @@ public class ScanManager {
                mSuspendedScanClients.remove(client);
                mSuspendedScanClients.remove(client);
            }
            }
            removeMessages(MSG_REVERT_SCAN_MODE_UPGRADE, client);
            removeMessages(MSG_REVERT_SCAN_MODE_UPGRADE, client);
            removeMessages(MSG_SCAN_TIMEOUT, client);
            if (mRegularScanClients.contains(client)) {
            if (mRegularScanClients.contains(client)) {
                mScanNative.stopRegularScan(client);
                mScanNative.stopRegularScan(client);


                if (mScanNative.numRegularScanClients() == 0) {
                    removeMessages(MSG_SCAN_TIMEOUT);
                }

                if (!mScanNative.isOpportunisticScanClient(client)) {
                if (!mScanNative.isOpportunisticScanClient(client)) {
                    mScanNative.configureRegularScanParams();
                    mScanNative.configureRegularScanParams();
                }
                }
@@ -493,7 +512,7 @@ public class ScanManager {
        @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
        @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
        void handleSuspendScans() {
        void handleSuspendScans() {
            for (ScanClient client : mRegularScanClients) {
            for (ScanClient client : mRegularScanClients) {
                if ((requiresScreenOn(client) && !isScreenOn())
                if ((requiresScreenOn(client) && !mScreenOn)
                        || (requiresLocationOn(client) && !mLocationManager.isLocationEnabled())) {
                        || (requiresLocationOn(client) && !mLocationManager.isLocationEnabled())) {
                    /*Suspend unfiltered scans*/
                    /*Suspend unfiltered scans*/
                    if (client.stats != null) {
                    if (client.stats != null) {
@@ -524,6 +543,9 @@ public class ScanManager {
        }
        }


        private boolean updateScanModeScreenOff(ScanClient client) {
        private boolean updateScanModeScreenOff(ScanClient client) {
            if (mScanNative.isTimeoutScanClient(client)) {
                return false;
            }
            if (!isAppForeground(client) && !mScanNative.isOpportunisticScanClient(client)) {
            if (!isAppForeground(client) && !mScanNative.isOpportunisticScanClient(client)) {
                return client.updateScanMode(ScanSettings.SCAN_MODE_SCREEN_OFF);
                return client.updateScanMode(ScanSettings.SCAN_MODE_SCREEN_OFF);
            }
            }
@@ -555,7 +577,7 @@ public class ScanManager {
            if (upgradeScanModeBeforeStart(client)) {
            if (upgradeScanModeBeforeStart(client)) {
                return true;
                return true;
            }
            }
            if (isScreenOn()) {
            if (mScreenOn) {
                return updateScanModeScreenOn(client);
                return updateScanModeScreenOn(client);
            } else {
            } else {
                return updateScanModeScreenOff(client);
                return updateScanModeScreenOff(client);
@@ -613,6 +635,10 @@ public class ScanManager {
        }
        }


        private boolean updateScanModeScreenOn(ScanClient client) {
        private boolean updateScanModeScreenOn(ScanClient client) {
            if (mScanNative.isTimeoutScanClient(client)) {
                return false;
            }

            int newScanMode =  (isAppForeground(client)
            int newScanMode =  (isAppForeground(client)
                    || mScanNative.isOpportunisticScanClient(client))
                    || mScanNative.isOpportunisticScanClient(client))
                    ? client.scanModeApp : SCAN_MODE_APP_IN_BACKGROUND;
                    ? client.scanModeApp : SCAN_MODE_APP_IN_BACKGROUND;
@@ -633,7 +659,7 @@ public class ScanManager {


        void handleResumeScans() {
        void handleResumeScans() {
            for (ScanClient client : mSuspendedScanClients) {
            for (ScanClient client : mSuspendedScanClients) {
                if ((!requiresScreenOn(client) || isScreenOn())
                if ((!requiresScreenOn(client) || mScreenOn)
                        && (!requiresLocationOn(client) || mLocationManager.isLocationEnabled())) {
                        && (!requiresLocationOn(client) || mLocationManager.isLocationEnabled())) {
                    if (client.stats != null) {
                    if (client.stats != null) {
                        client.stats.recordScanResume(client.scannerId);
                        client.stats.recordScanResume(client.scannerId);
@@ -871,14 +897,19 @@ public class ScanManager {
        }
        }


        private boolean isExemptFromScanDowngrade(ScanClient client) {
        private boolean isExemptFromScanDowngrade(ScanClient client) {
            return isOpportunisticScanClient(client) || isFirstMatchScanClient(client)
            return isOpportunisticScanClient(client) || isFirstMatchScanClient(client);
                    || !shouldUseAllPassFilter(client);
        }
        }


        private boolean isOpportunisticScanClient(ScanClient client) {
        private boolean isOpportunisticScanClient(ScanClient client) {
            return client.settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC;
            return client.settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC;
        }
        }


        private boolean isTimeoutScanClient(ScanClient client) {
            return (client.stats != null)
                    && (client.stats.getScanFromScannerId(client.scannerId) != null)
                    && (client.stats.getScanFromScannerId(client.scannerId).isTimeout);
        }

        private boolean isFirstMatchScanClient(ScanClient client) {
        private boolean isFirstMatchScanClient(ScanClient client) {
            return (client.settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
            return (client.settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
                    != 0;
                    != 0;
@@ -1046,11 +1077,23 @@ public class ScanManager {


        void regularScanTimeout(ScanClient client) {
        void regularScanTimeout(ScanClient client) {
            if (!isExemptFromScanDowngrade(client) && client.stats.isScanningTooLong()) {
            if (!isExemptFromScanDowngrade(client) && client.stats.isScanningTooLong()) {
                if (DBG) {
                    Log.d(TAG, "regularScanTimeout - client scan time was too long");
                }
                if (client.filters == null || client.filters.isEmpty()) {
                    Log.w(TAG,
                    Log.w(TAG,
                        "Moving scan client to opportunistic (scannerId " + client.scannerId + ")");
                            "Moving unfiltered scan client to opportunistic scan (scannerId "
                                    + client.scannerId + ")");
                    setOpportunisticScanClient(client);
                    setOpportunisticScanClient(client);
                    removeScanFilters(client.scannerId);
                    removeScanFilters(client.scannerId);
                    client.stats.setScanTimeout(client.scannerId);
                    client.stats.setScanTimeout(client.scannerId);
                } else {
                    Log.w(TAG,
                            "Moving filtered scan client to downgraded scan (scannerId "
                                    + client.scannerId + ")");
                    client.updateScanMode(ScanSettings.SCAN_MODE_LOW_POWER);
                    client.stats.setScanTimeout(client.scannerId);
                }
            }
            }


            // The scan should continue for background scans
            // The scan should continue for background scans
@@ -1527,6 +1570,11 @@ public class ScanManager {
        private native void gattClientReadScanReportsNative(int clientIf, int scanType);
        private native void gattClientReadScanReportsNative(int clientIf, int scanType);
    }
    }


    @VisibleForTesting
    ClientHandler getClientHandler() {
        return mHandler;
    }

    private boolean isScreenOn() {
    private boolean isScreenOn() {
        Display[] displays = mDm.getDisplays();
        Display[] displays = mDm.getDisplays();


@@ -1605,7 +1653,7 @@ public class ScanManager {
        }
        }


        for (ScanClient client : mRegularScanClients) {
        for (ScanClient client : mRegularScanClients) {
            if (client.appUid != uid) {
            if (client.appUid != uid || mScanNative.isTimeoutScanClient(client)) {
                continue;
                continue;
            }
            }
            if (isForeground) {
            if (isForeground) {
Loading