├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_background.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── sample │ │ │ └── scanning │ │ │ └── SampleAct.java │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── sample │ │ │ └── scanning │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── sample │ │ └── scanning │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── scanning ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── icon1.png │ │ │ │ ├── icon2.png │ │ │ │ ├── icon3.png │ │ │ │ ├── icon4.png │ │ │ │ ├── icon5.png │ │ │ │ ├── icon6.png │ │ │ │ ├── icon7.png │ │ │ │ ├── icon8.png │ │ │ │ ├── icon9.png │ │ │ │ ├── icon10.png │ │ │ │ ├── icon11.png │ │ │ │ ├── icon12.png │ │ │ │ └── ic_arrow.xml │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── attrs.xml │ │ │ └── layout │ │ │ │ └── activity_main.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── bluetoothscanning │ │ │ │ ├── IBluetooth.java │ │ │ │ ├── IDetected.java │ │ │ │ ├── controller │ │ │ │ ├── BluetoothInterface.java │ │ │ │ └── BluetoothController.java │ │ │ │ ├── DetectedDevice.java │ │ │ │ ├── BluetoothConfig.java │ │ │ │ ├── Config.java │ │ │ │ ├── BluetoothDetection.java │ │ │ │ └── PulsatorLayout.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── bluetoothscanning │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── bluetoothscanning │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── scanning_image.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .github └── workflows │ ├── android.yml │ └── appdisturbution.yml ├── gradle.properties ├── README.md ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /scanning/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':scanning' 2 | -------------------------------------------------------------------------------- /scanning_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning_image.png -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Sample 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon1.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon2.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon3.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon4.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon5.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon6.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon7.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon8.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon9.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon10.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon11.png -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/icon12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/scanning/src/main/res/drawable/icon12.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /scanning/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 48dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manishkummar21/bluetoothscanning/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /scanning/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Scanning 3 | Bluetooth Scanning 4 | 5 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/IBluetooth.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | public interface IBluetooth { 4 | 5 | public void startPulse(); 6 | 7 | public void setName(String displayname); 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /scanning/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffff 4 | #1E90FF 5 | #ffffff 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Jun 16 22:12:53 IST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 7 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/IDetected.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import android.bluetooth.BluetoothDevice; 4 | 5 | import java.io.Serializable; 6 | 7 | public interface IDetected extends Serializable { 8 | 9 | public void onSelectedDevice(BluetoothDevice device); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /scanning/src/main/res/drawable/ic_arrow.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/sample/scanning/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.sample.scanning; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/controller/BluetoothInterface.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning.controller; 2 | 3 | public interface BluetoothInterface { 4 | 5 | public boolean checkIfDeviceSupports(); 6 | 7 | public void enableAllPermission(); 8 | 9 | public void enableBluetooth(); 10 | 11 | public void startDiscovery(); 12 | 13 | public void startDiscoveryDelay(); 14 | 15 | public void stopDiscovery(); 16 | 17 | public void setName(); 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /scanning/src/test/java/com/bluetoothscanning/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /scanning/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /scanning/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | apk: 11 | name: Generate APK 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: set up JDK 1.8 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 1.8 20 | - name: Build a Debug Apk 21 | run: bash ./gradlew assembleDebug --stacktrace 22 | - name: Upload Apk 23 | uses: actions/upload-artifact@v1 24 | with: 25 | name: app 26 | path: app/build/outputs/apk/debug/app-debug.apk 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /scanning/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /scanning/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /.github/workflows/appdisturbution.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | apk: 9 | name: Upload APK To FireBase App Disturbution 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: set up JDK 1.8 15 | uses: actions/setup-java@v1 16 | with: 17 | java-version: 1.8 18 | - name: Build a Debug Apk 19 | run: bash ./gradlew assembleDebug --stacktrace 20 | - name: upload artifact to Firebase App Distribution 21 | uses: manishkummar21/FirebaseAppDistribution-GithubAction@master 22 | with: 23 | appId: ${{secrets.FIREBASE_APP_ID}} 24 | token: ${{secrets.FIREBASE_TOKEN}} 25 | releaseNotes: Testing App Disturbution 26 | groups: QA 27 | file: app/build/outputs/apk/debug/app-debug.apk 28 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/sample/scanning/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.sample.scanning; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.sample.scanning", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scanning/src/androidTest/java/com/bluetoothscanning/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.bluetoothscanning.test", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/sample/scanning/SampleAct.java: -------------------------------------------------------------------------------- 1 | package com.sample.scanning; 2 | 3 | import android.bluetooth.BluetoothDevice; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | 7 | import androidx.annotation.Nullable; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | import com.bluetoothscanning.BluetoothConfig; 11 | import com.bluetoothscanning.IDetected; 12 | 13 | public class SampleAct extends AppCompatActivity implements IDetected { 14 | 15 | @Override 16 | protected void onCreate(@Nullable Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | 19 | BluetoothConfig.with(this) 20 | .setBackgroundColor(Color.parseColor("#1E90FF")) 21 | .setPulseColor(Color.parseColor("#ffffff")) 22 | .setListener(this) 23 | .start(); 24 | 25 | } 26 | 27 | @Override 28 | public void onSelectedDevice(BluetoothDevice device) { 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /scanning/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | group='com.github.manishkummar21' 5 | 6 | android { 7 | compileSdkVersion 29 8 | 9 | 10 | defaultConfig { 11 | minSdkVersion 15 12 | targetSdkVersion 29 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | dataBinding { 27 | enabled = true 28 | } 29 | 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(dir: 'libs', include: ['*.jar']) 34 | implementation 'androidx.appcompat:appcompat:1.0.2' 35 | testImplementation 'junit:junit:4.12' 36 | androidTestImplementation 'androidx.test:runner:1.2.0' 37 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 38 | } 39 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | defaultConfig { 6 | applicationId "com.sample.scanning" 7 | minSdkVersion 15 8 | targetSdkVersion 29 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | dataBinding { 20 | enabled = true 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(dir: 'libs', include: ['*.jar']) 26 | implementation 'androidx.appcompat:appcompat:1.0.2' 27 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 28 | testImplementation 'junit:junit:4.12' 29 | androidTestImplementation 'androidx.test:runner:1.2.0' 30 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 31 | implementation project(path: ':scanning') 32 | } 33 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | 21 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/DetectedDevice.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import android.os.Build; 4 | 5 | import androidx.annotation.RequiresApi; 6 | 7 | import java.util.Objects; 8 | 9 | public class DetectedDevice { 10 | private float x; 11 | private float y; 12 | 13 | public DetectedDevice(float x, float y) { 14 | this.x = x; 15 | this.y = y; 16 | } 17 | 18 | public float getX() { 19 | return x; 20 | } 21 | 22 | public void setX(float x) { 23 | this.x = x; 24 | } 25 | 26 | public float getY() { 27 | return y; 28 | } 29 | 30 | public void setY(float y) { 31 | this.y = y; 32 | } 33 | 34 | @Override 35 | public boolean equals(Object o) { 36 | if (this == o) return true; 37 | if (o == null || getClass() != o.getClass()) return false; 38 | DetectedDevice that = (DetectedDevice) o; 39 | return Float.compare(that.x, x) == 0 && 40 | Float.compare(that.y, y) == 0; 41 | } 42 | 43 | @RequiresApi(api = Build.VERSION_CODES.KITKAT) 44 | @Override 45 | public int hashCode() { 46 | return Objects.hash(x, y); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bluetoothscanning 2 | Scanning nearby bluetooth devices 3 | 4 | [![](https://jitpack.io/v/manishkummar21/bluetoothscanning.svg)](https://jitpack.io/#manishkummar21/bluetoothscanning) 5 | 6 | [![Android Arsenal]( https://img.shields.io/badge/Android%20Arsenal-Bluetooth%20Scanning-green.svg?style=flat )]( https://android-arsenal.com/details/1/7715 ) 7 | 8 | This app helps us to find the nearby discovered device continously and it will listed. 9 | 10 | **To do add the below code snippet anywhere from your projects in either activity or fragment and also implement listner IDetect which is callback which returns bluetooth object of selected device** 11 | 12 | 13 | ``` 14 | BluetoothConfig.with(this) 15 | .setBackgroundColor(Color.parseColor("#1E90FF")) 16 | .setPulseColor(Color.parseColor("#ffffff")) 17 | .setListener(this) 18 | .start(); 19 | ``` 20 | 21 | 22 | ![Screenshot](scanning_image.png) 23 | 24 | 25 | To get a Git project into your build: 26 | 27 | Step 1. Add the JitPack repository to your build file 28 | 29 | Add it in your root build.gradle at the end of repositories: 30 | 31 | allprojects { 32 | repositories { 33 | ... 34 | maven { url 'https://jitpack.io' } 35 | } 36 | } 37 | 38 | Step 2. Add the dependency 39 | 40 | dependencies { 41 | implementation 'com.github.manishkummar21:bluetoothscanning:v1.0' 42 | } 43 | 44 | Step 3. Enable the databinding in your project 45 | 46 | ``` 47 | dataBinding { 48 | enabled = true 49 | } 50 | ``` 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/BluetoothConfig.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import androidx.fragment.app.Fragment; 8 | 9 | import java.util.ArrayList; 10 | 11 | public class BluetoothConfig { 12 | 13 | private static abstract class BaseBuilder { 14 | 15 | protected Config config; 16 | protected IDetected listener; 17 | 18 | private BaseBuilder(Context context) { 19 | this.config = new Config(); 20 | } 21 | } 22 | 23 | 24 | public static abstract class Builder extends BaseBuilder { 25 | 26 | public Builder(Activity activity) { 27 | super(activity); 28 | } 29 | 30 | public Builder(Fragment fragment) { 31 | super(fragment.getActivity()); 32 | } 33 | 34 | public Builder setTitle(String title) { 35 | config.setTitle(title); 36 | return this; 37 | } 38 | 39 | public Builder setBackgroundColor(int color) { 40 | config.setBackgroundcolor(color); 41 | return this; 42 | } 43 | 44 | public Builder setPulseColor(int color) { 45 | config.setPulsecolor(color); 46 | return this; 47 | } 48 | 49 | public Builder setAvators(ArrayList images) { 50 | config.setAvatars(images); 51 | return this; 52 | } 53 | 54 | public Builder setListener(IDetected listener) { 55 | this.listener = listener; 56 | return this; 57 | } 58 | 59 | 60 | public abstract void start(); 61 | 62 | } 63 | 64 | static class ActivityBuilder extends Builder { 65 | private Activity activity; 66 | 67 | private ActivityBuilder(Activity activity) { 68 | super(activity); 69 | this.activity = activity; 70 | } 71 | 72 | @Override 73 | public void start() { 74 | Intent intent = new Intent(activity, BluetoothDetection.class); 75 | intent.putExtra(Config.EXTRA_CONFIG, config); 76 | intent.putExtra(Config.EXTRA_Listener, listener); 77 | activity.startActivity(intent); 78 | } 79 | } 80 | 81 | public static Builder with(Activity activity) { 82 | return new ActivityBuilder(activity); 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /scanning/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 18 | 19 | 26 | 27 | 28 | 29 | 39 | 40 | 46 | 47 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/Config.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | 9 | public class Config implements Parcelable { 10 | 11 | public static final String EXTRA_CONFIG = "config"; 12 | public static final String EXTRA_Listener = "listener"; 13 | 14 | private String title; 15 | private int backgroundcolor; 16 | private int pulsecolor; 17 | private ArrayList avatars; 18 | 19 | public Config() { 20 | 21 | } 22 | 23 | private Config(Parcel in) { 24 | this.title = in.readString(); 25 | this.backgroundcolor = in.readInt(); 26 | this.pulsecolor = in.readInt(); 27 | this.avatars = in.readArrayList(Integer.class.getClassLoader()); 28 | } 29 | 30 | public static final Creator CREATOR = new Creator() { 31 | @Override 32 | public Config createFromParcel(Parcel in) { 33 | return new Config(in); 34 | } 35 | 36 | @Override 37 | public Config[] newArray(int size) { 38 | return new Config[size]; 39 | } 40 | }; 41 | 42 | public String getTitle() { 43 | return title; 44 | } 45 | 46 | public void setTitle(String title) { 47 | this.title = title; 48 | } 49 | 50 | public int getBackgroundcolor() { 51 | return backgroundcolor; 52 | } 53 | 54 | public void setBackgroundcolor(int backgroundcolor) { 55 | this.backgroundcolor = backgroundcolor; 56 | } 57 | 58 | public int getPulsecolor() { 59 | return pulsecolor; 60 | } 61 | 62 | public void setPulsecolor(int pulsecolor) { 63 | this.pulsecolor = pulsecolor; 64 | } 65 | 66 | public ArrayList getAvatars() { 67 | if (avatars == null || avatars.isEmpty()) 68 | return new ArrayList<>(Arrays.asList(R.drawable.icon1, R.drawable.icon2, R.drawable.icon3, R.drawable.icon4, R.drawable.icon5, R.drawable.icon6, R.drawable.icon7, R.drawable.icon8, R.drawable.icon9, R.drawable.icon10, R.drawable.icon11, R.drawable.icon12)); 69 | return avatars; 70 | } 71 | 72 | public void setAvatars(ArrayList avatars) { 73 | this.avatars = avatars; 74 | } 75 | 76 | @Override 77 | public int describeContents() { 78 | return 0; 79 | } 80 | 81 | @Override 82 | public void writeToParcel(Parcel parcel, int i) { 83 | parcel.writeString(title); 84 | parcel.writeInt(backgroundcolor); 85 | parcel.writeInt(pulsecolor); 86 | parcel.writeList(avatars); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/controller/BluetoothController.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning.controller; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.bluetooth.BluetoothAdapter; 6 | import android.bluetooth.BluetoothDevice; 7 | import android.content.BroadcastReceiver; 8 | import android.content.Intent; 9 | import android.content.IntentFilter; 10 | import android.content.pm.PackageManager; 11 | import android.text.TextUtils; 12 | 13 | import androidx.core.app.ActivityCompat; 14 | import androidx.core.content.ContextCompat; 15 | 16 | import com.bluetoothscanning.IBluetooth; 17 | 18 | import java.util.Timer; 19 | import java.util.TimerTask; 20 | 21 | public class BluetoothController implements BluetoothInterface { 22 | 23 | private BluetoothAdapter bluetoothAdapter; 24 | private Activity activity; 25 | public static final int MY_PERMISSIONS_REQUEST_Location = 1; 26 | public static final int REQUEST_ENABLE_BT = 2; 27 | private BroadcastReceiver receiver; 28 | private IBluetooth listener; 29 | 30 | 31 | public BluetoothController(Activity activity, IBluetooth listener, BroadcastReceiver receiver) { 32 | this.activity = activity; 33 | this.listener = listener; 34 | this.receiver = receiver; 35 | bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 36 | } 37 | 38 | 39 | @Override 40 | public boolean checkIfDeviceSupports() { 41 | return bluetoothAdapter == null; 42 | } 43 | 44 | @Override 45 | public void enableAllPermission() { 46 | 47 | if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 48 | // Permission is not granted 49 | ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, MY_PERMISSIONS_REQUEST_Location); 50 | } else 51 | enableBluetooth(); 52 | 53 | 54 | } 55 | 56 | @Override 57 | public void enableBluetooth() { 58 | if (!bluetoothAdapter.isEnabled()) { 59 | Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 60 | activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 61 | } else 62 | startDiscoveryDelay(); 63 | 64 | 65 | } 66 | 67 | @Override 68 | public void startDiscovery() { 69 | 70 | stopDiscovery(); 71 | 72 | bluetoothAdapter.startDiscovery(); 73 | 74 | // Register for broadcasts when a device is discovered. 75 | IntentFilter filter = new IntentFilter(); 76 | filter.addAction(BluetoothDevice.ACTION_FOUND); 77 | filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 78 | filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 79 | activity.registerReceiver(receiver, filter); 80 | 81 | } 82 | 83 | @Override 84 | public void startDiscoveryDelay() { 85 | 86 | new Timer().schedule(new TimerTask() { 87 | @Override 88 | public void run() { 89 | startDiscovery(); 90 | } 91 | }, 3000); 92 | 93 | } 94 | 95 | @Override 96 | public void stopDiscovery() { 97 | 98 | if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) 99 | bluetoothAdapter.cancelDiscovery(); 100 | 101 | } 102 | 103 | @Override 104 | public void setName() { 105 | listener.setName(TextUtils.isEmpty(bluetoothAdapter.getName()) ? "UnKnown" : bluetoothAdapter.getName()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/BluetoothDetection.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import android.app.Activity; 4 | import android.bluetooth.BluetoothAdapter; 5 | import android.bluetooth.BluetoothDevice; 6 | import android.content.BroadcastReceiver; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.pm.PackageManager; 10 | import android.os.Bundle; 11 | import android.text.TextUtils; 12 | import android.widget.Toast; 13 | 14 | import androidx.annotation.NonNull; 15 | import androidx.annotation.Nullable; 16 | import androidx.appcompat.app.AppCompatActivity; 17 | import androidx.databinding.DataBindingUtil; 18 | 19 | import com.bluetoothscanning.controller.BluetoothController; 20 | import com.bluetoothscanning.databinding.ActivityMainBinding; 21 | 22 | 23 | public class BluetoothDetection extends AppCompatActivity implements IBluetooth { 24 | 25 | private String TAG = BluetoothDetection.class.getCanonicalName(); 26 | private ActivityMainBinding mainBinding; 27 | private BluetoothController controller; 28 | private Config config; 29 | private IDetected listener = null; 30 | 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); 36 | controller = new BluetoothController(this, this, receiver); 37 | config = getIntent().getParcelableExtra(Config.EXTRA_CONFIG); 38 | if (getIntent().hasExtra(Config.EXTRA_Listener)) 39 | listener = (IDetected) getIntent().getSerializableExtra(Config.EXTRA_Listener); 40 | 41 | //Initializing data from config 42 | mainBinding.title.setText(TextUtils.isEmpty(config.getTitle()) ? getString(R.string.title) : config.getTitle()); 43 | mainBinding.backgroundcolor.setBackgroundColor(config.getBackgroundcolor() == 0 ? getResources().getColor(R.color.backgroundcolor) : config.getBackgroundcolor()); 44 | mainBinding.pulsator.setColor(config.getPulsecolor() == 0 ? getResources().getColor(R.color.pulsecolor) : config.getPulsecolor()); 45 | mainBinding.pulsator.setAvators(config.getAvatars()); 46 | 47 | // let us check bluetoothSupports or not if not then finish the activity 48 | if (controller.checkIfDeviceSupports()) { 49 | Toast.makeText(getApplicationContext(), "Device not Support Bluetooth", Toast.LENGTH_LONG).show(); 50 | finish(); 51 | return; 52 | } 53 | 54 | controller.setName(); 55 | 56 | //Check the bluetooth persmission 57 | controller.enableAllPermission(); 58 | 59 | //Start Animation 60 | startPulse(); 61 | 62 | 63 | } 64 | 65 | @Override 66 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 67 | super.onActivityResult(requestCode, resultCode, data); 68 | if (requestCode == BluetoothController.REQUEST_ENABLE_BT && resultCode == Activity.RESULT_OK) { 69 | controller.startDiscoveryDelay(); 70 | } else 71 | finish(); 72 | } 73 | 74 | @Override 75 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 76 | // If request is cancelled, the result arrays are empty. 77 | if (requestCode == BluetoothController.MY_PERMISSIONS_REQUEST_Location) { 78 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 79 | controller.enableBluetooth(); 80 | } else { 81 | finish(); 82 | } 83 | } 84 | } 85 | 86 | // Create a BroadcastReceiver for ACTION_FOUND. 87 | private final BroadcastReceiver receiver = new BroadcastReceiver() { 88 | public void onReceive(Context context, Intent intent) { 89 | String action = intent.getAction(); 90 | if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) { 91 | mainBinding.pulsator.clearedDetectedDevices(); 92 | } else if (BluetoothDevice.ACTION_FOUND.equals(action)) { 93 | BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 94 | mainBinding.pulsator.addDetecteddevice(device); 95 | } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { 96 | controller.startDiscovery(); 97 | } 98 | } 99 | }; 100 | 101 | @Override 102 | protected void onDestroy() { 103 | super.onDestroy(); 104 | controller.stopDiscovery(); 105 | unregisterReceiver(receiver); 106 | } 107 | 108 | @Override 109 | public void startPulse() { 110 | 111 | mainBinding.pulsator.post(new Runnable() { 112 | @Override 113 | public void run() { 114 | mainBinding.pulsator.setListener(listener); 115 | mainBinding.pulsator.start(); 116 | } 117 | }); 118 | } 119 | 120 | @Override 121 | public void setName(final String displayname) { 122 | runOnUiThread(new Runnable() { 123 | @Override 124 | public void run() { 125 | mainBinding.name.setText(displayname); 126 | } 127 | }); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /scanning/src/main/java/com/bluetoothscanning/PulsatorLayout.java: -------------------------------------------------------------------------------- 1 | package com.bluetoothscanning; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.animation.ObjectAnimator; 6 | import android.bluetooth.BluetoothDevice; 7 | import android.content.Context; 8 | import android.content.res.TypedArray; 9 | import android.graphics.Bitmap; 10 | import android.graphics.Canvas; 11 | import android.graphics.Color; 12 | import android.graphics.Paint; 13 | import android.graphics.drawable.BitmapDrawable; 14 | import android.graphics.drawable.Drawable; 15 | import android.text.TextUtils; 16 | import android.util.AttributeSet; 17 | import android.view.Gravity; 18 | import android.view.View; 19 | import android.view.animation.AccelerateDecelerateInterpolator; 20 | import android.view.animation.AccelerateInterpolator; 21 | import android.view.animation.DecelerateInterpolator; 22 | import android.view.animation.Interpolator; 23 | import android.view.animation.LinearInterpolator; 24 | import android.widget.ImageView; 25 | import android.widget.LinearLayout; 26 | import android.widget.RelativeLayout; 27 | import android.widget.TextView; 28 | 29 | import java.util.ArrayList; 30 | import java.util.HashMap; 31 | import java.util.List; 32 | import java.util.Random; 33 | 34 | 35 | public class PulsatorLayout extends RelativeLayout { 36 | 37 | public static final int INFINITE = 0; 38 | 39 | public static final int INTERP_LINEAR = 0; 40 | public static final int INTERP_ACCELERATE = 1; 41 | public static final int INTERP_DECELERATE = 2; 42 | public static final int INTERP_ACCELERATE_DECELERATE = 3; 43 | 44 | private static final int DEFAULT_COUNT = 4; 45 | private static final int DEFAULT_COLOR = Color.rgb(0, 116, 193); 46 | private static final int DEFAULT_DURATION = 7000; 47 | private static final int DEFAULT_REPEAT = INFINITE; 48 | private static final boolean DEFAULT_START_FROM_SCRATCH = true; 49 | private static final int DEFAULT_INTERPOLATOR = INTERP_LINEAR; 50 | private final List mViews = new ArrayList<>(); 51 | private int mCount; 52 | private int mDuration; 53 | private int mRepeat; 54 | private boolean mStartFromScratch; 55 | private int mColor; 56 | private int mInterpolator; 57 | private AnimatorSet mAnimatorSet; 58 | private Paint mPaint; 59 | private float mRadius; 60 | private float mCenterX; 61 | private float mCenterY; 62 | private boolean mIsStarted; 63 | private List regions = new ArrayList<>(); 64 | private ArrayList detectedDevices; 65 | private RelativeLayout detectedDevice; 66 | private HashMap bluetoothDeviceHashMap; 67 | private int prev_radii = -1; 68 | private int prev_cor = 0; 69 | private IDetected listener; 70 | private ArrayList avators = new ArrayList<>(); 71 | private Random cor; 72 | 73 | 74 | private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { 75 | 76 | @Override 77 | public void onAnimationStart(Animator animator) { 78 | mIsStarted = true; 79 | } 80 | 81 | @Override 82 | public void onAnimationEnd(Animator animator) { 83 | mIsStarted = false; 84 | } 85 | 86 | @Override 87 | public void onAnimationCancel(Animator animator) { 88 | mIsStarted = false; 89 | } 90 | 91 | @Override 92 | public void onAnimationRepeat(Animator animator) { 93 | } 94 | 95 | }; 96 | 97 | 98 | private OnClickListener onClickListener = new OnClickListener() { 99 | @Override 100 | public void onClick(View view) { 101 | if (view.getTag() != null && listener != null) { 102 | BluetoothDevice device = (BluetoothDevice) view.getTag(); 103 | listener.onSelectedDevice(device); 104 | } 105 | } 106 | }; 107 | 108 | 109 | public PulsatorLayout(Context context) { 110 | this(context, null, 0); 111 | } 112 | 113 | public PulsatorLayout(Context context, AttributeSet attrs) { 114 | this(context, attrs, 0); 115 | } 116 | 117 | public PulsatorLayout(Context context, AttributeSet attrs, int defStyleAttr) { 118 | super(context, attrs, defStyleAttr); 119 | 120 | // get attributes 121 | TypedArray attr = context.getTheme().obtainStyledAttributes( 122 | attrs, R.styleable.Pulsator4Droid, 0, 0); 123 | 124 | mCount = DEFAULT_COUNT; 125 | mDuration = DEFAULT_DURATION; 126 | mRepeat = DEFAULT_REPEAT; 127 | mStartFromScratch = DEFAULT_START_FROM_SCRATCH; 128 | mColor = DEFAULT_COLOR; 129 | mInterpolator = DEFAULT_INTERPOLATOR; 130 | detectedDevices = new ArrayList<>(); 131 | bluetoothDeviceHashMap = new HashMap<>(); 132 | cor = new Random(); 133 | 134 | try { 135 | mCount = attr.getInteger(R.styleable.Pulsator4Droid_pulse_count, DEFAULT_COUNT); 136 | mDuration = attr.getInteger(R.styleable.Pulsator4Droid_pulse_duration, 137 | DEFAULT_DURATION); 138 | mRepeat = attr.getInteger(R.styleable.Pulsator4Droid_pulse_repeat, DEFAULT_REPEAT); 139 | mStartFromScratch = attr.getBoolean(R.styleable.Pulsator4Droid_pulse_startFromScratch, 140 | DEFAULT_START_FROM_SCRATCH); 141 | mColor = attr.getColor(R.styleable.Pulsator4Droid_pulse_color, DEFAULT_COLOR); 142 | mInterpolator = attr.getInteger(R.styleable.Pulsator4Droid_pulse_interpolator, 143 | DEFAULT_INTERPOLATOR); 144 | } finally { 145 | attr.recycle(); 146 | } 147 | 148 | // create paint 149 | mPaint = new Paint(); 150 | mPaint.setAntiAlias(true); 151 | mPaint.setStyle(Paint.Style.STROKE); 152 | mPaint.setStrokeWidth(8f); 153 | mPaint.setColor(mColor); 154 | 155 | // create views 156 | build(); 157 | } 158 | 159 | /** 160 | * Create interpolator from type. 161 | * 162 | * @param type Interpolator type as int 163 | * @return Interpolator object of type 164 | */ 165 | private static Interpolator createInterpolator(int type) { 166 | switch (type) { 167 | case INTERP_ACCELERATE: 168 | return new AccelerateInterpolator(); 169 | case INTERP_DECELERATE: 170 | return new DecelerateInterpolator(); 171 | case INTERP_ACCELERATE_DECELERATE: 172 | return new AccelerateDecelerateInterpolator(); 173 | default: 174 | return new LinearInterpolator(); 175 | } 176 | } 177 | 178 | public ArrayList getAvators() { 179 | return avators; 180 | } 181 | 182 | public void setAvators(ArrayList avators) { 183 | this.avators = avators; 184 | } 185 | 186 | public IDetected getListener() { 187 | return listener; 188 | } 189 | 190 | public void setListener(IDetected listener) { 191 | this.listener = listener; 192 | } 193 | 194 | /** 195 | * Start pulse animation. 196 | */ 197 | public synchronized void start() { 198 | if (mAnimatorSet == null || mIsStarted) { 199 | return; 200 | } 201 | 202 | mAnimatorSet.start(); 203 | 204 | if (!mStartFromScratch) { 205 | ArrayList animators = mAnimatorSet.getChildAnimations(); 206 | for (Animator animator : animators) { 207 | ObjectAnimator objectAnimator = (ObjectAnimator) animator; 208 | 209 | long delay = objectAnimator.getStartDelay(); 210 | objectAnimator.setStartDelay(0); 211 | objectAnimator.setCurrentPlayTime(mDuration - delay); 212 | } 213 | } 214 | } 215 | 216 | /** 217 | * Stop pulse animation. 218 | */ 219 | public synchronized void stop() { 220 | if (mAnimatorSet == null || !mIsStarted) { 221 | return; 222 | } 223 | 224 | mAnimatorSet.end(); 225 | } 226 | 227 | public synchronized boolean isStarted() { 228 | return (mAnimatorSet != null && mIsStarted); 229 | } 230 | 231 | /** 232 | * Get number of pulses. 233 | * 234 | * @return Number of pulses 235 | */ 236 | public int getCount() { 237 | return mCount; 238 | } 239 | 240 | /** 241 | * Set number of pulses. 242 | * 243 | * @param count Number of pulses 244 | */ 245 | public void setCount(int count) { 246 | if (count < 0) { 247 | throw new IllegalArgumentException("Count cannot be negative"); 248 | } 249 | 250 | if (count != mCount) { 251 | mCount = count; 252 | reset(); 253 | invalidate(); 254 | } 255 | } 256 | 257 | /** 258 | * Get pulse duration. 259 | * 260 | * @return Duration of single pulse in milliseconds 261 | */ 262 | public int getDuration() { 263 | return mDuration; 264 | } 265 | 266 | /** 267 | * Set single pulse duration. 268 | * 269 | * @param millis Pulse duration in milliseconds 270 | */ 271 | public void setDuration(int millis) { 272 | if (millis < 0) { 273 | throw new IllegalArgumentException("Duration cannot be negative"); 274 | } 275 | 276 | if (millis != mDuration) { 277 | mDuration = millis; 278 | reset(); 279 | invalidate(); 280 | } 281 | } 282 | 283 | /** 284 | * Gets the current color of the pulse effect in integer 285 | * Defaults to Color.rgb(0, 116, 193); 286 | * 287 | * @return an integer representation of color 288 | */ 289 | public int getColor() { 290 | return mColor; 291 | } 292 | 293 | /** 294 | * Sets the current color of the pulse effect in integer 295 | * Takes effect immediately 296 | * Usage: Color.parseColor("") or getResources().getColor(R.color.colorAccent) 297 | * 298 | * @param color : an integer representation of color 299 | */ 300 | public void setColor(int color) { 301 | if (color != mColor) { 302 | this.mColor = color; 303 | 304 | if (mPaint != null) { 305 | mPaint.setColor(color); 306 | } 307 | } 308 | } 309 | 310 | /** 311 | * Get current interpolator type used for animating. 312 | * 313 | * @return Interpolator type as int 314 | */ 315 | public int getInterpolator() { 316 | return mInterpolator; 317 | } 318 | 319 | /** 320 | * Set current interpolator used for animating. 321 | * 322 | * @param type Interpolator type as int 323 | */ 324 | public void setInterpolator(int type) { 325 | if (type != mInterpolator) { 326 | mInterpolator = type; 327 | reset(); 328 | invalidate(); 329 | } 330 | } 331 | 332 | @Override 333 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 334 | int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); 335 | int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom(); 336 | 337 | mCenterX = width * 0.5f; 338 | mCenterY = height * 0.5f; 339 | mRadius = Math.min(width, height) * 0.5f; 340 | regions.clear(); 341 | for (int i = 0; i < mCount; i++) 342 | regions.add((int) ((mRadius / mCount) * (i + 1))); 343 | 344 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 345 | } 346 | 347 | /** 348 | * Remove all views and animators. 349 | */ 350 | private void clear() { 351 | // remove animators 352 | stop(); 353 | 354 | // remove old views 355 | for (View view : mViews) { 356 | removeView(view); 357 | } 358 | mViews.clear(); 359 | } 360 | 361 | /** 362 | * Build pulse views and animators. 363 | */ 364 | private void build() { 365 | // create views and animators 366 | LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 367 | 368 | int repeatCount = (mRepeat == INFINITE) ? ObjectAnimator.INFINITE : mRepeat; 369 | 370 | List animators = new ArrayList<>(); 371 | 372 | for (int index = 0; index < mCount; index++) { 373 | // setup view 374 | PulseView pulseView = new PulseView(getContext()); 375 | pulseView.setScaleX(0); 376 | pulseView.setScaleY(0); 377 | pulseView.setAlpha(1); 378 | 379 | addView(pulseView, index, layoutParams); 380 | mViews.add(pulseView); 381 | 382 | long delay = index * mDuration / mCount; 383 | 384 | // setup animators 385 | ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(pulseView, "ScaleX", 0f, 1f); 386 | scaleXAnimator.setRepeatCount(repeatCount); 387 | scaleXAnimator.setRepeatMode(ObjectAnimator.RESTART); 388 | scaleXAnimator.setStartDelay(delay); 389 | animators.add(scaleXAnimator); 390 | 391 | ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(pulseView, "ScaleY", 0f, 1f); 392 | scaleYAnimator.setRepeatCount(repeatCount); 393 | scaleYAnimator.setRepeatMode(ObjectAnimator.RESTART); 394 | scaleYAnimator.setStartDelay(delay); 395 | animators.add(scaleYAnimator); 396 | 397 | ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(pulseView, "Alpha", 1f, 0f); 398 | alphaAnimator.setRepeatCount(repeatCount); 399 | alphaAnimator.setRepeatMode(ObjectAnimator.RESTART); 400 | alphaAnimator.setStartDelay(delay); 401 | animators.add(alphaAnimator); 402 | } 403 | 404 | mAnimatorSet = new AnimatorSet(); 405 | mAnimatorSet.playTogether(animators); 406 | mAnimatorSet.setInterpolator(createInterpolator(mInterpolator)); 407 | mAnimatorSet.setDuration(mDuration); 408 | mAnimatorSet.addListener(mAnimatorListener); 409 | 410 | //AddView Bluetooth deviceDetected 411 | detectedDevice = new RelativeLayout(getContext()); 412 | addView(detectedDevice, layoutParams); 413 | } 414 | 415 | public void addImageview(float x, float y, BluetoothDevice device, boolean isDetecteddevice) { 416 | 417 | x = x - (regions.get(0) / 2F); 418 | y = y - (regions.get(0) / 2F); 419 | 420 | 421 | if (!detectedDevices.contains(new DetectedDevice(x, y))) { 422 | LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 423 | 424 | LinearLayout l = new LinearLayout(getContext()); 425 | l.setGravity(Gravity.CENTER); 426 | l.setX(x); 427 | l.setY(y); 428 | l.setTag(device); 429 | l.setOrientation(LinearLayout.VERTICAL); // set orientation 430 | l.setLayoutParams(layoutParams); 431 | l.setOnClickListener(onClickListener); 432 | 433 | //ProfileImage 434 | LayoutParams imglayoutParams = new LayoutParams((int) getResources().getDimension(R.dimen.fourtyeight), (int) getResources().getDimension(R.dimen.fourtyeight)); 435 | ImageView useravator = new ImageView(getContext()); 436 | useravator.setLayoutParams(imglayoutParams); 437 | useravator.setImageDrawable(resize(getResources().getDrawable(getRandomAvators()), regions.get(0))); 438 | l.addView(useravator); 439 | 440 | //name of the device 441 | TextView name = new TextView(getContext()); 442 | name.setTextColor(getResources().getColor(R.color.white)); 443 | name.setLayoutParams(layoutParams); 444 | 445 | name.setText(TextUtils.isEmpty(device.getName()) ? "UNKNOWN" : device.getName()); 446 | 447 | l.addView(name); 448 | 449 | detectedDevice.addView(l); 450 | 451 | detectedDevices.add(new DetectedDevice(x, y)); 452 | } 453 | } 454 | 455 | /** 456 | * Reset views and animations. 457 | */ 458 | private void reset() { 459 | boolean isStarted = isStarted(); 460 | prev_radii = -1; 461 | 462 | clear(); 463 | build(); 464 | 465 | if (isStarted) { 466 | start(); 467 | } 468 | } 469 | 470 | @Override 471 | protected void onDetachedFromWindow() { 472 | super.onDetachedFromWindow(); 473 | 474 | if (mAnimatorSet != null) { 475 | mAnimatorSet.cancel(); 476 | mAnimatorSet = null; 477 | } 478 | } 479 | 480 | private Drawable resize(Drawable image, int size) { 481 | Bitmap b = ((BitmapDrawable) image).getBitmap(); 482 | Bitmap bitmapResized = Bitmap.createScaledBitmap(b, size, size, false); 483 | return new BitmapDrawable(getResources(), bitmapResized); 484 | } 485 | 486 | public void clearedDetectedDevices() { 487 | detectedDevice.removeAllViews(); 488 | detectedDevices.clear(); 489 | bluetoothDeviceHashMap.clear(); 490 | prev_radii = -1; 491 | } 492 | 493 | public void addDetecteddevice(BluetoothDevice device) { 494 | 495 | 496 | if (device != null && !TextUtils.isEmpty(device.getAddress()) && !bluetoothDeviceHashMap.containsKey(device.getAddress())) { 497 | bluetoothDeviceHashMap.put(device.getAddress(), device); 498 | double toDegrees = (getRandomCordinatesinPercentage() / 100F) * (2 * Math.PI); 499 | int radii = getRandomRadius(); 500 | float cor_x = (float) (mCenterX + Math.cos(toDegrees) * regions.get(radii)); 501 | float cor_y = (float) (mCenterY + Math.sin(toDegrees) * regions.get(radii)); 502 | addImageview(cor_x, cor_y, device, true); 503 | } 504 | 505 | 506 | } 507 | 508 | private class PulseView extends View { 509 | 510 | 511 | public PulseView(Context context) { 512 | super(context); 513 | } 514 | 515 | 516 | @Override 517 | protected void onDraw(Canvas canvas) { 518 | canvas.drawCircle(mCenterX, mCenterY, mRadius, mPaint); 519 | } 520 | 521 | } 522 | 523 | private int getRandomRadius() { 524 | int radii = new Random().nextInt((regions.size() - 2)) + 1; 525 | 526 | if (prev_radii != radii) { 527 | prev_radii = radii; 528 | return radii; 529 | } else 530 | return getRandomRadius(); 531 | } 532 | 533 | private int getRandomCordinatesinPercentage() { 534 | //Link i referred to learn is https://qiita.com/YuYuYuYoYoYo/items/8295a7db1cc818b00d15 535 | 536 | int percentage = cor.nextInt(75); 537 | 538 | if (percentage != prev_cor) { 539 | prev_cor = percentage; 540 | return percentage + 25; 541 | } else 542 | return getRandomCordinatesinPercentage(); 543 | 544 | } 545 | 546 | private int getRandomAvators() { 547 | return (int) avators.get(new Random().nextInt(avators.size())); 548 | } 549 | 550 | } 551 | --------------------------------------------------------------------------------