├── .github
└── workflows
│ └── dart-flutter-package-analyzer.yml
├── .gitignore
├── .metadata
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── polidea
│ └── blemulator
│ ├── BlemulatorPlugin.java
│ ├── DeviceContainer.java
│ ├── SimulatedAdapter.java
│ └── bridging
│ ├── CharacteristicContainer.java
│ ├── DartMethodCaller.java
│ ├── DartValueHandler.java
│ ├── JSONToBleErrorConverter.java
│ ├── constants
│ ├── ArgumentName.java
│ ├── ChannelName.java
│ ├── DartMethodName.java
│ ├── PlatformMethodName.java
│ └── SimulationArgumentName.java
│ └── decoder
│ ├── BleErrorDartValueDecoder.java
│ ├── CharacteristicDartValueDecoder.java
│ ├── DescriptorDartValueDecoder.java
│ └── ServiceDartValueDecoder.java
├── example
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── polidea
│ │ │ │ │ └── blemulator_example
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── assets
│ └── ti_logo.png
├── ios
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
├── lib
│ ├── adapter
│ │ └── ble_adapter.dart
│ ├── common
│ │ └── components
│ │ │ ├── property_row.dart
│ │ │ ├── title_icon.dart
│ │ │ └── title_image_icon.dart
│ ├── device_details
│ │ ├── device_detail_view.dart
│ │ ├── device_details_bloc.dart
│ │ ├── devices_details_bloc_provider.dart
│ │ └── view
│ │ │ ├── auto_test_view.dart
│ │ │ ├── button_view.dart
│ │ │ ├── logs_container_view.dart
│ │ │ └── manual_test_view.dart
│ ├── devices_list
│ │ ├── devices_bloc.dart
│ │ ├── devices_bloc_provider.dart
│ │ ├── devices_list_view.dart
│ │ └── hex_painter.dart
│ ├── di
│ │ └── ble_adapter_injector.dart
│ ├── example_peripherals
│ │ ├── generic_peripheral.dart
│ │ └── sensor_tag.dart
│ ├── main.dart
│ ├── model
│ │ ├── ble_device.dart
│ │ ├── ble_peripheral.dart
│ │ ├── ble_service.dart
│ │ └── signal_level.dart
│ ├── navigation
│ │ ├── bloc.dart
│ │ ├── navigation_bloc.dart
│ │ ├── navigation_event.dart
│ │ ├── route_factory.dart
│ │ ├── route_name.dart
│ │ └── router.dart
│ ├── peripheral_details
│ │ ├── bloc.dart
│ │ ├── components
│ │ │ ├── characteristics_view.dart
│ │ │ ├── peripheral_details_view.dart
│ │ │ └── services_sliver.dart
│ │ ├── peripheral_details_bloc.dart
│ │ ├── peripheral_details_event.dart
│ │ ├── peripheral_details_screen.dart
│ │ └── peripheral_details_state.dart
│ ├── peripheral_list
│ │ ├── bloc.dart
│ │ ├── components
│ │ │ ├── peripheral_category_icon.dart
│ │ │ ├── peripheral_item.dart
│ │ │ └── rssi_view.dart
│ │ ├── peripheral_list_bloc.dart
│ │ ├── peripheral_list_event.dart
│ │ ├── peripheral_list_screen.dart
│ │ └── peripheral_list_state.dart
│ ├── repository
│ │ └── device_repository.dart
│ ├── sensor_tag_config.dart
│ ├── styles
│ │ ├── custom_colors.dart
│ │ ├── custom_sizes.dart
│ │ ├── custom_text_style.dart
│ │ └── custom_theme.dart
│ ├── test_scenarios
│ │ ├── base.dart
│ │ ├── bluetooth_state_toggle_scenario.dart
│ │ ├── peripheral_test_operations.dart
│ │ ├── sensor_tag_test_scenario.dart
│ │ ├── sensor_tag_test_with_scan_and_connection_scenario.dart
│ │ └── test_scenarios.dart
│ └── util
│ │ └── pair.dart
├── pubspec.yaml
└── test
│ ├── adapter
│ └── ble_adapter_test.dart
│ ├── mock
│ ├── mocks.dart
│ ├── sample_ble_peripheral.dart
│ └── sample_ble_service.dart
│ ├── model
│ └── signal_level_test.dart
│ ├── peripheral_details
│ └── peripheral_details_bloc_test.dart
│ └── peripheral_list
│ └── peripheral_list_bloc_test.dart
├── ios
├── .gitignore
├── Assets
│ └── .gitkeep
├── Classes
│ ├── BlemulatorPlugin.h
│ ├── BlemulatorPlugin.m
│ ├── Bridging
│ │ ├── CharacteristicContainer.h
│ │ ├── CharacteristicContainer.m
│ │ ├── Converter
│ │ │ ├── DartCallArgumentsConverter.h
│ │ │ ├── DartCallArgumentsConverter.m
│ │ │ ├── DartResultConverter.h
│ │ │ ├── DartResultConverter.m
│ │ │ ├── DomainTypesConverter.h
│ │ │ └── DomainTypesConverter.m
│ │ ├── DartMethodCaller.h
│ │ ├── DartMethodCaller.m
│ │ ├── DartValueHandler.h
│ │ └── DartValueHandler.m
│ ├── Constants
│ │ ├── DartCallArgumentKeys.h
│ │ ├── DartCallArgumentKeys.m
│ │ ├── DartMethodName.h
│ │ ├── DartMethodName.m
│ │ ├── DartResultKeys.h
│ │ ├── DartResultKeys.m
│ │ ├── PlatformMethodName.h
│ │ ├── PlatformMethodName.m
│ │ ├── SimulationChannelName.h
│ │ └── SimulationChannelName.m
│ ├── DeviceContainer.h
│ ├── DeviceContainer.m
│ ├── Error
│ │ ├── BleError.h
│ │ ├── BleError.m
│ │ └── BleErrorCode.h
│ ├── Model
│ │ ├── AdvertisementData.h
│ │ ├── AdvertisementData.m
│ │ ├── Characteristic.h
│ │ ├── Characteristic.m
│ │ ├── ConnectionStateEvent.h
│ │ ├── ConnectionStateEvent.m
│ │ ├── Descriptor.h
│ │ ├── Descriptor.m
│ │ ├── Peripheral.h
│ │ ├── Peripheral.m
│ │ ├── ScannedPeripheral.h
│ │ ├── ScannedPeripheral.m
│ │ ├── Service.h
│ │ └── Service.m
│ ├── Response
│ │ ├── BlemulatorCharacteristicResponse.h
│ │ ├── BlemulatorCharacteristicResponse.m
│ │ ├── BlemulatorDescriptorResponse.h
│ │ ├── BlemulatorDescriptorResponse.m
│ │ ├── BlemulatorPeripheralResponse.h
│ │ └── BlemulatorPeripheralResponse.m
│ ├── SimulatedAdapter.h
│ ├── SimulatedAdapter.m
│ └── Util
│ │ ├── ArrayUtilities.h
│ │ ├── ArrayUtilities.m
│ │ ├── Base64Coder.h
│ │ ├── Base64Coder.m
│ │ ├── BlemulatorCommonTypes.h
│ │ ├── BlemulatorJSONStringifier.h
│ │ ├── BlemulatorJSONStringifier.m
│ │ ├── FlutterMethodCallHandler.h
│ │ ├── StringUtilities.h
│ │ └── StringUtilities.m
└── blemulator.podspec
├── lib
├── blemulator.dart
├── blemulator_core.dart
├── simulated_ble_error.dart
├── simulation
│ ├── simulated_characteristic.dart
│ ├── simulated_descriptor.dart
│ ├── simulated_peripheral.dart
│ └── simulated_service.dart
└── src
│ ├── bridge
│ ├── constants.dart
│ ├── dart_to_platform_bridge.dart
│ └── platform_to_dart_bridge.dart
│ ├── defaults.dart
│ ├── id_generator.dart
│ ├── internal.dart
│ ├── scan_result.dart
│ ├── simulation_manager.dart
│ ├── simulation_manager_mixins
│ ├── characteristics_mixin.dart
│ ├── client_managing_mixin.dart
│ ├── descriptors_mixin.dart
│ ├── discovery_mixin.dart
│ ├── error_checks_mixin.dart
│ ├── mtu_mixin.dart
│ ├── peripheral_connection_mixin.dart
│ ├── peripheral_scanning_mixin.dart
│ ├── response_models.dart
│ ├── rssi_mixin.dart
│ └── simulation_manager_base.dart
│ └── util
│ └── mappers.dart
├── pubspec.yaml
├── site
└── logo_Blemulator.png
└── test
├── factory
├── simulated_peripheral_factory.dart
└── simulation_manager_factory.dart
└── internal
├── bridge
└── platform_to_dart_bridge_test.dart
└── simulation_manager_mixin
├── discovery_mixin_test.dart
└── mtu_mixin_test.dart
/.github/workflows/dart-flutter-package-analyzer.yml:
--------------------------------------------------------------------------------
1 | name: Dart/Flutter Package Analyzer
2 | on: [push, pull_request]
3 |
4 | jobs:
5 |
6 | package-analysis:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v2
12 |
13 | - uses: axel-op/dart-package-analyzer@v3
14 | # set an id for the current step
15 | id: analysis
16 | with:
17 | githubToken: ${{ secrets.GITHUB_TOKEN }}
18 |
19 | # You can then use this id to retrieve the outputs in the next steps.
20 | # The following step shows how to exit the workflow with an error if the total score in percentage is below 50:
21 | - name: Check scores
22 | env:
23 | # NB: "analysis" is the id set above. Replace it with the one you used if different.
24 | TOTAL: ${{ steps.analysis.outputs.total }}
25 | TOTAL_MAX: ${{ steps.analysis.outputs.total_max }}
26 | ANALYSIS: ${{ steps.analysis.outputs.analysis }}
27 | ANALYSIS_MAX: ${{ steps.analysis.outputs.analysis_max }}
28 | run: |
29 | if (( $ANALYSIS < $ANALYSIS_MAX ))
30 | then
31 | echo Unacceptable analysis score! Needs to be maxed out!
32 | exit 1
33 | elif (( $TOTAL < ($TOTAL_MAX - 10) ))
34 | then
35 | echo Unacceptable total score! Check dependencies and other factors!
36 | exit 2
37 | fi
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .atom/
3 | .dart_tool/package_config.json
4 | .idea
5 | .packages
6 | .pub/
7 | build/
8 | ios/.generated/
9 | packages
10 | pubspec.lock
11 | *.iml
12 | example/android/res/values/strings_en.arb
13 | res/values/strings_en.arb
14 | lib/generated/
15 | example/lib/generated/
16 | example/ios/Podfile.lock
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: cc949a8e8b9cf394b9290a8e80f87af3e207dce5
8 | channel: stable
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | git checlanguage: generic
2 |
3 | stages:
4 | - name: self-test
5 | if: type = push
6 | - name: flutter
7 | if: branch = master OR type = pull_request
8 | - name: flutter_example
9 | if: branch = master OR type = pull_request
10 | - name: native
11 | if: branch = master OR type = pull_request
12 |
13 | _flutter_job_template: &_flutter_job_template
14 | before_script:
15 | - git clone https://github.com/flutter/flutter.git -b stable
16 | - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
17 | script:
18 | - flutter packages get
19 | - flutter test
20 |
21 | _flutter_example_job_template: &_flutter_example_job_template
22 | before_script:
23 | - git clone https://github.com/flutter/flutter.git -b stable
24 | - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
25 | script:
26 | - cd example
27 | - flutter packages get
28 | - flutter test
29 |
30 | _android_job_template: &android_job_template
31 | language: android
32 | android:
33 | components:
34 | - tools
35 | - build-tools-28.0.3
36 | - android-28
37 | - build-tools-29.0.5
38 | - android-29
39 | - extra-android-m2repository
40 | licenses:
41 | - 'android-sdk-license-.+'
42 | env:
43 | global:
44 | - GRADLE_OPTS="-Xms128m"
45 | - ABI="default;armeabi-v7a"
46 | before_cache:
47 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
48 | cache:
49 | directories:
50 | - $HOME/.m2
51 | - $HOME/.gradle/caches/
52 | - $HOME/.gradle/wrapper/
53 | before_script:
54 | - git clone https://github.com/flutter/flutter.git -b stable
55 | - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
56 | script:
57 | - cd example
58 | - flutter build apk
59 |
60 | _ios_job_template: &ios_job_template
61 | language: objective-c
62 | os: osx
63 | osx_image: xcode11.6
64 | xcode_project: example/ios/Runner.xcworkspace
65 | xcode_scheme: Runner
66 | before_script:
67 | - git clone https://github.com/flutter/flutter.git -b stable
68 | - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH
69 | script:
70 | - cd example
71 | - flutter build ios --no-codesign --verbose
72 |
73 | matrix:
74 | include:
75 | - <<: *android_job_template
76 | name: Build Android
77 | stage: native
78 | - <<: *ios_job_template
79 | name: Build iOS
80 | stage: native
81 | - <<: *_flutter_job_template
82 | name: Build Flutter
83 | stage: flutter
84 | - <<: *_flutter_example_job_template
85 | name: Test Flutter Example
86 | stage: flutter_example
87 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.2.1
2 |
3 | * Fix crash on iOS when manufacturer's data was present in the advertising packet
4 |
5 | ## 1.2.0
6 |
7 | * Add support for connecting to peripheral without launching scan first
8 |
9 | ## 1.1.3
10 |
11 | * Fix incorrect iOS plugin class name causing `Duplicate plugin key: FlutterBleLib`
12 |
13 | ## 1.1.2
14 |
15 | * Unify internal representation of UUIDs to lower case, making simulated GATTs case insensitive
16 |
17 | ## 1.1.1
18 |
19 | * hide private API
20 | * remove unnecessary log
21 | * update dependencies
22 |
23 | ## 1.1.0
24 |
25 | * **NEW** characteristics may now contain descriptors
26 |
27 | ## 1.0.1
28 |
29 | * Fix an issue causing characteristics' properties to be null on iOS
30 |
31 | ## 1.0.0
32 | First release of BLEmulator for Flutter!
33 |
34 | BLEmulator supports:
35 | * switching simulation on
36 | * peripherals (manipulation of advertisement data and interval, connection, discovery)
37 | * services (fetching characteristics)
38 | * characteristics (reading, writing, notifications/indications)
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Polidea Sp. z o.o
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 | http://www.apache.org/licenses/LICENSE-2.0
7 |
8 | Unless required by applicable law or agreed to in writing, software
9 | distributed under the License is distributed on an "AS IS" BASIS,
10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | See the License for the specific language governing permissions and
12 | limitations under the License.
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:pedantic/analysis_options.1.9.0.yaml
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.polidea.blemulator'
2 | version '1.2.1'
3 |
4 | buildscript {
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 |
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.2.1'
12 | }
13 | }
14 |
15 | rootProject.allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | maven { url "https://jitpack.io" }
20 | }
21 | }
22 |
23 | apply plugin: 'com.android.library'
24 |
25 | android {
26 | compileSdkVersion 28
27 |
28 | defaultConfig {
29 | minSdkVersion 18
30 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
31 | }
32 | lintOptions {
33 | disable 'InvalidPackage'
34 | }
35 | }
36 |
37 | dependencies {
38 | implementation 'com.github.Polidea:MultiPlatformBleAdapter:0.1.7'
39 | }
40 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
3 | org.gradle.jvmargs=-Xmx1536M
4 |
5 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'blemulator'
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/BlemulatorPlugin.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator;
2 |
3 | import android.content.Context;
4 | import androidx.annotation.NonNull;
5 |
6 | import com.polidea.blemulator.bridging.DartMethodCaller;
7 | import com.polidea.blemulator.bridging.DartValueHandler;
8 | import com.polidea.blemulator.bridging.constants.ChannelName;
9 | import com.polidea.blemulator.bridging.constants.PlatformMethodName;
10 | import com.polidea.multiplatformbleadapter.BleAdapter;
11 | import com.polidea.multiplatformbleadapter.BleAdapterCreator;
12 | import com.polidea.multiplatformbleadapter.BleAdapterFactory;
13 |
14 | import io.flutter.plugin.common.MethodCall;
15 | import io.flutter.plugin.common.MethodChannel;
16 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
17 | import io.flutter.plugin.common.PluginRegistry;
18 |
19 | public class BlemulatorPlugin implements MethodCallHandler {
20 |
21 | private DartMethodCaller dartMethodCaller;
22 | private DartValueHandler dartValueHandler;
23 |
24 | public static void registerWith(PluginRegistry.Registrar registrar) {
25 | MethodChannel dartToPlatformChannel = new MethodChannel(registrar.messenger(), ChannelName.TO_PLATFORM);
26 | MethodChannel platformToDartChannel = new MethodChannel(registrar.messenger(), ChannelName.TO_DART);
27 |
28 | dartToPlatformChannel.setMethodCallHandler(new BlemulatorPlugin(platformToDartChannel));
29 | }
30 |
31 | private BlemulatorPlugin(MethodChannel platformToDartChannel) {
32 | dartMethodCaller = new DartMethodCaller(platformToDartChannel);
33 | dartValueHandler = new DartValueHandler();
34 | }
35 |
36 | @Override
37 | public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
38 | switch (call.method) {
39 | case PlatformMethodName.SIMULATE:
40 | switchToSimulation(result);
41 | return;
42 | default:
43 | dartValueHandler.onMethodCall(call, result);
44 | return;
45 | }
46 | }
47 |
48 | private void switchToSimulation(MethodChannel.Result result) {
49 | BleAdapterFactory.setBleAdapterCreator(new BleAdapterCreator() {
50 | @Override
51 | public BleAdapter createAdapter(Context context) {
52 | SimulatedAdapter adapter = new SimulatedAdapter(dartMethodCaller, dartValueHandler);
53 | return adapter;
54 | }
55 | });
56 | result.success(null);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/DeviceContainer.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator;
2 |
3 | import com.polidea.blemulator.bridging.CharacteristicContainer;
4 | import com.polidea.multiplatformbleadapter.Service;
5 |
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | public class DeviceContainer {
10 | private String identifier;
11 | private String name;
12 | private List services;
13 | private Map> characteristicContainersIndexedByServiceUuids;
14 | private boolean isConnected = false;
15 |
16 | public DeviceContainer(String identifier, String name, List services, Map> characteristicContainersIndexedByServiceUuids) {
17 | this.identifier = identifier;
18 | this.name = name;
19 | this.services = services;
20 | this.characteristicContainersIndexedByServiceUuids = characteristicContainersIndexedByServiceUuids;
21 | }
22 |
23 | public boolean isConnected() {
24 | return isConnected;
25 | }
26 |
27 | public void setConnected(boolean connected) {
28 | isConnected = connected;
29 | }
30 |
31 | public String getIdentifier() {
32 | return identifier;
33 | }
34 |
35 | public String getName() {
36 | return name;
37 | }
38 |
39 | public List getServices() {
40 | return services;
41 | }
42 |
43 | public Map> getCharacteristicContainersIndexedByServiceUuids() {
44 | return characteristicContainersIndexedByServiceUuids;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/CharacteristicContainer.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging;
2 |
3 | import com.polidea.multiplatformbleadapter.Characteristic;
4 | import com.polidea.multiplatformbleadapter.Descriptor;
5 |
6 | import java.util.List;
7 |
8 | public class CharacteristicContainer {
9 | private final Characteristic characteristic;
10 | private final List descriptors;
11 |
12 | public CharacteristicContainer(Characteristic characteristic, List descriptors) {
13 | this.characteristic = characteristic;
14 | this.descriptors = descriptors;
15 | }
16 |
17 | public Characteristic getCharacteristic() {
18 | return characteristic;
19 | }
20 |
21 | public List getDescriptors() {
22 | return descriptors;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/JSONToBleErrorConverter.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging;
2 |
3 | import com.polidea.multiplatformbleadapter.errors.BleError;
4 | import com.polidea.multiplatformbleadapter.errors.BleErrorCode;
5 |
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | public class JSONToBleErrorConverter {
10 | private static final String ERROR_CODE = "errorCode";
11 | private static final String REASON = "reason";
12 |
13 | public BleError bleErrorFromJSON(String jsonString) {
14 | try {
15 | JSONObject jsonObject = new JSONObject(jsonString);
16 | return new BleError(findValue(jsonObject.getInt(ERROR_CODE)), jsonObject.getString(REASON), -1);
17 | } catch (JSONException e) {
18 | return new BleError(BleErrorCode.UnknownError, "Failed to convert: " + jsonString, -1);
19 | }
20 | }
21 |
22 | private BleErrorCode findValue(int errorCode) throws JSONException {
23 | for (BleErrorCode value : BleErrorCode.values()) {
24 | if (value.code == errorCode) {
25 | return value;
26 | }
27 | }
28 |
29 | throw new JSONException("Failed to find value for " + errorCode);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/constants/ArgumentName.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.constants;
2 |
3 | public interface ArgumentName {
4 | String IDENTIFIER = "id";
5 | String SERVICE_UUID = "serviceUuid";
6 | String TRANSACTION_ID = "transactionId";
7 | String DEVICE_IDENTIFIER = "deviceIdentifier";
8 | String CHARACTERISTIC_UUID = "characteristicUuid";
9 | String SERVICE_IDENTIFIER = "serviceId";
10 | String CHARACTERISTIC_IDENTIFIER = "characteristicIdentifier";
11 | String DESCRIPTOR_IDENTIFIER = "descriptorIdentifier";
12 | String DESCRIPTOR_UUID = "descriptorUuid";
13 | String VALUE = "value";
14 | }
15 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/constants/ChannelName.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.constants;
2 |
3 | public interface ChannelName {
4 | String BASE = "com.polidea.blemulator";
5 |
6 | String TO_DART = BASE + "/toDart";
7 | String TO_PLATFORM = BASE + "/toJava";
8 | }
9 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/constants/DartMethodName.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.constants;
2 |
3 | public interface DartMethodName {
4 | String CREATE_CLIENT = "createClient";
5 | String DESTROY_CLIENT = "destroyClient";
6 |
7 | String START_DEVICE_SCAN = "startDeviceScan";
8 | String STOP_DEVICE_SCAN = "stopDeviceScan";
9 |
10 | String CONNECT_TO_DEVICE = "connectToDevice";
11 | String IS_DEVICE_CONNECTED = "isDeviceConnected";
12 | String DISCONNECT_OR_CANCEL_CONNECTION = "disconnectOrCancelConnection";
13 |
14 | String DISCOVER_ALL_SERVICES_AND_CHARACTERISTICS = "discoverAllServicesAndCharacteristics";
15 | String GET_SERVICES = "services";
16 | String GET_CHARACTERISTICS = "characteristics";
17 |
18 | String READ_CHARACTERISTIC_FOR_IDENTIFIER = "readCharacteristicForIdentifier";
19 | String READ_CHARACTERISTIC_FOR_DEVICE = "readCharacteristicForDevice";
20 | String READ_CHARACTERISTIC_FOR_SERVICE = "readCharacteristicForService";
21 | String WRITE_CHARACTERISTIC_FOR_IDENTIFIER = "writeCharacteristicForIdentifier";
22 | String WRITE_CHARACTERISTIC_FOR_DEVICE = "writeCharacteristicForDevice";
23 | String WRITE_CHARACTERISTIC_FOR_SERVICE = "writeCharacteristicForService";
24 | String MONITOR_CHARACTERISTIC_FOR_IDENTIFIER = "monitorCharacteristicForIdentifier";
25 | String MONITOR_CHARACTERISTIC_FOR_DEVICE = "monitorCharacteristicForDevice";
26 | String MONITOR_CHARACTERISTIC_FOR_SERVICE = "monitorCharacteristicForService";
27 |
28 | String READ_DESCRIPTOR_FOR_IDENTIFIER = "readDescriptorForIdentifier";
29 | String READ_DESCRIPTOR_FOR_CHARACTERISTIC = "readDescriptorForCharacteristic";
30 | String READ_DESCRIPTOR_FOR_SERVICE = "readDescriptorForService";
31 | String READ_DESCRIPTOR_FOR_DEVICE = "readDescriptorForDevice";
32 |
33 | String WRITE_DESCRIPTOR_FOR_IDENTIFIER = "writeDescriptorForIdentifier";
34 | String WRITE_DESCRIPTOR_FOR_CHARACTERISTIC = "writeDescriptorForCharacteristic";
35 | String WRITE_DESCRIPTOR_FOR_SERVICE = "writeDescriptorForService";
36 | String WRITE_DESCRIPTOR_FOR_DEVICE = "writeDescriptorForDevice";
37 |
38 | String RSSI = "rssi";
39 | String REQUEST_MTU = "requestMtu";
40 | String CANCEL_TRANSACTION = "cancelTransaction";
41 | }
42 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/constants/PlatformMethodName.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.constants;
2 |
3 | public interface PlatformMethodName {
4 | String SIMULATE = "simulate";
5 |
6 | String PUBLISH_SCAN_RESULT = "publishScanResult";
7 | String PUBLISH_CONNECTION_STATE = "publishConnectionState";
8 | String PUBLISH_CHARACTERISTIC_UPDATE = "publishCharacteristicUpdate";
9 | String PUBLISH_CHARACTERISTIC_MONITORING_ERROR = "publishCharacteristicMonitoringError";
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/constants/SimulationArgumentName.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.constants;
2 |
3 | public interface SimulationArgumentName {
4 | String DEVICE_IDENTIFIER = "deviceIdentifier";
5 | String DEVICE_NAME = "name";
6 | String DEVICE_ID = "id";
7 | String RSSI = "rssi";
8 | String MTU = "mtu";
9 | String IS_CONNECTABLE = "isConnectable";
10 | String TX_POWER_LEVEL = "txPowerLevel";
11 | String MANUFACTURER_DATA = "manufacturerData";
12 | String SERVICE_DATA = "serviceData";
13 | String SERVICE_UUIDS = "serviceUuids";
14 | String LOCAL_NAME = "localName";
15 | String SOLICITED_SERVICE_UUIDS = "solicitedServiceUuids";
16 | String OVERFLOW_SERVICE_UUIDS = "overflowUuids";
17 |
18 | String CONNECTION_STATE = "connectionState";
19 |
20 | String CHARACTERISTICS = "characteristics";
21 | String UUID = "uuid";
22 | String SERVICE_ID = "serviceId";
23 | String SERVICE_UUID = "serviceUuid";
24 | String CHARACTERISTIC_UUID = "characteristicUuid";
25 | String CHARACTERISTIC_ID = "characteristicId";
26 | String IS_READABLE = "isReadable";
27 | String IS_WRITABLE_WITH_RESPONSE = "isWritableWithResponse";
28 | String IS_WRITABLE_WITHOUT_RESPONSE = "isWritableWithoutResponse";
29 | String IS_NOTIFIABLE = "isNotifiable";
30 | String IS_NOTIFYING = "isNotifying";
31 | String IS_INDICATABLE = "isIndicatable";
32 | String VALUE = "value";
33 |
34 | String DESCRIPTORS = "descriptors";
35 |
36 | String TRANSACTION_ID = "transactionId";
37 | }
38 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/decoder/BleErrorDartValueDecoder.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.decoder;
2 |
3 | import com.polidea.multiplatformbleadapter.errors.BleError;
4 | import com.polidea.multiplatformbleadapter.errors.BleErrorCode;
5 |
6 | import java.util.Map;
7 |
8 | public class BleErrorDartValueDecoder {
9 |
10 | private interface Metadata {
11 | String ERROR_CODE = "errorCode";
12 | String REASON = "reason";
13 | }
14 |
15 | public BleError decode(Map values) {
16 | return new BleError(
17 | mapToBleErrorCode((Integer) values.get(Metadata.ERROR_CODE)),
18 | (String) values.get(Metadata.REASON),
19 | null);
20 | }
21 |
22 | private BleErrorCode mapToBleErrorCode(int code) {
23 | for (BleErrorCode errorCode : BleErrorCode.values()) {
24 | if (errorCode.code == code) return errorCode;
25 | }
26 | return BleErrorCode.UnknownError;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/decoder/DescriptorDartValueDecoder.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.decoder;
2 |
3 | import android.bluetooth.BluetoothGattDescriptor;
4 |
5 | import com.polidea.multiplatformbleadapter.Descriptor;
6 |
7 | import java.util.Map;
8 | import java.util.UUID;
9 |
10 | public class DescriptorDartValueDecoder {
11 |
12 | private interface Metadata {
13 | String DESCRIPTOR_UUID = "descriptorUuid";
14 | String DESCRIPTOR_ID = "descriptorId";
15 | String CHARACTERISTIC_ID = "characteristicId";
16 | String CHARACTERISTIC_UUID = "characteristicUuid";
17 | String SERVICE_ID = "serviceId";
18 | String SERVICE_UUID = "serviceUuid";
19 | String DEVICE_ID = "deviceIdentifier";
20 | String VALUE = "value";
21 | }
22 |
23 | public Descriptor decode(Map values) {
24 | BluetoothGattDescriptor gattDescriptor = new BluetoothGattDescriptor(
25 | UUID.fromString(
26 | (String) values.get(Metadata.DESCRIPTOR_UUID)),
27 | 0);
28 |
29 | Descriptor descriptor = new Descriptor(
30 | (Integer) values.get(Metadata.CHARACTERISTIC_ID),
31 | (Integer) values.get(Metadata.SERVICE_ID),
32 | UUID.fromString((String) values.get(Metadata.CHARACTERISTIC_UUID)),
33 | UUID.fromString((String) values.get(Metadata.SERVICE_UUID)),
34 | (String) values.get(Metadata.DEVICE_ID),
35 | gattDescriptor,
36 | (Integer) values.get(Metadata.DESCRIPTOR_ID),
37 | UUID.fromString(
38 | (String) values.get(Metadata.DESCRIPTOR_UUID))
39 | );
40 |
41 | byte[] value = (byte[]) values.get(Metadata.VALUE);
42 | descriptor.setValue(value);
43 |
44 | return descriptor;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/android/src/main/java/com/polidea/blemulator/bridging/decoder/ServiceDartValueDecoder.java:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator.bridging.decoder;
2 |
3 | import android.bluetooth.BluetoothGattService;
4 |
5 | import com.polidea.blemulator.bridging.constants.SimulationArgumentName;
6 | import com.polidea.multiplatformbleadapter.Service;
7 | import com.polidea.multiplatformbleadapter.utils.UUIDConverter;
8 |
9 | import java.util.Map;
10 | import java.util.UUID;
11 |
12 | public class ServiceDartValueDecoder {
13 |
14 | public Service decode(String deviceId, Map values) {
15 | int serviceId = (int) values.get(SimulationArgumentName.SERVICE_ID);
16 | UUID serviceUuid = UUIDConverter.convert((String) values.get(SimulationArgumentName.SERVICE_UUID));
17 | BluetoothGattService bluetoothGattService = new BluetoothGattService(serviceUuid, BluetoothGattService.SERVICE_TYPE_PRIMARY);
18 | return new Service(serviceId, deviceId, bluetoothGattService);
19 | }
20 | }
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | /build/
32 |
33 | # Android related
34 | **/android/**/gradle-wrapper.jar
35 | **/android/.gradle
36 | **/android/captures/
37 | **/android/gradlew
38 | **/android/gradlew.bat
39 | **/android/local.properties
40 | **/android/**/GeneratedPluginRegistrant.java
41 |
42 | # iOS/XCode related
43 | **/ios/**/*.mode1v3
44 | **/ios/**/*.mode2v3
45 | **/ios/**/*.moved-aside
46 | **/ios/**/*.pbxuser
47 | **/ios/**/*.perspectivev3
48 | **/ios/**/*sync/
49 | **/ios/**/.sconsign.dblite
50 | **/ios/**/.tags*
51 | **/ios/**/.vagrant/
52 | **/ios/**/DerivedData/
53 | **/ios/**/Icon?
54 | **/ios/**/Pods/
55 | **/ios/**/.symlinks/
56 | **/ios/**/profile
57 | **/ios/**/xcuserdata
58 | **/ios/.generated/
59 | **/ios/Flutter/App.framework
60 | **/ios/Flutter/Flutter.framework
61 | **/ios/Flutter/Flutter.podspec
62 | **/ios/Flutter/Generated.xcconfig
63 | **/ios/Flutter/app.flx
64 | **/ios/Flutter/app.zip
65 | **/ios/Flutter/flutter_assets/
66 | **/ios/Flutter/flutter_export_environment.sh
67 | **/ios/ServiceDefinitions.json
68 | **/ios/Runner/GeneratedPluginRegistrant.*
69 |
70 | # Exceptions to above rules.
71 | !**/ios/**/default.mode1v3
72 | !**/ios/**/default.mode2v3
73 | !**/ios/**/default.pbxuser
74 | !**/ios/**/default.perspectivev3
75 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
76 |
77 | # Code coverage related
78 | /coverage/
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: cc949a8e8b9cf394b9290a8e80f87af3e207dce5
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # blemulator_example
2 |
3 | Demonstrates how to use the blemulator plugin.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.polidea.blemulator_example"
42 | minSdkVersion 18
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
47 | }
48 |
49 | buildTypes {
50 | release {
51 | // TODO: Add your own signing config for the release build.
52 | // Signing with the debug keys for now, so `flutter run --release` works.
53 | signingConfig signingConfigs.debug
54 | }
55 | }
56 |
57 | packagingOptions {
58 | exclude 'META-INF/proguard/androidx-annotations.pro'
59 | }
60 | }
61 |
62 | flutter {
63 | source '../..'
64 | }
65 |
66 | dependencies {
67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
68 | testImplementation 'junit:junit:4.12'
69 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
70 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
71 | }
72 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
15 |
22 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/polidea/blemulator_example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.polidea.blemulator_example
2 |
3 | import android.os.Bundle
4 |
5 | import io.flutter.app.FlutterActivity
6 | import io.flutter.plugins.GeneratedPluginRegistrant
7 |
8 | class MainActivity: FlutterActivity() {
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | GeneratedPluginRegistrant.registerWith(this)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.61'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.3'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
3 | android.enableR8=true
4 | android.enableJetifier=true
5 | android.useAndroidX=true
6 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Feb 11 14:37:45 CET 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/example/assets/ti_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/assets/ti_logo.png
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Polidea/blemulator_flutter/5046c7d4b3bfd59529914efa0411852db145f52f/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | blemulator_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/example/lib/common/components/title_icon.dart:
--------------------------------------------------------------------------------
1 | import 'package:blemulator_example/styles/custom_sizes.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class TitleIcon extends Icon {
5 | TitleIcon(IconData icon, {Color color})
6 | : super(icon, size: CustomSizes.titleIcon, color: color);
7 | }
8 |
--------------------------------------------------------------------------------
/example/lib/common/components/title_image_icon.dart:
--------------------------------------------------------------------------------
1 | import 'package:blemulator_example/styles/custom_sizes.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class TitleImageIcon extends ImageIcon {
5 | TitleImageIcon(ImageProvider image, {Color color})
6 | : super(image, size: CustomSizes.titleIcon, color: color);
7 | }
8 |
--------------------------------------------------------------------------------
/example/lib/device_details/device_detail_view.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:fimber/fimber.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:blemulator_example/device_details/device_details_bloc.dart';
6 | import 'package:blemulator_example/device_details/devices_details_bloc_provider.dart';
7 | import 'package:blemulator_example/device_details/view/auto_test_view.dart';
8 | import 'package:blemulator_example/device_details/view/manual_test_view.dart';
9 |
10 | class DeviceDetailsView extends StatefulWidget {
11 | @override
12 | State createState() => DeviceDetailsViewState();
13 |
14 | }
15 |
16 | class DeviceDetailsViewState extends State {
17 | DeviceDetailsBloc _deviceDetailsBloc;
18 | StreamSubscription _appStateSubscription;
19 |
20 | bool _shouldRunOnResume = true;
21 |
22 | @override
23 | void didChangeDependencies() {
24 | super.didChangeDependencies();
25 | Fimber.d('didChangeDependencies');
26 | if (_deviceDetailsBloc == null) {
27 | _deviceDetailsBloc = DeviceDetailsBlocProvider.of(context);
28 | if (_shouldRunOnResume) {
29 | _shouldRunOnResume = false;
30 | _onResume();
31 | }
32 | }
33 | }
34 |
35 | void _onResume() {
36 | Fimber.d('onResume');
37 | _deviceDetailsBloc.init();
38 | _appStateSubscription =
39 | _deviceDetailsBloc.disconnectedDevice.listen((bleDevice) async {
40 | Fimber.d('navigate to details');
41 | _onPause();
42 | Navigator.pop(context);
43 | _shouldRunOnResume = true;
44 | Fimber.d('back from details');
45 | });
46 | }
47 |
48 | void _onPause() {
49 | Fimber.d('onPause');
50 | _appStateSubscription.cancel();
51 | _deviceDetailsBloc.dispose();
52 | }
53 |
54 | @override
55 | void dispose() {
56 | Fimber.d('Dispose DeviceListScreenState');
57 | _onPause();
58 | super.dispose();
59 | }
60 |
61 | @override
62 | Widget build(BuildContext context) {
63 | return WillPopScope(
64 | onWillPop: () {
65 | return _deviceDetailsBloc.disconnect().then((_) {
66 | return false;
67 | });
68 | },
69 | child: DefaultTabController(
70 | length: 2,
71 | child: Scaffold(
72 | backgroundColor: Colors.grey[300],
73 | appBar: AppBar(
74 | title: Text('Device Details'),
75 | bottom: TabBar(
76 | tabs: [
77 | Tab(icon: Icon(Icons.autorenew), text: 'Automatic',),
78 | Tab(icon: Icon(Icons.settings), text: 'Manual',),
79 | ],
80 | ),
81 | ),
82 | body: TabBarView(
83 | children: [
84 | AutoTestView(_deviceDetailsBloc),
85 | ManualTestView(_deviceDetailsBloc),
86 | ],
87 | )),
88 | ),
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/example/lib/device_details/devices_details_bloc_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 | import 'package:blemulator_example/repository/device_repository.dart';
3 | import 'package:flutter_ble_lib/flutter_ble_lib.dart';
4 |
5 | import 'device_details_bloc.dart';
6 |
7 |
8 | class DeviceDetailsBlocProvider extends InheritedWidget {
9 | final DeviceDetailsBloc deviceDetailsBloc;
10 |
11 | DeviceDetailsBlocProvider({
12 | Key key,
13 | DeviceDetailsBloc deviceDetailsBloc,
14 | Widget child,
15 | }) : deviceDetailsBloc = deviceDetailsBloc ?? DeviceDetailsBloc(DeviceRepository(), BleManager()),
16 | super(key: key, child: child);
17 |
18 | @override
19 | bool updateShouldNotify(InheritedWidget oldWidget) => true;
20 |
21 | static DeviceDetailsBloc of(BuildContext context) =>
22 | (context.inheritFromWidgetOfExactType(DeviceDetailsBlocProvider)
23 | as DeviceDetailsBlocProvider)
24 | .deviceDetailsBloc;
25 | }
26 |
--------------------------------------------------------------------------------
/example/lib/device_details/view/auto_test_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:blemulator_example/device_details/device_details_bloc.dart';
4 | import 'package:blemulator_example/device_details/view/button_view.dart';
5 | import 'package:blemulator_example/device_details/view/logs_container_view.dart';
6 |
7 |
8 | class AutoTestView extends StatelessWidget {
9 |
10 | final DeviceDetailsBloc _deviceDetailsBloc;
11 |
12 | AutoTestView(this._deviceDetailsBloc);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Padding(
17 | padding: const EdgeInsets.all(16.0),
18 | child: Column(children: [
19 | Expanded(
20 | flex: 1,
21 | child: SingleChildScrollView(
22 | child: _createAutoTestControlPanel(),
23 | ),
24 | ),
25 | Expanded(
26 | flex: 9,
27 | child: LogsContainerView(_deviceDetailsBloc.logs),
28 | )
29 | ]),
30 | );
31 | }
32 |
33 | Widget _createAutoTestControlPanel() {
34 | return Row(
35 | children: [
36 | ButtonView('Start Auto Test', action: _startAutoTest),
37 | ],
38 | );
39 | }
40 |
41 | void _startAutoTest() {
42 | _deviceDetailsBloc.startAutoTest();
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/example/lib/device_details/view/button_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 |
4 | class ButtonView extends StatelessWidget {
5 |
6 | final String _text;
7 | final Function action;
8 |
9 | ButtonView(this._text, { this.action });
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Expanded(
14 | child: Padding(
15 | padding: const EdgeInsets.all(2.0),
16 | child: RaisedButton(
17 | color: Colors.blue,
18 | textColor: Colors.white,
19 | child: Text(_text),
20 | onPressed: action,
21 | ),
22 | ),
23 | );
24 | }
25 | }
--------------------------------------------------------------------------------
/example/lib/device_details/view/logs_container_view.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:blemulator_example/device_details/device_details_bloc.dart';
4 | import 'package:rxdart/rxdart.dart';
5 |
6 | class LogsContainerView extends StatelessWidget {
7 |
8 | final Observable> _logs;
9 |
10 | LogsContainerView(this._logs);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | margin: EdgeInsets.symmetric(vertical: 8.0),
16 | decoration: BoxDecoration(
17 | color: Colors.white,
18 | borderRadius: BorderRadius.all(Radius.circular(4.0))),
19 | child: SizedBox.expand(
20 | child: Column(
21 | children: [
22 | Flexible(
23 | child: StreamBuilder>(
24 | initialData: [],
25 | stream: _logs,
26 | builder: (context, snapshot) => _buildLogs(context, snapshot),
27 | ),
28 | ),
29 | ],
30 | ),
31 | ),
32 | );
33 | }
34 |
35 | Widget _buildLogs(BuildContext context, AsyncSnapshot> logs) {
36 | return ListView.builder(
37 | itemCount: logs.data.length,
38 | shrinkWrap: true,
39 | itemBuilder: (buildContext, index) => Container(
40 | decoration: BoxDecoration(
41 | border: Border(
42 | top: BorderSide(
43 | color: Colors.grey,
44 | width: 0.5,
45 | ),
46 | bottom: BorderSide(
47 | color: Colors.grey,
48 | width: 0.5,
49 | ),
50 | ),
51 | ),
52 | child: Padding(
53 | padding: const EdgeInsets.only(top: 2.0),
54 | child: Row(
55 | crossAxisAlignment: CrossAxisAlignment.start,
56 | children: [
57 | Padding(
58 | padding: const EdgeInsets.only(right: 8.0),
59 | child: Text(
60 | logs.data[index].time,
61 | style: TextStyle(fontSize: 9),
62 | ),
63 | ),
64 | Flexible(
65 | child: Text(logs.data[index].content,
66 | overflow: TextOverflow.ellipsis,
67 | softWrap: true,
68 | style: TextStyle(fontSize: 13)),
69 | ),
70 | ],
71 | ),
72 | ),
73 | ),
74 | );
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/example/lib/devices_list/devices_bloc_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 | import 'package:blemulator_example/devices_list/devices_bloc.dart';
3 | import 'package:blemulator_example/repository/device_repository.dart';
4 | import 'package:flutter_ble_lib/flutter_ble_lib.dart';
5 |
6 | class DevicesBlocProvider extends InheritedWidget {
7 | final DevicesBloc devicesBloc;
8 |
9 | DevicesBlocProvider({
10 | Key key,
11 | DevicesBloc devicesBloc,
12 | Widget child,
13 | }) : devicesBloc = devicesBloc ??
14 | DevicesBloc(DeviceRepository(), BleManager()),
15 | super(key: key, child: child);
16 |
17 | @override
18 | bool updateShouldNotify(InheritedWidget oldWidget) => true;
19 |
20 | static DevicesBloc of(BuildContext context) =>
21 | (context.inheritFromWidgetOfExactType(DevicesBlocProvider)
22 | as DevicesBlocProvider)
23 | .devicesBloc;
24 | }
25 |
--------------------------------------------------------------------------------
/example/lib/devices_list/hex_painter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class HexPainter extends CustomPainter {
4 | final Color _foregroundColor;
5 | final Color _backgroundColor;
6 |
7 | HexPainter({
8 | Color backgroundColor,
9 | Color foregroundColor,
10 | }) : _backgroundColor = backgroundColor ?? Colors.white,
11 | _foregroundColor = foregroundColor ?? Colors.black,
12 | super();
13 |
14 | @override
15 | void paint(Canvas canvas, Size size) {
16 | final paint = Paint();
17 | drawHexagon(canvas, size, paint);
18 | drawButton(canvas, size, paint);
19 | }
20 |
21 | /// Draws rounded hexagon shape imitating Humon Hex device.
22 | void drawHexagon(Canvas canvas, Size size, Paint paint) {
23 | paint.color = _backgroundColor;
24 | paint.strokeWidth = size.width * 0.5;
25 | paint.strokeJoin = StrokeJoin.round;
26 | paint.style = PaintingStyle.stroke;
27 | var path = Path();
28 | path.addPolygon([
29 | Offset(size.width * 0.25, size.height * 0.375),
30 | Offset(size.width * 0.5, size.height * 0.25),
31 | Offset(size.width * 0.75, size.height * 0.375),
32 | Offset(size.width * 0.75, size.height * 0.625),
33 | Offset(size.width * 0.5, size.height * 0.75),
34 | Offset(size.width * 0.25, size.height * 0.625)
35 | ], true);
36 | canvas.drawPath(path, paint);
37 | }
38 |
39 | /// Draws Humon Hex button.
40 | void drawButton(Canvas canvas, Size size, Paint paint) {
41 | paint.color = _foregroundColor;
42 | paint.style = PaintingStyle.fill;
43 | canvas.drawCircle(Offset(size.width * 0.5, size.height * 0.23),
44 | size.height * 0.08, paint);
45 | }
46 |
47 | @override
48 | bool shouldRepaint(CustomPainter oldDelegate) => false;
49 | }
50 |
--------------------------------------------------------------------------------
/example/lib/di/ble_adapter_injector.dart:
--------------------------------------------------------------------------------
1 | import 'package:blemulator_example/adapter/ble_adapter.dart';
2 | import 'package:flutter_ble_lib/flutter_ble_lib.dart';
3 | import 'package:blemulator/blemulator.dart';
4 |
5 | class BleAdapterInjector {
6 | static BleAdapter _instance;
7 |
8 | static BleAdapter get inject {
9 | _instance ??= BleAdapter(BleManager(), Blemulator());
10 | return _instance;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/example/lib/example_peripherals/generic_peripheral.dart:
--------------------------------------------------------------------------------
1 | import 'dart:typed_data';
2 |
3 | import 'package:blemulator/blemulator.dart';
4 |
5 | class GenericPeripheral extends SimulatedPeripheral {
6 | GenericPeripheral(
7 | {String name = 'Generic Peripheral',
8 | String id = 'generic-peripheral-id',
9 | int milliseconds = 1000,
10 | List services = const []})
11 | : super(
12 | name: name,
13 | id: id,
14 | advertisementInterval: Duration(milliseconds: milliseconds),
15 | services: [
16 | SimulatedService(
17 | uuid: 'F000AA00-0001-4000-B000-000000000000',
18 | isAdvertised: true,
19 | characteristics: [
20 | SimulatedCharacteristic(
21 | uuid: 'F000AA10-0001-4000-B000-000000000000',
22 | value: Uint8List.fromList([0]),
23 | convenienceName: 'Generic characteristic 1'),
24 | ],
25 | convenienceName: 'Generic service 1',
26 | ),
27 | SimulatedService(
28 | uuid: 'F000AA01-0001-4000-B000-000000000000',
29 | isAdvertised: true,
30 | characteristics: [
31 | SimulatedCharacteristic(
32 | uuid: 'F000AA11-0001-4000-B000-000000000000',
33 | value: Uint8List.fromList([0]),
34 | convenienceName: 'Generic characteristic 2'),
35 | ],
36 | convenienceName: 'Generic service 2',
37 | ),
38 | SimulatedService(
39 | uuid: 'F000AA02-0001-4000-B000-000000000000',
40 | isAdvertised: true,
41 | characteristics: [
42 | SimulatedCharacteristic(
43 | uuid: 'F000AA12-0001-4000-B000-000000000000',
44 | value: Uint8List.fromList([0]),
45 | convenienceName: 'Generic characteristic 3'),
46 | ],
47 | convenienceName: 'Generic service 3',
48 | ),
49 | SimulatedService(
50 | uuid: 'F000AA03-0001-4000-B000-000000000000',
51 | isAdvertised: true,
52 | characteristics: [
53 | SimulatedCharacteristic(
54 | uuid: 'F000AA13-0001-4000-B000-000000000000',
55 | value: Uint8List.fromList([0]),
56 | convenienceName: 'Generic characteristic 4'),
57 | ],
58 | convenienceName: 'Generic service 4',
59 | ),
60 | ],
61 | );
62 |
63 | @override
64 | Future onConnectRequest() async {
65 | await Future.delayed(Duration(milliseconds: 500));
66 | return super.onConnectRequest();
67 | }
68 |
69 | @override
70 | Future onDiscoveryRequest() async {
71 | await Future.delayed(Duration(milliseconds: 1000));
72 | return super.onDiscoveryRequest();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:blemulator_example/device_details/device_detail_view.dart';
2 | import 'package:blemulator_example/device_details/devices_details_bloc_provider.dart';
3 | import 'package:blemulator_example/devices_list/devices_bloc_provider.dart';
4 | import 'package:blemulator_example/devices_list/devices_list_view.dart';
5 | import 'package:blemulator_example/navigation/bloc.dart';
6 | import 'package:blemulator_example/navigation/route_name.dart';
7 | import 'package:blemulator_example/navigation/router.dart';
8 | import 'package:blemulator_example/styles/custom_colors.dart';
9 | import 'package:blemulator_example/styles/custom_theme.dart';
10 | import 'package:fimber/fimber.dart';
11 | import 'package:flutter/material.dart' hide Router;
12 | import 'package:flutter_bloc/flutter_bloc.dart';
13 |
14 | void main() {
15 | Fimber.plantTree(DebugTree());
16 | runApp(MyApp());
17 | }
18 |
19 | final RouteObserver routeObserver = RouteObserver();
20 |
21 | class MyApp extends StatelessWidget {
22 | final GlobalKey _navigatorKey = GlobalKey();
23 | final bool useNewExample = false;
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return useNewExample ? _buildNewExample() : _buildExample();
28 | }
29 |
30 | Widget _buildExample() {
31 | return MaterialApp(title: 'Blemulator example',
32 | theme: ThemeData(
33 | primaryColor: Color(0xFF0A3D91),
34 | accentColor: Color(0xFFCC0000),
35 | ),
36 | initialRoute: '/',
37 | routes: {
38 | '/': (context) => DevicesBlocProvider(child: DevicesListScreen()),
39 | '/details': (context) =>
40 | DeviceDetailsBlocProvider(child: DeviceDetailsView()),
41 | },
42 | navigatorObservers: [routeObserver],
43 | );
44 | }
45 |
46 | Widget _buildNewExample() {
47 | return BlocProvider(
48 | create: (context) => NavigationBloc(navigatorKey: _navigatorKey),
49 | child: MaterialApp(
50 | navigatorKey: _navigatorKey,
51 | title: 'Blemulator example',
52 | theme: ThemeData(
53 | primaryColor: CustomColors.primary,
54 | accentColor: CustomColors.accent,
55 | scaffoldBackgroundColor: CustomColors.scaffoldBackground,
56 | cardTheme: CustomTheme.card,
57 | ),
58 | initialRoute: RouteName.home,
59 | onGenerateRoute: (settings) => Router.generateRoute(settings),
60 | ),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/example/lib/model/ble_device.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:collection/collection.dart';
4 | import 'package:flutter_ble_lib/flutter_ble_lib.dart';
5 |
6 | abstract class BleDevice {
7 | String id;
8 | int counter = 0;
9 | final String name;
10 | DeviceCategory _category;
11 | bool _isConnected = false;
12 | Peripheral peripheral;
13 |
14 | bool get isConnected => _isConnected;
15 |
16 | DeviceCategory get category => _category;
17 |
18 | BleDevice(this.name, this.id, this.peripheral) {
19 | _category = _nameToCategory(name);
20 | if (name == null) {}
21 | }
22 |
23 | factory BleDevice.connected(BleDevice bleDevice) {
24 | return ConnectedBleDevice(
25 | bleDevice.name, bleDevice.id, bleDevice.peripheral);
26 | }
27 |
28 | factory BleDevice.notConnected(
29 | String name, String id, Peripheral peripheral) {
30 | return DisconnectedBleDevice(name, id, peripheral);
31 | }
32 |
33 | DeviceCategory _nameToCategory(String name) {
34 | if (name == 'SensorTag') {
35 | return DeviceCategory.sensorTag;
36 | } else if (name != null && name.startsWith('Hex')) {
37 | return DeviceCategory.hex;
38 | } else {
39 | return DeviceCategory.other;
40 | }
41 | }
42 |
43 | @override
44 | int get hashCode => 123;
45 |
46 | @override
47 | bool operator ==(other) =>
48 | other is BleDevice &&
49 | name != null &&
50 | other.name != null &&
51 | compareAsciiLowerCase(name, other.name) == 0 &&
52 | id == other.id;
53 |
54 | @override
55 | String toString() {
56 | return 'BleDevice{counter: $counter, name: $name}';
57 | }
58 |
59 | void abandon();
60 | }
61 |
62 | class DisconnectedBleDevice extends BleDevice {
63 | StreamController _devicesInConnectingProcess;
64 |
65 | DisconnectedBleDevice(String name, String id, Peripheral peripheral)
66 | : super(name ?? '', id, peripheral);
67 |
68 | @override
69 | String toString() {
70 | return 'DisconnectedBleDevice{} ${super.toString()}';
71 | }
72 |
73 | @override
74 | void abandon() {
75 | _devicesInConnectingProcess?.close();
76 | }
77 | }
78 |
79 | class ConnectedBleDevice extends BleDevice {
80 | ConnectedBleDevice(String name, String id, Peripheral peripheral)
81 | : super(name ?? '', id, peripheral);
82 |
83 | @override
84 | void abandon() {}
85 | }
86 |
87 | enum DeviceCategory { sensorTag, hex, other }
88 |
--------------------------------------------------------------------------------
/example/lib/model/ble_peripheral.dart:
--------------------------------------------------------------------------------
1 | import 'package:equatable/equatable.dart';
2 | import 'package:flutter_ble_lib/flutter_ble_lib.dart';
3 |
4 | class BlePeripheral extends Equatable {
5 | final String name;
6 | final String id;
7 | final int rssi;
8 | final bool isConnected;
9 | final BlePeripheralCategory category;
10 |
11 | BlePeripheral(this.name, this.id, this.rssi, this.isConnected, this.category);
12 |
13 | @override
14 | List