Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeBuds Pro 1 Gen Compat #15

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![resolved Github issues](https://img.shields.io/github/issues-closed/TheLastGimbus/FreeBuddy?label=resolved%20issues)](https://github.com/TheLastGimbus/FreeBuddy/issues)
[![commit activity](https://img.shields.io/github/commit-activity/y/TheLastGimbus/FreeBuddy)](https://github.com/TheLastGimbus/FreeBuddy/graphs/contributors)

Free and open source app for Huawei Freebuds 4i headphones 🎧
Free and open source app for Huawei Freebuds 4i/ FreeBudsPro headphones 🎧

## Why 🧐

Expand Down
Binary file added assets/app_icons/freebuds_pro_one.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dump.rdb
Binary file not shown.
1 change: 1 addition & 0 deletions ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
1 change: 1 addition & 0 deletions ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
44 changes: 44 additions & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}

def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end

File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
use_frameworks!
use_modular_headers!

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
6 changes: 3 additions & 3 deletions lib/headphones/cubit/headphones_connection_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class HeadphonesConnectionCubit extends Cubit<HeadphonesConnectionState> {
}
if (_connection != null) return; // already connected and working, skip
final otter = devices
.firstWhereOrNull((d) => OtterConst.btDevNameRegex.hasMatch(d.name));
.firstWhereOrNull((d) => OtterConst.btDevNameRegex.any((regex) => regex.hasMatch(d.name)));
if (otter == null) {
emit(HeadphonesNotPaired());
return;
Expand Down Expand Up @@ -106,8 +106,8 @@ class HeadphonesConnectionCubit extends Cubit<HeadphonesConnectionState> {
if (!_btEnabledCache) return;
emit(
((await _bluetooth.pairedDevices)
.firstWhereOrNull(
(d) => OtterConst.btDevNameRegex.hasMatch(d.name))
.firstWhereOrNull(
(d) => OtterConst.btDevNameRegex.any((regex) => regex.hasMatch(d.name)))
?.isConnected ??
false)
? HeadphonesConnectedClosed()
Expand Down
2 changes: 1 addition & 1 deletion lib/headphones/headphones_mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class HeadphonesMockPrettyFake extends HeadphonesBase {
}

@override
String? get alias => "Freebuds 4i😺";
String? get alias => "Freebuds😺";

@override
ValueStream<HeadphonesBatteryData> get batteryData => _batteryData.stream;
Expand Down
3 changes: 3 additions & 0 deletions lib/headphones/huawei/mbb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:typed_data';

import 'package:collection/collection.dart';
import 'package:crclib/catalog.dart';
import '../../../logger.dart';

import '../headphones_data_objects.dart';

Expand Down Expand Up @@ -98,6 +99,7 @@ class MbbCommand {
commandId,
...dataBytes, // Make sure they are >0 and <256
];
logg.t("⬆ data: ${Uint8List.fromList(bytesList..addAll(MbbUtils.checksum(bytesList)))}");
return Uint8List.fromList(bytesList..addAll(MbbUtils.checksum(bytesList)));
}

Expand All @@ -106,6 +108,7 @@ class MbbCommand {
bool verify = true,
bool smartDivide = true,
}) {
logg.t("📥 received: ${payload}");
final divided = <Uint8List>[];
if (smartDivide) {
while (payload.length >= 8) {
Expand Down
20 changes: 18 additions & 2 deletions lib/headphones/huawei/otter/otter_constants.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
class OtterConst {
static const String name = 'Huawei Freebuds 4i';

static const BUDS_4I = 0;
static const BUDS_PRO = 1;

@Deprecated("This seems to not work... use [btDevNameRegex] instead")
static final btMacRegex = RegExp(r'60:AA:..:..:..:7E', caseSensitive: false);

// Copied straight from decompiled app
static final btDevNameRegex =
RegExp(r'^(?=(HUAWEI FreeBuds 4i))', caseSensitive: true);
[
RegExp(r'^(?=(HUAWEI FreeBuds 4i))', caseSensitive: true),
RegExp(r'^(?=(HUAWEI FreeBuds Pro))', caseSensitive: true)
];

static final names =
[
'Huawei Freebuds 4i',
'Huawei Freebuds Pro'
];

static final imageAsset = [
'assets/app_icons/ic_launcher.png',
'assets/app_icons/freebuds_pro_one.png',
];
}
4 changes: 2 additions & 2 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"pageHomeBluetoothDisabled": "Bluetooth is disabled 📶🚫",
"pageHomeBluetoothDisabledEnable": "Enable ☝",
"pageHomeBluetoothDisabledOpenSettings": "Open settings to enable 💙",
"pageHomeNotPaired": "You don't have Freebuds 4i paired to your phone 😿",
"pageHomeNotPaired": "You don't have Freebuds 4i or Freebuds Pro paired to your phone 😿",
"pageHomeNotPairedPairOpenSettings": "Open bluetooth settings to pair 🔌",
"pageHomeNotPairedPairOpenDemo": "Try app without headphones 🌐",
"pageHomeConnectedClosed": "Headphones are connected, but not with FreeBuddy 🤨",
Expand Down Expand Up @@ -66,7 +66,7 @@
"pageAboutOpenSourceLicensesBtn": "Open source licenses",
"pageIntroTitle": "Welcome to FreeBuddy 👋",
"pageIntroWhatIsThis": "FreeBuddy is open source app for your headphones 🎧",
"pageIntroSupported": "Currently supported are:\n - Huawei Freebuds 4i",
"pageIntroSupported": "Currently supported are:\n - Huawei Freebuds 4i \n - Huawei FreeBuds Pro",
"pageIntroShortPrivacyPolicy": "This app doesn't collect any emails, identifiers, or any personal data 🎉 You can read more about it here: ",
"pageIntroAnyQuestions": "If you have any questions, feel free to contact me 💌 Look at \"Settings->About\" for my socials!",
"pageIntroQuit": "Okay 👍"
Expand Down
4 changes: 2 additions & 2 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"pageHomeBluetoothDisabled": "Bluetooth jest wyłączony 📶🚫",
"pageHomeBluetoothDisabledEnable": "Włącz ☝",
"pageHomeBluetoothDisabledOpenSettings": "Otwórz ustawienia żeby włączyć 💙",
"pageHomeNotPaired": "Nie masz sparowanych Freebuds 4i z telefonem 😿",
"pageHomeNotPaired": "Nie masz sparowanych Freebuds 4i/ Freebuds Pro z telefonem 😿",
"pageHomeNotPairedPairOpenSettings": "Otwórz ustawienia bluetooth żeby sparować 🔌",
"pageHomeNotPairedPairOpenDemo": "Wypróbuj apke bez słuchawek 🌐",
"pageHomeConnectedClosed": "Słuchawki są połączone, ale nie z FreeBuddy 🤨",
Expand Down Expand Up @@ -66,7 +66,7 @@
"pageAboutOpenSourceLicensesBtn": "Licencje open source",
"pageIntroTitle": "Witaj we FreeBuddy 👋",
"pageIntroWhatIsThis": "FreeBuddy to open-source aplikacja do twoich słuchaweczek 🎧",
"pageIntroSupported": "Obecnie wspierane są:\n - Huawei Freebuds 4i",
"pageIntroSupported": "Obecnie wspierane są:\n - Huawei Freebuds 4i\n - Huawei Freebuds Pro",
"pageIntroShortPrivacyPolicy": "Ta aplikacja nie zbiera żadnych maili, identyfikatorów, czy innych osobistych danych 🎉 Możesz o tym poczytać tutaj: ",
"pageIntroAnyQuestions": "Jeśli masz jakiekolwiek pytania, napisz do mnie śmiało 💌 Wejdź w \"Ustawienia->O aplikacji\" po moje socjale!",
"pageIntroQuit": "Oki doki 👍"
Expand Down
22 changes: 18 additions & 4 deletions lib/ui/pages/home/controls/headphones_controls_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import '../../../../headphones/headphones_base.dart';
import '../../../../headphones/huawei/otter/otter_constants.dart';
import '../../../theme/layouts.dart';
import 'anc_card.dart';
import 'battery_card.dart';
Expand Down Expand Up @@ -33,10 +34,10 @@ class HeadphonesControlsWidget extends StatelessWidget {
children: [
Text(
// TODO: This hardcode
headphones.alias ?? 'FreeBuds 4i',
headphones.alias ?? 'FreeBuds',
style: tt.headlineMedium,
),
HeadphonesImage(headphones),
HeadphonesImage(headphones, getAsset(headphones.alias?? 'FreeBuds')),
Align(
alignment: Alignment.centerRight,
child: _HeadphonesSettingsButton(headphones),
Expand All @@ -53,10 +54,10 @@ class HeadphonesControlsWidget extends StatelessWidget {
children: [
Text(
// TODO: This hardcode
headphones.alias ?? 'FreeBuds 4i',
headphones.alias ?? 'FreeBuds',
style: tt.headlineMedium,
),
HeadphonesImage(headphones),
HeadphonesImage(headphones, getAsset(headphones.alias ?? 'FreeBus')),
],
),
),
Expand All @@ -79,6 +80,19 @@ class HeadphonesControlsWidget extends StatelessWidget {
),
);
}

String getAsset(String name) {

int pos = 0;

for (int i = 0; i < OtterConst.btDevNameRegex.length; i++) {
if (OtterConst.btDevNameRegex[i].hasMatch(name)) {
pos = i ;
}
}
return OtterConst.imageAsset[pos];
}

}

/// Simple button leading to headphones settings page
Expand Down
5 changes: 3 additions & 2 deletions lib/ui/pages/home/controls/headphones_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import '../../../../headphones/headphones_base.dart';
/// ...well, in the future :D
class HeadphonesImage extends StatelessWidget {
final HeadphonesBase headphones;
final String assetPath;

const HeadphonesImage(this.headphones, {Key? key}) : super(key: key);
const HeadphonesImage(this.headphones, this.assetPath, {Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
Expand All @@ -19,7 +20,7 @@ class HeadphonesImage extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 64),
child: Image.asset(
'assets/app_icons/ic_launcher.png',
assetPath,
fit: BoxFit.contain,
filterQuality: FilterQuality.none,
),
Expand Down
1 change: 1 addition & 0 deletions macos/Flutter/Flutter-Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
1 change: 1 addition & 0 deletions macos/Flutter/Flutter-Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
43 changes: 43 additions & 0 deletions macos/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
platform :osx, '10.14'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}

def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end

File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_macos_podfile_setup

target 'Runner' do
use_frameworks!
use_modular_headers!

flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end
11 changes: 6 additions & 5 deletions macos/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {

/* Begin PBXAggregateTarget section */
Expand Down Expand Up @@ -182,7 +182,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
Expand Down Expand Up @@ -235,6 +235,7 @@
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand Down Expand Up @@ -344,7 +345,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
Expand Down Expand Up @@ -423,7 +424,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
Expand Down Expand Up @@ -470,7 +471,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: freebuddy
description: Open-source app for Huawei Freebuds 4i headphones
description: Open-source app for Huawei Freebuds 4i/Freebuds Pro headphones

# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
Expand Down Expand Up @@ -121,6 +121,7 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- "assets/app_icons/ic_launcher.png"
- "assets/app_icons/freebuds_pro_one.png"
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg

Expand Down
8 changes: 4 additions & 4 deletions test/unit/device_constants_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import 'package:freebuddy/headphones/huawei/otter/otter_constants.dart';
void main() {
group("Device constants tests", () {
test("Otter name regex match", () {
expect(OtterConst.btDevNameRegex.hasMatch("HUAWEI FreeBuds 4i"), true);
expect(OtterConst.btDevNameRegex.hasMatch("HUAWEI FreeBuds 4i "), true);
expect(OtterConst.btDevNameRegex.hasMatch("huawei freebuds 4i"), false);
expect(OtterConst.btDevNameRegex.hasMatch("HUAWEI FreeBuds Pro"), false);
expect(OtterConst.btDevNameRegex.any((regex) => regex.hasMatch("HUAWEI FreeBuds 4i")), true);
expect(OtterConst.btDevNameRegex.any((regex) => regex.hasMatch("HUAWEI FreeBuds 4i ")), true);
expect(OtterConst.btDevNameRegex.any((regex) => regex.hasMatch("huawei freebuds 4i")), false);
expect(OtterConst.btDevNameRegex.any((regex) => regex.hasMatch("HUAWEI FreeBuds Pro")), true);
});
});
}