From 885ee78985b1f5cc69ea6e58f095a62e838a001b Mon Sep 17 00:00:00 2001 From: "Bryant, Charles" Date: Wed, 5 Oct 2022 15:28:54 -0700 Subject: [PATCH] Deprecate wayfinding --- android/app/src/main/AndroidManifest.xml | 1 - ios/Podfile | 2 +- lib/app_constants.dart | 5 - lib/app_provider.dart | 13 +- lib/app_router.dart | 17 +- lib/core/models/wayfinding.dart | 1 - lib/core/models/wayfinding_constants.dart | 50 - lib/core/providers/bluetooth.dart | 67 -- lib/core/providers/wayfinding.dart | 956 ------------------ lib/core/services/wayfinding.dart | 63 -- lib/ui/home/home.dart | 17 - lib/ui/profile/profile.dart | 21 - lib/ui/wayfinding/beacon_view.dart | 120 --- lib/ui/wayfinding/bluetooth_logger.dart | 195 ---- lib/ui/wayfinding/wayfinding_permissions.dart | 417 -------- pubspec.lock | 30 - pubspec.yaml | 5 - 17 files changed, 3 insertions(+), 1977 deletions(-) delete mode 100644 lib/core/models/wayfinding.dart delete mode 100644 lib/core/models/wayfinding_constants.dart delete mode 100644 lib/core/providers/bluetooth.dart delete mode 100644 lib/core/providers/wayfinding.dart delete mode 100644 lib/core/services/wayfinding.dart delete mode 100644 lib/ui/wayfinding/beacon_view.dart delete mode 100644 lib/ui/wayfinding/bluetooth_logger.dart delete mode 100644 lib/ui/wayfinding/wayfinding_permissions.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0f67efecf..d9a68c14a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,7 +7,6 @@ - dependentServices = [ } return classScheduleDataProvider; }), - ChangeNotifierProxyProvider2(create: (_) { - var proximityAwarenessSingleton = WayfindingProvider(); - return proximityAwarenessSingleton; - }, update: (_, coordinates, userDataProvider, proximityAwarenessSingleton) { - proximityAwarenessSingleton! - .coordinateAndLocation(coordinates, locationProvider!); - proximityAwarenessSingleton.userProvider = userDataProvider; - return proximityAwarenessSingleton; - }), ChangeNotifierProxyProvider( create: (_) { var studentIdDataProvider = StudentIdDataProvider(); diff --git a/lib/app_router.dart b/lib/app_router.dart index aa5aa8021..54dd624e6 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -4,8 +4,8 @@ import 'package:campus_mobile_experimental/core/models/dining.dart'; import 'package:campus_mobile_experimental/core/models/dining_menu.dart'; import 'package:campus_mobile_experimental/core/models/events.dart'; import 'package:campus_mobile_experimental/core/models/news.dart'; -import 'package:campus_mobile_experimental/ui/availability/manage_availability_view.dart'; import 'package:campus_mobile_experimental/ui/availability/availability_detail_view.dart'; +import 'package:campus_mobile_experimental/ui/availability/manage_availability_view.dart'; import 'package:campus_mobile_experimental/ui/classes/classes_list.dart'; import 'package:campus_mobile_experimental/ui/dining/dining_detail_view.dart'; import 'package:campus_mobile_experimental/ui/dining/dining_list.dart'; @@ -37,9 +37,6 @@ import 'package:campus_mobile_experimental/ui/profile/profile.dart'; import 'package:campus_mobile_experimental/ui/scanner/native_scanner_view.dart'; import 'package:campus_mobile_experimental/ui/shuttle/add_shuttle_stops_view.dart'; import 'package:campus_mobile_experimental/ui/shuttle/manage_shuttle_view.dart'; -import 'package:campus_mobile_experimental/ui/wayfinding/beacon_view.dart'; -import 'package:campus_mobile_experimental/ui/wayfinding/bluetooth_logger.dart'; -import 'package:campus_mobile_experimental/ui/wayfinding/wayfinding_permissions.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -160,16 +157,6 @@ class Router { Provider.of(_).changeTitle(settings.name); return NotificationsSettingsView(); }); - case RoutePaths.BluetoothPermissionsView: - return MaterialPageRoute(builder: (_) { - Provider.of(_).changeTitle(settings.name); - return AdvancedWayfindingPermission(); - }); - case RoutePaths.AutomaticBluetoothLoggerView: - return MaterialPageRoute(builder: (_) { - Provider.of(_).changeTitle(settings.name); - return AutomaticBluetoothLoggerView(); - }); case RoutePaths.ClassScheduleViewAll: return MaterialPageRoute(builder: (_) { Provider.of(_).changeTitle(settings.name); @@ -206,8 +193,6 @@ class Router { Provider.of(_).changeTitle(settings.name); return SpotTypesView(); }); - case RoutePaths.BeaconView: - return MaterialPageRoute(builder: (_) => BeaconView()); case RoutePaths.ScanditScanner: return MaterialPageRoute(builder: (_) => ScanditScanner()); default: diff --git a/lib/core/models/wayfinding.dart b/lib/core/models/wayfinding.dart deleted file mode 100644 index 8b1378917..000000000 --- a/lib/core/models/wayfinding.dart +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/core/models/wayfinding_constants.dart b/lib/core/models/wayfinding_constants.dart deleted file mode 100644 index 6aeda7b17..000000000 --- a/lib/core/models/wayfinding_constants.dart +++ /dev/null @@ -1,50 +0,0 @@ -class WayfindingConstantsModel { - int? qualifyingDevices; - int? qualifiedDevicesThreshold; - int? distanceThreshold; - int? dwellTimeThreshold; - int? scanIntervalAllowance; - int? backgroundScanInterval; - int? deletionInterval; - int? scanDuration; - int? scanWaitTime; - int? currentDwellTime; - double? milesFromPC; - final double pcLongitude = -117.237006; - final double pcLatitude = 32.880006; - double? userDistanceFromPriceCenter; - List? allowableDevices; - Map? deviceTypes; - - WayfindingConstantsModel( - {this.allowableDevices, - this.deviceTypes, - this.qualifyingDevices, - this.qualifiedDevicesThreshold, - this.distanceThreshold, - this.dwellTimeThreshold, - this.scanDuration, - this.scanWaitTime, - this.scanIntervalAllowance, - this.backgroundScanInterval, - this.deletionInterval, - this.milesFromPC}); - - factory WayfindingConstantsModel.fromJson( - Map deviceTypesJson, - Map constantsJson) => - WayfindingConstantsModel( - allowableDevices: List.from(constantsJson['deviceCharacteristics']), - deviceTypes: deviceTypesJson, - qualifyingDevices: 0, - qualifiedDevicesThreshold: int.parse(constantsJson["uniqueDevices"]), - distanceThreshold: int.parse(constantsJson["distanceThreshold"]), - dwellTimeThreshold: int.parse(constantsJson["dwellTimeThreshold"]), - scanDuration: int.parse(constantsJson["scanDuration"]), - scanWaitTime: int.parse(constantsJson["waitTime"]), - scanIntervalAllowance: - int.parse(constantsJson["scanIntervalAllowance"]), - backgroundScanInterval: constantsJson["backgroundScanInterval"], - deletionInterval: constantsJson["deletionInterval"], - milesFromPC: constantsJson['milesFromPC'].toDouble()); -} diff --git a/lib/core/providers/bluetooth.dart b/lib/core/providers/bluetooth.dart deleted file mode 100644 index 39666430a..000000000 --- a/lib/core/providers/bluetooth.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'dart:math'; - -import 'package:beacon_broadcast/beacon_broadcast.dart'; -import 'package:uuid/uuid.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class BeaconSingleton { - String? advertisingUUID; - String ucsdAppPrefix = "08506708-3068-0650-8008-0"; // UCSDAPP in ASCII - List hexLetters = ["A", "B", "C", "D", "E", "F"]; - BeaconBroadcast beaconBroadcast = BeaconBroadcast(); - - //Internal Declaration - static final BeaconSingleton _beaconSingleton = BeaconSingleton._internal(); - - BeaconSingleton._internal(); - - factory BeaconSingleton() { - return _beaconSingleton; - } - init() async { - changeUUID(); - SharedPreferences prefs = await SharedPreferences.getInstance(); - checkTime(); - prefs.setString('uuid', advertisingUUID!); - beaconBroadcast - .setUUID(advertisingUUID!) - .setMajorId(1) - .setMinorId(100) - .setIdentifier('ucsd.app.mobile') - .setLayout(BeaconBroadcast.ALTBEACON_LAYOUT) - .start(); - } - - void checkTime() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - advertisingUUID = prefs.get('uuid') as String? ?? "null"; - var previousTime = prefs.get('previousTime') ?? DateTime(1990).toString(); - var difference = DateTime.now() - .difference(DateTime.parse(previousTime as String)) - .inHours; - if (difference > 24) { - changeUUID(); - prefs.setString('previousTime', DateTime.now().toString()); - } - } - - void changeUUID() { - advertisingUUID = Uuid().v4(); - - advertisingUUID = randomUUID(); - } - - String randomUUID() { - final random = Random(); - String newUUID = ucsdAppPrefix; - for (int uuidIndex = 0; uuidIndex < 11; uuidIndex++) { - bool useLetter = random.nextBool(); - if (useLetter) { - newUUID += hexLetters[random.nextInt(6)]; - } else { - newUUID += random.nextInt(10).toString(); - } - } - return newUUID; - } -} diff --git a/lib/core/providers/wayfinding.dart b/lib/core/providers/wayfinding.dart deleted file mode 100644 index ce2ec4369..000000000 --- a/lib/core/providers/wayfinding.dart +++ /dev/null @@ -1,956 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:math' as math; -import 'dart:typed_data'; - -import 'package:campus_mobile_experimental/app_constants.dart'; -import 'package:campus_mobile_experimental/app_networking.dart'; -import 'package:campus_mobile_experimental/core/models/location.dart'; -import 'package:campus_mobile_experimental/core/models/wayfinding_constants.dart'; -import 'package:campus_mobile_experimental/core/providers/location.dart'; -import 'package:campus_mobile_experimental/core/providers/user.dart'; -import 'package:campus_mobile_experimental/core/services/wayfinding.dart'; -import 'package:campus_mobile_experimental/core/utils/maps.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_blue/flutter_blue.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:location/location.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import 'bluetooth.dart'; - -enum ScannedDevice { - SCANNED_DEVICE_ID, - SCANNED_DEVICE_TYPE, - SCANNED_DEVICE_ADVERTISEMENT_ID, - SCANNED_DEVICE_DETECT_START, - SCANNED_DEVICE_DETECT_SIGNAL_STRENGTH, - SCANNED_DEVICE_DETECT_DISTANCE -} - -/// A file that handles AdvancedWayfinding feature to scan and identify nearby BT devices. -class WayfindingProvider extends ChangeNotifier { - /// A structured model to simplify constants management and UCSD-ITS configurations. - late WayfindingConstantsModel _wayfindingConstantsModel; - - /// A service for fetching UCSD-ITS configurations from network. - late WayfindingService _wayfindingService; - - /// Responsible for managing the broadcasting of [advertisementValue]. - late BeaconSingleton beaconSingleton; - - /// Distinguishes running in the background vs having app open. - bool inBackground = false; - - /// Advertisement string - String? advertisementValue; - - /// Operating system of device - String? operatingSystem; - - /// Confirms that this is the first instance of the Wayfinding feature, preventing parallel scanning. - bool firstInstance = true; - - bool advancedWayfindingEnabled = false; - - /// Access previous bt setting/permissions - late SharedPreferences sharedPreferences; - - /// Ensures AdvancedWayfinding is disabled when location & BT are unavailable. - bool forceOff = false; - - /// Provides location of device for logging scans. - Coordinates? _coordinates; - - /// Not directly accessed but used to check permissions - LocationDataProvider? _locationDataProvider; - - /// Keeps track of scanned unique BT devices. - HashMap scannedObjects = new HashMap(); - - /// Instance of FlutterBlue library to handle raw BT processing. - FlutterBlue flutterBlueInstance = FlutterBlue.instance; - - /// Stores data from background scans to preserve scan continuation. - final FlutterSecureStorage _storage = FlutterSecureStorage(); - - /// Holds header for mobile logger POST. - Map? loggerHeader; - - /// Holds header for user token retrieval. - final Map tokenHeader = { - "accept": "application/json", - }; - - /// Provides specialized support for requests to WSO2 APIs. - final NetworkHelper _networkHelper = NetworkHelper(); - - /// Endpoint used to send device logs to ITS specified destination. - String mobileLoggerEndpoint = - "https://api-qa.ucsd.edu:8243/mobileapplogger/v1.1.0/log?type=WAYFINDING"; - - //Thresholds for logging location - int qualifiedDevicesThreshold = 0; - int distanceThreshold = 10; // default in ZenHub - int scanIntervalAllowance = 0; - int? backgroundScanInterval = 15; // Minutes - int? deletionInterval = 30; // Minutes - double milesFromPriceCenter = 5; - int dwellTimeThreshold = 200; // In seconds (10 minutes -> 600 seconds) - - /// Keep track of devices that meet our requirements - int qualifyingDevices = 0; - - /// Default constant for scans - int scanDuration = 2; //Seconds - int waitTime = 15; // Minutes - int dwellMinutes = 30; - - /// Coordinates for Price Center - final double pcLongitude = -117.237006; - final double pcLatitude = 32.880006; - late double distanceFromPriceCenter; - - /// Allows for continuous scan - Timer? ongoingScanner; - - /// Displays BT devices that have been scanned (only for debugger view). - List loggedItems = []; - - /// Gives an unfiltered list of scanned devices. - static List> unprocessedDevices = []; - List displayingDevices = []; - var btStream; - - /// Device types list for local caching - Map? deviceTypes = {}; - // initialize location and permissions to be checked - double? userLatitude; - double? userLongitude; - - /// Access user's profile to offload data - UserDataProvider? userDataProvider; - - /// Provides sole instance of AdvancedWayfinding feature. - static final WayfindingProvider _bluetoothSingleton = - WayfindingProvider._internal(); - - /// Constructor for AdvancedWayfinding feature and prevents multiple instances. - factory WayfindingProvider() { - return _bluetoothSingleton; - } - - /// Runs if AdvancedWayfinding was turned on. - void init() async { - btStream = Stream>.periodic( - Duration(seconds: 1), (x) => displayingDevices); - checkAdvancedWayfindingEnabled(); - userLongitude = (_coordinates == null) ? null : _coordinates!.lon; - userLatitude = (_coordinates == null) ? null : _coordinates!.lat; - - // Verify that BT module is present in this device. - await flutterBlueInstance.isAvailable.then((value) { - flutterBlueInstance.state.listen((event) async { - // Verify BT is available to start scanning. - if (event.index == 4) { - notifyListeners(); - // Set Wayfinding preferences - advancedWayfindingEnabled = true; - sharedPreferences = await SharedPreferences.getInstance(); - sharedPreferences.setBool("advancedWayfindingEnabled", true); - - // Fetch UCSD_ITS scanning configurations. - _wayfindingService = WayfindingService(); - await _wayfindingService.fetchData(); - _wayfindingConstantsModel = - _wayfindingService.wayfindingConstantsModel!; - - // Set up broadcasting for UCSD App Identification - startBeaconBroadcast(); - - // Set the minimum change to activate a new scan. - //location.changeSettings(accuracy: LocationAccuracy.low); - - // Enable location listening - checkLocationPermission(); - - // Enable continuous scan - enableScanning(); - } - }); - }); - } - - /// Enables periodic scanning based on [_wayfindingConstantsModel.scanWaitTime]. - enableScanning() { - // Start the initial scan - startScan(); - - // Enable timer and wait duration before starting next scan. - ongoingScanner = new Timer.periodic( - Duration(minutes: _wayfindingConstantsModel.scanWaitTime!), - (Timer t) => startScan()); - } - - /// Scans for BT LE devices and processes them to send to ITS specified destination. - /// - /// Short circuits when not within ITS defined distance of UCSD. - startScan() async { - //Ensure that we are still within X miles of Price Center - if (userLongitude != null && userLatitude != null) { - _wayfindingConstantsModel.userDistanceFromPriceCenter = - getHaversineDistance( - _wayfindingConstantsModel.pcLatitude, - _wayfindingConstantsModel.pcLongitude, - userLatitude, - userLongitude); - - // Convert km to miles - _wayfindingConstantsModel.userDistanceFromPriceCenter = - _wayfindingConstantsModel.userDistanceFromPriceCenter! / 1.609; - } - - //prevent scanning if not within boundaries - if (_wayfindingConstantsModel.userDistanceFromPriceCenter! > - _wayfindingConstantsModel.milesFromPC!) { - return; - } - - flutterBlueInstance.startScan( - timeout: Duration(seconds: 2), allowDuplicates: false); - - // Process the scan results (synchronously) - flutterBlueInstance.scanResults.listen((results) { - for (ScanResult scanResult in results) { - String? calculatedUUID; - - // Identify possible advertisement ID - calculatedUUID = extractAdvertisementUUID(scanResult); - - //Create BT objects to check continuity and store data - identifyDevices(scanResult); - - // Filter out duplicated devices - bool repeatedDevice = checkForDuplicates(scanResult); - - // Determines threshold qualifying devices and connects to devices when necessary - bluetoothLogAnalysis(repeatedDevice, scanResult, calculatedUUID); - } - }); - - // Remove objects that are no longer continuous found (+ grace period) - removeNoncontinuousDevices(); - - // Include device type for threshold - List processedDevices = identifyDeviceTypes(); - // Remove objects that are no longer continuous found (+ grace period) - removeNoncontinuousDevices(); - - displayingDevices = List.of(processedDevices); - notifyListeners(); - // If there are more than three devices, log location - processOffloadingLogs(List.of(processedDevices)); - - // Close on going scan in case it has not time out - flutterBlueInstance.stopScan(); - - // If app is not open, send logs when scanned - if (inBackground) { - _storage.deleteAll(); - await _storage.write( - key: "lastBackgroundScan", value: DateTime.now().toString()); - - // Reset dwell times - resetDevices(); - _wayfindingConstantsModel.qualifyingDevices = 0; - - //LOG VALUE - Map log = { - "SOURCE_DEVICE_ADVERTISEMENT_ID": this.advertisementValue, - "SOURCE": "$operatingSystem-UCSDMobileApp", - "OPERATING_SYSTEM": operatingSystem, - "LAT": (userLatitude == null) ? 0 : userLatitude, - "LONG": (userLongitude == null) ? 0 : userLongitude, - "DEVICE_LIST": processedDevices - }; - - // Send logs to API - sendLogs(log); - return; - } - - // Write scannedObjects to storage - scannedObjects.forEach((key, value) { - _storage.write(key: key, value: jsonEncode(value)); - }); - - // Clear previous scan results - unprocessedDevices.clear(); - processedDevices.clear(); - } - - /// Gathers location data and prepares log to offload - /// - /// Will only send logs if threshold is met - void processOffloadingLogs(List processedDevices) { - // Identify OS of scanning device - if (Platform.isAndroid) { - operatingSystem = "Android"; - } else if (Platform.isIOS) { - operatingSystem = "iOS"; - } - if (_wayfindingConstantsModel.qualifyingDevices! >= - _wayfindingConstantsModel.qualifiedDevicesThreshold!) { - // Reset dwell times - resetDevices(); - _wayfindingConstantsModel.qualifyingDevices = 0; - - //LOG VALUE - Map log = { - "SOURCE_DEVICE_ADVERTISEMENT_ID": this.advertisementValue, - "SOURCE": "$operatingSystem-UCSDMobileApp", - "OPERATING_SYSTEM": operatingSystem, - "LAT": (userLatitude == null) ? 0 : userLatitude, - "LONG": (userLongitude == null) ? 0 : userLongitude, - "DEVICE_LIST": processedDevices - }; - // Send logs to API - sendLogs(log); - } - } - - /// Sends BT LE logs to API - /// - /// Will attach access token if logged in - Future sendLogs(Map log) async { - // Attach token from user if logged in - if (userDataProvider != null && userDataProvider!.isLoggedIn) { - if (loggerHeader == null) { - loggerHeader = { - 'Authorization': - 'Bearer ${userDataProvider?.authenticationModel?.accessToken}' - }; - } - - // Send to offload API - try { - _networkHelper - .authorizedPost( - mobileLoggerEndpoint, loggerHeader, json.encode(log.toString())) - .then((value) {}); - } catch (Exception) { - // Silent login if access token is expired - if (Exception.toString().contains(ErrorConstants.invalidBearerToken)) { - userDataProvider!.silentLogin(); - loggerHeader = { - 'Authorization': - 'Bearer ${userDataProvider?.authenticationModel?.accessToken}' - }; - _networkHelper.authorizedPost( - mobileLoggerEndpoint, loggerHeader, json.encode(log.toString())); - } - } - } else { - // Send logs to API for visitors - try { - await getNewToken(); - _networkHelper.authorizedPost( - mobileLoggerEndpoint, tokenHeader, json.encode(log.toString())); - } catch (Exception) { - await getNewToken(); - _networkHelper.authorizedPost( - mobileLoggerEndpoint, tokenHeader, json.encode(log.toString())); - } - } - } - - // Calculates Advertisement ID if one is available - String extractAdvertisementUUID(ScanResult scanResult) { - String calculatedUUID = ""; - scanResult.advertisementData.manufacturerData.forEach((key, decimalArray) { - calculatedUUID = calculateHexFromArray( - decimalArray); //https://stackoverflow.com/questions/60902976/flutter-ios-to-ios-broadcast-beacon-not-working - }); - //Add formatting to applicable uuid - if (calculatedUUID.length == 30) { - calculatedUUID = calculatedUUID.substring(0, 8) + - "-" + - calculatedUUID.substring(8, 12) + - "-" + - calculatedUUID.substring(12, 16) + - "-" + - calculatedUUID.substring(16, 20) + - "-" + - calculatedUUID.substring(20); - } - return calculatedUUID; - } - - // Identify types of device, most reliable for Apple devices - List identifyDeviceTypes() { - bool iOSDevice = false; - List formattedLists = []; - List> newBufferList = []; - for (List deviceEntry in unprocessedDevices) { - // Handle differences among platform - if (Platform.isIOS) { - deviceEntry.insert( - 1, - ((scannedObjects[(deviceEntry[0].toString().substring(0, 36))]! - .deviceType != - "") - ? "${getAppleClassification(scannedObjects[deviceEntry[0].toString().substring(0, 36)]!.deviceType!)}" - : "Unavailable")); - if (getAppleClassification( - scannedObjects[deviceEntry[0].toString().substring(0, 36)]! - .deviceType!) != - "") { - iOSDevice = true; - } - } else if (Platform.isAndroid) { - deviceEntry.insert( - 1, - ((scannedObjects[deviceEntry[0].toString().substring(0, 17)]! - .deviceType != - "") - ? "${getAppleClassification(scannedObjects[deviceEntry[ScannedDevice.SCANNED_DEVICE_ID.index].toString().substring(0, 17)]!.deviceType!)}" - : "Unavailable")); - if (getAppleClassification(scannedObjects[ - deviceEntry[ScannedDevice.SCANNED_DEVICE_ID.index] - .toString() - .substring(0, 17)]! - .deviceType!) != - "") { - iOSDevice = true; - } - } - - // Add identified device to temporary log - newBufferList.add(deviceEntry); - } - - /// Format Map for each device - for (List deviceEntry in newBufferList) { - Map deviceLog = { - "SCANNED_DEVICE_ADVERTISEMENT_ID": - deviceEntry[ScannedDevice.SCANNED_DEVICE_ADVERTISEMENT_ID.index], - "SCANNED_DEVICE_ID": deviceEntry[ScannedDevice.SCANNED_DEVICE_ID.index], - "SCANNED_DEVICE_TYPE": - deviceEntry[ScannedDevice.SCANNED_DEVICE_TYPE.index], - "SCANNED_DEVICE_DETECT_START": - deviceEntry[ScannedDevice.SCANNED_DEVICE_DETECT_START.index], - "SCANNED_DEVICE_DETECT_CURRENT": DateTime.fromMillisecondsSinceEpoch( - DateTime.now().millisecondsSinceEpoch) - .toString(), - "SCANNED_DEVICE_DETECT_SIGNAL_STRENGTH": deviceEntry[ - ScannedDevice.SCANNED_DEVICE_DETECT_SIGNAL_STRENGTH.index], - "SCANNED_DEVICE_DETECT_DISTANCE": - deviceEntry[ScannedDevice.SCANNED_DEVICE_DETECT_DISTANCE.index], - "DEVICE_OS": (iOSDevice ? "iOS" : "non-iOS") - }; - formattedLists.add(deviceLog); - } - return formattedLists; - } - - /// Reset device dwell time when used to track user's location - void resetDevices() { - int currentMinutes = getMinutesTimeOfDay(); - scannedObjects.removeWhere((key, value) { - if (currentMinutes < value.scanTimeMinutes!) { - return (currentMinutes + 60) - value.scanTimeMinutes! >= 2; - } - return currentMinutes - value.scanTimeMinutes! >= 2; - }); - } - - bool checkDeviceDwellTime(BluetoothDeviceProfile device) { - int currentMinutes = getMinutesTimeOfDay(); - if (currentMinutes < device.scanTimeMinutes!) { - return (currentMinutes + 60) - device.scanTimeMinutes! < - _wayfindingConstantsModel.dwellTimeThreshold!; - } - return currentMinutes - device.scanTimeMinutes! < - _wayfindingConstantsModel.dwellTimeThreshold!; - } - - //Gather information on device scanned - void identifyDevices(ScanResult scanResult) { - int currentMinutes = getMinutesTimeOfDay(); - scannedObjects.update(scanResult.device.id.toString(), (value) { - value.continuousDuration = true; - value.rssi = scanResult.rssi; - if (scanResult.advertisementData.txPowerLevel != null) { - value.txPowerLevel = scanResult.advertisementData.txPowerLevel; - } - value.scanTimeMinutes = currentMinutes; - value.scanIntervalAllowancesUsed = 0; - return value; - }, - ifAbsent: () => new BluetoothDeviceProfile( - scanResult.device.id.toString(), - scanResult.rssi, - "", - new List.from({ - DateTime.fromMillisecondsSinceEpoch( - DateTime.now().millisecondsSinceEpoch) - .toString() - }), - true, - currentMinutes)); - } - - // Ensure we only process unique devices during one scan - bool checkForDuplicates(ScanResult scanResult) { - bool repeatedDevice = false; - unprocessedDevices.forEach((element) { - String toFind = '${scanResult.device.id}'; - if (element.contains(toFind)) { - repeatedDevice = true; - } - }); - return repeatedDevice; - } - - String getCurrentTimeOfDay() { - TimeOfDay currentTime = TimeOfDay.now(); - return "${currentTime.hour}:${currentTime.minute}"; - } - - int getMinutesTimeOfDay() { - TimeOfDay currentTime = TimeOfDay.now(); - return currentTime.minute; - } - - // Identify the Apple device type - String getAppleClassification(String manufacturerName) { - String deviceType = ""; - if (manufacturerName.contains("Mac")) { - deviceType = "Computer"; - } else if (manufacturerName.contains("iPhone")) { - deviceType = "Phone"; - } else if (manufacturerName.contains("Audio")) { - deviceType = "Audio Output"; - } else if (manufacturerName.contains("iPad")) { - deviceType = "Tablet"; - } else if (manufacturerName.contains("Watch")) { - deviceType = "Watch"; - } - return deviceType; - } - - //Remove devices that are no longer scanned - void removeNoncontinuousDevices() { - scannedObjects.removeWhere((key, value) { - bool isDeviceContinuous = checkDeviceDwellTime(value); - if (!isDeviceContinuous && - value.scanIntervalAllowancesUsed! >= - _wayfindingConstantsModel.scanIntervalAllowance!) { - return true; - } else if (!isDeviceContinuous && - value.scanIntervalAllowancesUsed! < - _wayfindingConstantsModel.scanIntervalAllowance!) { - value.scanIntervalAllowancesUsed = - value.scanIntervalAllowancesUsed! + 1; - } - return false; - }); - - List objectsToRemove = []; - scannedObjects.forEach((key, value) { - if (!value.continuousDuration! && - value.scanIntervalAllowancesUsed! > - _wayfindingConstantsModel.scanIntervalAllowance!) { - objectsToRemove.add(key); - } else if (!value.continuousDuration! && - value.scanIntervalAllowancesUsed! <= - _wayfindingConstantsModel.scanIntervalAllowance!) { - value.scanIntervalAllowancesUsed = - value.scanIntervalAllowancesUsed! + 1; - } - }); - objectsToRemove.forEach((element) { - scannedObjects.remove(element); - }); - } - - // Determine if we use the type to log location - bool eligibleType(String manufacturerName) { - return _wayfindingConstantsModel.allowableDevices! - .contains(getAppleClassification(manufacturerName)) || - _wayfindingConstantsModel.allowableDevices!.contains(manufacturerName); - } - - // Originally for on screen rendering but also calculates devices that meet our requirements - void bluetoothLogAnalysis( - bool repeatedDevice, ScanResult scanResult, String? calculatedUUID) { - if (!repeatedDevice) { - scannedObjects[scanResult.device.id.toString()]!.dwellTime = - scannedObjects[scanResult.device.id.toString()]!.dwellTime! + - (_wayfindingConstantsModel.scanWaitTime! * - 60); //account for seconds - scannedObjects[scanResult.device.id.toString()]!.distance = - getDistance(scanResult.rssi); - if (scannedObjects[scanResult.device.id.toString()]!.dwellTime! >= - _wayfindingConstantsModel.dwellTimeThreshold!) { - // Remove to reinstate thresholds - // && - // scannedObjects[scanResult.device.id.toString()].distance <= - // distanceThreshold && - // eligibleType( - // scannedObjects[scanResult.device.id.toString()].deviceType)) { - _wayfindingConstantsModel.qualifyingDevices = - _wayfindingConstantsModel.qualifyingDevices! + - 1; // Add the # of unique devices detected - } - - // Log important information - String deviceLog = '${scanResult.device.id}'; - - if (calculatedUUID == null) { - calculatedUUID = ""; - } - List actualDeviceLog = [ - deviceLog, - calculatedUUID.toString(), - scannedObjects[scanResult.device.id.toString()]! - .timeStamps![0] - .toString(), - scanResult.rssi.toInt(), - scannedObjects[scanResult.device.id.toString()]!.distance!.toInt() - ]; - - unprocessedDevices.add(actualDeviceLog); - - if (Platform.isAndroid) { - scannedObjects[scanResult.device.id.toString()]!.deviceType = - parseForAppearance(scanResult); - } - - if (scanResult.advertisementData.connectable && - scannedObjects[scanResult.device.id.toString()]!.deviceType == "") { - extractBTServices(scanResult); - } - } - } - - // Parse raw BT data for advertised info. - String parseForAppearance(ScanResult scanResult) { - Uint8List adData = scanResult.advertisementData.rawData as Uint8List; - int index = 0; - String data; - - while (index < adData.length) { - data = "0x"; - int length = adData[index++]; - if (length == 0) //check if reached end of advertisement - break; - - if (index + length > - adData - .length) //check if there is not enough data in the advertisement - break; - int type = adData[index++]; - length--; - - switch (type) { - case 0x19: - int i = index + length; - for (; (index < i); index++) { - data += adData[index].toRadixString(16).padLeft(2, '0'); - } - return data; - default: - index += length; - break; - } - } - return ""; - } - - // Extract services from connect device to identify type - void extractBTServices(ScanResult scanResult) async { - try { - var scannedDevice = scanResult.device; - scannedDevice.connect().then((value) { - scannedDevice.discoverServices().then((discoveredServices) { - discoveredServices.forEach((service) { - if (service.uuid.toString().toUpperCase().contains("1800")) { - // GAP Service - service.characteristics.forEach((characteristic) { - if (characteristic.toString().toUpperCase().contains("2A01")) { - // Appearance - characteristic.read().then((deviceType) { - scannedObjects[scannedDevice.id.toString()]!.deviceType = - _wayfindingConstantsModel.deviceTypes! - .containsKey(deviceType.toString()) - ? _wayfindingConstantsModel - .deviceTypes![deviceType.toString()] - : " "; - }); - } - }); - } else if (service.uuid.toString().toUpperCase().contains("180A")) { - // Manufacturer Data - service.characteristics.forEach((characteristic) { - if (characteristic.toString().toUpperCase().contains("2A24")) { - // Device Type Name - characteristic.read().then((deviceType) { - scannedObjects[scannedDevice.id.toString()]!.deviceType = - "${ascii.decode(deviceType).toString()}"; - }); - } - }); - } - }); - }); - }); - } catch (exception) {} - } - - // Used to log current user location or enable the location change listener - Future checkLocationPermission() async { - return await _locationDataProvider!.locationObject.hasPermission(); - } - - Future checkLocationService() async { - return await _locationDataProvider!.locationObject.serviceEnabled(); - } - - // Get the rough distance from bt device - double getDistance(int rssi) { - var txPower = -59; //hardcoded for now - var ratio = (rssi * 1.0) / txPower; - if (ratio < 1.0) { - return (math.pow(ratio, 10) * - 3.28084); //multiply by 3.. for meters to feet conversion - } else { - return ((0.89976 * math.pow(ratio, 7.7095) + 0.111) * - 3.28084); //https://haddadi.github.io/papers/UBICOMP2016iBeacon.pdf - } - } - - // Internal constructor - WayfindingProvider._internal(); - - //Parse advertisement data - String calculateHexFromArray(decimalArray) { - String uuid = ''; - decimalArray.forEach((i) => {uuid += i.toRadixString(16).padLeft(2, '0')}); - try { - String uuid1 = uuid.substring(4, uuid.length - 12); - return uuid1.toUpperCase(); - } catch (Exception) { - return uuid; - } - } - - Future getNewToken() async { - final String tokenEndpoint = "https://api-qa.ucsd.edu:8243/token"; - final Map tokenHeaders = { - "content-type": 'application/x-www-form-urlencoded', - "Authorization": - "Basic djJlNEpYa0NJUHZ5akFWT0VRXzRqZmZUdDkwYTp2emNBZGFzZWpmaWZiUDc2VUJjNDNNVDExclVh" - }; - try { - var response = await _networkHelper.authorizedPost( - tokenEndpoint, tokenHeaders, "grant_type=client_credentials"); - - tokenHeader["Authorization"] = "Bearer " + response["access_token"]; - - return true; - } catch (e) { - return false; - } - } - -// Stops all ongoing processes - void stopScans() { - if (ongoingScanner != null) { - ongoingScanner!.cancel(); - ongoingScanner = null; - } - flutterBlueInstance.stopScan(); - flutterBlueInstance.scanResults.listen((event) {}).cancel(); - beaconSingleton.beaconBroadcast.stop(); - } - - void coordinateAndLocation( - Coordinates value, LocationDataProvider locationDataProvider) { - _locationDataProvider = locationDataProvider; - // Toggle off 'force off" value - if (_coordinates != null) { - forceOff = false; - } - _coordinates = value; - notifyListeners(); - } - - get processedDevices => displayingDevices; - get locationDataProvider => _locationDataProvider; - get coordinate => _coordinates; - set userProvider(UserDataProvider userDataProvider) { - userDataProvider = userDataProvider; - notifyListeners(); - } - - // Check previous permissions granted - Future checkAdvancedWayfindingEnabled() async { - await SharedPreferences.getInstance().then((value) { - sharedPreferences = value; - if (sharedPreferences.containsKey("advancedWayfindingEnabled")) { - advancedWayfindingEnabled = - sharedPreferences.getBool("advancedWayfindingEnabled")!; - } else { - //Write to bt value - sharedPreferences.setBool( - "advancedWayfindingEnabled", advancedWayfindingEnabled); - } - }); - } - - // Checks bt state of the device - bool permissionState(BuildContext context, AsyncSnapshot snapshot) { - // checkAdvancedWayfindingEnabled(); - // checkAdvancedWayfindingEnabled(); - checkForceOff(snapshot); - if (snapshot.data as BluetoothState == BluetoothState.unauthorized || - snapshot.data as BluetoothState == BluetoothState.off || - forceOff) { - if (ongoingScanner != null) ongoingScanner = null; - forceOff = true; - advancedWayfindingEnabled = false; - } - - if (advancedWayfindingEnabled) init(); - return advancedWayfindingEnabled; - } - - // Verify permissions are enabled - void checkToResumeBluetooth(BuildContext context) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - - if (prefs.containsKey("advancedWayfindingEnabled") && - prefs.getBool('advancedWayfindingEnabled')!) { - if (firstInstance) { - firstInstance = false; - init(); - } - } - } - - void checkForceOff(AsyncSnapshot snapshot) async { - if (snapshot.data as BluetoothState == BluetoothState.unauthorized || - snapshot.data as BluetoothState == BluetoothState.off || - !(await locationDataProvider.locationObject.serviceEnabled()) || - (PermissionStatus.granted != - await locationDataProvider.locationObject.hasPermission())) { - forceOff = true; - if (ongoingScanner != null) ongoingScanner = null; - } else - forceOff = false; - } - - /// permissionGranted = true - /// forceOff (currently false) - void startBluetooth(BuildContext context, bool permissionGranted, - AsyncSnapshot snapshot) async { - checkForceOff(snapshot); - if (forceOff) { - advancedWayfindingEnabled = false; - notifyListeners(); - return; - } - - if (permissionGranted) { - advancedWayfindingEnabled = true; - init(); - forceOff = false; - } else { - forceOff = false; - } - notifyListeners(); - } - - // Sets up signal broadcasting with a random UUID - void startBeaconBroadcast() { - beaconSingleton = BeaconSingleton(); - beaconSingleton.init(); - advertisementValue = beaconSingleton.advertisingUUID; - } - - Future instantiateScannedObjects() async { - var savedDevices = await _storage.readAll(); - savedDevices.forEach((key, value) { - if (key == "previousState") { - } else if (key == "lastBackgroundScan") { - } else if (key == "storageTime") { - } else { - scannedObjects.update( - key, (v) => new BluetoothDeviceProfile.fromJson(jsonDecode(value)), - ifAbsent: () => - new BluetoothDeviceProfile.fromJson(jsonDecode(value))); - } - }); - _storage.deleteAll(); - } - - double deg2rad(deg) { - return deg * (math.pi / 180); - } - - void setAWPreference() { - SharedPreferences.getInstance().then((value) { - value.setBool("advancedWayfindingEnabled", advancedWayfindingEnabled); - }); - } -} - -// Helper Class -class BluetoothDeviceProfile { - String? uuid; - int? rssi; - String? deviceType; - List? timeStamps; - bool? continuousDuration; - double? distance; // Feet - int? txPowerLevel; - double? dwellTime = 0; - int? scanTimeMinutes; - bool? timeThresholdMet = false; - int? scanIntervalAllowancesUsed = 0; - - BluetoothDeviceProfile(this.uuid, this.rssi, this.deviceType, this.timeStamps, - this.continuousDuration, this.scanTimeMinutes); - - BluetoothDeviceProfile.fromJson(Map json) - : uuid = json['uuid'], - rssi = json['rssi'], - deviceType = json['deviceType'], - timeStamps = json['timeStamps'].cast(), - continuousDuration = json['continuousDuration'], - distance = json['distance'], - txPowerLevel = json['txPowerLevel'], - dwellTime = json['dwellTime'], - scanTimeMinutes = json['scanTimeMinutes'], - timeThresholdMet = json['timeThresholdMet'], - scanIntervalAllowancesUsed = json['scanIntervalAllowancesUsed']; - - Map toJson() { - return { - 'uuid': uuid, - 'rssi': rssi, - 'deviceType': deviceType, - 'timeStamps': timeStamps, - 'continuousDuration': continuousDuration, - 'distance': distance, - 'txPowerLevel': txPowerLevel, - 'dwellTime': dwellTime, - 'scanTimeMinutes': scanTimeMinutes, - 'timeThresholdMet': timeThresholdMet, - 'scanIntervalAllowancesUsed': scanIntervalAllowancesUsed - }; - } -} diff --git a/lib/core/services/wayfinding.dart b/lib/core/services/wayfinding.dart deleted file mode 100644 index 8c4da3e47..000000000 --- a/lib/core/services/wayfinding.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'dart:convert'; - -import 'package:campus_mobile_experimental/app_networking.dart'; -import 'package:campus_mobile_experimental/core/models/wayfinding_constants.dart'; - -class WayfindingService { - bool? isLoading; - NetworkHelper? networkHelper; - String? error; - WayfindingConstantsModel? wayfindingConstantsModel; - final String bluetoothServiceEndpoint = - "https://api-qa.ucsd.edu:8243/bluetoothservice/v1.0.0"; - final Map tokenHeader = { - "accept": "application/json", - }; - Map? authorizedHeader; - - WayfindingService() { - isLoading = false; - networkHelper = NetworkHelper(); - } - - Future fetchData() async { - isLoading = true; - - try { - await getNewToken(); - String deviceTypesResponse = await networkHelper!.authorizedFetch( - "$bluetoothServiceEndpoint/service_constants", tokenHeader); - String constantsResponse = await networkHelper!.authorizedFetch( - "$bluetoothServiceEndpoint/configurations", tokenHeader); - Map deviceTypesJson = json.decode(deviceTypesResponse); - Map constantsJson = json.decode(constantsResponse); - wayfindingConstantsModel = - WayfindingConstantsModel.fromJson(deviceTypesJson, constantsJson); - isLoading = false; - return true; - } catch (exception) { - error = exception.toString(); - isLoading = false; - return false; - } - } - - Future getNewToken() async { - final String tokenEndpoint = "https://api-qa.ucsd.edu:8243/token"; - final Map tokenHeaders = { - "content-type": 'application/x-www-form-urlencoded', - "Authorization": - "Basic djJlNEpYa0NJUHZ5akFWT0VRXzRqZmZUdDkwYTp2emNBZGFzZWpmaWZiUDc2VUJjNDNNVDExclVh" - }; - try { - var response = await networkHelper!.authorizedPost( - tokenEndpoint, tokenHeaders, "grant_type=client_credentials"); - - tokenHeader["Authorization"] = "Bearer " + response["access_token"]; - - return true; - } catch (e) { - return false; - } - } -} diff --git a/lib/ui/home/home.dart b/lib/ui/home/home.dart index ff3cd7241..2b2b544d2 100644 --- a/lib/ui/home/home.dart +++ b/lib/ui/home/home.dart @@ -9,7 +9,6 @@ import 'package:campus_mobile_experimental/core/providers/cards.dart'; import 'package:campus_mobile_experimental/core/providers/connectivity.dart'; import 'package:campus_mobile_experimental/core/providers/map.dart'; import 'package:campus_mobile_experimental/core/providers/notices.dart'; -import 'package:campus_mobile_experimental/core/providers/wayfinding.dart'; import 'package:campus_mobile_experimental/main.dart'; import 'package:campus_mobile_experimental/ui/availability/availability_card.dart'; import 'package:campus_mobile_experimental/ui/classes/classes_card.dart'; @@ -32,7 +31,6 @@ import 'package:campus_mobile_experimental/ui/wifi/wifi_card.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:uni_links2/uni_links.dart'; class Home extends StatefulWidget { @@ -87,7 +85,6 @@ class _HomeState extends State { @override Widget build(BuildContext context) { initUniLinks(context); - checkToResumeBluetooth(context); _connectivityProvider = Provider.of(context); return Padding( padding: EdgeInsets.symmetric(horizontal: cardMargin, vertical: 0.0), @@ -182,18 +179,4 @@ class _HomeState extends State { } return orderedCards; } - - void checkToResumeBluetooth(BuildContext context) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - bool? preference = prefs.getBool("advancedWayfindingEnabled"); - - if (prefs.containsKey("advancedWayfindingEnabled") && preference == true) { - WayfindingProvider bluetoothSingleton = - Provider.of(context, listen: false); - bluetoothSingleton.advancedWayfindingEnabled = true; - if (bluetoothSingleton.ongoingScanner == null) { - bluetoothSingleton.init(); - } - } - } } diff --git a/lib/ui/profile/profile.dart b/lib/ui/profile/profile.dart index e747344e4..f520736ed 100644 --- a/lib/ui/profile/profile.dart +++ b/lib/ui/profile/profile.dart @@ -73,27 +73,6 @@ class Profile extends StatelessWidget { onTap: handlePrivacyTap, ), ), - Card( - child: ListTile( - leading: Icon(Icons.wifi_tethering), - title: Text('Advanced Wayfinding'), - onTap: () { - Navigator.pushNamed( - context, RoutePaths.BluetoothPermissionsView); - }, - ), - ), - //TODO: Reinstate to view AW developer view in debug mode - // if(!kReleaseMode) Card( - // child: ListTile( - // leading: Icon(Icons.settings_bluetooth), - // title: Text('Advanced Wayfinding Developer View'), - // onTap: () { - // Navigator.pushNamed( - // context, RoutePaths.AutomaticBluetoothLoggerView); - // }, - // ), - // ), BuildInfo(), ], ), diff --git a/lib/ui/wayfinding/beacon_view.dart b/lib/ui/wayfinding/beacon_view.dart deleted file mode 100644 index 1252576dc..000000000 --- a/lib/ui/wayfinding/beacon_view.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:beacon_broadcast/beacon_broadcast.dart'; -import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:uuid/uuid.dart'; - -class BeaconView extends StatefulWidget { - @override - _BeaconViewState createState() => _BeaconViewState(); -} - -class _BeaconViewState extends State { - var _isTransmissionSupported; - var _isAdvertising = false; - late var _isAdvertisingSubscription; - late BeaconBroadcast beaconBroadcast; - var beaconUuid = 'null'; - - @override - void initState() { - super.initState(); - - checkTime(); - beaconBroadcast = BeaconBroadcast(); - beaconBroadcast - .checkTransmissionSupported() - .then((isTransmissionSupported) { - setState(() { - _isTransmissionSupported = isTransmissionSupported; - }); - }); - - _isAdvertisingSubscription = - beaconBroadcast.getAdvertisingStateChange().listen((isAdvertising) { - setState(() { - _isAdvertising = isAdvertising; - }); - }); - } - - @override - void dispose() async { - super.dispose(); - - SharedPreferences prefs = await SharedPreferences.getInstance(); - prefs.setString('uuid', beaconUuid); - _isAdvertisingSubscription.cancel(); - beaconBroadcast.stop(); - } - - void checkTime() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - beaconUuid = prefs.get('uuid') as String? ?? "null"; - var previousTime = prefs.get('previousTime') ?? DateTime(1990).toString(); - var difference = DateTime.now() - .difference(DateTime.parse(previousTime as String)) - .inSeconds; - if (difference > 10) { - changeUUID(); - prefs.setString('previousTime', DateTime.now().toString()); - } - } - - void _startBroadcast() { - if (_isAdvertising) return null; - - beaconBroadcast - .setUUID(beaconUuid) - .setMajorId(1) - .setMinorId(100) - .setIdentifier('com.example.myDevice') - .setLayout(BeaconBroadcast.ALTBEACON_LAYOUT) - .start(); - } - - void _stopBroadcast() => beaconBroadcast.stop(); - - void changeUUID() { - beaconUuid = Uuid().v4(); - beaconUuid = "00000000" + beaconUuid.substring(8); - setState(() {}); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("Bluetooth Beacon Broadcasting"), - ), - body: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: _startBroadcast, - child: Text( - "Start Broadcasting", - style: TextStyle(color: Colors.white), - ), - ), - ElevatedButton( - onPressed: _stopBroadcast, - child: Text( - "Stop Broadcasting", - style: TextStyle(color: Colors.white), - ), - ), - ], - ), - Text("Is transmission supported?"), - Text("$_isTransmissionSupported"), - Text("Is beacon broadcasting?"), - Text("$_isAdvertising"), - Text("Broadcasting UUID"), - Text(beaconUuid), - ], - ), - ); - } -} diff --git a/lib/ui/wayfinding/bluetooth_logger.dart b/lib/ui/wayfinding/bluetooth_logger.dart deleted file mode 100644 index 228eda5aa..000000000 --- a/lib/ui/wayfinding/bluetooth_logger.dart +++ /dev/null @@ -1,195 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:campus_mobile_experimental/core/providers/wayfinding.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_blue/flutter_blue.dart'; -import 'package:location_platform_interface/location_platform_interface.dart'; -import 'package:provider/provider.dart'; - -import '../../app_styles.dart'; - -class AutomaticBluetoothLoggerView extends StatefulWidget { - // Instantiate bluetooth singleton - - @override - State createState() => _AutomaticBluetoothLoggerViewState(); -} - -class _AutomaticBluetoothLoggerViewState - extends State { - WayfindingProvider _wayfindingProvider = WayfindingProvider(); - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _wayfindingProvider = Provider.of(context); - } - - // List for rendering the ongoing log - List loggedItems = []; - - _AutomaticBluetoothLoggerViewState(); - - // // Set the state when a new scan occurs - // void initState() { - // bluetoothSingleton = widget.bluetoothSingleton; - // super.initState(); - // if (bluetoothSingleton.loggedItems.length > 0) { - // Timer.periodic(Duration(seconds: 3), (timer) { - // setState(() { - // loggedItems = bluetoothSingleton.loggedItems; - // build(context); - // }); - // }); - // } - // subscription = bluetoothSingleton.flutterBlueInstance.scanResults - // .listen((event) async { - // setState(() { - // loggedItems = bluetoothSingleton.loggedItems; - // }); - // }); - // } - - // build Card container to hold log display - @override - Widget build(BuildContext context) { - _wayfindingProvider = Provider.of(context); - - // //Start dynamic resizing - // MediaQueryData queryData = MediaQuery.of(context); - // double verticalSafeBlock = (queryData.size.height - - // (queryData.padding.top + queryData.padding.bottom)) / - // 100; - // double cardHeight = verticalSafeBlock * 85; - - return Scaffold( - appBar: AppBar( - title: Text("AW Developer View"), - ), - body: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - statusCard(), - Padding( - padding: const EdgeInsets.all(8.0), - child: Card( - child: Container( - height: cardContentMaxHeight, - child: ListView.builder( - itemCount: _wayfindingProvider.processedDevices.length, - shrinkWrap: true, - itemBuilder: (context, index) { - return buildText(index); - }), - ), - ), - ) - ], - ), - ), - ); - } - - // // Return normal text for device display - // return Text(loggedItems[index]); - - Card statusCard() { - return Card( - color: _wayfindingProvider.ongoingScanner != null - ? Colors.green - : Colors.red, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Column( - children: [ - _wayfindingProvider.ongoingScanner == null - ? Text( - "Not scanning...", - style: Theme.of(context).textTheme.headline5, - ) - : Text( - "Scanning...", - style: Theme.of(context).textTheme.headline5, - ), - FutureBuilder( - future: checkPermissions(), - builder: - (BuildContext context, AsyncSnapshot snapshot) { - return snapshot.hasData - ? snapshot.data as Widget - : LinearProgressIndicator(); - }), - ], - ), - ), - ), - ); - } - - Future checkPermissions() async { - BluetoothState bluetoothStatus = - await _wayfindingProvider.flutterBlueInstance.state.first; - PermissionStatus locationStatus = - await _wayfindingProvider.checkLocationPermission(); - bool locationService = await _wayfindingProvider.checkLocationService(); - - return Text( - "OS: ${Platform.isIOS ? "iOS" : "Android"} \nLocation: ${locationStatus.toString()} \nService enabled: $locationService \nBluetooth: ${bluetoothStatus.toString()} \nAW Enabled: ${_wayfindingProvider.advancedWayfindingEnabled} \nForce off: ${_wayfindingProvider.forceOff}"); - } - - // // Bold location and timestamp to differentiate scans - Text buildText(int index) { - if (_wayfindingProvider.processedDevices[index] - .toString() - .contains("LATITUDE") || - _wayfindingProvider.processedDevices[index] - .toString() - .contains("TIMESTAMP")) { - return Text( - _wayfindingProvider.processedDevices[index], - style: TextStyle(fontWeight: FontWeight.bold), - ); - } - return Text(_wayfindingProvider.processedDevices[index].toString() + '\n'); - } -} - -// -// // Detach the listener to avoid calling setState() -// @override -// void dispose() { -// subscription.cancel(); -// super.dispose(); -// } -// } -// Row( -// children: [ -// Expanded( -// child: Column( -// mainAxisAlignment: MainAxisAlignment.center, -// children: [ -// Text( -// "Devices Scanned", -// style: -// TextStyle(fontSize: 18, fontWeight: FontWeight.bold), -// ), -// Card( -// child: Container( -// height: cardHeight, -// child: ListView.builder( -// itemCount: loggedItems.length, -// shrinkWrap: true, -// itemBuilder: (context, index) { -// return buildText(index); -// }), -// ), -// ), -// ], -// ), -// ), -// ], -// ), diff --git a/lib/ui/wayfinding/wayfinding_permissions.dart b/lib/ui/wayfinding/wayfinding_permissions.dart deleted file mode 100644 index 7a8d336a1..000000000 --- a/lib/ui/wayfinding/wayfinding_permissions.dart +++ /dev/null @@ -1,417 +0,0 @@ -import 'dart:io'; - -import 'package:app_settings/app_settings.dart'; -import 'package:campus_mobile_experimental/app_styles.dart'; -import 'package:campus_mobile_experimental/core/providers/wayfinding.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_blue/flutter_blue.dart'; -import 'package:location/location.dart'; -import 'package:provider/provider.dart'; - -class AdvancedWayfindingPermission extends StatefulWidget { - @override - _AdvancedWayfindingPermissionState createState() => - _AdvancedWayfindingPermissionState(); -} - -class _AdvancedWayfindingPermissionState - extends State { - late WayfindingProvider _wayfindingProvider; - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _wayfindingProvider = Provider.of(context); - } - - @override - Widget build(BuildContext context) { - _wayfindingProvider = Provider.of(context); - return Scaffold( - appBar: PreferredSize( - preferredSize: Size.fromHeight(42), - child: AppBar( - backgroundColor: ColorPrimary, - brightness: Brightness.dark, - primary: true, - centerTitle: true, - title: Text("Advanced Wayfinding"), - ), - ), - body: buildBody(context), - ); - } - - Widget buildBody(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - toggleSwitch(context), - Container( - padding: const EdgeInsets.all(16.0), - child: Text("Advanced wayfinding benefits", - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - textAlign: TextAlign.left)), - Container( - padding: const EdgeInsets.only(left: 16, top: 4, right: 16), - child: Text( - "\u2022 Getting directions\n\n\u2022 Locate areas of interest on campus\n\n\u2022 Context aware communication with other Bluetooth devices", - style: TextStyle(fontSize: 17))) - ]); - } - - Widget toggleSwitch(BuildContext context) { - return Row( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - "Enable advanced wayfinding", - style: TextStyle(fontSize: 17), - ), - ), - Spacer(), - StreamBuilder( - stream: FlutterBlue.instance.state, - builder: (context, streamSnapshot) { - return streamSnapshot.hasData - ? FutureBuilder( - future: checkStatuses(_wayfindingProvider - .locationDataProvider.locationObject), - builder: (context, futureSnapshot) { - if (futureSnapshot.hasData) { - return Switch( - value: _wayfindingProvider.permissionState( - context, streamSnapshot), - onChanged: (permissionGranted) { - _wayfindingProvider.startBluetooth( - context, permissionGranted, streamSnapshot); - if (_wayfindingProvider.forceOff) { - if (streamSnapshot.data as BluetoothState == - BluetoothState.unauthorized || - streamSnapshot.data as BluetoothState == - BluetoothState.off) { - if (((futureSnapshot.data! as List)[1] != - PermissionStatus.granted) || - !(futureSnapshot.data! as List)[0]) { - bluetoothAndLocationMessage(); - } else - bluetoothMessage(); - } else { - if ((futureSnapshot.data! as List)[1] != - PermissionStatus.granted) { - locationPermissionMessage(); - } - if (!(futureSnapshot.data! as List)[0]) { - devicelocationMessage(); - } - } - } - setState(() { - if (_wayfindingProvider.forceOff) { - _wayfindingProvider - .advancedWayfindingEnabled = false; - } else { - _wayfindingProvider - .advancedWayfindingEnabled = - !_wayfindingProvider - .advancedWayfindingEnabled; - } - - if (!_wayfindingProvider - .advancedWayfindingEnabled) { - _wayfindingProvider.stopScans(); - } - _wayfindingProvider.setAWPreference(); - }); - }, - activeColor: Theme.of(context).buttonColor, - ); - } else { - return CircularProgressIndicator( - color: Theme.of(context).colorScheme.secondary); - } - }) - : CircularProgressIndicator( - color: Theme.of(context).colorScheme.secondary); - }) - ], - ); - } - - Future checkStatuses(Location locationObject) async { - return Future.wait( - [locationObject.serviceEnabled(), locationObject.hasPermission()]); - } - - void bluetoothAndLocationMessage() { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - if (Platform.isIOS) { - return CupertinoAlertDialog( - title: - Text("UCSD Mobile would like to use Bluetooth and location."), - content: Text( - "This feature uses Bluetooth and location to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - } - return AlertDialog( - title: - Text("UCSD Mobile would like to use Bluetooth and location."), - content: Text( - "This feature uses Bluetooth and location to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - }); - } - - void bluetoothMessage() { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - if (Platform.isIOS) { - return CupertinoAlertDialog( - title: Text("UCSD Mobile would like to use Bluetooth."), - content: Text( - "This feature uses Bluetooth to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - } - return AlertDialog( - title: Text("UCSD Mobile would like to use Bluetooth"), - content: Text( - "This feature uses Bluetooth to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - }); - } - - void locationPermissionMessage() { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - if (Platform.isIOS) { - return CupertinoAlertDialog( - title: Text("UCSD Mobile would like to use location."), - content: Text( - "This feature use location to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - } - return AlertDialog( - title: Text("UCSD Mobile would like to use location."), - content: Text( - "This feature use location to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - }); - } - - void devicelocationMessage() { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - if (Platform.isIOS) { - return CupertinoAlertDialog( - title: - Text("UCSD Mobile would like to use Bluetooth and location."), - content: Text( - "This feature uses Bluetooth and location to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - } - return AlertDialog( - title: Text("UCSD Mobile would like to use device location."), - content: Text( - "This feature uses device location to connect with other devices."), - actions: [ - TextButton( - child: Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: Text('Settings'), - onPressed: () { - AppSettings.openAppSettings(); - }, - ) - ], - ); - }); - } -} - -// return snapshot.hasData -// ? Switch( -// value: _wayfindingProvider.permissionState( -// context, snapshot), -// onChanged: (permissionGranted) { -// _wayfindingProvider.startBluetooth( -// context, permissionGranted); -// if (_wayfindingProvider.forceOff) { -// showDialog( -// context: context, -// barrierDismissible: false, -// builder: (BuildContext context) { -// if (Platform.isIOS) { -// return CupertinoAlertDialog( -// title: Text( -// "UCSD Mobile would like to use Bluetooth and location."), -// content: Text( -// "This feature use Bluetooth and location to connect with other devices."), -// actions: [ -// TextButton( -// child: Text('Cancel'), -// onPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// TextButton( -// child: Text('Settings'), -// onPressed: () { -// AppSettings.openAppSettings(); -// }, -// ) -// ], -// ); -// } -// return AlertDialog( -// title: Text( -// "UCSD Mobile would like to use Bluetooth and location."), -// content: Text( -// "This feature use Bluetooth and location to connect with other devices."), -// actions: [ -// TextButton( -// child: Text('Cancel'), -// onPressed: () { -// Navigator.of(context).pop(); -// }, -// ), -// TextButton( -// child: Text('Settings'), -// onPressed: () { -// AppSettings.openAppSettings(); -// }, -// ) -// ], -// ); -// }); -// } -// setState(() { -// if (_wayfindingProvider.forceOff) { -// _wayfindingProvider.advancedWayfindingEnabled = -// false; -// } else { -// _wayfindingProvider.advancedWayfindingEnabled = -// !_wayfindingProvider.advancedWayfindingEnabled; -// } -// -// if (!_wayfindingProvider.advancedWayfindingEnabled) { -// _wayfindingProvider.stopScans(); -// } -// _wayfindingProvider.setAWPreference(); -// }); -// }, -// activeColor: Theme.of(context).buttonColor, -// ) -// : CircularProgressIndicator(); diff --git a/pubspec.lock b/pubspec.lock index 128f4b196..646d519e4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,13 +57,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" - beacon_broadcast: - dependency: "direct main" - description: - name: beacon_broadcast - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" boolean_selector: dependency: transitive description: @@ -377,15 +370,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_blue: - dependency: "direct main" - description: - path: "." - ref: "470b128cd463373d0ec4b668d5b4f449dc728d72" - resolved-ref: "470b128cd463373d0ec4b668d5b4f449dc728d72" - url: "https://github.com/UCSD/flutter_blue.git" - source: git - version: "0.8.0" flutter_linkify: dependency: "direct main" description: @@ -806,13 +790,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.4" - protobuf: - dependency: transitive - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" provider: dependency: "direct main" description: @@ -841,13 +818,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" - rxdart: - dependency: transitive - description: - name: rxdart - url: "https://pub.dartlang.org" - source: hosted - version: "0.26.0" shared_preferences: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index d60c0a836..14fb568eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,7 +7,6 @@ environment: dependencies: app_settings: 4.1.0 barcode_widget: 2.0.1 - beacon_broadcast: 0.3.0 connectivity: 3.0.6 device_info: 2.0.2 dio: 4.0.0 @@ -23,10 +22,6 @@ dependencies: git: url: https://github.com/UCSD/flutter_scandit.git ref: 41fb666299ed90d8277c24e0065149e83cd71494 - flutter_blue: - git: - url: https://github.com/UCSD/flutter_blue.git - ref: 470b128cd463373d0ec4b668d5b4f449dc728d72 flutter_linkify: 5.0.2 flutter_local_notifications: 8.2.0 flutter_secure_storage: 5.0.2