From bdc33c218e3e62e5a3121d3ab0de6e26ef7ad3eb Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Tue, 24 Sep 2024 16:10:43 -0400 Subject: Fix storage API and databroker interaction on start up Changes: - The persisted values read in by the forced early init of the storage API were getting overridden by the defaults coming from the databroker in the case of preferences that map directly to VSS signals. Refactor the preference updating code to move the VSS updating calls to reusable functions in ValClient, and then use those to update the VSS signal values right after connecting to the databroker. - Remove the recursive initialization call from UnitsNotifier's loadSettingsUnits function, as in my testing it broke start up, and the recursion seems incorrect. There are definitely issues with racing with the storage API daemon, and the homescreen completely hangs if it is not running. The fix for that is to switch to a more Flutter typical asynchronous initialization of the storage API connection, and future rework will be in that direction. - Change various prints in the storage API code to debugPrint to start trying to clean up complaints from "flutter analyze". Bug-AGL: SPEC-5250 Change-Id: I6dc9a45569453254d1565038048305f94d121db6 Signed-off-by: Scott Murray --- lib/data/data_providers/units_notifier.dart | 83 ++++++++---------- lib/data/data_providers/users_notifier.dart | 127 ++++++++++++++++------------ lib/data/data_providers/val_client.dart | 28 ++++++ 3 files changed, 136 insertions(+), 102 deletions(-) (limited to 'lib') diff --git a/lib/data/data_providers/units_notifier.dart b/lib/data/data_providers/units_notifier.dart index daf9c92..9f4a1ac 100644 --- a/lib/data/data_providers/units_notifier.dart +++ b/lib/data/data_providers/units_notifier.dart @@ -11,21 +11,21 @@ class UnitsNotifier extends Notifier { } // Load Units state of the selected user from the storage API. - Future loadSettingsUnits() async { + Future loadSettingsUnits() async { final storageClient = ref.read(storageClientProvider); final userClient = ref.read(usersProvider); - - try { - await initializeSettingsUser(ref); - } catch (e) { - print('Error loading settings of user: $e'); - } - + try { // Read unit values from the selected user namespace. - final distanceResponse = await storageClient.read(storage_api.Key(key: VSSPath.vehicleHmiDistanceUnit, namespace: userClient.selectedUser.id)); - final temperatureResponse = await storageClient.read(storage_api.Key(key: VSSPath.vehicleHmiTemperatureUnit, namespace: userClient.selectedUser.id)); - final pressureResponse = await storageClient.read(storage_api.Key(key: VSSPath.vehicleHmiPressureUnit, namespace: userClient.selectedUser.id)); + final distanceResponse = await storageClient.read(storage_api.Key( + key: VSSPath.vehicleHmiDistanceUnit, + namespace: userClient.selectedUser.id)); + final temperatureResponse = await storageClient.read(storage_api.Key( + key: VSSPath.vehicleHmiTemperatureUnit, + namespace: userClient.selectedUser.id)); + final pressureResponse = await storageClient.read(storage_api.Key( + key: VSSPath.vehicleHmiPressureUnit, + namespace: userClient.selectedUser.id)); // Prepare state declaration and fall back to default values if the key is not present in the storage API. final distanceUnit = distanceResponse.result == 'MILES' @@ -40,10 +40,10 @@ class UnitsNotifier extends Notifier { ? PressureUnit.psi : PressureUnit.kilopascals; - state = Units(distanceUnit, temperatureUnit, pressureUnit); + state = Units(distanceUnit, temperatureUnit, pressureUnit); } catch (e) { // Fallback to initial defaults if error occurs. - print('Error loading settings for units: $e'); + debugPrint('Error loading settings for units: $e'); state = const Units.initial(); } } @@ -81,69 +81,60 @@ class UnitsNotifier extends Notifier { return handled; } - Future setDistanceUnit(DistanceUnit unit) async { + Future setDistanceUnit(DistanceUnit unit) async { state = state.copyWith(distanceUnit: unit); + var valClient = ref.read(valClientProvider); - valClient.setString( - VSSPath.vehicleHmiDistanceUnit, - unit == DistanceUnit.kilometers ? "KILOMETERS" : "MILES", - true, - ); + valClient.setDistanceUnit(unit); + // Write to storage API (to selected user namespace). var storageClient = ref.read(storageClientProvider); final userClient = ref.read(usersProvider); try { await storageClient.write(storage_api.KeyValue( - key: VSSPath.vehicleHmiDistanceUnit, - value: unit == DistanceUnit.kilometers ? 'KILOMETERS' : 'MILES', - namespace: userClient.selectedUser.id - )); + key: VSSPath.vehicleHmiDistanceUnit, + value: unit == DistanceUnit.kilometers ? 'KILOMETERS' : 'MILES', + namespace: userClient.selectedUser.id)); } catch (e) { - print('Error saving distance unit: $e'); + debugPrint('Error saving distance unit: $e'); } } - Future setTemperatureUnit(TemperatureUnit unit) async { + Future setTemperatureUnit(TemperatureUnit unit) async { state = state.copyWith(temperatureUnit: unit); + var valClient = ref.read(valClientProvider); - valClient.setString( - VSSPath.vehicleHmiTemperatureUnit, - unit == TemperatureUnit.celsius ? "C" : "F", - true, - ); + valClient.setTemperatureUnit(unit); + // Write to storage API (to selected user namespace). var storageClient = ref.read(storageClientProvider); final userClient = ref.read(usersProvider); try { await storageClient.write(storage_api.KeyValue( - key: VSSPath.vehicleHmiTemperatureUnit, - value: unit == TemperatureUnit.celsius ? "C" : "F", - namespace: userClient.selectedUser.id - )); + key: VSSPath.vehicleHmiTemperatureUnit, + value: unit == TemperatureUnit.celsius ? "C" : "F", + namespace: userClient.selectedUser.id)); } catch (e) { - print('Error saving distance unit: $e'); + debugPrint('Error saving distance unit: $e'); } } - Future setPressureUnit(PressureUnit unit) async { + Future setPressureUnit(PressureUnit unit) async { state = state.copyWith(pressureUnit: unit); + var valClient = ref.read(valClientProvider); - valClient.setString( - VSSPath.vehicleHmiPressureUnit, - unit == PressureUnit.kilopascals ? "KPA" : "PSI", - true, - ); + valClient.setPressureUnit(unit); + // Write to storage API (to selected user namespace). var storageClient = ref.read(storageClientProvider); final userClient = ref.read(usersProvider); try { await storageClient.write(storage_api.KeyValue( - key: VSSPath.vehicleHmiPressureUnit, - value: unit == PressureUnit.kilopascals ? "KPA" : "PSI", - namespace: userClient.selectedUser.id - )); + key: VSSPath.vehicleHmiPressureUnit, + value: unit == PressureUnit.kilopascals ? "KPA" : "PSI", + namespace: userClient.selectedUser.id)); } catch (e) { - print('Error saving distance unit: $e'); + debugPrint('Error saving pressure unit: $e'); } } } diff --git a/lib/data/data_providers/users_notifier.dart b/lib/data/data_providers/users_notifier.dart index c2755f6..a4e056c 100644 --- a/lib/data/data_providers/users_notifier.dart +++ b/lib/data/data_providers/users_notifier.dart @@ -9,6 +9,12 @@ import 'initialize_settings.dart'; class UsersNotifier extends Notifier { @override + final List _users = [ + const User(id: '1', name: 'Heather'), + const User(id: '2', name: 'George'), + const User(id: '3', name: 'Riley'), + ]; + Users build() { // Initialize default state. state = Users.initial(); @@ -16,52 +22,70 @@ class UsersNotifier extends Notifier { return state; } - Future loadSettingsUsers() async { + Future loadSettingsUsers() async { final storageClient = ref.read(storageClientProvider); try { // Access users branch. - final searchResponseUsers = await storageClient.search(storage_api.Key(key: UsersPath.InfotainmentUsers)); - // Add default users if no users are inside the storage API. + final searchResponseUsers = await storageClient + .search(storage_api.Key(key: UsersPath.InfotainmentUsers)); if (searchResponseUsers.result.isEmpty) { + // Add default users if no users are inside the storage API. + debugPrint("Adding default demo user profiles"); loadUsers(); - await storageClient.write(storage_api.KeyValue(key: '${UsersPath.InfotainmentUsers}.${_users[0].id}.id', value: _users[0].id)); - await storageClient.write(storage_api.KeyValue(key: '${UsersPath.InfotainmentUsers}.${_users[0].id}.name', value: _users[0].name)); - await storageClient.write(storage_api.KeyValue(key: '${UsersPath.InfotainmentUsers}.${_users[1].id}.id', value: _users[1].id)); - await storageClient.write(storage_api.KeyValue(key: '${UsersPath.InfotainmentUsers}.${_users[1].id}.name', value: _users[1].name)); - await storageClient.write(storage_api.KeyValue(key: '${UsersPath.InfotainmentUsers}.${_users[2].id}.id', value: _users[2].id)); - await storageClient.write(storage_api.KeyValue(key: '${UsersPath.InfotainmentUsers}.${_users[2].id}.name', value: _users[2].name)); + await storageClient.write(storage_api.KeyValue( + key: '${UsersPath.InfotainmentUsers}.${_users[0].id}.id', + value: _users[0].id)); + await storageClient.write(storage_api.KeyValue( + key: '${UsersPath.InfotainmentUsers}.${_users[0].id}.name', + value: _users[0].name)); + await storageClient.write(storage_api.KeyValue( + key: '${UsersPath.InfotainmentUsers}.${_users[1].id}.id', + value: _users[1].id)); + await storageClient.write(storage_api.KeyValue( + key: '${UsersPath.InfotainmentUsers}.${_users[1].id}.name', + value: _users[1].name)); + await storageClient.write(storage_api.KeyValue( + key: '${UsersPath.InfotainmentUsers}.${_users[2].id}.id', + value: _users[2].id)); + await storageClient.write(storage_api.KeyValue( + key: '${UsersPath.InfotainmentUsers}.${_users[2].id}.name', + value: _users[2].name)); await selectUser(_users[0].id); - } - else { + } else { List users = []; List idList = []; // Get list of all ids. for (var key in searchResponseUsers.result) { - var readResponse = await storageClient.read(storage_api.Key(key: key)); + var readResponse = + await storageClient.read(storage_api.Key(key: key)); if (key.contains('.id')) { idList.insert(0, readResponse.result); } } // Extract names corresponding to ids. for (var id in idList) { - var readResponse = await storageClient.read(storage_api.Key(key:'${UsersPath.InfotainmentUsers}.$id.name')); + var readResponse = await storageClient.read( + storage_api.Key(key: '${UsersPath.InfotainmentUsers}.$id.name')); users.insert(0, User(id: id, name: readResponse.result)); } // Extract id of selected user. - final readResponseSelectedUser = await storageClient.read(storage_api.Key(key: UsersPath.InfotainmentCurrentUser)); + final readResponseSelectedUser = await storageClient + .read(storage_api.Key(key: UsersPath.InfotainmentCurrentUser)); User selectedUser; final userCurrentId = readResponseSelectedUser.result; // Extract name of selected user. - final readResponseCurrentUserName = await storageClient.read(storage_api.Key(key: '${UsersPath.InfotainmentUsers}.$userCurrentId.name')); + final readResponseCurrentUserName = await storageClient.read( + storage_api.Key( + key: '${UsersPath.InfotainmentUsers}.$userCurrentId.name')); final userCurrentName = readResponseCurrentUserName.result; selectedUser = User(id: userCurrentId, name: userCurrentName); - state = Users(users: users, selectedUser: selectedUser); + state = Users(users: users, selectedUser: selectedUser); } } catch (e) { - // Fallback to initial defaults if error. - print('Error loading settings for units: $e'); - loadUsers(); - state = state.copyWith(selectedUser: _users[0]); + // Fallback to initial defaults if error. + debugPrint('Error loading users: $e'); + loadUsers(); + state = state.copyWith(selectedUser: _users[0]); } } @@ -69,16 +93,10 @@ class UsersNotifier extends Notifier { state = state.copyWith(users: _users); } - final List _users = [ - const User(id: '1', name: 'Heather'), - const User(id: '2', name: 'George'), - const User(id: '3', name: 'Riley'), - ]; - - Future selectUser(String userId) async { + Future selectUser(String userId) async { final storageClient = ref.read(storageClientProvider); - var seletedUser = state.users.firstWhere((user) => user.id == userId); - state = state.copyWith(selectedUser: seletedUser); + var selectedUser = state.users.firstWhere((user) => user.id == userId); + state = state.copyWith(selectedUser: selectedUser); // Write to storage API. try { await storageClient.write(storage_api.KeyValue( @@ -86,68 +104,65 @@ class UsersNotifier extends Notifier { value: userId, )); } catch (e) { - print('Error saving user: $e'); + debugPrint('Error selecting user: $e'); } - + try { await initializeSettingsUser(ref); } catch (e) { - print('Error loading settings of user: $e'); + debugPrint('Error loading settings of user: $e'); } - } - Future removeUser(String userId) async { + Future removeUser(String userId) async { final storageClient = ref.read(storageClientProvider); var currentUserId = state.selectedUser.id; state.users.removeWhere((user) => user.id == userId); if (state.users.isNotEmpty && currentUserId == userId) { state = state.copyWith(selectedUser: state.users.first); - //Write to API to change selected user. - await storageClient.write(storage_api.KeyValue(key: UsersPath.InfotainmentCurrentUser, value: state.users.first.id)); + // Write to API to change selected user. + await storageClient.write(storage_api.KeyValue( + key: UsersPath.InfotainmentCurrentUser, value: state.users.first.id)); } if (state.users.isEmpty) { state = state.copyWith(selectedUser: const User(id: '0', name: '')); - //Write to API to change selected user. - await storageClient.write(storage_api.KeyValue(key: UsersPath.InfotainmentCurrentUser, value: '0')); + // Write to API to change selected user. + await storageClient.write(storage_api.KeyValue( + key: UsersPath.InfotainmentCurrentUser, value: '0')); } // Delete from storage API. try { - final searchResponse = await storageClient.search(storage_api.Key(key: userId)); + final searchResponse = + await storageClient.search(storage_api.Key(key: userId)); final keyList = searchResponse.result; - //Delete id, name entries of the user from the default namespace. + // Delete id, name entries of the user from the default namespace. for (final key in keyList) { - await storageClient.delete(storage_api.Key( - key: key - )); + await storageClient.delete(storage_api.Key(key: key)); } - //Delete all VSS keys from the user namespace. - await storageClient.deleteNodes(storage_api.Key(key: "Vehicle", namespace: userId)); + // Delete all VSS keys from the user namespace. + await storageClient + .deleteNodes(storage_api.Key(key: "Vehicle", namespace: userId)); } catch (e) { - print('Error removing user with id $userId: $e'); + debugPrint('Error removing user with id $userId: $e'); } } - Future addUser(String userName) async { + Future addUser(String userName) async { final storageClient = ref.read(storageClientProvider); final id = const Uuid().v1(); final user = User(id: id, name: userName); state.users.insert(0, user); - // New user is automaticaly selected. - await selectUser(user.id); + // New user is automatically selected. + await selectUser(user.id); // Write to storage API. try { await storageClient.write(storage_api.KeyValue( - key: '${UsersPath.InfotainmentUsers}.$id.name', - value: userName - )); + key: '${UsersPath.InfotainmentUsers}.$id.name', value: userName)); await storageClient.write(storage_api.KeyValue( - key: '${UsersPath.InfotainmentUsers}.$id.id', - value: id - )); + key: '${UsersPath.InfotainmentUsers}.$id.id', value: id)); } catch (e) { - print('Error adding user with id $id: $e'); + debugPrint('Error adding user with id $id: $e'); } } diff --git a/lib/data/data_providers/val_client.dart b/lib/data/data_providers/val_client.dart index 173dbfb..8436012 100644 --- a/lib/data/data_providers/val_client.dart +++ b/lib/data/data_providers/val_client.dart @@ -35,6 +35,13 @@ class ValClient { metadata = {'authorization': "Bearer ${config.authorization}"}; } + // Push out persisted user preferences so databroker defaults + // will not overwrite them. + var units = ref.read(unitStateProvider); + setDistanceUnit(units.distanceUnit); + setTemperatureUnit(units.temperatureUnit); + setPressureUnit(units.pressureUnit); + // Initialize signal states for (int i = 0; i < signals.length; i++) { get(signals[i]); @@ -145,4 +152,25 @@ class ValClient { handleSignalUpdate(entry); } } + + void setDistanceUnit(DistanceUnit unit) async { + setString(VSSPath.vehicleHmiDistanceUnit, + unit == DistanceUnit.kilometers ? "KILOMETERS" : "MILES", + true, + ); + } + + void setTemperatureUnit(TemperatureUnit unit) async { + setString(VSSPath.vehicleHmiTemperatureUnit, + unit == TemperatureUnit.celsius ? "C" : "F", + true, + ); + } + + void setPressureUnit(PressureUnit unit) async { + setString(VSSPath.vehicleHmiPressureUnit, + unit == PressureUnit.kilopascals ? "KPA" : "PSI", + true, + ); + } } -- cgit 1.2.3-korg