packages = new PackageList(this).getPackages();
27 | // Packages that cannot be autolinked yet can be added manually here, for example:
28 | // packages.add(new MyReactNativePackage());
29 | return packages;
30 | }
31 |
32 | @Override
33 | protected String getJSMainModuleName() {
34 | return "index";
35 | }
36 | };
37 |
38 | @Override
39 | public ReactNativeHost getReactNativeHost() {
40 | return mReactNativeHost;
41 | }
42 |
43 | @Override
44 | public void onCreate() {
45 | super.onCreate();
46 | SoLoader.init(this, /* native exopackage */ false);
47 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
48 | }
49 |
50 | /**
51 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like
52 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
53 | *
54 | * @param context
55 | * @param reactInstanceManager
56 | */
57 | private static void initializeFlipper(
58 | Context context, ReactInstanceManager reactInstanceManager) {
59 | if (BuildConfig.DEBUG) {
60 | try {
61 | /*
62 | We use reflection here to pick up the class that initializes Flipper,
63 | since Flipper library is not available in release mode
64 | */
65 | Class> aClass = Class.forName("com.contacttracerexample.ReactNativeFlipper");
66 | aClass
67 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
68 | .invoke(null, context, reactInstanceManager);
69 | } catch (ClassNotFoundException e) {
70 | e.printStackTrace();
71 | } catch (NoSuchMethodException e) {
72 | e.printStackTrace();
73 | } catch (IllegalAccessException e) {
74 | e.printStackTrace();
75 | } catch (InvocationTargetException e) {
76 | e.printStackTrace();
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/java/com/contacttracerexample/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.contacttracerexample;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceManager;
23 | import com.facebook.react.bridge.ReactContext;
24 | import com.facebook.react.modules.network.NetworkingModule;
25 | import okhttp3.OkHttpClient;
26 |
27 | public class ReactNativeFlipper {
28 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
29 | if (FlipperUtils.shouldEnableFlipper(context)) {
30 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
31 |
32 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
33 | client.addPlugin(new ReactFlipperPlugin());
34 | client.addPlugin(new DatabasesFlipperPlugin(context));
35 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
36 | client.addPlugin(CrashReporterPlugin.getInstance());
37 |
38 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
39 | NetworkingModule.setCustomClientBuilder(
40 | new NetworkingModule.CustomClientBuilder() {
41 | @Override
42 | public void apply(OkHttpClient.Builder builder) {
43 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
44 | }
45 | });
46 | client.addPlugin(networkFlipperPlugin);
47 | client.start();
48 |
49 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
50 | // Hence we run if after all native modules have been initialized
51 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
52 | if (reactContext == null) {
53 | reactInstanceManager.addReactInstanceEventListener(
54 | new ReactInstanceManager.ReactInstanceEventListener() {
55 | @Override
56 | public void onReactContextInitialized(ReactContext reactContext) {
57 | reactInstanceManager.removeReactInstanceEventListener(this);
58 | reactContext.runOnNativeModulesQueueThread(
59 | new Runnable() {
60 | @Override
61 | public void run() {
62 | client.addPlugin(new FrescoFlipperPlugin());
63 | }
64 | });
65 | }
66 | });
67 | } else {
68 | client.addPlugin(new FrescoFlipperPlugin());
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/example/ios/ContactTracerExample.xcodeproj/xcshareddata/xcschemes/ContactTracerExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/example/ios/ContactTracerExample/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example/ios/ContactTracerExample.xcodeproj/xcshareddata/xcschemes/ContactTracerExample-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '9.0'
2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
3 |
4 | def add_flipper_pods!(versions = {})
5 | versions['Flipper'] ||= '~> 0.33.1'
6 | versions['DoubleConversion'] ||= '1.1.7'
7 | versions['Flipper-Folly'] ||= '~> 2.1'
8 | versions['Flipper-Glog'] ||= '0.3.6'
9 | versions['Flipper-PeerTalk'] ||= '~> 0.0.4'
10 | versions['Flipper-RSocket'] ||= '~> 1.0'
11 |
12 | pod 'FlipperKit', versions['Flipper'], :configuration => 'Debug'
13 | pod 'FlipperKit/FlipperKitLayoutPlugin', versions['Flipper'], :configuration => 'Debug'
14 | pod 'FlipperKit/SKIOSNetworkPlugin', versions['Flipper'], :configuration => 'Debug'
15 | pod 'FlipperKit/FlipperKitUserDefaultsPlugin', versions['Flipper'], :configuration => 'Debug'
16 | pod 'FlipperKit/FlipperKitReactPlugin', versions['Flipper'], :configuration => 'Debug'
17 |
18 | # List all transitive dependencies for FlipperKit pods
19 | # to avoid them being linked in Release builds
20 | pod 'Flipper', versions['Flipper'], :configuration => 'Debug'
21 | pod 'Flipper-DoubleConversion', versions['DoubleConversion'], :configuration => 'Debug'
22 | pod 'Flipper-Folly', versions['Flipper-Folly'], :configuration => 'Debug'
23 | pod 'Flipper-Glog', versions['Flipper-Glog'], :configuration => 'Debug'
24 | pod 'Flipper-PeerTalk', versions['Flipper-PeerTalk'], :configuration => 'Debug'
25 | pod 'Flipper-RSocket', versions['Flipper-RSocket'], :configuration => 'Debug'
26 | pod 'FlipperKit/Core', versions['Flipper'], :configuration => 'Debug'
27 | pod 'FlipperKit/CppBridge', versions['Flipper'], :configuration => 'Debug'
28 | pod 'FlipperKit/FBCxxFollyDynamicConvert', versions['Flipper'], :configuration => 'Debug'
29 | pod 'FlipperKit/FBDefines', versions['Flipper'], :configuration => 'Debug'
30 | pod 'FlipperKit/FKPortForwarding', versions['Flipper'], :configuration => 'Debug'
31 | pod 'FlipperKit/FlipperKitHighlightOverlay', versions['Flipper'], :configuration => 'Debug'
32 | pod 'FlipperKit/FlipperKitLayoutTextSearchable', versions['Flipper'], :configuration => 'Debug'
33 | pod 'FlipperKit/FlipperKitNetworkPlugin', versions['Flipper'], :configuration => 'Debug'
34 | end
35 |
36 | # Post Install processing for Flipper
37 | def flipper_post_install(installer)
38 | installer.pods_project.targets.each do |target|
39 | if target.name == 'YogaKit'
40 | target.build_configurations.each do |config|
41 | config.build_settings['SWIFT_VERSION'] = '4.1'
42 | end
43 | end
44 | end
45 | end
46 |
47 | target 'ContactTracerExample' do
48 | # Pods for ContactTracerExample
49 | pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
50 | pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
51 | pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
52 | pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
53 | pod 'React', :path => '../node_modules/react-native/'
54 | pod 'React-Core', :path => '../node_modules/react-native/'
55 | pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
56 | pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
57 | pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
58 | pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
59 | pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
60 | pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
61 | pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
62 | pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
63 | pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
64 | pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
65 | pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
66 | pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
67 |
68 | pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
69 | pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
70 | pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
71 | pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
72 | pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon"
73 | pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
74 | pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true
75 |
76 | pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
77 | pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
78 | pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
79 |
80 | target 'ContactTracerExampleTests' do
81 | inherit! :complete
82 | # Pods for testing
83 | end
84 |
85 | use_native_modules!
86 |
87 | # Enables Flipper.
88 | #
89 | # Note that if you have use_frameworks! enabled, Flipper will not work and
90 | # you should disable these next few lines.
91 | add_flipper_pods!
92 | post_install do |installer|
93 | flipper_post_install(installer)
94 | end
95 | end
96 |
97 | target 'ContactTracerExample-tvOS' do
98 | # Pods for ContactTracerExample-tvOS
99 |
100 | target 'ContactTracerExample-tvOSTests' do
101 | inherit! :search_paths
102 | # Pods for testing
103 | end
104 | end
105 |
--------------------------------------------------------------------------------
/windows/RNContactTracer.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio 14
3 | VisualStudioVersion = 14.0.25123.0
4 | MinimumVisualStudioVersion = 10.0.40219.1
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RNContactTracer", "RNContactTracer\RNContactTracer.csproj", "{308C61D0-7627-11EA-B453-3FA25FCF513C}"
6 | EndProject
7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactNative", "..\node_modules\react-native-windows\ReactWindows\ReactNative\ReactNative.csproj", "{C7673AD5-E3AA-468C-A5FD-FA38154E205C}"
8 | EndProject
9 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ReactNative.Shared", "..\node_modules\react-native-windows\ReactWindows\ReactNative.Shared\ReactNative.Shared.shproj", "{EEA8B852-4D07-48E1-8294-A21AB5909FE5}"
10 | EndProject
11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChakraBridge", "..\node_modules\react-native-windows\ReactWindows\ChakraBridge\ChakraBridge.vcxproj", "{4B72C796-16D5-4E3A-81C0-3E36F531E578}"
12 | EndProject
13 | Global
14 | GlobalSection(SharedMSBuildProjectFiles) = preSolution
15 | ..\node_modules\react-native-windows\ReactWindows\ReactNative.Shared\ReactNative.Shared.projitems*{c7673ad5-e3aa-468c-a5fd-fa38154e205c}*SharedItemsImports = 4
16 | ..\node_modules\react-native-windows\ReactWindows\ReactNative.Shared\ReactNative.Shared.projitems*{eea8b852-4d07-48e1-8294-a21ab5909fe5}*SharedItemsImports = 13
17 | EndGlobalSection
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|ARM = Debug|ARM
20 | Debug|x64 = Debug|x64
21 | Debug|x86 = Debug|x86
22 | Development|ARM = Development|ARM
23 | Development|x64 = Development|x64
24 | Development|x86 = Development|x86
25 | Release|ARM = Release|ARM
26 | Release|x64 = Release|x64
27 | Release|x86 = Release|x86
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Debug|ARM.ActiveCfg = Debug|ARM
31 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Debug|ARM.Build.0 = Debug|ARM
32 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Debug|x64.ActiveCfg = Debug|x64
33 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Debug|x64.Build.0 = Debug|x64
34 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Debug|x86.ActiveCfg = Debug|x86
35 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Debug|x86.Build.0 = Debug|x86
36 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Development|ARM.ActiveCfg = Development|ARM
37 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Development|ARM.Build.0 = Development|ARM
38 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Development|x64.ActiveCfg = Development|x64
39 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Development|x64.Build.0 = Development|x64
40 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Development|x86.ActiveCfg = Development|x86
41 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Development|x86.Build.0 = Development|x86
42 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Release|ARM.ActiveCfg = Release|ARM
43 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Release|ARM.Build.0 = Release|ARM
44 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Release|x64.ActiveCfg = Release|x64
45 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Release|x64.Build.0 = Release|x64
46 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Release|x86.ActiveCfg = Release|x86
47 | {308C61D0-7627-11EA-B453-3FA25FCF513C}.Release|x86.Build.0 = Release|x86
48 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|ARM.ActiveCfg = Debug|ARM
49 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|ARM.Build.0 = Debug|ARM
50 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x64.ActiveCfg = Debug|x64
51 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x64.Build.0 = Debug|x64
52 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x86.ActiveCfg = Debug|x86
53 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x86.Build.0 = Debug|x86
54 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Development|ARM.ActiveCfg = Debug|ARM
55 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Development|ARM.Build.0 = Debug|ARM
56 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Development|x64.ActiveCfg = Debug|x64
57 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Development|x64.Build.0 = Debug|x64
58 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Development|x86.ActiveCfg = Debug|x86
59 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Development|x86.Build.0 = Debug|x86
60 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|ARM.ActiveCfg = Release|ARM
61 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|ARM.Build.0 = Release|ARM
62 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x64.ActiveCfg = Release|x64
63 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x64.Build.0 = Release|x64
64 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x86.ActiveCfg = Release|x86
65 | {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x86.Build.0 = Release|x86
66 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|ARM.ActiveCfg = Debug|ARM
67 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|ARM.Build.0 = Debug|ARM
68 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x64.ActiveCfg = Debug|x64
69 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x64.Build.0 = Debug|x64
70 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x86.ActiveCfg = Debug|Win32
71 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x86.Build.0 = Debug|Win32
72 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Development|ARM.ActiveCfg = Debug|ARM
73 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Development|ARM.Build.0 = Debug|ARM
74 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Development|x64.ActiveCfg = Debug|x64
75 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Development|x64.Build.0 = Debug|x64
76 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Development|x86.ActiveCfg = Debug|Win32
77 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Development|x86.Build.0 = Debug|Win32
78 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|ARM.ActiveCfg = Release|ARM
79 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|ARM.Build.0 = Release|ARM
80 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x64.ActiveCfg = Release|x64
81 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x64.Build.0 = Release|x64
82 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x86.ActiveCfg = Release|Win32
83 | {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x86.Build.0 = Release|Win32
84 | EndGlobalSection
85 | GlobalSection(SolutionProperties) = preSolution
86 | HideSolutionNode = FALSE
87 | EndGlobalSection
88 | EndGlobal
89 |
--------------------------------------------------------------------------------
/android/src/main/java/com/nuuneoi/lib/contacttracer/utils/ParseLeAdvData.java:
--------------------------------------------------------------------------------
1 | package com.nuuneoi.lib.contacttracer.utils;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.Serializable;
6 | import java.util.*;
7 |
8 | public final class ParseLeAdvData {
9 | private final static String TAG = "ParseLeAdvData";
10 |
11 | // =LE �㲥����������
12 | public static final short BLE_GAP_AD_TYPE_FLAGS = 0x01;
13 | /** < Flags for discoverability. */
14 | public static final short BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE = 0x02;
15 | /** < Partial list of 16 bit service UUIDs. */
16 | public static final short BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE = 0x03;
17 | /** < Complete list of 16 bit service UUIDs. */
18 | public static final short BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE = 0x04;
19 | /** < Partial list of 32 bit service UUIDs. */
20 | public static final short BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE = 0x05;
21 | /** < Complete list of 32 bit service UUIDs. */
22 | public static final short BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE = 0x06;
23 | /** < Partial list of 128 bit service UUIDs. */
24 | public static final short BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE = 0x07;
25 | /** < Complete list of 128 bit service UUIDs. */
26 | public static final short BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME = 0x08;
27 | /** < Short local device name. */
28 | public static final short BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME = 0x09;
29 | /** < Complete local device name. */
30 | public static final short BLE_GAP_AD_TYPE_TX_POWER_LEVEL = 0x0A;
31 | /** < Transmit power level. */
32 | public static final short BLE_GAP_AD_TYPE_CLASS_OF_DEVICE = 0x0D;
33 | /** < Class of device. */
34 | public static final short BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C = 0x0E;
35 | /** < Simple Pairing Hash C. */
36 | public static final short BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F;
37 | /** < Simple Pairing Randomizer R. */
38 | public static final short BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE = 0x10;
39 | /** < Security Manager TK Value. */
40 | public static final short BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS = 0x11;
41 | /** < Security Manager Out Of Band Flags. */
42 | public static final short BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE = 0x12;
43 | /** < Slave Connection Interval Range. */
44 | public static final short BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT = 0x14;
45 | /** < List of 16-bit Service Solicitation UUIDs. */
46 | public static final short BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT = 0x15;
47 | /** < List of 128-bit Service Solicitation UUIDs. */
48 | public static final short BLE_GAP_AD_TYPE_SERVICE_DATA = 0x16;
49 | /** < Service Data. */
50 | public static final short BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS = 0x17;
51 | /** < Public Target Address. */
52 | public static final short BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS = 0x18;
53 | /** < Random Target Address. */
54 | public static final short BLE_GAP_AD_TYPE_APPEARANCE = 0x19;
55 | /** < Appearance. */
56 | public static final short BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
57 |
58 | /** < Manufacturer Specific Data. */
59 |
60 |
61 | public ParseLeAdvData() {
62 | Log.d(TAG, "ParseLeAdvData init....");
63 | }
64 |
65 | /////// �����㲥����/////////////////////////
66 | public static byte[] adv_report_parse(short type, byte[] adv_data) {
67 | int index = 0;
68 | int length;
69 |
70 | byte[] data;
71 |
72 | byte field_type = 0;
73 | byte field_length = 0;
74 |
75 | length = adv_data.length;
76 | while (index < length) {
77 | try {
78 | field_length = adv_data[index];
79 | field_type = adv_data[index + 1];
80 | } catch (Exception e) {
81 | Log.d(TAG, "There is a exception here.");
82 | return null;
83 | }
84 |
85 | if (field_type == (byte) type) {
86 | data = new byte[field_length - 1];
87 |
88 | byte i;
89 | for (i = 0; i < field_length - 1; i++) {
90 | data[i] = adv_data[index + 2 + i];
91 | }
92 | return data;
93 | }
94 | index += field_length + 1;
95 | if (index >= 60) {
96 | return null;
97 | }
98 | }
99 | return null;
100 | }
101 |
102 | public static List parse_iBeacon_info(byte[] adv_data)
103 | {
104 | byte[] type_data =ParseLeAdvData.adv_report_parse(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA,adv_data);
105 |
106 | if(type_data!=null)
107 | {
108 | if(type_data.length==25)
109 | {
110 | if((type_data[0] == 0x4C) && (type_data[1] == 0x00))
111 | {
112 | byte[] uuid = new byte[16];
113 | for(int i = 0;i < 16;i++)
114 | {
115 | uuid[i] = type_data[4+i];
116 | }
117 | int major = (type_data[20]<<8)| type_data[21]; //major
118 | int minor = (type_data[22]<<8)| type_data[23]; //minor
119 | int rssi_at_1m = (int)type_data[24]; //rssi_at_1m
120 |
121 | return Arrays.asList(ByteArrToHex(uuid), Integer.toString(major), Integer.toString(minor), Integer.toString(rssi_at_1m));
122 | }
123 | return null;
124 |
125 | }
126 | return null;
127 |
128 | }
129 | return null;
130 | }
131 |
132 |
133 | private static String Byte2Hex(Byte paramByte) {
134 | Object[] arrayOfObject = new Object[1];
135 | arrayOfObject[0] = paramByte;
136 | return String.format("%02x", arrayOfObject).toUpperCase();
137 | }
138 |
139 | private static String ByteArrToHex(byte[] paramArrayOfByte) {
140 | StringBuilder localStringBuilder = new StringBuilder();
141 | int i = paramArrayOfByte.length;
142 | for (int j = 0; j < i; j++) {
143 | localStringBuilder.append(Byte2Hex(Byte.valueOf(paramArrayOfByte[j])));
144 | // localStringBuilder.append(" ");
145 | }
146 | return localStringBuilder.toString();
147 | }
148 |
149 | public static byte[] HexToByteArr(String paramString) {
150 | int j = paramString.length();
151 | byte[] arrayOfByte;
152 | if (isOdd(j) != 1) {
153 | arrayOfByte = new byte[j / 2];
154 | } else {
155 | j++;
156 | arrayOfByte = new byte[j / 2];
157 | paramString = "0" + paramString;
158 | }
159 | int k = 0;
160 | for (int i = 0; i < j; i += 2) {
161 | arrayOfByte[k] = HexToByte(paramString.substring(i, i + 2));
162 | k++;
163 | }
164 | return arrayOfByte;
165 | }
166 |
167 | public static byte HexToByte(String paramString) {
168 | paramString.replace(" ", "");
169 | return (byte) Integer.parseInt(paramString, 16);
170 | }
171 |
172 | public static int isOdd(int paramInt) {
173 | return paramInt & 0x1;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ] ; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ] ; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109 | MAX_FD_LIMIT=`ulimit -H -n`
110 | if [ $? -eq 0 ] ; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ] ; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin or MSYS, switch paths to Windows format before running java
129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 | JAVACMD=`cygpath --unix "$JAVACMD"`
133 |
134 | # We build the pattern for arguments to be converted via cygpath
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136 | SEP=""
137 | for dir in $ROOTDIRSRAW ; do
138 | ROOTDIRS="$ROOTDIRS$SEP$dir"
139 | SEP="|"
140 | done
141 | OURCYGPATTERN="(^($ROOTDIRS))"
142 | # Add a user-defined pattern to the cygpath arguments
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145 | fi
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
147 | i=0
148 | for arg in "$@" ; do
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
151 |
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154 | else
155 | eval `echo args$i`="\"$arg\""
156 | fi
157 | i=$((i+1))
158 | done
159 | case $i in
160 | (0) set -- ;;
161 | (1) set -- "$args0" ;;
162 | (2) set -- "$args0" "$args1" ;;
163 | (3) set -- "$args0" "$args1" "$args2" ;;
164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 | esac
171 | fi
172 |
173 | # Escape application args
174 | save () {
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 | echo " "
177 | }
178 | APP_ARGS=$(save "$@")
179 |
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 |
183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
185 | cd "$(dirname "$0")"
186 | fi
187 |
188 | exec "$JAVACMD" "$@"
189 |
--------------------------------------------------------------------------------
/windows/RNContactTracer/RNContactTracer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x86
7 | {308C61D0-7627-11EA-B453-3FA25FCF513C}
8 | Library
9 | Properties
10 | Contact.Tracer
11 | Contact.Tracer
12 | en-US
13 | UAP
14 | 10.0.10586.0
15 | 10.0.10240.0
16 | 14
17 | 512
18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 | ..\..\node_modules
20 |
21 |
22 | ..\..
23 |
24 |
25 | x86
26 | true
27 | bin\x86\Debug\
28 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
29 | ;2008
30 | full
31 | x86
32 | false
33 | prompt
34 |
35 |
36 | x86
37 | bin\x86\Release\
38 | TRACE;NETFX_CORE;WINDOWS_UWP
39 | true
40 | ;2008
41 | pdbonly
42 | x86
43 | false
44 | prompt
45 |
46 |
47 | ARM
48 | true
49 | bin\ARM\Debug\
50 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
51 | ;2008
52 | full
53 | ARM
54 | false
55 | prompt
56 |
57 |
58 | ARM
59 | bin\ARM\Release\
60 | TRACE;NETFX_CORE;WINDOWS_UWP
61 | true
62 | ;2008
63 | pdbonly
64 | ARM
65 | false
66 | prompt
67 |
68 |
69 | x64
70 | true
71 | bin\x64\Debug\
72 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
73 | ;2008
74 | full
75 | x64
76 | false
77 | prompt
78 |
79 |
80 | x64
81 | bin\x64\Release\
82 | TRACE;NETFX_CORE;WINDOWS_UWP
83 | true
84 | ;2008
85 | pdbonly
86 | x64
87 | false
88 | prompt
89 |
90 |
91 | true
92 | bin\x86\Development\
93 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
94 | ;2008
95 | true
96 | full
97 | x86
98 | false
99 | prompt
100 | MinimumRecommendedRules.ruleset
101 |
102 |
103 | true
104 | bin\ARM\Development\
105 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
106 | ;2008
107 | true
108 | full
109 | ARM
110 | false
111 | prompt
112 | MinimumRecommendedRules.ruleset
113 |
114 |
115 | true
116 | bin\x64\Development\
117 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
118 | ;2008
119 | true
120 | full
121 | x64
122 | false
123 | prompt
124 | MinimumRecommendedRules.ruleset
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 | {c7673ad5-e3aa-468c-a5fd-fa38154e205c}
139 | ReactNative
140 |
141 |
142 |
143 | 14.0
144 |
145 |
146 |
153 |
154 |
--------------------------------------------------------------------------------
/ios/ContactTracer.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B3E7B58A1CC2AC0600A0062D /* RNContactTracer.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNContactTracer.m */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 58B511D91A9E6C8500147676 /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = "include/$(PRODUCT_NAME)";
18 | dstSubfolderSpec = 16;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 0;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 134814201AA4EA6300B7C361 /* libRNContactTracer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNContactTracer.a; sourceTree = BUILT_PRODUCTS_DIR; };
27 | B3E7B5881CC2AC0600A0062D /* RNContactTracer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNContactTracer.h; sourceTree = ""; };
28 | B3E7B5891CC2AC0600A0062D /* RNContactTracer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNContactTracer.m; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 58B511D81A9E6C8500147676 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 134814211AA4EA7D00B7C361 /* Products */ = {
43 | isa = PBXGroup;
44 | children = (
45 | 134814201AA4EA6300B7C361 /* libRNContactTracer.a */,
46 | );
47 | name = Products;
48 | sourceTree = "";
49 | };
50 | 58B511D21A9E6C8500147676 = {
51 | isa = PBXGroup;
52 | children = (
53 | B3E7B5881CC2AC0600A0062D /* RNContactTracer.h */,
54 | B3E7B5891CC2AC0600A0062D /* RNContactTracer.m */,
55 | 134814211AA4EA7D00B7C361 /* Products */,
56 | );
57 | sourceTree = "";
58 | };
59 | /* End PBXGroup section */
60 |
61 | /* Begin PBXNativeTarget section */
62 | 58B511DA1A9E6C8500147676 /* RNContactTracer */ = {
63 | isa = PBXNativeTarget;
64 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNContactTracer" */;
65 | buildPhases = (
66 | 58B511D71A9E6C8500147676 /* Sources */,
67 | 58B511D81A9E6C8500147676 /* Frameworks */,
68 | 58B511D91A9E6C8500147676 /* CopyFiles */,
69 | );
70 | buildRules = (
71 | );
72 | dependencies = (
73 | );
74 | name = RNContactTracer;
75 | productName = RCTDataManager;
76 | productReference = 134814201AA4EA6300B7C361 /* libRNContactTracer.a */;
77 | productType = "com.apple.product-type.library.static";
78 | };
79 | /* End PBXNativeTarget section */
80 |
81 | /* Begin PBXProject section */
82 | 58B511D31A9E6C8500147676 /* Project object */ = {
83 | isa = PBXProject;
84 | attributes = {
85 | LastUpgradeCheck = 0830;
86 | ORGANIZATIONNAME = Facebook;
87 | TargetAttributes = {
88 | 58B511DA1A9E6C8500147676 = {
89 | CreatedOnToolsVersion = 6.1.1;
90 | };
91 | };
92 | };
93 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNContactTracer" */;
94 | compatibilityVersion = "Xcode 3.2";
95 | developmentRegion = English;
96 | hasScannedForEncodings = 0;
97 | knownRegions = (
98 | en,
99 | );
100 | mainGroup = 58B511D21A9E6C8500147676;
101 | productRefGroup = 58B511D21A9E6C8500147676;
102 | projectDirPath = "";
103 | projectRoot = "";
104 | targets = (
105 | 58B511DA1A9E6C8500147676 /* RNContactTracer */,
106 | );
107 | };
108 | /* End PBXProject section */
109 |
110 | /* Begin PBXSourcesBuildPhase section */
111 | 58B511D71A9E6C8500147676 /* Sources */ = {
112 | isa = PBXSourcesBuildPhase;
113 | buildActionMask = 2147483647;
114 | files = (
115 | B3E7B58A1CC2AC0600A0062D /* RNContactTracer.m in Sources */,
116 | );
117 | runOnlyForDeploymentPostprocessing = 0;
118 | };
119 | /* End PBXSourcesBuildPhase section */
120 |
121 | /* Begin XCBuildConfiguration section */
122 | 58B511ED1A9E6C8500147676 /* Debug */ = {
123 | isa = XCBuildConfiguration;
124 | buildSettings = {
125 | ALWAYS_SEARCH_USER_PATHS = NO;
126 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
127 | CLANG_CXX_LIBRARY = "libc++";
128 | CLANG_ENABLE_MODULES = YES;
129 | CLANG_ENABLE_OBJC_ARC = YES;
130 | CLANG_WARN_BOOL_CONVERSION = YES;
131 | CLANG_WARN_CONSTANT_CONVERSION = YES;
132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
133 | CLANG_WARN_EMPTY_BODY = YES;
134 | CLANG_WARN_ENUM_CONVERSION = YES;
135 | CLANG_WARN_INFINITE_RECURSION = YES;
136 | CLANG_WARN_INT_CONVERSION = YES;
137 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
138 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
139 | CLANG_WARN_UNREACHABLE_CODE = YES;
140 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
141 | COPY_PHASE_STRIP = NO;
142 | ENABLE_STRICT_OBJC_MSGSEND = YES;
143 | ENABLE_TESTABILITY = YES;
144 | GCC_C_LANGUAGE_STANDARD = gnu99;
145 | GCC_DYNAMIC_NO_PIC = NO;
146 | GCC_NO_COMMON_BLOCKS = YES;
147 | GCC_OPTIMIZATION_LEVEL = 0;
148 | GCC_PREPROCESSOR_DEFINITIONS = (
149 | "DEBUG=1",
150 | "$(inherited)",
151 | );
152 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
153 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
154 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
155 | GCC_WARN_UNDECLARED_SELECTOR = YES;
156 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
157 | GCC_WARN_UNUSED_FUNCTION = YES;
158 | GCC_WARN_UNUSED_VARIABLE = YES;
159 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
160 | MTL_ENABLE_DEBUG_INFO = YES;
161 | ONLY_ACTIVE_ARCH = YES;
162 | SDKROOT = iphoneos;
163 | };
164 | name = Debug;
165 | };
166 | 58B511EE1A9E6C8500147676 /* Release */ = {
167 | isa = XCBuildConfiguration;
168 | buildSettings = {
169 | ALWAYS_SEARCH_USER_PATHS = NO;
170 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
171 | CLANG_CXX_LIBRARY = "libc++";
172 | CLANG_ENABLE_MODULES = YES;
173 | CLANG_ENABLE_OBJC_ARC = YES;
174 | CLANG_WARN_BOOL_CONVERSION = YES;
175 | CLANG_WARN_CONSTANT_CONVERSION = YES;
176 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
177 | CLANG_WARN_EMPTY_BODY = YES;
178 | CLANG_WARN_ENUM_CONVERSION = YES;
179 | CLANG_WARN_INFINITE_RECURSION = YES;
180 | CLANG_WARN_INT_CONVERSION = YES;
181 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
182 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
183 | CLANG_WARN_UNREACHABLE_CODE = YES;
184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
185 | COPY_PHASE_STRIP = YES;
186 | ENABLE_NS_ASSERTIONS = NO;
187 | ENABLE_STRICT_OBJC_MSGSEND = YES;
188 | GCC_C_LANGUAGE_STANDARD = gnu99;
189 | GCC_NO_COMMON_BLOCKS = YES;
190 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
191 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
192 | GCC_WARN_UNDECLARED_SELECTOR = YES;
193 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
194 | GCC_WARN_UNUSED_FUNCTION = YES;
195 | GCC_WARN_UNUSED_VARIABLE = YES;
196 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
197 | MTL_ENABLE_DEBUG_INFO = NO;
198 | SDKROOT = iphoneos;
199 | VALIDATE_PRODUCT = YES;
200 | };
201 | name = Release;
202 | };
203 | 58B511F01A9E6C8500147676 /* Debug */ = {
204 | isa = XCBuildConfiguration;
205 | buildSettings = {
206 | HEADER_SEARCH_PATHS = (
207 | "$(inherited)",
208 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
209 | "$(SRCROOT)/../../../React/**",
210 | "$(SRCROOT)/../../react-native/React/**",
211 | );
212 | LIBRARY_SEARCH_PATHS = "$(inherited)";
213 | OTHER_LDFLAGS = "-ObjC";
214 | PRODUCT_NAME = RNContactTracer;
215 | SKIP_INSTALL = YES;
216 | };
217 | name = Debug;
218 | };
219 | 58B511F11A9E6C8500147676 /* Release */ = {
220 | isa = XCBuildConfiguration;
221 | buildSettings = {
222 | HEADER_SEARCH_PATHS = (
223 | "$(inherited)",
224 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
225 | "$(SRCROOT)/../../../React/**",
226 | "$(SRCROOT)/../../react-native/React/**",
227 | );
228 | LIBRARY_SEARCH_PATHS = "$(inherited)";
229 | OTHER_LDFLAGS = "-ObjC";
230 | PRODUCT_NAME = RNContactTracer;
231 | SKIP_INSTALL = YES;
232 | };
233 | name = Release;
234 | };
235 | /* End XCBuildConfiguration section */
236 |
237 | /* Begin XCConfigurationList section */
238 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNContactTracer" */ = {
239 | isa = XCConfigurationList;
240 | buildConfigurations = (
241 | 58B511ED1A9E6C8500147676 /* Debug */,
242 | 58B511EE1A9E6C8500147676 /* Release */,
243 | );
244 | defaultConfigurationIsVisible = 0;
245 | defaultConfigurationName = Release;
246 | };
247 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNContactTracer" */ = {
248 | isa = XCConfigurationList;
249 | buildConfigurations = (
250 | 58B511F01A9E6C8500147676 /* Debug */,
251 | 58B511F11A9E6C8500147676 /* Release */,
252 | );
253 | defaultConfigurationIsVisible = 0;
254 | defaultConfigurationName = Release;
255 | };
256 | /* End XCConfigurationList section */
257 | };
258 | rootObject = 58B511D31A9E6C8500147676 /* Project object */;
259 | }
260 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation. If none specified and
19 | * // "index.android.js" exists, it will be used. Otherwise "index.js" is
20 | * // default. Can be overridden with ENTRY_FILE environment variable.
21 | * entryFile: "index.android.js",
22 | *
23 | * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
24 | * bundleCommand: "ram-bundle",
25 | *
26 | * // whether to bundle JS and assets in debug mode
27 | * bundleInDebug: false,
28 | *
29 | * // whether to bundle JS and assets in release mode
30 | * bundleInRelease: true,
31 | *
32 | * // whether to bundle JS and assets in another build variant (if configured).
33 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
34 | * // The configuration property can be in the following formats
35 | * // 'bundleIn${productFlavor}${buildType}'
36 | * // 'bundleIn${buildType}'
37 | * // bundleInFreeDebug: true,
38 | * // bundleInPaidRelease: true,
39 | * // bundleInBeta: true,
40 | *
41 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
42 | * // for example: to disable dev mode in the staging build type (if configured)
43 | * devDisabledInStaging: true,
44 | * // The configuration property can be in the following formats
45 | * // 'devDisabledIn${productFlavor}${buildType}'
46 | * // 'devDisabledIn${buildType}'
47 | *
48 | * // the root of your project, i.e. where "package.json" lives
49 | * root: "../../",
50 | *
51 | * // where to put the JS bundle asset in debug mode
52 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
53 | *
54 | * // where to put the JS bundle asset in release mode
55 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
56 | *
57 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
58 | * // require('./image.png')), in debug mode
59 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
60 | *
61 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
62 | * // require('./image.png')), in release mode
63 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
64 | *
65 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
66 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
67 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
68 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
69 | * // for example, you might want to remove it from here.
70 | * inputExcludes: ["android/**", "ios/**"],
71 | *
72 | * // override which node gets called and with what additional arguments
73 | * nodeExecutableAndArgs: ["node"],
74 | *
75 | * // supply additional arguments to the packager
76 | * extraPackagerArgs: []
77 | * ]
78 | */
79 |
80 | project.ext.react = [
81 | enableHermes: false, // clean and rebuild if changing
82 | bundleAssetName: "index.android.bundle",
83 | bundleInDebug: true,
84 | bundleInRelease: true
85 | ]
86 |
87 | apply from: "../../node_modules/react-native/react.gradle"
88 |
89 | /**
90 | * Set this to true to create two separate APKs instead of one:
91 | * - An APK that only works on ARM devices
92 | * - An APK that only works on x86 devices
93 | * The advantage is the size of the APK is reduced by about 4MB.
94 | * Upload all the APKs to the Play Store and people will download
95 | * the correct one based on the CPU architecture of their device.
96 | */
97 | def enableSeparateBuildPerCPUArchitecture = false
98 |
99 | /**
100 | * Run Proguard to shrink the Java bytecode in release builds.
101 | */
102 | def enableProguardInReleaseBuilds = false
103 |
104 | /**
105 | * The preferred build flavor of JavaScriptCore.
106 | *
107 | * For example, to use the international variant, you can use:
108 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
109 | *
110 | * The international variant includes ICU i18n library and necessary data
111 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
112 | * give correct results when using with locales other than en-US. Note that
113 | * this variant is about 6MiB larger per architecture than default.
114 | */
115 | def jscFlavor = 'org.webkit:android-jsc:+'
116 |
117 | /**
118 | * Whether to enable the Hermes VM.
119 | *
120 | * This should be set on project.ext.react and mirrored here. If it is not set
121 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
122 | * and the benefits of using Hermes will therefore be sharply reduced.
123 | */
124 | def enableHermes = project.ext.react.get("enableHermes", false);
125 |
126 | android {
127 | compileSdkVersion rootProject.ext.compileSdkVersion
128 |
129 | compileOptions {
130 | sourceCompatibility JavaVersion.VERSION_1_8
131 | targetCompatibility JavaVersion.VERSION_1_8
132 | }
133 |
134 | defaultConfig {
135 | applicationId "com.contacttracerexample"
136 | minSdkVersion rootProject.ext.minSdkVersion
137 | targetSdkVersion rootProject.ext.targetSdkVersion
138 | versionCode 1
139 | versionName "1.0"
140 | }
141 | splits {
142 | abi {
143 | reset()
144 | enable enableSeparateBuildPerCPUArchitecture
145 | universalApk false // If true, also generate a universal APK
146 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
147 | }
148 | }
149 | signingConfigs {
150 | debug {
151 | storeFile file('debug.keystore')
152 | storePassword 'android'
153 | keyAlias 'androiddebugkey'
154 | keyPassword 'android'
155 | }
156 | }
157 | buildTypes {
158 | debug {
159 | signingConfig signingConfigs.debug
160 | }
161 | release {
162 | // Caution! In production, you need to generate your own keystore file.
163 | // see https://facebook.github.io/react-native/docs/signed-apk-android.
164 | signingConfig signingConfigs.debug
165 | minifyEnabled enableProguardInReleaseBuilds
166 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
167 | }
168 | }
169 |
170 | packagingOptions {
171 | pickFirst "lib/armeabi-v7a/libc++_shared.so"
172 | pickFirst "lib/arm64-v8a/libc++_shared.so"
173 | pickFirst "lib/x86/libc++_shared.so"
174 | pickFirst "lib/x86_64/libc++_shared.so"
175 | }
176 |
177 | // applicationVariants are e.g. debug, release
178 | applicationVariants.all { variant ->
179 | variant.outputs.each { output ->
180 | // For each separate APK per architecture, set a unique version code as described here:
181 | // https://developer.android.com/studio/build/configure-apk-splits.html
182 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
183 | def abi = output.getFilter(OutputFile.ABI)
184 | if (abi != null) { // null for the universal-debug, universal-release variants
185 | output.versionCodeOverride =
186 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
187 | }
188 |
189 | }
190 | }
191 | }
192 |
193 | dependencies {
194 | implementation fileTree(dir: "libs", include: ["*.jar"])
195 | //noinspection GradleDynamicVersion
196 | implementation "com.facebook.react:react-native:+" // From node_modules
197 |
198 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
199 |
200 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
201 | exclude group:'com.facebook.fbjni'
202 | }
203 |
204 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
205 | exclude group:'com.facebook.flipper'
206 | }
207 |
208 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
209 | exclude group:'com.facebook.flipper'
210 | }
211 |
212 | if (enableHermes) {
213 | def hermesPath = "../../node_modules/hermes-engine/android/";
214 | debugImplementation files(hermesPath + "hermes-debug.aar")
215 | releaseImplementation files(hermesPath + "hermes-release.aar")
216 | } else {
217 | implementation jscFlavor
218 | }
219 | }
220 |
221 | // Run this once to be able to run the application with BUCK
222 | // puts all compile dependencies into folder libs for BUCK to use
223 | task copyDownloadableDepsToLibs(type: Copy) {
224 | from configurations.compile
225 | into 'libs'
226 | }
227 |
228 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
229 |
--------------------------------------------------------------------------------
/example/src/App.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | * @flow strict-local
7 | */
8 |
9 | import React from 'react';
10 | import {
11 | SafeAreaView,
12 | StyleSheet,
13 | ScrollView,
14 | View,
15 | Text,
16 | StatusBar,
17 | Switch,
18 | NativeModules,
19 | NativeEventEmitter,
20 | DeviceEventEmitter,
21 | } from 'react-native';
22 |
23 | import {Colors} from 'react-native/Libraries/NewAppScreen';
24 | import {requestLocationPermission} from './Permission';
25 | import {setUserId, getUserId} from './User';
26 | import 'react-native-get-random-values';
27 | import {nanoid} from 'nanoid';
28 |
29 | const eventEmitter = new NativeEventEmitter(NativeModules.ContactTracerModule);
30 |
31 | class App extends React.Component {
32 | constructor() {
33 | super();
34 | this.state = {
35 | userId: '',
36 | serviceEnabled: false,
37 | statusText: '',
38 | };
39 | }
40 |
41 | componentDidMount() {
42 | getUserId()
43 | .then((userId) => {
44 | if (userId == null) {
45 | // User ID not existed, generate a new one
46 | // User ID maximum length is 20
47 | userId = nanoid().substr(0, 20);
48 | // Save generated ID
49 | setUserId(userId).then(() => {});
50 | }
51 | this.setState({userId: userId});
52 | return userId;
53 | })
54 | .then((userId) => {
55 | this.initializeContactTracer(userId);
56 | });
57 |
58 | // Register for event from Native code
59 | this.registerListeners();
60 |
61 | this.appendStatusText('Welcome to Contact Tracer Example');
62 | }
63 |
64 | componentWillUnmount() {
65 | // Unegister for event from Native code
66 | this.unregisterListeners();
67 | }
68 |
69 | /******************
70 | * Initialization *
71 | ******************/
72 |
73 | // Initialize Contact Tracer
74 | async initializeContactTracer(anonymousId) {
75 | // Set User ID in native level for furthur use
76 | NativeModules.ContactTracerModule.setUserId(
77 | anonymousId,
78 | ).then((anonymousId) => {});
79 |
80 | // Check if Tracer Service has been enabled
81 | NativeModules.ContactTracerModule.isTracerServiceEnabled()
82 | .then((enabled) => {
83 | this.setState({
84 | serviceEnabled: enabled,
85 | });
86 | // Refresh Tracer Service Status in case the service is down
87 | // to make sure Service is started again
88 | NativeModules.ContactTracerModule.refreshTracerServiceStatus();
89 | })
90 | .then(() => {});
91 |
92 | // Check if BLE is available
93 | await NativeModules.ContactTracerModule.initialize()
94 | .then((result) => {
95 | return NativeModules.ContactTracerModule.isBLEAvailable();
96 | })
97 | // For NativeModules.ContactTracerModule.isBLEAvailable()
98 | .then((isBLEAvailable) => {
99 | if (isBLEAvailable) {
100 | this.appendStatusText('BLE is available');
101 | // BLE is available, continue requesting Location Permission
102 | return requestLocationPermission();
103 | } else {
104 | // BLE is not available, don't do anything furthur since BLE is required
105 | this.appendStatusText('BLE is NOT available');
106 | }
107 | })
108 | // For requestLocationPermission()
109 | .then((locationPermissionGranted) => {
110 | this.setState({
111 | isLocationPermissionGranted: locationPermissionGranted,
112 | });
113 | if (locationPermissionGranted) {
114 | // Location permission is granted, try turning on Bluetooth now
115 | this.appendStatusText('Location permission is granted');
116 | return NativeModules.ContactTracerModule.tryToTurnBluetoothOn();
117 | } else {
118 | // Location permission is required, we cannot continue working without this permission
119 | this.appendStatusText('Location permission is NOT granted');
120 | }
121 | })
122 | // For NativeModules.ContactTracerModule.tryToTurnBluetoothOn()
123 | .then((bluetoothOn) => {
124 | this.setState({
125 | isBluetoothOn: bluetoothOn,
126 | });
127 |
128 | if (bluetoothOn) {
129 | this.appendStatusText('Bluetooth is On');
130 | // See if Multiple Advertisement is supported
131 | // Refresh Tracer Service Status in case the service is down
132 | NativeModules.ContactTracerModule.refreshTracerServiceStatus();
133 | return NativeModules.ContactTracerModule.isMultipleAdvertisementSupported();
134 | } else {
135 | this.appendStatusText('Bluetooth is Off');
136 | }
137 | })
138 | // For NativeModules.ContactTracerModule.isMultipleAdvertisementSupported()
139 | .then((supported) => {
140 | if (supported)
141 | this.appendStatusText('Mulitple Advertisement is supported');
142 | else this.appendStatusText('Mulitple Advertisement is NOT supported');
143 | });
144 |
145 | return '';
146 | }
147 |
148 | /**
149 | * Initialize Listeners
150 | */
151 |
152 | registerListeners() {
153 | // Register Event Emitter
154 | if (Platform.OS == 'ios') {
155 | console.log('add listener');
156 | this.advertiserEventSubscription = eventEmitter.addListener(
157 | 'AdvertiserMessage',
158 | this.onAdvertiserMessageReceived,
159 | );
160 |
161 | this.nearbyDeviceFoundEventSubscription = eventEmitter.addListener(
162 | 'NearbyDeviceFound',
163 | this.onNearbyDeviceFoundReceived,
164 | );
165 | } else {
166 | console.log('add listener');
167 | this.advertiserEventSubscription = DeviceEventEmitter.addListener(
168 | 'AdvertiserMessage',
169 | this.onAdvertiserMessageReceived,
170 | );
171 |
172 | this.nearbyDeviceFoundEventSubscription = DeviceEventEmitter.addListener(
173 | 'NearbyDeviceFound',
174 | this.onNearbyDeviceFoundReceived,
175 | );
176 | }
177 | }
178 |
179 | /**
180 | * Destroy Listeners
181 | */
182 | unregisterListeners() {
183 | // Unregister Event Emitter
184 | if (this.advertiserEventSubscription != null) {
185 | this.advertiserEventSubscription.remove();
186 | this.advertiserEventSubscription = null;
187 | }
188 | if (this.nearbyDeviceFoundEventSubscription != null) {
189 | this.nearbyDeviceFoundEventSubscription.remove();
190 | this.nearbyDeviceFoundEventSubscription = null;
191 | }
192 | }
193 |
194 | /**************************
195 | * Event Emitting Handler *
196 | **************************/
197 |
198 | onAdvertiserMessageReceived = (e) => {
199 | this.appendStatusText(e['message']);
200 | };
201 |
202 | onNearbyDeviceFoundReceived = (e) => {
203 | this.appendStatusText('');
204 | this.appendStatusText('***** RSSI: ' + e['rssi']);
205 | this.appendStatusText('***** Found Nearby Device: ' + e['name']);
206 | this.appendStatusText('');
207 | };
208 |
209 | /*********
210 | * Utils *
211 | *********/
212 |
213 | appendStatusText(text) {
214 | this.setState({statusText: text + '\n' + this.state.statusText});
215 | }
216 |
217 | /******************
218 | * Event Handling *
219 | ******************/
220 |
221 | onServiceCheckBoxChanged() {
222 | if (this.state.serviceEnabled) {
223 | // To Disable
224 | NativeModules.ContactTracerModule.disableTracerService();
225 | } else {
226 | // To Enable
227 | NativeModules.ContactTracerModule.enableTracerService();
228 | }
229 | this.setState({serviceEnabled: !this.state.serviceEnabled});
230 | }
231 |
232 | render() {
233 | return (
234 | <>
235 |
236 |
237 |
238 |
239 |
240 | User ID:{' '}
241 | {this.state.userId}
242 |
243 |
244 | Service:
245 | this.onServiceCheckBoxChanged()}
249 | />
250 |
251 |
252 |
253 |
256 |
257 | {this.state.statusText}
258 |
259 |
260 |
261 | >
262 | );
263 | }
264 | }
265 |
266 | const styles = StyleSheet.create({
267 | scrollView: {
268 | backgroundColor: Colors.lighter,
269 | },
270 | engine: {
271 | position: 'absolute',
272 | right: 0,
273 | },
274 | body: {
275 | backgroundColor: Colors.white,
276 | },
277 | headerArea: {
278 | marginTop: 32,
279 | marginBottom: 24,
280 | paddingHorizontal: 24,
281 | },
282 | mediumText: {
283 | fontSize: 18,
284 | fontWeight: '400',
285 | color: Colors.dark,
286 | },
287 | serviceCheckBoxArea: {
288 | flexDirection: 'row',
289 | fontSize: 16,
290 | marginTop: 12,
291 | },
292 | statusTextArea: {
293 | padding: 24,
294 | },
295 | statusText: {
296 | fontSize: 16,
297 | color: Colors.black,
298 | },
299 | scanButton: {
300 | height: 24,
301 | },
302 | highlight: {
303 | fontWeight: '700',
304 | },
305 | });
306 |
307 | export default App;
308 |
--------------------------------------------------------------------------------
/android/src/main/java/com/nuuneoi/lib/contacttracer/ContactTracerModule.java:
--------------------------------------------------------------------------------
1 |
2 | package com.nuuneoi.lib.contacttracer;
3 |
4 | import android.app.Activity;
5 | import android.bluetooth.BluetoothAdapter;
6 | import android.bluetooth.BluetoothManager;
7 | import android.content.BroadcastReceiver;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.IntentFilter;
11 | import android.os.Build;
12 | import android.widget.Toast;
13 |
14 | import com.nuuneoi.lib.contacttracer.mock.User;
15 | import com.nuuneoi.lib.contacttracer.service.TracerService;
16 | import com.nuuneoi.lib.contacttracer.utils.BluetoothUtils;
17 | import com.facebook.react.bridge.ActivityEventListener;
18 | import com.facebook.react.bridge.Arguments;
19 | import com.facebook.react.bridge.Callback;
20 | import com.facebook.react.bridge.LifecycleEventListener;
21 | import com.facebook.react.bridge.Promise;
22 | import com.facebook.react.bridge.ReactApplicationContext;
23 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
24 | import com.facebook.react.bridge.ReactMethod;
25 | import com.facebook.react.bridge.WritableMap;
26 | import com.facebook.react.modules.core.DeviceEventManagerModule;
27 |
28 | import androidx.annotation.NonNull;
29 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
30 |
31 | public class ContactTracerModule extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
32 |
33 | private static int REQUEST_ENABLE_BT = 1001;
34 | Promise tryToTurnBluetoothOn;
35 |
36 | BluetoothAdapter bluetoothAdapter;
37 | User user;
38 |
39 | private BroadcastReceiver advertiserMessageReceiver;
40 | private BroadcastReceiver nearbyDeviceFoundReceiver;
41 | private BroadcastReceiver nearbyBeaconFoundReceiver;
42 |
43 | private boolean isAdvertiserMessageReceiverRegistered = false;
44 | private boolean isNearbyDeviceFoundReceiverRegistered = false;
45 | private boolean isNearbyBeaconFoundReceiverRegistered = false;
46 |
47 | public ContactTracerModule(ReactApplicationContext reactContext) {
48 | super(reactContext);
49 | reactContext.addActivityEventListener(this);
50 | // reactContext.addLifecycleEventListener(this);
51 |
52 | user = new User(getReactApplicationContext());
53 |
54 | initBluetoothInstances();
55 |
56 | initAdvertiserReceiver();
57 | initScannerReceiver();
58 | initBeaconScanerReceiver();
59 |
60 | IntentFilter advertiserMessageFilter = new IntentFilter(TracerService.ADVERTISING_MESSAGE);
61 | LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(advertiserMessageReceiver, advertiserMessageFilter);
62 |
63 | IntentFilter nearbyDeviceFoundFilter = new IntentFilter(TracerService.NEARBY_DEVICE_FOUND_MESSAGE);
64 | LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(nearbyDeviceFoundReceiver, nearbyDeviceFoundFilter);
65 |
66 | IntentFilter nearbyBeaconFoundFilter = new IntentFilter(TracerService.NEARBY_BEACON_FOUND_MESSAGE);
67 | LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(nearbyBeaconFoundReceiver, nearbyBeaconFoundFilter);
68 | }
69 |
70 | @NonNull
71 | @Override
72 | public String getName() {
73 | return "ContactTracerModule";
74 | }
75 |
76 | private void initBluetoothInstances() {
77 | final BluetoothManager bluetoothManager = (BluetoothManager) getReactApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
78 | bluetoothAdapter = bluetoothManager.getAdapter();
79 | }
80 |
81 | @ReactMethod
82 | public void initialize(final Promise promise) {
83 | promise.resolve(null);
84 | }
85 |
86 | @ReactMethod
87 | public void isBLEAvailable(final Promise promise) {
88 | boolean isBLEAvailable = BluetoothUtils.isBLEAvailable(getReactApplicationContext().getApplicationContext());
89 | promise.resolve(isBLEAvailable);
90 | }
91 |
92 | @ReactMethod
93 | public void isMultipleAdvertisementSupported(final Promise promise) {
94 | if (bluetoothAdapter == null) {
95 | promise.resolve(false);
96 | return;
97 | }
98 | boolean isMultipleAdvertisementSupported = BluetoothUtils.isMultipleAdvertisementSupported(bluetoothAdapter);
99 | promise.resolve(isMultipleAdvertisementSupported);
100 | }
101 |
102 | private boolean _isBluetoothTurnedOn() {
103 | if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled())
104 | return false;
105 | return true;
106 | }
107 |
108 | @ReactMethod
109 | public void isBluetoothTurnedOn(final Promise promise) {
110 | promise.resolve(_isBluetoothTurnedOn());
111 | }
112 |
113 | @ReactMethod
114 | public void tryToTurnBluetoothOn(final Promise promise) {
115 | tryToTurnBluetoothOn = promise;
116 | Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
117 | getReactApplicationContext().getCurrentActivity().startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
118 | }
119 |
120 | // Activity Result
121 |
122 | @Override
123 | public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
124 | if (requestCode == REQUEST_ENABLE_BT) {
125 | tryToTurnBluetoothOn.resolve(_isBluetoothTurnedOn());
126 | }
127 | }
128 |
129 | @Override
130 | public void onNewIntent(Intent intent) {
131 |
132 | }
133 |
134 | // Background Service
135 |
136 | @ReactMethod
137 | public void setUserId(String userId, final Promise promise) {
138 | user.setUserId(userId);
139 | promise.resolve(userId);
140 | }
141 |
142 | @ReactMethod
143 | public void getUserId(final Promise promise) {
144 | promise.resolve(user.getUserId());
145 | }
146 |
147 | @ReactMethod
148 | public void isTracerServiceEnabled(final Promise promise) {
149 | boolean isEnabled = TracerService.isEnabled(getReactApplicationContext());
150 | promise.resolve(isEnabled);
151 | }
152 |
153 | @ReactMethod
154 | public void enableTracerService(final Promise promise) {
155 | TracerService.enable(getReactApplicationContext());
156 | _startTracerService(getReactApplicationContext());
157 | promise.resolve(null);
158 | }
159 |
160 | @ReactMethod
161 | public void disableTracerService(final Promise promise) {
162 | TracerService.disable(getReactApplicationContext());
163 | _stopTracerService(getReactApplicationContext());
164 | promise.resolve(null);
165 | }
166 |
167 | @ReactMethod
168 | public void refreshTracerServiceStatus(final Promise promise) {
169 | if (TracerService.isEnabled(getReactApplicationContext())) {
170 | _startTracerService(getReactApplicationContext());
171 | promise.resolve(true);
172 | } else {
173 | _stopTracerService(getReactApplicationContext());
174 | promise.resolve(false);
175 | }
176 | }
177 |
178 | @ReactMethod
179 | public void stopTracerService(final Promise promise) {
180 | _stopTracerService(getReactApplicationContext());
181 | promise.resolve(true);
182 | }
183 |
184 | private void _startTracerService(Context context) {
185 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
186 | context.startForegroundService(new Intent(context, TracerService.class));
187 | else
188 | context.startService(new Intent(context, TracerService.class));
189 | }
190 |
191 | private void _stopTracerService(Context context) {
192 | context.stopService(new Intent(context, TracerService.class));
193 | }
194 |
195 | // Broadcast Receiver and Event Emitter
196 |
197 |
198 | private void initAdvertiserReceiver() {
199 | advertiserMessageReceiver = new BroadcastReceiver() {
200 | @Override
201 | public void onReceive(Context context, Intent intent) {
202 | String message = intent.getStringExtra(TracerService.ADVERTISING_MESSAGE_EXTRA_MESSAGE);
203 |
204 | WritableMap params = Arguments.createMap();
205 | params.putString("message", message);
206 |
207 | getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
208 | .emit("AdvertiserMessage", params);
209 | }
210 | };
211 | }
212 |
213 |
214 | private void initScannerReceiver() {
215 | nearbyDeviceFoundReceiver = new BroadcastReceiver() {
216 | @Override
217 | public void onReceive(Context context, Intent intent) {
218 | String name = intent.getStringExtra(TracerService.NEARBY_DEVICE_FOUND_EXTRA_NAME);
219 | int rssi = intent.getIntExtra(TracerService.NEARBY_DEVICE_FOUND_EXTRA_RSSI, 0);
220 |
221 | WritableMap params = Arguments.createMap();
222 | params.putString("name", name);
223 | params.putInt("rssi", rssi);
224 |
225 | getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
226 | .emit("NearbyDeviceFound", params);
227 | }
228 | };
229 | }
230 |
231 | private void initBeaconScanerReceiver() {
232 | nearbyBeaconFoundReceiver = new BroadcastReceiver() {
233 | @Override
234 | public void onReceive(Context context, Intent intent) {
235 | String rssi = intent.getStringExtra(TracerService.NEARBY_BEACON_FOUND_EXTRA_RSSI);
236 | String uuid = intent.getStringExtra(TracerService.NEARBY_BEACON_FOUND_EXTRA_UUID);
237 | String major = intent.getStringExtra(TracerService.NEARBY_BEACON_FOUND_EXTRA_MAJOR);
238 | String minor = intent.getStringExtra(TracerService.NEARBY_BEACON_FOUND_EXTRA_MINOR);
239 |
240 | WritableMap params = Arguments.createMap();
241 | params.putString("uuid", uuid);
242 | params.putString("major", major);
243 | params.putString("minor", minor);
244 | params.putString("rssi", rssi);
245 |
246 | getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
247 | .emit("NearbyBeaconFound", params);
248 | }
249 | };
250 | }
251 |
252 | // Life Cycle
253 |
254 | @Override
255 | public void onHostResume() {
256 |
257 | }
258 |
259 | @Override
260 | public void onHostPause() {
261 |
262 | }
263 |
264 | @Override
265 | public void onHostDestroy() {
266 |
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/ios/ContactTracerModule.m:
--------------------------------------------------------------------------------
1 | //
2 | // ContactTracerModule.m
3 | // ContactTracerReact
4 | //
5 | // Created by Sittiphol Phanvilai on 31/3/2563 BE.
6 | //
7 |
8 | #import "ContactTracerModule.h"
9 |
10 | #import "React/RCTBridgeModule.h"
11 | #import
12 |
13 | @import CoreBluetooth;
14 | @import CoreLocation; //Added by Urng 20200712
15 |
16 | @implementation ContactTracerModule {
17 | CBCentralManager* centralManager;
18 | CBPeripheralManager* peripheralManager;
19 | RCTPromiseResolveBlock bluetoothOnResolve;
20 | CLLocationManager* locationManager;//Added by Urng 20200712
21 | BOOL isBluetoothOn;
22 |
23 | CBUUID* cbuuid;
24 | CBUUID* kDataClass;
25 |
26 | NSUUID *beaconuuid; //Added by Urng 20200712
27 | NSString *beaconID; //Added by Urng 20200712
28 | CLBeaconRegion *beaconRegion; //Added by Urng 20200712
29 | }
30 |
31 | RCT_EXPORT_MODULE()
32 |
33 | // Constructor
34 | - (id) init {
35 | self = [super init];
36 |
37 | centralManager = nil;
38 | peripheralManager = nil;
39 | locationManager = nil; //Added by Urng 20200712
40 |
41 | NSString *bluetoothUUID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"contact_tracer_bluetooth_uuid"];
42 | NSString *beaconUUID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"beacon_uuid"];
43 | if (bluetoothUUID == nil)
44 | bluetoothUUID = @"00008FFF-0000-1000-8000-00805f9b34fc";
45 |
46 | if (beaconUUID == nil) { //Added by Urng 20200712
47 | beaconUUID = @"26600EFA-ED3D-971A-3676-295C85BE6CE5"; //Added by Urng 20200712
48 | beaconID = @"morchana.in.th"; //Added by Urng 20200712
49 | } //Added by Urng 20200712
50 |
51 | NSString *bluetoothDataClass = [[bluetoothUUID substringWithRange:NSMakeRange(4, 4)] uppercaseString];
52 |
53 | cbuuid = [CBUUID UUIDWithString:bluetoothUUID];
54 | beaconuuid = [[NSUUID alloc] initWithUUIDString:beaconUUID]; //Added by Urng 20200712
55 |
56 | kDataClass = [CBUUID UUIDWithString:bluetoothDataClass];
57 |
58 | isBluetoothOn = false;
59 |
60 | beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconuuid //Added by Urng 20200712
61 | identifier:beaconID]; //Added by Urng 20200712
62 |
63 |
64 | return self;
65 | }
66 |
67 | // Declare Events that can be sent to JS
68 | - (NSArray *)supportedEvents
69 | {
70 | return @[@"AdvertiserMessage", @"NearbyDeviceFound",@"NearbyBeaconFound"];
71 | }
72 |
73 | + (BOOL)requiresMainQueueSetup
74 | {
75 | return NO;
76 | }
77 |
78 | RCT_EXPORT_METHOD(initialize: (RCTPromiseResolveBlock)resolve
79 | rejecter: (RCTPromiseRejectBlock)reject)
80 | {
81 | bool pendingCallback = false;
82 |
83 | bluetoothOnResolve = resolve;
84 | if (centralManager == nil) {
85 | centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
86 | // Callback will be called in centralManager delegate
87 | pendingCallback = true;
88 | }
89 | if (peripheralManager == nil) {
90 | peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
91 | }
92 |
93 | // Resolve now since there would be no delegate called
94 | if (!pendingCallback)
95 | resolve(@(true));
96 |
97 | if (locationManager == nil) { //Added by Urng 20200712
98 | __strong typeof(self) strongSelf = self;
99 | dispatch_async(dispatch_get_main_queue(), ^{
100 | // do work here
101 | strongSelf->locationManager = [[CLLocationManager alloc] init]; //Added by Urng 20200712
102 | strongSelf->locationManager.delegate = strongSelf; //Added by Urng 20200712
103 | if ([strongSelf->locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) //Added by Urng 20200712
104 | {
105 | //[locationManager requestWhenInUseAuthorization]; //Added by Urng 20200712
106 | [strongSelf->locationManager requestAlwaysAuthorization]; //Added by Urng 20200712
107 | }
108 |
109 |
110 | // Callback will be called in locationManager delegate //Added by Urng 20200712
111 | //pendingCallback = true; //Added by Urng 20200712
112 | });
113 | }
114 |
115 | // Resolve now since there would be no delegate called //Added by Urng 20200712
116 | if (!pendingCallback) //Added by Urng 20200712
117 | resolve(@(true)); //Added by Urng 20200712
118 |
119 | }
120 |
121 | RCT_EXPORT_METHOD(isTracerServiceEnabled: (RCTPromiseResolveBlock)resolve
122 | rejecter: (RCTPromiseRejectBlock)reject)
123 | {
124 | BOOL result = [self _isTracerServiceEnabled];
125 | resolve(@(result));
126 | }
127 |
128 | - (void)_setTracerServiceEnabled: (BOOL)enabled {
129 | [NSUserDefaults.standardUserDefaults setBool:enabled forKey:@"tracerServiceEnabled"];
130 | }
131 |
132 | - (BOOL)_isTracerServiceEnabled {
133 | BOOL tracerServiceEnabled = [NSUserDefaults.standardUserDefaults boolForKey:@"tracerServiceEnabled"];
134 | return tracerServiceEnabled;
135 | }
136 |
137 | RCT_EXPORT_METHOD(enableTracerService: (RCTPromiseResolveBlock)resolve
138 | rejecter: (RCTPromiseRejectBlock)reject)
139 | {
140 | [self emitAdvertiserMessage:@"Enabling Tracer Service"];
141 | [self _setTracerServiceEnabled:true];
142 | [self startScanning];
143 | [self startAdvertising];
144 | resolve(@(true));
145 | }
146 |
147 | RCT_EXPORT_METHOD(disableTracerService: (RCTPromiseResolveBlock)resolve
148 | rejecter: (RCTPromiseRejectBlock)reject)
149 | {
150 | [self emitAdvertiserMessage:@"Disabling Tracer Service"];
151 | [self _setTracerServiceEnabled:false];
152 | [self stopScanning];
153 | [self stopAdvertising];
154 | resolve(@(true));
155 | }
156 |
157 | - (void) _refreshTracerServiceStatus
158 | {
159 | if ([self _isTracerServiceEnabled]) {
160 | [self startScanning];
161 | [self startAdvertising];
162 | } else {
163 | [self stopScanning];
164 | [self stopAdvertising];
165 | }
166 | }
167 |
168 | RCT_EXPORT_METHOD(refreshTracerServiceStatus: (RCTPromiseResolveBlock)resolve
169 | rejecter: (RCTPromiseRejectBlock)reject)
170 | {
171 | [self _refreshTracerServiceStatus];
172 | BOOL result = [self _isTracerServiceEnabled];
173 | resolve(@(result));
174 | }
175 |
176 | RCT_EXPORT_METHOD(stopTracerService: (RCTPromiseResolveBlock)resolve
177 | rejecter: (RCTPromiseRejectBlock)reject)
178 | {
179 | [self stopScanning];
180 | [self stopAdvertising];
181 | }
182 |
183 | RCT_EXPORT_METHOD(isBLEAvailable: (RCTPromiseResolveBlock)resolve
184 | rejecter: (RCTPromiseRejectBlock)reject)
185 | {
186 | resolve(@(true));
187 | }
188 |
189 | RCT_EXPORT_METHOD(isMultipleAdvertisementSupported: (RCTPromiseResolveBlock)resolve
190 | rejecter: (RCTPromiseRejectBlock)reject)
191 | {
192 | resolve(@(true));
193 | }
194 |
195 | RCT_EXPORT_METHOD(isBluetoothTurnedOn: (RCTPromiseResolveBlock)resolve
196 | rejecter: (RCTPromiseRejectBlock)reject)
197 | {
198 | resolve(@(isBluetoothOn));
199 | }
200 |
201 | RCT_EXPORT_METHOD(tryToTurnBluetoothOn: (RCTPromiseResolveBlock)resolve
202 | rejecter: (RCTPromiseRejectBlock)reject)
203 | {
204 | resolve(@(true));
205 | }
206 |
207 | RCT_EXPORT_METHOD(setUserId: (NSString*)userId
208 | resolver: (RCTPromiseResolveBlock)resolve
209 | rejecter: (RCTPromiseRejectBlock)reject)
210 | {
211 | [[NSUserDefaults standardUserDefaults] setObject:userId forKey:@"userId"];
212 | resolve(userId);
213 | }
214 |
215 | RCT_EXPORT_METHOD(getUserId: (RCTPromiseResolveBlock)resolve
216 | rejecter: (RCTPromiseRejectBlock)reject)
217 | {
218 | resolve([self _getUserId]);
219 | }
220 |
221 | - (NSString*) _getUserId {
222 | NSString* userId = [[NSUserDefaults standardUserDefaults] stringForKey:@"userId"];
223 | if (userId == nil)
224 | return @"NOIDIOS";
225 | return userId;
226 | }
227 |
228 | // Delegate
229 |
230 | - (void) centralManagerDidUpdateState:(CBCentralManager *)central
231 | {
232 | if (@available(iOS 10.0, *)) {
233 | if (central.state == CBManagerStatePoweredOn) {
234 | NSLog(@"Bluetooth is On");
235 | [self emitAdvertiserMessage:@"Bluetooth is On. You can start scanning now."];
236 | bluetoothOnResolve(@(true));
237 | } else {
238 | NSLog(@"Bluetooth is not active");
239 | [self emitAdvertiserMessage:@"Bluetooth is not active. Scanning function is disabled."];
240 | bluetoothOnResolve(@(false));
241 | }
242 | } else {
243 | // Fallback on earlier versions
244 | }
245 | }
246 |
247 | - (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
248 | {
249 | NSDictionary* adData = [advertisementData objectForKey:@"kCBAdvDataServiceData"];
250 | if (adData == nil)
251 | return;
252 |
253 | NSString* nearbyDeviceUserId;
254 |
255 | NSData* data = [adData objectForKey:kDataClass];
256 | if (data == nil) {
257 | nearbyDeviceUserId = [peripheral name];
258 | } else {
259 | nearbyDeviceUserId = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
260 | }
261 |
262 | [self emitNearbyDeviceFound:nearbyDeviceUserId rssi:[RSSI stringValue]];
263 |
264 | NSLog(@"nFound Nearby Device: %@", nearbyDeviceUserId);
265 | NSLog(@"RSSI: %@", [RSSI stringValue]);
266 | }
267 |
268 | - (void) peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
269 | {
270 | switch (peripheral.state) {
271 | case CBManagerStateUnknown:
272 | NSLog(@"Bluetooth Device is UNKNOWN");
273 | break;
274 | case CBManagerStateUnsupported:
275 | NSLog(@"Bluetooth Device is UNSUPPORTED");
276 | break;
277 | case CBManagerStateUnauthorized:
278 | NSLog(@"Bluetooth Device is UNAUTHORIZED");
279 | break;
280 | case CBManagerStateResetting:
281 | NSLog(@"Bluetooth Device is RESETTING");
282 | break;
283 | case CBManagerStatePoweredOff:
284 | NSLog(@"Bluetooth Device is POWERED OFF");
285 | break;
286 | case CBManagerStatePoweredOn:
287 | NSLog(@"Bluetooth Device is POWERED ON");
288 | isBluetoothOn = true;
289 | [self emitAdvertiserMessage:@"Bluetooth Device is POWERED ON. You can start advertising now."];
290 | break;
291 | default:
292 | NSLog(@"Unknown State");
293 | break;
294 | }
295 | }
296 |
297 |
298 | - (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion*)region //Added by Urng 20200712
299 | {
300 | NSLog(@"Enter Beacon Region!");
301 | [locationManager startRangingBeaconsInRegion:beaconRegion];
302 | [locationManager stopRangingBeaconsInRegion:beaconRegion];
303 | }
304 |
305 | -(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion*)region //Added by Urng 20200712
306 | {
307 | [locationManager stopRangingBeaconsInRegion:beaconRegion];
308 | NSLog(@"Exit Beacon Region!");
309 | }
310 |
311 | - (void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error //Added by Urng 20200712
312 | {
313 | // NSLog(@"RangingBeaconsDidFailForRegion: %@", region);
314 | // NSLog(@"error: %@", error);
315 | }
316 |
317 | -(void)locationManager:(CLLocationManager*)manager
318 | didRangeBeacons:(NSArray*)beacons
319 | inRegion:(CLBeaconRegion*)region //Added by Urng 20200712
320 | {
321 | // Beacon found!
322 |
323 | NSLog(@"Beacon Found!");
324 | for (CLBeacon *foundBeacon in beacons) {
325 | NSString *uuid = foundBeacon.proximityUUID.UUIDString;
326 | NSString *major = [NSString stringWithFormat:@"%@", foundBeacon.major];
327 | NSString *minor = [NSString stringWithFormat:@"%@", foundBeacon.minor];
328 | NSLog(@"uuid: %@", uuid);
329 | NSLog(@"major: %@", major);
330 | NSLog(@"minor: %@", minor);
331 |
332 | [self emitNearbyBeaconFound: uuid major: major mainor: minor ];
333 | }
334 | NSLog(@"------------------------------------");
335 | }
336 |
337 | // Advertiser
338 |
339 | - (void) startAdvertising
340 | {
341 | if (peripheralManager == nil)
342 | return;
343 |
344 | NSString* userId = [self _getUserId];
345 |
346 | [peripheralManager startAdvertising:@{
347 | CBAdvertisementDataLocalNameKey: userId,
348 | CBAdvertisementDataServiceUUIDsKey: @[cbuuid]
349 | }];
350 | NSLog(@"Started Advertising");
351 | [self emitAdvertiserMessage:@"Starting Advertising"];
352 | }
353 |
354 | - (void) stopAdvertising
355 | {
356 | if (peripheralManager == nil)
357 | return;
358 | [peripheralManager stopAdvertising];
359 | NSLog(@"Stop Advertising");
360 | [self emitAdvertiserMessage:@"Stopping Advertising"];
361 | }
362 |
363 | // Scanner
364 |
365 | - (void) startScanning
366 | {
367 | if (centralManager == nil)
368 | return;
369 | [self emitAdvertiserMessage:@"Start Scanning for Nearby Device\n"];
370 | [centralManager scanForPeripheralsWithServices:@[cbuuid] options:nil];
371 |
372 | if (locationManager == nil) //Added by Urng 20200712
373 | return; //Added by Urng 20200712
374 | NSLog(@"Start Scanning Beacon"); //Added by Urng 20200712
375 | [locationManager startRangingBeaconsInRegion:beaconRegion]; //Added by Urng 20200712
376 | }
377 |
378 | - (void) stopScanning
379 | {
380 | if (centralManager == nil)
381 | return;
382 | [self emitAdvertiserMessage:@"Stop Scanning for Nearby Device\n"];
383 | [centralManager stopScan];
384 |
385 | if (locationManager == nil) //Added by Urng 20200712
386 | return; //Added by Urng 20200712
387 | NSLog(@"Stop Scanning Beacon"); //Added by Urng 20200712
388 | [locationManager stopRangingBeaconsInRegion:beaconRegion]; //Added by Urng 20200712
389 |
390 | }
391 |
392 | // Event
393 |
394 | - (void) emitAdvertiserMessage: (NSString*)message
395 | {
396 | [self sendEventWithName:@"AdvertiserMessage" body:@{@"message": message}];
397 | }
398 |
399 | - (void) emitNearbyDeviceFound: (NSString*)name rssi: (NSString*)rssi
400 | {
401 | [self sendEventWithName:@"NearbyDeviceFound" body:@{@"name": name, @"rssi": rssi}];
402 | }
403 |
404 | - (void) emitNearbyBeaconFound: (NSString*)uuid major: (NSString*)major mainor: (NSString*)minor //Added by Urng 20200712
405 | {
406 | [self sendEventWithName:@"NearbyBeaconFound" body:@{@"uuid": uuid, @"major": major, @"minor": minor}];
407 | }
408 |
409 | @end
410 |
--------------------------------------------------------------------------------
/example/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - boost-for-react-native (1.63.0)
3 | - CocoaAsyncSocket (7.6.4)
4 | - CocoaLibEvent (1.0.0)
5 | - ContactTracerReactNative (1.1.0):
6 | - React
7 | - DoubleConversion (1.1.6)
8 | - FBLazyVector (0.62.2)
9 | - FBReactNativeSpec (0.62.2):
10 | - Folly (= 2018.10.22.00)
11 | - RCTRequired (= 0.62.2)
12 | - RCTTypeSafety (= 0.62.2)
13 | - React-Core (= 0.62.2)
14 | - React-jsi (= 0.62.2)
15 | - ReactCommon/turbomodule/core (= 0.62.2)
16 | - Flipper (0.33.1):
17 | - Flipper-Folly (~> 2.1)
18 | - Flipper-RSocket (~> 1.0)
19 | - Flipper-DoubleConversion (1.1.7)
20 | - Flipper-Folly (2.1.1):
21 | - boost-for-react-native
22 | - CocoaLibEvent (~> 1.0)
23 | - Flipper-DoubleConversion
24 | - Flipper-Glog
25 | - OpenSSL-Universal (= 1.0.2.19)
26 | - Flipper-Glog (0.3.6)
27 | - Flipper-PeerTalk (0.0.4)
28 | - Flipper-RSocket (1.0.0):
29 | - Flipper-Folly (~> 2.0)
30 | - FlipperKit (0.33.1):
31 | - FlipperKit/Core (= 0.33.1)
32 | - FlipperKit/Core (0.33.1):
33 | - Flipper (~> 0.33.1)
34 | - FlipperKit/CppBridge
35 | - FlipperKit/FBCxxFollyDynamicConvert
36 | - FlipperKit/FBDefines
37 | - FlipperKit/FKPortForwarding
38 | - FlipperKit/CppBridge (0.33.1):
39 | - Flipper (~> 0.33.1)
40 | - FlipperKit/FBCxxFollyDynamicConvert (0.33.1):
41 | - Flipper-Folly (~> 2.1)
42 | - FlipperKit/FBDefines (0.33.1)
43 | - FlipperKit/FKPortForwarding (0.33.1):
44 | - CocoaAsyncSocket (~> 7.6)
45 | - Flipper-PeerTalk (~> 0.0.4)
46 | - FlipperKit/FlipperKitHighlightOverlay (0.33.1)
47 | - FlipperKit/FlipperKitLayoutPlugin (0.33.1):
48 | - FlipperKit/Core
49 | - FlipperKit/FlipperKitHighlightOverlay
50 | - FlipperKit/FlipperKitLayoutTextSearchable
51 | - YogaKit (~> 1.18)
52 | - FlipperKit/FlipperKitLayoutTextSearchable (0.33.1)
53 | - FlipperKit/FlipperKitNetworkPlugin (0.33.1):
54 | - FlipperKit/Core
55 | - FlipperKit/FlipperKitReactPlugin (0.33.1):
56 | - FlipperKit/Core
57 | - FlipperKit/FlipperKitUserDefaultsPlugin (0.33.1):
58 | - FlipperKit/Core
59 | - FlipperKit/SKIOSNetworkPlugin (0.33.1):
60 | - FlipperKit/Core
61 | - FlipperKit/FlipperKitNetworkPlugin
62 | - Folly (2018.10.22.00):
63 | - boost-for-react-native
64 | - DoubleConversion
65 | - Folly/Default (= 2018.10.22.00)
66 | - glog
67 | - Folly/Default (2018.10.22.00):
68 | - boost-for-react-native
69 | - DoubleConversion
70 | - glog
71 | - glog (0.3.5)
72 | - OpenSSL-Universal (1.0.2.19):
73 | - OpenSSL-Universal/Static (= 1.0.2.19)
74 | - OpenSSL-Universal/Static (1.0.2.19)
75 | - RCTRequired (0.62.2)
76 | - RCTTypeSafety (0.62.2):
77 | - FBLazyVector (= 0.62.2)
78 | - Folly (= 2018.10.22.00)
79 | - RCTRequired (= 0.62.2)
80 | - React-Core (= 0.62.2)
81 | - React (0.62.2):
82 | - React-Core (= 0.62.2)
83 | - React-Core/DevSupport (= 0.62.2)
84 | - React-Core/RCTWebSocket (= 0.62.2)
85 | - React-RCTActionSheet (= 0.62.2)
86 | - React-RCTAnimation (= 0.62.2)
87 | - React-RCTBlob (= 0.62.2)
88 | - React-RCTImage (= 0.62.2)
89 | - React-RCTLinking (= 0.62.2)
90 | - React-RCTNetwork (= 0.62.2)
91 | - React-RCTSettings (= 0.62.2)
92 | - React-RCTText (= 0.62.2)
93 | - React-RCTVibration (= 0.62.2)
94 | - React-Core (0.62.2):
95 | - Folly (= 2018.10.22.00)
96 | - glog
97 | - React-Core/Default (= 0.62.2)
98 | - React-cxxreact (= 0.62.2)
99 | - React-jsi (= 0.62.2)
100 | - React-jsiexecutor (= 0.62.2)
101 | - Yoga
102 | - React-Core/CoreModulesHeaders (0.62.2):
103 | - Folly (= 2018.10.22.00)
104 | - glog
105 | - React-Core/Default
106 | - React-cxxreact (= 0.62.2)
107 | - React-jsi (= 0.62.2)
108 | - React-jsiexecutor (= 0.62.2)
109 | - Yoga
110 | - React-Core/Default (0.62.2):
111 | - Folly (= 2018.10.22.00)
112 | - glog
113 | - React-cxxreact (= 0.62.2)
114 | - React-jsi (= 0.62.2)
115 | - React-jsiexecutor (= 0.62.2)
116 | - Yoga
117 | - React-Core/DevSupport (0.62.2):
118 | - Folly (= 2018.10.22.00)
119 | - glog
120 | - React-Core/Default (= 0.62.2)
121 | - React-Core/RCTWebSocket (= 0.62.2)
122 | - React-cxxreact (= 0.62.2)
123 | - React-jsi (= 0.62.2)
124 | - React-jsiexecutor (= 0.62.2)
125 | - React-jsinspector (= 0.62.2)
126 | - Yoga
127 | - React-Core/RCTActionSheetHeaders (0.62.2):
128 | - Folly (= 2018.10.22.00)
129 | - glog
130 | - React-Core/Default
131 | - React-cxxreact (= 0.62.2)
132 | - React-jsi (= 0.62.2)
133 | - React-jsiexecutor (= 0.62.2)
134 | - Yoga
135 | - React-Core/RCTAnimationHeaders (0.62.2):
136 | - Folly (= 2018.10.22.00)
137 | - glog
138 | - React-Core/Default
139 | - React-cxxreact (= 0.62.2)
140 | - React-jsi (= 0.62.2)
141 | - React-jsiexecutor (= 0.62.2)
142 | - Yoga
143 | - React-Core/RCTBlobHeaders (0.62.2):
144 | - Folly (= 2018.10.22.00)
145 | - glog
146 | - React-Core/Default
147 | - React-cxxreact (= 0.62.2)
148 | - React-jsi (= 0.62.2)
149 | - React-jsiexecutor (= 0.62.2)
150 | - Yoga
151 | - React-Core/RCTImageHeaders (0.62.2):
152 | - Folly (= 2018.10.22.00)
153 | - glog
154 | - React-Core/Default
155 | - React-cxxreact (= 0.62.2)
156 | - React-jsi (= 0.62.2)
157 | - React-jsiexecutor (= 0.62.2)
158 | - Yoga
159 | - React-Core/RCTLinkingHeaders (0.62.2):
160 | - Folly (= 2018.10.22.00)
161 | - glog
162 | - React-Core/Default
163 | - React-cxxreact (= 0.62.2)
164 | - React-jsi (= 0.62.2)
165 | - React-jsiexecutor (= 0.62.2)
166 | - Yoga
167 | - React-Core/RCTNetworkHeaders (0.62.2):
168 | - Folly (= 2018.10.22.00)
169 | - glog
170 | - React-Core/Default
171 | - React-cxxreact (= 0.62.2)
172 | - React-jsi (= 0.62.2)
173 | - React-jsiexecutor (= 0.62.2)
174 | - Yoga
175 | - React-Core/RCTSettingsHeaders (0.62.2):
176 | - Folly (= 2018.10.22.00)
177 | - glog
178 | - React-Core/Default
179 | - React-cxxreact (= 0.62.2)
180 | - React-jsi (= 0.62.2)
181 | - React-jsiexecutor (= 0.62.2)
182 | - Yoga
183 | - React-Core/RCTTextHeaders (0.62.2):
184 | - Folly (= 2018.10.22.00)
185 | - glog
186 | - React-Core/Default
187 | - React-cxxreact (= 0.62.2)
188 | - React-jsi (= 0.62.2)
189 | - React-jsiexecutor (= 0.62.2)
190 | - Yoga
191 | - React-Core/RCTVibrationHeaders (0.62.2):
192 | - Folly (= 2018.10.22.00)
193 | - glog
194 | - React-Core/Default
195 | - React-cxxreact (= 0.62.2)
196 | - React-jsi (= 0.62.2)
197 | - React-jsiexecutor (= 0.62.2)
198 | - Yoga
199 | - React-Core/RCTWebSocket (0.62.2):
200 | - Folly (= 2018.10.22.00)
201 | - glog
202 | - React-Core/Default (= 0.62.2)
203 | - React-cxxreact (= 0.62.2)
204 | - React-jsi (= 0.62.2)
205 | - React-jsiexecutor (= 0.62.2)
206 | - Yoga
207 | - React-CoreModules (0.62.2):
208 | - FBReactNativeSpec (= 0.62.2)
209 | - Folly (= 2018.10.22.00)
210 | - RCTTypeSafety (= 0.62.2)
211 | - React-Core/CoreModulesHeaders (= 0.62.2)
212 | - React-RCTImage (= 0.62.2)
213 | - ReactCommon/turbomodule/core (= 0.62.2)
214 | - React-cxxreact (0.62.2):
215 | - boost-for-react-native (= 1.63.0)
216 | - DoubleConversion
217 | - Folly (= 2018.10.22.00)
218 | - glog
219 | - React-jsinspector (= 0.62.2)
220 | - React-jsi (0.62.2):
221 | - boost-for-react-native (= 1.63.0)
222 | - DoubleConversion
223 | - Folly (= 2018.10.22.00)
224 | - glog
225 | - React-jsi/Default (= 0.62.2)
226 | - React-jsi/Default (0.62.2):
227 | - boost-for-react-native (= 1.63.0)
228 | - DoubleConversion
229 | - Folly (= 2018.10.22.00)
230 | - glog
231 | - React-jsiexecutor (0.62.2):
232 | - DoubleConversion
233 | - Folly (= 2018.10.22.00)
234 | - glog
235 | - React-cxxreact (= 0.62.2)
236 | - React-jsi (= 0.62.2)
237 | - React-jsinspector (0.62.2)
238 | - react-native-checkbox (0.3.0):
239 | - React
240 | - react-native-get-random-values (1.3.1):
241 | - React
242 | - React-RCTActionSheet (0.62.2):
243 | - React-Core/RCTActionSheetHeaders (= 0.62.2)
244 | - React-RCTAnimation (0.62.2):
245 | - FBReactNativeSpec (= 0.62.2)
246 | - Folly (= 2018.10.22.00)
247 | - RCTTypeSafety (= 0.62.2)
248 | - React-Core/RCTAnimationHeaders (= 0.62.2)
249 | - ReactCommon/turbomodule/core (= 0.62.2)
250 | - React-RCTBlob (0.62.2):
251 | - FBReactNativeSpec (= 0.62.2)
252 | - Folly (= 2018.10.22.00)
253 | - React-Core/RCTBlobHeaders (= 0.62.2)
254 | - React-Core/RCTWebSocket (= 0.62.2)
255 | - React-jsi (= 0.62.2)
256 | - React-RCTNetwork (= 0.62.2)
257 | - ReactCommon/turbomodule/core (= 0.62.2)
258 | - React-RCTImage (0.62.2):
259 | - FBReactNativeSpec (= 0.62.2)
260 | - Folly (= 2018.10.22.00)
261 | - RCTTypeSafety (= 0.62.2)
262 | - React-Core/RCTImageHeaders (= 0.62.2)
263 | - React-RCTNetwork (= 0.62.2)
264 | - ReactCommon/turbomodule/core (= 0.62.2)
265 | - React-RCTLinking (0.62.2):
266 | - FBReactNativeSpec (= 0.62.2)
267 | - React-Core/RCTLinkingHeaders (= 0.62.2)
268 | - ReactCommon/turbomodule/core (= 0.62.2)
269 | - React-RCTNetwork (0.62.2):
270 | - FBReactNativeSpec (= 0.62.2)
271 | - Folly (= 2018.10.22.00)
272 | - RCTTypeSafety (= 0.62.2)
273 | - React-Core/RCTNetworkHeaders (= 0.62.2)
274 | - ReactCommon/turbomodule/core (= 0.62.2)
275 | - React-RCTSettings (0.62.2):
276 | - FBReactNativeSpec (= 0.62.2)
277 | - Folly (= 2018.10.22.00)
278 | - RCTTypeSafety (= 0.62.2)
279 | - React-Core/RCTSettingsHeaders (= 0.62.2)
280 | - ReactCommon/turbomodule/core (= 0.62.2)
281 | - React-RCTText (0.62.2):
282 | - React-Core/RCTTextHeaders (= 0.62.2)
283 | - React-RCTVibration (0.62.2):
284 | - FBReactNativeSpec (= 0.62.2)
285 | - Folly (= 2018.10.22.00)
286 | - React-Core/RCTVibrationHeaders (= 0.62.2)
287 | - ReactCommon/turbomodule/core (= 0.62.2)
288 | - ReactCommon/callinvoker (0.62.2):
289 | - DoubleConversion
290 | - Folly (= 2018.10.22.00)
291 | - glog
292 | - React-cxxreact (= 0.62.2)
293 | - ReactCommon/turbomodule/core (0.62.2):
294 | - DoubleConversion
295 | - Folly (= 2018.10.22.00)
296 | - glog
297 | - React-Core (= 0.62.2)
298 | - React-cxxreact (= 0.62.2)
299 | - React-jsi (= 0.62.2)
300 | - ReactCommon/callinvoker (= 0.62.2)
301 | - RNCAsyncStorage (1.9.0):
302 | - React
303 | - Yoga (1.14.0)
304 | - YogaKit (1.18.1):
305 | - Yoga (~> 1.14)
306 |
307 | DEPENDENCIES:
308 | - ContactTracerReactNative (from `../node_modules/react-native-contact-tracer`)
309 | - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
310 | - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
311 | - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
312 | - Flipper (~> 0.33.1)
313 | - Flipper-DoubleConversion (= 1.1.7)
314 | - Flipper-Folly (~> 2.1)
315 | - Flipper-Glog (= 0.3.6)
316 | - Flipper-PeerTalk (~> 0.0.4)
317 | - Flipper-RSocket (~> 1.0)
318 | - FlipperKit (~> 0.33.1)
319 | - FlipperKit/Core (~> 0.33.1)
320 | - FlipperKit/CppBridge (~> 0.33.1)
321 | - FlipperKit/FBCxxFollyDynamicConvert (~> 0.33.1)
322 | - FlipperKit/FBDefines (~> 0.33.1)
323 | - FlipperKit/FKPortForwarding (~> 0.33.1)
324 | - FlipperKit/FlipperKitHighlightOverlay (~> 0.33.1)
325 | - FlipperKit/FlipperKitLayoutPlugin (~> 0.33.1)
326 | - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.33.1)
327 | - FlipperKit/FlipperKitNetworkPlugin (~> 0.33.1)
328 | - FlipperKit/FlipperKitReactPlugin (~> 0.33.1)
329 | - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.33.1)
330 | - FlipperKit/SKIOSNetworkPlugin (~> 0.33.1)
331 | - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
332 | - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
333 | - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
334 | - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
335 | - React (from `../node_modules/react-native/`)
336 | - React-Core (from `../node_modules/react-native/`)
337 | - React-Core/DevSupport (from `../node_modules/react-native/`)
338 | - React-Core/RCTWebSocket (from `../node_modules/react-native/`)
339 | - React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
340 | - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
341 | - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
342 | - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
343 | - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
344 | - "react-native-checkbox (from `../node_modules/@react-native-community/checkbox`)"
345 | - react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
346 | - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
347 | - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
348 | - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
349 | - React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
350 | - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
351 | - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
352 | - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
353 | - React-RCTText (from `../node_modules/react-native/Libraries/Text`)
354 | - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
355 | - ReactCommon/callinvoker (from `../node_modules/react-native/ReactCommon`)
356 | - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
357 | - "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
358 | - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
359 |
360 | SPEC REPOS:
361 | https://github.com/cocoapods/specs.git:
362 | - boost-for-react-native
363 | - CocoaAsyncSocket
364 | - CocoaLibEvent
365 | - Flipper
366 | - Flipper-DoubleConversion
367 | - Flipper-Folly
368 | - Flipper-Glog
369 | - Flipper-PeerTalk
370 | - Flipper-RSocket
371 | - FlipperKit
372 | - OpenSSL-Universal
373 | - YogaKit
374 |
375 | EXTERNAL SOURCES:
376 | ContactTracerReactNative:
377 | :path: "../node_modules/react-native-contact-tracer"
378 | DoubleConversion:
379 | :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
380 | FBLazyVector:
381 | :path: "../node_modules/react-native/Libraries/FBLazyVector"
382 | FBReactNativeSpec:
383 | :path: "../node_modules/react-native/Libraries/FBReactNativeSpec"
384 | Folly:
385 | :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec"
386 | glog:
387 | :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
388 | RCTRequired:
389 | :path: "../node_modules/react-native/Libraries/RCTRequired"
390 | RCTTypeSafety:
391 | :path: "../node_modules/react-native/Libraries/TypeSafety"
392 | React:
393 | :path: "../node_modules/react-native/"
394 | React-Core:
395 | :path: "../node_modules/react-native/"
396 | React-CoreModules:
397 | :path: "../node_modules/react-native/React/CoreModules"
398 | React-cxxreact:
399 | :path: "../node_modules/react-native/ReactCommon/cxxreact"
400 | React-jsi:
401 | :path: "../node_modules/react-native/ReactCommon/jsi"
402 | React-jsiexecutor:
403 | :path: "../node_modules/react-native/ReactCommon/jsiexecutor"
404 | React-jsinspector:
405 | :path: "../node_modules/react-native/ReactCommon/jsinspector"
406 | react-native-checkbox:
407 | :path: "../node_modules/@react-native-community/checkbox"
408 | react-native-get-random-values:
409 | :path: "../node_modules/react-native-get-random-values"
410 | React-RCTActionSheet:
411 | :path: "../node_modules/react-native/Libraries/ActionSheetIOS"
412 | React-RCTAnimation:
413 | :path: "../node_modules/react-native/Libraries/NativeAnimation"
414 | React-RCTBlob:
415 | :path: "../node_modules/react-native/Libraries/Blob"
416 | React-RCTImage:
417 | :path: "../node_modules/react-native/Libraries/Image"
418 | React-RCTLinking:
419 | :path: "../node_modules/react-native/Libraries/LinkingIOS"
420 | React-RCTNetwork:
421 | :path: "../node_modules/react-native/Libraries/Network"
422 | React-RCTSettings:
423 | :path: "../node_modules/react-native/Libraries/Settings"
424 | React-RCTText:
425 | :path: "../node_modules/react-native/Libraries/Text"
426 | React-RCTVibration:
427 | :path: "../node_modules/react-native/Libraries/Vibration"
428 | ReactCommon:
429 | :path: "../node_modules/react-native/ReactCommon"
430 | RNCAsyncStorage:
431 | :path: "../node_modules/@react-native-community/async-storage"
432 | Yoga:
433 | :path: "../node_modules/react-native/ReactCommon/yoga"
434 |
435 | SPEC CHECKSUMS:
436 | boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
437 | CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
438 | CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
439 | ContactTracerReactNative: 5b01f94268e609784ee40bd4171e4e81e37360e0
440 | DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
441 | FBLazyVector: 4aab18c93cd9546e4bfed752b4084585eca8b245
442 | FBReactNativeSpec: 5465d51ccfeecb7faa12f9ae0024f2044ce4044e
443 | Flipper: 6c1f484f9a88d30ab3e272800d53688439e50f69
444 | Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
445 | Flipper-Folly: 2de3d03e0acc7064d5e4ed9f730e2f217486f162
446 | Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
447 | Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
448 | Flipper-RSocket: 1260a31c05c238eabfa9bb8a64e3983049048371
449 | FlipperKit: 6dc9b8f4ef60d9e5ded7f0264db299c91f18832e
450 | Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
451 | glog: 1f3da668190260b06b429bb211bfbee5cd790c28
452 | OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
453 | RCTRequired: cec6a34b3ac8a9915c37e7e4ad3aa74726ce4035
454 | RCTTypeSafety: 93006131180074cffa227a1075802c89a49dd4ce
455 | React: 29a8b1a02bd764fb7644ef04019270849b9a7ac3
456 | React-Core: b12bffb3f567fdf99510acb716ef1abd426e0e05
457 | React-CoreModules: 4a9b87bbe669d6c3173c0132c3328e3b000783d0
458 | React-cxxreact: e65f9c2ba0ac5be946f53548c1aaaee5873a8103
459 | React-jsi: b6dc94a6a12ff98e8877287a0b7620d365201161
460 | React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da
461 | React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493
462 | react-native-checkbox: 2d04aeb0c7e2c2cbd9a9a902ca6a5cf642688d09
463 | react-native-get-random-values: 148a42f97f2ce180a52d219144e83c278d4fe24b
464 | React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
465 | React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0
466 | React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71
467 | React-RCTImage: e70be9b9c74fe4e42d0005f42cace7981c994ac3
468 | React-RCTLinking: c1b9739a88d56ecbec23b7f63650e44672ab2ad2
469 | React-RCTNetwork: 73138b6f45e5a2768ad93f3d57873c2a18d14b44
470 | React-RCTSettings: 6e3738a87e21b39a8cb08d627e68c44acf1e325a
471 | React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d
472 | React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256
473 | ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3
474 | RNCAsyncStorage: b16697280b08bab4b5f2f67f752d93d13a52e9ed
475 | Yoga: 3ebccbdd559724312790e7742142d062476b698e
476 | YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
477 |
478 | PODFILE CHECKSUM: 5bd16e8faf7545cf93bae9c78526b82ad07c74d9
479 |
480 | COCOAPODS: 1.7.2
481 |
--------------------------------------------------------------------------------
/android/src/main/java/com/nuuneoi/lib/contacttracer/service/TracerService.java:
--------------------------------------------------------------------------------
1 | package com.nuuneoi.lib.contacttracer.service;
2 |
3 | import android.app.ActivityManager;
4 | import android.app.AlarmManager;
5 | import android.app.Notification;
6 | import android.app.NotificationChannel;
7 | import android.app.NotificationManager;
8 | import android.app.PendingIntent;
9 | import android.app.Service;
10 | import android.app.job.JobInfo;
11 | import android.app.job.JobScheduler;
12 | import android.bluetooth.BluetoothAdapter;
13 | import android.bluetooth.BluetoothManager;
14 | import android.bluetooth.le.AdvertiseCallback;
15 | import android.bluetooth.le.AdvertiseData;
16 | import android.bluetooth.le.AdvertiseSettings;
17 | import android.bluetooth.le.BluetoothLeAdvertiser;
18 | import android.bluetooth.le.BluetoothLeScanner;
19 | import android.bluetooth.le.ScanCallback;
20 | import android.bluetooth.le.ScanFilter;
21 | import android.bluetooth.le.ScanRecord;
22 | import android.bluetooth.le.ScanResult;
23 | import android.bluetooth.le.ScanSettings;
24 | import android.content.ComponentName;
25 | import android.content.Context;
26 | import android.content.Intent;
27 | import android.content.SharedPreferences;
28 | import android.graphics.Color;
29 | import android.os.Build;
30 | import android.os.Handler;
31 | import android.os.IBinder;
32 | import android.os.ParcelUuid;
33 | import android.os.PowerManager;
34 | import android.os.SystemClock;
35 | import android.util.Log;
36 | import android.util.SparseArray;
37 | import android.widget.Toast;
38 |
39 | import com.nuuneoi.lib.contacttracer.R;
40 | import com.nuuneoi.lib.contacttracer.mock.IUser;
41 | import com.nuuneoi.lib.contacttracer.mock.User;
42 | import com.nuuneoi.lib.contacttracer.receiver.BootCompletedReceiver;
43 | import com.nuuneoi.lib.contacttracer.utils.BluetoothUtils;
44 | import com.nuuneoi.lib.contacttracer.utils.ResourcesUtils;
45 | import com.nuuneoi.lib.contacttracer.utils.Constants;
46 |
47 | import com.nuuneoi.lib.contacttracer.utils.ParseLeAdvData; // Added by Urng 2020.08.11
48 |
49 | import java.util.ArrayList;
50 | import java.util.List;
51 | import java.util.UUID;
52 |
53 | import androidx.annotation.Nullable;
54 | import androidx.annotation.RequiresApi;
55 | import androidx.core.app.NotificationCompat;
56 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
57 |
58 | public class TracerService extends Service {
59 |
60 | private static final int FOREGROUND_NOTIFICATION_ID = 20011;
61 |
62 | public static final String ADVERTISING_MESSAGE =
63 | "com.nuuneoi.contacttracer.advertiser_message";
64 | public static final String ADVERTISING_MESSAGE_EXTRA_MESSAGE = "message";
65 |
66 | public static final String NEARBY_DEVICE_FOUND_MESSAGE =
67 | "com.nuuneoi.contacttracer.nearbydevicefound_message";
68 | public static final String NEARBY_DEVICE_FOUND_EXTRA_NAME = "name";
69 | public static final String NEARBY_DEVICE_FOUND_EXTRA_RSSI = "rssi";
70 |
71 |
72 | public static final String NEARBY_BEACON_FOUND_MESSAGE =
73 | "com.nuuneoi.contacttracer.nearbybeaconfound_message";
74 | public static final String NEARBY_BEACON_FOUND_EXTRA_UUID = "uuid";
75 | public static final String NEARBY_BEACON_FOUND_EXTRA_MAJOR = "major";
76 | public static final String NEARBY_BEACON_FOUND_EXTRA_MINOR = "minor";
77 | public static final String NEARBY_BEACON_FOUND_EXTRA_RSSI = "rssi";
78 |
79 | // Bluetooth General
80 | private BluetoothAdapter bluetoothAdapter;
81 |
82 | // Bluetooth Advertiser
83 | private BluetoothLeAdvertiser bluetoothLeAdvertiser;
84 | SampleAdvertiseCallback advertiseCallback;
85 |
86 | // Bluetooth Scanner
87 | private BluetoothLeScanner bluetoothLeScanner;
88 | private SampleScanCallback scanCallback;
89 | private Handler handler;
90 |
91 | // User
92 | IUser user;
93 |
94 | // Wake Lock
95 | PowerManager.WakeLock wakeLock;
96 |
97 | // Misc
98 | Runnable autoRefreshTimerRunnable;
99 |
100 | // Scanner Timer
101 | Runnable scannerStartTimerRunnable;
102 |
103 | private boolean isStoppingSelf = false;
104 |
105 | @Override
106 | public void onCreate() {
107 | super.onCreate();
108 |
109 | goForeground();
110 |
111 | initInstances();
112 |
113 | initBluetoothInstances();
114 |
115 | if (bluetoothAdapter == null)
116 | exithWithToast(R.string.ble_not_supported);
117 |
118 | initBluetoothAdvertiser();
119 |
120 | initWakeLock();
121 |
122 | startAdvertising();
123 | startAdvertisingAutoRefresh();
124 |
125 | initBluetoothScanner();
126 | startScanning();
127 | startScannerTimer();
128 |
129 | initAlarm();
130 | }
131 |
132 | @Override
133 | public void onDestroy() {
134 | releaseWakeLock();
135 |
136 | stopAdvertising();
137 | stopForeground(true);
138 | stopAdvertisingAutoRefresh();
139 |
140 | stopScannerTimer();
141 | stopScanning();
142 |
143 | if (!isStoppingSelf)
144 | broadcastHealthCheck();
145 |
146 | super.onDestroy();
147 | }
148 |
149 | @Nullable
150 | @Override
151 | public IBinder onBind(Intent intent) {
152 | return null;
153 | }
154 |
155 | @Override
156 | public void onTaskRemoved(Intent rootIntent) {
157 | Intent restartServiceTask = new Intent(getApplicationContext(), this.getClass());
158 | restartServiceTask.setPackage(getPackageName());
159 | PendingIntent restartPendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceTask, PendingIntent.FLAG_ONE_SHOT);
160 | AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
161 | myAlarmService.set(
162 | AlarmManager.ELAPSED_REALTIME,
163 | SystemClock.elapsedRealtime() + 1000,
164 | restartPendingIntent);
165 |
166 | broadcastHealthCheck();
167 |
168 | super.onTaskRemoved(rootIntent);
169 | }
170 |
171 | private void exithWithToast(int string_resource_id) {
172 | Toast.makeText(this, string_resource_id, Toast.LENGTH_SHORT).show();
173 | isStoppingSelf = true;
174 | stopSelf();
175 | }
176 |
177 | private void initInstances() {
178 | user = new User(TracerService.this);
179 |
180 | handler = new Handler();
181 | autoRefreshTimerRunnable = new Runnable() {
182 | @Override
183 | public void run() {
184 | refreshAdvertiser();
185 | startAdvertisingAutoRefresh();
186 | }
187 | };
188 | scannerStartTimerRunnable = new Runnable() {
189 | @Override
190 | public void run() {
191 | startScanning();
192 | startScannerTimer();
193 | }
194 | };
195 | }
196 |
197 | /*************
198 | * Bluetooth *
199 | *************/
200 |
201 | private void initBluetoothInstances() {
202 | final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
203 | bluetoothAdapter = bluetoothManager.getAdapter();
204 | }
205 |
206 | /************************
207 | * Bluetooth Advertiser *
208 | ************************/
209 |
210 | private void initBluetoothAdvertiser() {
211 | if (bluetoothAdapter == null)
212 | return;
213 | if (bluetoothAdapter.getState() != BluetoothAdapter.STATE_ON)
214 | return;
215 | if (bluetoothLeAdvertiser == null) {
216 | final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
217 | if (bluetoothManager != null) {
218 | bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
219 | } else {
220 |
221 | }
222 | }
223 | }
224 |
225 | /**
226 | * Move service to the foreground, to avoid execution limits on background processes.
227 | *
228 | * Callers should call stopForeground(true) when background work is complete.
229 | */
230 | private void goForeground() {
231 | Intent notificationIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
232 |
233 | PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
234 | notificationIntent, 0);
235 |
236 | String channelId = "";
237 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
238 | channelId = createNotificationChannel("contact_tracer_service", "Contact Tracer Background Service");
239 |
240 | int icon_id = ResourcesUtils.getResourceId(TracerService.this, "ic_contact_tracer_noti", "drawable", getPackageName());
241 | if (icon_id <= 0)
242 | icon_id = R.drawable.ic_contact_tracer_noti_default;
243 |
244 | Notification n = new NotificationCompat.Builder(this, channelId)
245 | .setContentTitle("Advertising device via Bluetooth")
246 | .setContentText("This device is discoverable to others nearby.")
247 | .setSmallIcon(icon_id)
248 | .setContentIntent(pendingIntent)
249 | .setPriority(NotificationCompat.PRIORITY_HIGH)
250 | .build();
251 |
252 | startForeground(FOREGROUND_NOTIFICATION_ID, n);
253 | }
254 |
255 | @RequiresApi(Build.VERSION_CODES.O)
256 | private String createNotificationChannel(String channelId, String channelName) {
257 | NotificationChannel chan = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE);
258 | chan.setLightColor(Color.BLUE);
259 | chan.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
260 | NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
261 | service.createNotificationChannel(chan);
262 | return channelId;
263 | }
264 |
265 | @Override
266 | public int onStartCommand(Intent intent, int flags, int startId) {
267 | return START_STICKY;
268 | }
269 |
270 | /**
271 | * Starts BLE Advertising.
272 | */
273 | private void startAdvertising() {
274 | // Multiple Advertisement Required
275 | if (!BluetoothUtils.isMultipleAdvertisementSupported(bluetoothAdapter))
276 | return;
277 |
278 | if (bluetoothAdapter == null || bluetoothAdapter.getState() != BluetoothAdapter.STATE_ON)
279 | return;
280 |
281 | if (advertiseCallback == null) {
282 | sendSignalAndLog("Service: Starting Advertising");
283 |
284 | AdvertiseSettings settings = buildAdvertiseSettings();
285 | AdvertiseData data = buildAdvertiseData();
286 | advertiseCallback = new SampleAdvertiseCallback();
287 | if (bluetoothLeAdvertiser != null) {
288 | bluetoothLeAdvertiser.startAdvertising(settings, data,
289 | advertiseCallback);
290 | }
291 | }
292 | }
293 |
294 | /**
295 | * Stops BLE Advertising.
296 | */
297 | private void stopAdvertising() {
298 | sendSignalAndLog("Service: Stopping Advertising");
299 |
300 | if (bluetoothAdapter == null || bluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) {
301 | advertiseCallback = null;
302 | return;
303 | }
304 |
305 | if (bluetoothLeAdvertiser != null && advertiseCallback != null)
306 | bluetoothLeAdvertiser.stopAdvertising(advertiseCallback);
307 | advertiseCallback = null;
308 | }
309 |
310 | /**
311 | * Refresh Advertising
312 | */
313 | private void refreshAdvertiser() {
314 | sendSignalAndLog("Refresh Advertiser");
315 | stopAdvertising();
316 | startAdvertising();
317 | }
318 |
319 | /**
320 | * Setup Timer to Auto Refresh Advertising
321 | */
322 | private void startAdvertisingAutoRefresh() {
323 | handler.postDelayed(autoRefreshTimerRunnable, Constants.ADVERTISER_REFRESH_INTERVAL);
324 | }
325 |
326 | /**
327 | * Stop Advertising Auto Refresh Timer
328 | */
329 | private void stopAdvertisingAutoRefresh() {
330 | handler.removeCallbacks(autoRefreshTimerRunnable);
331 | }
332 |
333 | /**
334 | * Returns an AdvertiseData object which includes the Service UUID and Device Name.
335 | */
336 | private AdvertiseData buildAdvertiseData() {
337 | /**
338 | * Note: There is a strict limit of 31 Bytes on packets sent over BLE Advertisements.
339 | * This includes everything put into AdvertiseData including UUIDs, device info, &
340 | * arbitrary service or manufacturer data.
341 | * Attempting to send packets over this limit will result in a failure with error code
342 | * AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE. Catch this error in the
343 | * onStartFailure() method of an AdvertiseCallback implementation.
344 | */
345 | String id = user.getUserId();
346 | AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
347 | dataBuilder.addServiceUuid(BluetoothUtils.getServiceUUID(TracerService.this));
348 | //dataBuilder.setIncludeDeviceName(true);
349 | //dataBuilder.addServiceData(BluetoothUtils.getServiceUUID(TracerService.this), ByteUtils.intToByteArray(id));
350 | dataBuilder.addServiceData(BluetoothUtils.getServiceUUID(TracerService.this), id.getBytes());
351 | /* For example - this will cause advertising to fail (exceeds size limit) */
352 | // String failureData = "asdghkajsghalkxcjhfa;sghtalksjcfhalskfjhasldkjfhdskf";
353 | // dataBuilder.addServiceData(BluetoothUtils.getServiceUUID(TracerService.this), failureData.getBytes());
354 | return dataBuilder.build();
355 | }
356 |
357 | /**
358 | * Returns an AdvertiseSettings object set to use low power (to help preserve battery life)
359 | * and disable the built-in timeout since this code uses its own timeout runnable.
360 | */
361 |
362 | private AdvertiseSettings buildAdvertiseSettings() {
363 | AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
364 | settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
365 | settingsBuilder.setTimeout(0);
366 | return settingsBuilder.build();
367 | }
368 |
369 | /**
370 | * Custom callback after Advertising succeeds or fails to start. Broadcasts the error code
371 | * in an Intent to be picked up by AdvertiserFragment and stops this Service.
372 | */
373 | private class SampleAdvertiseCallback extends AdvertiseCallback {
374 | @Override
375 | public void onStartFailure(int errorCode) {
376 | super.onStartFailure(errorCode);
377 | sendSignalAndLog("Advertising failed");
378 | }
379 |
380 | @Override
381 | public void onStartSuccess(AdvertiseSettings settingsInEffect) {
382 | super.onStartSuccess(settingsInEffect);
383 | sendSignalAndLog("Advertising successfully started");
384 | }
385 | }
386 |
387 | private void sendSignalAndLog(CharSequence text) {
388 | Intent failureIntent = new Intent();
389 | failureIntent.setAction(ADVERTISING_MESSAGE);
390 | failureIntent.putExtra(ADVERTISING_MESSAGE_EXTRA_MESSAGE, text);
391 | LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(failureIntent);
392 | }
393 |
394 |
395 | private void sendNearbyDeviceFoundMessage(CharSequence name, int rssi) {
396 | Intent failureIntent = new Intent();
397 | failureIntent.setAction(NEARBY_DEVICE_FOUND_MESSAGE);
398 | failureIntent.putExtra(NEARBY_DEVICE_FOUND_EXTRA_NAME, name);
399 | failureIntent.putExtra(NEARBY_DEVICE_FOUND_EXTRA_RSSI, rssi);
400 | LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(failureIntent);
401 | }
402 |
403 | private void sendNearbyBeaconFoundMessage(String uuid, String major, String minor, String rssi) {
404 | Intent failureIntent = new Intent();
405 | failureIntent.setAction(NEARBY_BEACON_FOUND_MESSAGE);
406 | failureIntent.putExtra(NEARBY_BEACON_FOUND_EXTRA_UUID, uuid);
407 | failureIntent.putExtra(NEARBY_BEACON_FOUND_EXTRA_MAJOR, major);
408 | failureIntent.putExtra(NEARBY_BEACON_FOUND_EXTRA_MINOR, minor);
409 | failureIntent.putExtra(NEARBY_BEACON_FOUND_EXTRA_RSSI, rssi);
410 | LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(failureIntent);
411 | }
412 |
413 | /*********************
414 | * Bluetooth Scanner *
415 | *********************/
416 |
417 | private void initBluetoothScanner() {
418 | if (bluetoothAdapter == null)
419 | return;
420 | bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
421 | }
422 |
423 | /**
424 | * Setup Timer to Auto Refresh Advertising
425 | */
426 | private void startScannerTimer() {
427 | handler.postDelayed(scannerStartTimerRunnable, Constants.SCAN_INTERVAL);
428 | }
429 |
430 | /**
431 | * Stop Advertising Auto Refresh Timer
432 | */
433 | private void stopScannerTimer() {
434 | handler.removeCallbacks(scannerStartTimerRunnable);
435 | }
436 |
437 | /**
438 | * Start scanning for BLE Advertisements (& set it up to stop after a set period of time).
439 | */
440 | public void startScanning() {
441 | if (bluetoothAdapter == null || bluetoothAdapter.getState() != BluetoothAdapter.STATE_ON)
442 | return;
443 |
444 | if (scanCallback == null) {
445 | sendSignalAndLog("Start Scanning");
446 |
447 | // Will stop the scanning after a set time.
448 | handler.postDelayed(new Runnable() {
449 | @Override
450 | public void run() {
451 | stopScanning();
452 | }
453 | }, Constants.SCAN_PERIOD);
454 | // Kick off a new scan.
455 | scanCallback = new SampleScanCallback();
456 | if (bluetoothLeScanner != null)
457 | bluetoothLeScanner.startScan(buildScanFilters(), buildScanSettings(), scanCallback);
458 | } else {
459 |
460 | }
461 | }
462 | /**
463 | * Stop scanning for BLE Advertisements.
464 | */
465 | public void stopScanning() {
466 | sendSignalAndLog("Stop Scanning");
467 |
468 | if (bluetoothAdapter == null || bluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) {
469 | scanCallback = null;
470 | return;
471 | }
472 |
473 | // Stop the scan, wipe the callback.
474 | if (bluetoothLeScanner != null && scanCallback != null)
475 | bluetoothLeScanner.stopScan(scanCallback);
476 | scanCallback = null;
477 | // Even if no new results, update 'last seen' times.
478 | //mAdapter.notifyDataSetChanged();
479 | }
480 |
481 |
482 | /**
483 | * Return a List of {@link ScanFilter} objects to filter by Service UUID.
484 | */
485 | private List buildScanFilters() {
486 | List scanFilters = new ArrayList<>();
487 | ScanFilter.Builder builder = new ScanFilter.Builder();
488 |
489 | // // Comment out the below line to see all BLE devices around you - This is Other Phone that has MorChana
490 | // builder.setServiceUuid(BluetoothUtils.getServiceUUID(TracerService.this), ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"));
491 | // scanFilters.add(builder.build());
492 | //
493 | //
494 |
495 | //// // Comment out the below line to see all BLE devices around you - This is iBeacon
496 | ////// builder.setServiceUuid(ParcelUuid.fromString("26600EFA-ED3D-971A-3676-295C85BE6CE5"), ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"));
497 | //
498 | //
499 | // UUID uuid = UUID.fromString("26600EFA-ED3D-971A-3676-295C85BE6CE5");
500 | // final String hex = uuid.toString().replace("-","");;
501 | // final int length = hex.length();
502 | // final byte[] uuidByteArr = new byte[length / 2];
503 | // for (int i = 0; i < length; i += 2)
504 | // {
505 | // uuidByteArr[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i+1), 16));
506 | // }
507 | //
508 | // final byte[] manufacturerData = new byte[]
509 | // {
510 | // 0,0,
511 | //
512 | // // uuid
513 | // 0,0,0,0,
514 | // 0,0,
515 | // 0,0,
516 | // 0,0,0,0,0,0,0,0,
517 | //
518 | // // major
519 | // 0,0,
520 | //
521 | // // minor
522 | // 0,0,
523 | //
524 | // 0
525 | // };
526 | // // the mask tells what bytes in the filter need to match, 1 if it has to match, 0 if not
527 | // final byte[] manufacturerDataMask = new byte[]
528 | // {
529 | // 0,0,
530 | //
531 | // // uuid
532 | // 1,1,1,1,
533 | // 1,1,
534 | // 1,1,
535 | // 1,1,1,1,1,1,1,1,
536 | //
537 | // // major
538 | // 1,1,
539 | //
540 | // // minor
541 | // 1,1,
542 | //
543 | // 0
544 | // };
545 | //// byte[] manufacturerData = ParseLeAdvData.HexToByteArr("000026600EFAED3D971A3676295C85BE6CE50000000000"); //"00 00 26 60 0E FA ED 3D 97 1A 36 76 29 5C 85 BE 6C E5 00 00 00 00 00"
546 | //// byte[] manufacturerDataMask = ParseLeAdvData.HexToByteArr("0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000"); //"00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00"
547 | //
548 | // // copy UUID (with no dashes) into data array
549 | // System.arraycopy(uuidByteArr, 0, manufacturerData, 2, 16);
550 | //
551 | // // copy major into data array
552 | // System.arraycopy(integerToByteArray(0), 0, manufacturerData, 18, 2);
553 | //
554 | // // copy minor into data array
555 | // System.arraycopy(integerToByteArray(2), 0, manufacturerData, 20, 2);
556 | //
557 | // int MANUFACTURER_ID = 76;
558 | // builder.setManufacturerData( MANUFACTURER_ID,manufacturerData,manufacturerDataMask);
559 | // scanFilters.add(builder.build());
560 |
561 | return scanFilters;
562 |
563 |
564 | }
565 | /**
566 | * Return a {@link ScanSettings} object set to use low power (to preserve battery life).
567 | */
568 | private ScanSettings buildScanSettings() {
569 | ScanSettings.Builder builder = new ScanSettings.Builder();
570 | builder.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER);
571 | return builder.build();
572 | }
573 |
574 |
575 | /**
576 | * Custom ScanCallback object - adds to adapter on success, displays error on failure.
577 | */
578 | private class SampleScanCallback extends ScanCallback {
579 | @Override
580 | public void onBatchScanResults(List results) {
581 | super.onBatchScanResults(results);
582 | for (ScanResult result : results) {
583 | checkScanResult(result);
584 | }
585 | }
586 | @Override
587 | public void onScanResult(int callbackType, ScanResult result) {
588 | super.onScanResult(callbackType, result);
589 | checkScanResult(result);
590 |
591 | }
592 | @Override
593 | public void onScanFailed(int errorCode) {
594 | super.onScanFailed(errorCode);
595 | //Toast.makeText(TracerService.this, "Scan failed with error: " + errorCode, Toast.LENGTH_LONG)
596 | // .show();
597 | }
598 |
599 | private void checkScanResult(ScanResult result) {
600 | List serviceUuids;
601 | ScanRecord record = result.getScanRecord();
602 |
603 | // ParcelUuid DeviceUuid = BluetoothUtils.getServiceUUID(TracerService.this);
604 |
605 | // SparseArray manufacturerData = record.getManufacturerSpecificData();
606 | // for(int i = 0; i < manufacturerData.size(); i++){
607 | // int manufacturerId = manufacturerData.keyAt(i);
608 | // int a = 5;
609 | // }
610 |
611 | if (record!=null) {
612 |
613 | serviceUuids = record.getServiceUuids();
614 | String deviceName = result.getDevice().getName();
615 |
616 | //Check whether it is Phone(Device) with MorChana App -> [NearbyDeviceFound]
617 | //By Checking that ServiceUUID that was advertised is the same value as what we set
618 | if (serviceUuids != null) {
619 | ParcelUuid serviceUuid = serviceUuids.get(0);
620 | if (serviceUuid.equals(BluetoothUtils.getServiceUUID(TracerService.this))) {
621 | Log.i("DeviceScanFound", serviceUuid.toString());
622 | String value = getUserIdFromResult(result);
623 | sendNearbyDeviceFoundMessage(value, result.getRssi());
624 | Log.i("BluetoothScanFound", "userID:" + value + " rssi:" + result.getRssi());
625 | }
626 | } else {
627 | //Otherwise
628 | //Check if it is "iBeacon" -> [NearbyBeaconFound]
629 | // Is the found ScanResult iBeacon? if yes, the method from iBeacon Manufacturer will
630 | // successfully return the iBeaconInfo [uuid, major, minor, rssi_at_1m]
631 | byte[] buff = result.getScanRecord().getBytes();
632 | if (buff != null && buff.length > 0) {
633 | List iBeaconInfo = ParseLeAdvData.parse_iBeacon_info(buff); // [uuid, major, minor, rssi_at_1m]
634 | if (iBeaconInfo != null) {
635 | if (iBeaconInfo.get(0) != null) {
636 | String uuid = iBeaconInfo.get(0);
637 | String major = iBeaconInfo.get(1);
638 | String minor = iBeaconInfo.get(2);
639 | String rssi_at_1m = iBeaconInfo.get(3);
640 |
641 | Log.i("BeaconFound", "UUID:" + uuid);
642 |
643 | //check UUID Beacon
644 | // if (uuid.equals("26600EFAED3D971A3676295C85BE6CE5")) {
645 | // Log.i("MorChanaBeaconFound", uuid + "." + major + "." + minor + "(" + rssi_at_1m + ")");
646 | // // String value2 = getUserIdFromResult(result);
647 | sendNearbyBeaconFoundMessage(uuid, major, minor, rssi_at_1m);
648 | // }
649 | }
650 | }
651 |
652 | }
653 | }
654 | }
655 | }
656 | private String getUserIdFromResult(ScanResult result) {
657 | String value;
658 | byte[] data = result.getScanRecord().getServiceData(BluetoothUtils.getServiceUUID(TracerService.this));
659 |
660 | if (data != null)
661 | value = new String(data);
662 | else
663 | value = result.getDevice().getName();
664 | return value;
665 |
666 | }
667 |
668 |
669 | }
670 |
671 | /**
672 | * Wake lock
673 | */
674 | private void initWakeLock() {
675 | PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
676 | wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
677 | "AdvertiserService::lock");
678 | }
679 |
680 | private void releaseWakeLock() {
681 | try {
682 | if (wakeLock != null && wakeLock.isHeld()) {
683 | wakeLock.release();
684 | }
685 | } catch (Exception e) {
686 |
687 | }
688 | }
689 |
690 | /**
691 | * Alarm for forever running
692 | */
693 |
694 | private void initAlarm() {
695 | JobScheduler mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
696 | JobInfo.Builder builder = new JobInfo.Builder(1,
697 | new ComponentName(getPackageName(), SchedulerService.class.getName()));
698 | builder.setPeriodic(Constants.SERVICE_HEALTH_CHECK_INTERVAL);
699 | builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
700 | mJobScheduler.schedule(builder.build());
701 |
702 | AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
703 | Intent i = new Intent(TracerService.this, BootCompletedReceiver.class);
704 | PendingIntent pi = PendingIntent.getBroadcast(TracerService.this, 0, i, 0);
705 | am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000, Constants.SERVICE_HEALTH_CHECK_INTERVAL, pi); // Millisec * Second * Minute
706 | }
707 |
708 | private void broadcastHealthCheck() {
709 | Intent intent = new Intent("com.thaialert.servicehealthcheck");
710 | sendBroadcast(intent);
711 | }
712 |
713 | /**
714 | * Helper
715 | */
716 |
717 | public static boolean isRunning(Context context) {
718 | ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
719 | for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
720 | if (TracerService.class.getName().equals(service.service.getClassName())) {
721 | return true;
722 | }
723 | }
724 | return false;
725 | }
726 |
727 | public static boolean isEnabled(Context context) {
728 | SharedPreferences prefs = context.getSharedPreferences("Advertising", Context.MODE_PRIVATE);
729 | return prefs.getBoolean("service_enabled", false);
730 | }
731 |
732 | public static void enable(Context context) {
733 | SharedPreferences prefs = context.getSharedPreferences("Advertising", Context.MODE_PRIVATE);
734 | SharedPreferences.Editor editor = prefs.edit();
735 | editor.putBoolean("service_enabled", true);
736 | editor.apply();
737 | }
738 |
739 | public static void disable(Context context) {
740 | SharedPreferences prefs = context.getSharedPreferences("Advertising", Context.MODE_PRIVATE);
741 | SharedPreferences.Editor editor = prefs.edit();
742 | editor.putBoolean("service_enabled", false);
743 | editor.apply();
744 | }
745 |
746 | private static byte[] integerToByteArray(final int value)
747 | {
748 | final byte[] result = new byte[2];
749 | result[0] = (byte) (value / 256);
750 | result[1] = (byte) (value % 256);
751 |
752 | return result;
753 | }
754 | }
755 |
--------------------------------------------------------------------------------