From 0ebe51b26d98ed402888616d07a5d9639aa99272 Mon Sep 17 00:00:00 2001 From: Paolo Rotolo Date: Fri, 22 Mar 2019 22:12:40 +0100 Subject: [PATCH] Initial public release. Co-authored-by: Anna Labellarte Co-authored-by: Andrea Lops --- .gitignore | 13 + LICENSE | 201 ++++++++ README.md | 163 ++++++ advertiser/.gitignore | 1 + advertiser/build.gradle | 57 +++ advertiser/proguard-rules.pro | 21 + advertiser/src/main/AndroidManifest.xml | 48 ++ .../MainActivity.kt | 54 ++ .../drawable-v24/ic_launcher_foreground.xml | 50 ++ .../res/drawable/ic_launcher_background.xml | 90 ++++ .../src/main/res/layout/activity_main.xml | 36 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes advertiser/src/main/res/values/colors.xml | 22 + advertiser/src/main/res/values/strings.xml | 19 + advertiser/src/main/res/values/styles.xml | 27 + build.gradle | 50 ++ discoverer/.gitignore | 1 + discoverer/build.gradle | 69 +++ discoverer/proguard-rules.pro | 21 + discoverer/src/main/AndroidManifest.xml | 42 ++ .../MainActivity.kt | 163 ++++++ .../adapter/MainPagerAdapter.kt | 42 ++ .../fragment/AdvertiserConnectedFragment.kt | 47 ++ .../fragment/BaseFragment.kt | 62 +++ .../fragment/DoneFragment.kt | 47 ++ .../fragment/ErrorFragment.kt | 47 ++ .../fragment/PasswordDialogFragment.kt | 81 +++ .../fragment/ScanningFragment.kt | 47 ++ .../fragment/WelcomeFragment.kt | 48 ++ .../fragment/WifiConnectingFragment.kt | 47 ++ .../fragment/WifiSelectFragment.kt | 164 ++++++ .../helper/DiscovererViewPager.kt | 54 ++ .../viewmodel/MainViewModel.kt | 27 + .../viewmodel/WifiViewModel.kt | 29 ++ .../drawable-v24/ic_launcher_foreground.xml | 50 ++ discoverer/src/main/res/drawable/cancel.png | Bin 0 -> 14838 bytes discoverer/src/main/res/drawable/checked.png | Bin 0 -> 14518 bytes .../res/drawable/ic_launcher_background.xml | 90 ++++ .../main/res/drawable/ic_logo_nearby_48dp.xml | 75 +++ .../src/main/res/layout/activity_main.xml | 22 + .../src/main/res/layout/dialog_password.xml | 64 +++ .../main/res/layout/fragment_wifi_select.xml | 58 +++ .../src/main/res/layout/view_connected.xml | 72 +++ discoverer/src/main/res/layout/view_done.xml | 64 +++ discoverer/src/main/res/layout/view_error.xml | 65 +++ .../src/main/res/layout/view_item_wifi.xml | 39 ++ .../src/main/res/layout/view_scanning.xml | 72 +++ .../src/main/res/layout/view_welcome.xml | 64 +++ .../main/res/layout/view_wificonnecting.xml | 70 +++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes discoverer/src/main/res/values/colors.xml | 23 + discoverer/src/main/res/values/strings.xml | 19 + discoverer/src/main/res/values/styles.xml | 30 ++ docs/headlesswifimanager/alltypes/index.html | 83 +++ .../-generic-payload/-init-.html | 14 + .../-generic-payload/connection-ack.html | 14 + .../-generic-payload/id.html | 14 + .../-generic-payload/index.html | 58 +++ .../-generic-payload/results.html | 14 + .../-generic-payload/the-chosen-one.html | 14 + .../-wifi-connection-ack/-init-.html | 14 + .../-wifi-connection-ack/-s-s-i-d.html | 14 + .../-wifi-connection-ack/index.html | 44 ++ .../-wifi-connection-ack/result.html | 14 + .../-wifi-credentials-payload/-init-.html | 14 + .../-wifi-credentials-payload/index.html | 44 ++ .../-wifi-credentials-payload/password.html | 14 + .../-wifi-credentials-payload/result.html | 14 + .../-wifi-scan-result/-init-.html | 17 + .../-wifi-scan-result/-s-s-i-d.html | 14 + .../-wifi-scan-result/index.html | 65 +++ .../-wifi-scan-result/level.html | 14 + .../-wifi-scan-result/password.html | 14 + .../-wifi-scan-result/protected.html | 14 + .../index.html | 49 ++ .../-scan-result-converter/-init-.html | 14 + .../-scan-result-converter/index.html | 37 ++ .../scan-results-to-wifi-scan-results.html | 14 + .../-wifi-helper/-i-e-e-e8021-x.html | 14 + .../-wifi-helper/-init-.html | 14 + .../-wifi-helper/-w-e-p.html | 14 + .../-wifi-helper/-w-p-a.html | 14 + .../-wifi-helper/-w-p-a2.html | 14 + .../-wifi-helper/-w-p-a_-e-a-p.html | 14 + .../get-drawable-from-r-s-s-i.html | 23 + .../-wifi-helper/index.html | 87 ++++ .../-wifi-helper/is-network-protected.html | 14 + .../index.html | 31 ++ .../-advertising-callback/index.html | 45 ++ .../on-advertising-started.html | 15 + .../-advertising-callback/on-error.html | 15 + .../-advertising-callback/on-success.html | 15 + .../-discovery-callback/index.html | 53 ++ .../-discovery-callback/on-connected.html | 14 + .../-discovery-callback/on-device-found.html | 14 + .../on-discovery-started.html | 14 + .../-discovery-callback/on-error.html | 14 + .../on-network-list-available.html | 14 + .../-network-callback/index.html | 32 ++ .../-network-callback/on-connected.html | 14 + .../-network-callback/on-error.html | 14 + .../index.html | 38 ++ .../-init-.html | 14 + ...-y-l-o-a-d_-c-h-o-s-e-n_-w-i-f-i_-i-d.html | 14 + ...-l-o-a-d_-s-c-a-n_-r-e-s-u-l-t-s_-i-d.html | 14 + .../-p-a-y-l-o-a-d_-w-i-f-i_-a-c-k_-i-d.html | 14 + .../index.html | 51 ++ .../-headless-wifi-manager/-init-.html | 20 + .../-scan-result-listener/index.html | 26 + .../on-scan-result-available.html | 14 + .../abort-procedure.html | 15 + .../advertising-callback.html | 14 + .../-headless-wifi-manager/app-i-d.html | 14 + .../connect-to-endpoint.html | 18 + .../current-connected-endpoint-id.html | 14 + .../discovery-callback.html | 14 + .../-headless-wifi-manager/index.html | 133 +++++ .../network-callback.html | 14 + .../send-wifi-credentials.html | 20 + .../start-advertising.html | 20 + .../start-discovery.html | 20 + .../index.html | 31 ++ docs/headlesswifimanager/index-outline.html | 473 ++++++++++++++++++ docs/headlesswifimanager/index.html | 46 ++ docs/headlesswifimanager/package-list | 7 + docs/style.css | 283 +++++++++++ gradle.properties | 37 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 22 + gradlew | 172 +++++++ gradlew.bat | 84 ++++ headlesswifimanager/.gitignore | 1 + headlesswifimanager/build.gradle | 72 +++ headlesswifimanager/proguard-rules.pro | 21 + .../src/main/AndroidManifest.xml | 25 + .../HeadlessWifiManager.kt | 350 +++++++++++++ .../HeadlessWifiManagerConstants.kt | 26 + .../data/GenericPayload.kt | 26 + .../data/WifiConnectionAck.kt | 22 + .../data/WifiCredentialsPayload.kt | 23 + .../data/WifiScanResult.kt | 30 ++ .../helper/ScanResultConverter.kt | 35 ++ .../headlesswifimanager/helper/WifiHelper.kt | 80 +++ .../interfaces/AdvertisingCallback.kt | 36 ++ .../interfaces/DiscoveryCallback.kt | 29 ++ .../interfaces/NetworkCallback.kt | 24 + .../ic_signal_wifi_0_bar_black_24dp.xml | 26 + .../ic_signal_wifi_1_bar_black_24dp.xml | 29 ++ .../ic_signal_wifi_1_bar_lock_black_24dp.xml | 32 ++ .../ic_signal_wifi_2_bar_black_24dp.xml | 29 ++ .../ic_signal_wifi_2_bar_lock_black_24dp.xml | 32 ++ .../ic_signal_wifi_3_bar_black_24dp.xml | 29 ++ .../ic_signal_wifi_3_bar_lock_black_24dp.xml | 29 ++ .../ic_signal_wifi_4_bar_black_24dp.xml | 25 + .../ic_signal_wifi_4_bar_lock_black_24dp.xml | 25 + .../ic_signal_wifi_off_black_24dp.xml | 25 + .../src/main/res/values/strings.xml | 19 + images/demo01.png | Bin 0 -> 63758 bytes images/demo02.png | Bin 0 -> 50860 bytes images/demo03.png | Bin 0 -> 47750 bytes images/demo04.png | Bin 0 -> 70028 bytes images/demo05.png | Bin 0 -> 77621 bytes images/demo06.png | Bin 0 -> 66849 bytes settings.gradle | 17 + 186 files changed, 6771 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 advertiser/.gitignore create mode 100644 advertiser/build.gradle create mode 100644 advertiser/proguard-rules.pro create mode 100644 advertiser/src/main/AndroidManifest.xml create mode 100644 advertiser/src/main/java/com/wideverse/headlesswifimanager_advertiser/MainActivity.kt create mode 100644 advertiser/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 advertiser/src/main/res/drawable/ic_launcher_background.xml create mode 100644 advertiser/src/main/res/layout/activity_main.xml create mode 100644 advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 advertiser/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 advertiser/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 advertiser/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 advertiser/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 advertiser/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 advertiser/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 advertiser/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 advertiser/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 advertiser/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 advertiser/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 advertiser/src/main/res/values/colors.xml create mode 100644 advertiser/src/main/res/values/strings.xml create mode 100644 advertiser/src/main/res/values/styles.xml create mode 100644 build.gradle create mode 100644 discoverer/.gitignore create mode 100644 discoverer/build.gradle create mode 100644 discoverer/proguard-rules.pro create mode 100644 discoverer/src/main/AndroidManifest.xml create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/MainActivity.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/adapter/MainPagerAdapter.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/AdvertiserConnectedFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/BaseFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/DoneFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ErrorFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/PasswordDialogFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ScanningFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WelcomeFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiConnectingFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiSelectFragment.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/helper/DiscovererViewPager.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/MainViewModel.kt create mode 100644 discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/WifiViewModel.kt create mode 100644 discoverer/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 discoverer/src/main/res/drawable/cancel.png create mode 100644 discoverer/src/main/res/drawable/checked.png create mode 100644 discoverer/src/main/res/drawable/ic_launcher_background.xml create mode 100644 discoverer/src/main/res/drawable/ic_logo_nearby_48dp.xml create mode 100644 discoverer/src/main/res/layout/activity_main.xml create mode 100644 discoverer/src/main/res/layout/dialog_password.xml create mode 100644 discoverer/src/main/res/layout/fragment_wifi_select.xml create mode 100644 discoverer/src/main/res/layout/view_connected.xml create mode 100644 discoverer/src/main/res/layout/view_done.xml create mode 100644 discoverer/src/main/res/layout/view_error.xml create mode 100644 discoverer/src/main/res/layout/view_item_wifi.xml create mode 100644 discoverer/src/main/res/layout/view_scanning.xml create mode 100644 discoverer/src/main/res/layout/view_welcome.xml create mode 100644 discoverer/src/main/res/layout/view_wificonnecting.xml create mode 100644 discoverer/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 discoverer/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 discoverer/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 discoverer/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 discoverer/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 discoverer/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 discoverer/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 discoverer/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 discoverer/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 discoverer/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 discoverer/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 discoverer/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 discoverer/src/main/res/values/colors.xml create mode 100644 discoverer/src/main/res/values/strings.xml create mode 100644 discoverer/src/main/res/values/styles.xml create mode 100644 docs/headlesswifimanager/alltypes/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-generic-payload/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-generic-payload/connection-ack.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-generic-payload/id.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-generic-payload/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-generic-payload/results.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-generic-payload/the-chosen-one.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-connection-ack/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-connection-ack/-s-s-i-d.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-connection-ack/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-connection-ack/result.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-credentials-payload/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-credentials-payload/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-credentials-payload/password.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-credentials-payload/result.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-scan-result/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-scan-result/-s-s-i-d.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-scan-result/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-scan-result/level.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-scan-result/password.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/-wifi-scan-result/protected.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.data/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-scan-result-converter/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-scan-result-converter/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-scan-result-converter/scan-results-to-wifi-scan-results.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/-i-e-e-e8021-x.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/-w-e-p.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/-w-p-a.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/-w-p-a2.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/-w-p-a_-e-a-p.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/get-drawable-from-r-s-s-i.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/-wifi-helper/is-network-protected.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.helper/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-advertising-callback/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-advertising-callback/on-advertising-started.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-advertising-callback/on-error.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-advertising-callback/on-success.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-discovery-callback/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-discovery-callback/on-connected.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-discovery-callback/on-device-found.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-discovery-callback/on-discovery-started.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-discovery-callback/on-error.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-discovery-callback/on-network-list-available.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-network-callback/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-network-callback/on-connected.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/-network-callback/on-error.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager.interfaces/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager-constants/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager-constants/-p-a-y-l-o-a-d_-c-h-o-s-e-n_-w-i-f-i_-i-d.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager-constants/-p-a-y-l-o-a-d_-s-c-a-n_-r-e-s-u-l-t-s_-i-d.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager-constants/-p-a-y-l-o-a-d_-w-i-f-i_-a-c-k_-i-d.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager-constants/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/-init-.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/-scan-result-listener/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/-scan-result-listener/on-scan-result-available.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/abort-procedure.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/advertising-callback.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/app-i-d.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/connect-to-endpoint.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/current-connected-endpoint-id.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/discovery-callback.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/index.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/network-callback.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/send-wifi-credentials.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/start-advertising.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/-headless-wifi-manager/start-discovery.html create mode 100644 docs/headlesswifimanager/com.wideverse.headlesswifimanager/index.html create mode 100644 docs/headlesswifimanager/index-outline.html create mode 100644 docs/headlesswifimanager/index.html create mode 100644 docs/headlesswifimanager/package-list create mode 100644 docs/style.css create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 headlesswifimanager/.gitignore create mode 100644 headlesswifimanager/build.gradle create mode 100644 headlesswifimanager/proguard-rules.pro create mode 100644 headlesswifimanager/src/main/AndroidManifest.xml create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/HeadlessWifiManager.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/HeadlessWifiManagerConstants.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/data/GenericPayload.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/data/WifiConnectionAck.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/data/WifiCredentialsPayload.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/data/WifiScanResult.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/helper/ScanResultConverter.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/helper/WifiHelper.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/interfaces/AdvertisingCallback.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/interfaces/DiscoveryCallback.kt create mode 100644 headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/interfaces/NetworkCallback.kt create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_0_bar_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_1_bar_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_1_bar_lock_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_2_bar_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_2_bar_lock_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_3_bar_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_3_bar_lock_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_4_bar_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_4_bar_lock_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/drawable/ic_signal_wifi_off_black_24dp.xml create mode 100644 headlesswifimanager/src/main/res/values/strings.xml create mode 100755 images/demo01.png create mode 100755 images/demo02.png create mode 100755 images/demo03.png create mode 100755 images/demo04.png create mode 100755 images/demo05.png create mode 100755 images/demo06.png create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b75303 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4f2d460 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Wideverse + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ee74f1 --- /dev/null +++ b/README.md @@ -0,0 +1,163 @@ +# Headless Wifi Manager + + + + +## Why this library +Imagine the classic "Google Home" situation. + +You have an Headless device (your Google Home) that isn't connected to WiFi. +Using your phone, you can configure your Google Home to connect to a specific network and then communicate with it more easily. + +## What this library do +This library assumes you have 2 devices. + * An **advertiser**, your headless device that is totally disconnected to WiFi and any other network. + * A **discoverer**, your phone that has a screen indeed (\o/) and can scan for nearby WiFi access points. + +Using Android **Nearby API**, the **discoverer** and the **advertiser** communicate without the need to be on the same network using a combination of Wifi hotspots and Bluetooth. + +The whole process can be summarized as follows: + 1. The **advertiser** starts advertising it's presence to nearby devices; + 2. The **discover** connects to an available advertiser and **receives a list of Wifi Networks from it**; + 3. The **discover** selects a network and sends it's credentials back to the **advertiser**; + 4. The **advertiser** connects to the network with the given credentials; + 5. The **advertiser** sends an acknowledgment with a positive or negative result to the **discoverer**; + +At the end of the procedure, the **advertiser** will be connected to the WiFi network and you'll be able to communicate with it, for example via standard HTTP requests. + + ## How to use it +1. **Add the JitPack repository to your build file** + + Add it in your root build.gradle at the end of repositories: +```gradle + allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } + } +``` + +2. **Add the dependency** + +```gradle + dependencies { + // AndroidX capable version + implementation 'com.github.wideverse:headless-wifi-manager:1.0.0' + } +``` + +**Initialize** the main object: + + + +```kotlin + val headlessWifiManager = HeadlessWifiManager(applicationContext, APP_ID) +``` + +**APP_ID** is an unique identifier that will allow your discoverers to filter and talk only with your advertisers and not other Nearby devices. + +## Device configuration +The following steps differs if you're deploying on your **Advertiser** or your **Discoverer** + +### Advertiser +```kotlin +headlessWifiManager.startAdvertising(object: AdvertisingCallback { + + override fun onAdvertisingStarted() { + Log.d(TAG, "Successfully started Advertising.") + } + + override fun onError(e: Exception) { + Log.e(TAG, "Procedure failed") + e.printStackTrace() + } + + override fun onSuccess() { + Log.d(TAG, "Successfully connected to Wifi.") + } + }) +``` + +### Discoverer +```kotlin +headlessWifiManager.startDiscovery(object: DiscoveryCallback { + override fun onDiscoveryStarted() { + Log.d(TAG, "Successfully started looking for nearby devices to configure") + } + + override fun onDeviceFound(endpointId: String,deviceName: String) { + Log.d(TAG, "Trying to connect to $deviceName") + // Here you can show a list with all the devices available + + // Let's assume we want to configure the first one discovered + headlessWifiManager.connectToEndpoint(endpointId) + } + + override fun onConnected() { + Log.d(TAG, "Sucessifully connected to a hub device") + Log.d(TAG, "Now waiting to get WiFi List from advertiser") + } + + override fun onNetworkListAvailable(results: List) { + Log.d(TAG, "Successfully made a connection. Wifi list is available.") + + // Here you can show a list with all the WiFi network available + // that are stored in results + + // Let's take the first discovered network for semplicity + results[0].password = "sherLocked" + // If the network doesn't have a protection, leave the password filed empty + + // Then call sendWifiCredentials to send data back to the advertiser + headlessWifiManager.sendWifiCredentials(result, + object : NetworkCallback { + override fun onError(e: Exception) { + Log.e(TAG, "An error has occurred") + } + + override fun onConnected(SSID: String) { + Log.d(TAG, "ALL DONE! \o/") + + // Your advertiser is now connected to internet! + } + }) + } + + override fun onError(e: Exception) { + Log.e(TAG, "An error has occurred.") + } + }) + +``` + +## WifiHelper +This library contains an helper you can use to show users more accurate info about available WiFi networks in a nicer way. + +Using the method ```getDrawableFromRSSI(level: Int, protected: Boolean)``` you can directly get the appropriate resource drawable to show the **detected network RSSI** and a **lock if the network is protected** in an immediate way, similar to Android WiFi dialog. + + + +## WifiScanResult +```WifiScanResult``` is our internal object to pass info about WiFi networks. + +We decided to convert system object [ScanResult](https://developer.android.com/reference/android/net/wifi/ScanResult) available in the Android SDK to our [WifiScanResult](https://github.com/wideverse/headless-wifi-manager/blob/master/headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/data/WifiScanResult.kt). + +This allows us to **transfer only the useful data** between advertiser and discoverer and keep the payload simple and small. + +You can expect a ```List``` after a successful scanning and pass a ```WifiScanResult``` with a valorized ```password``` field to advertiser to connect on. You can find how the mapping between the two objects is done [here](https://github.com/wideverse/headless-wifi-manager/blob/master/headlesswifimanager/src/main/java/com/wideverse/headlesswifimanager/helper/ScanResultConverter.kt). + +If you think more fields of ```ScanResults``` needs to be added to our ```WifiScanResult``` to improve your logic, please feel free to **open a Pull Request**. + +# Example +An fully working Example app is available for you on this repo to see how to use the API and for insipration. +When you ```Import``` the project in Android Studio, you will see two modules ```advertiser``` and ```discoverer``` that you can deploy on your testing devices. + +The Example app also shows how to handle edge cases like **errors** and **empty WiFi list** received from the advertiser. + +The adveriser module DOESN'T have an UI since the device is supposed to be headless. Refer to system logs to figure what's happening. + +JavaDoc is available [here](https://wideverse.github.io/headless-wifi-manager/headlesswifimanager/). + +# About +This library has been developed at [Wideverse](https://www.wideverse.com/it/home-it/) @ [Polytechnic University of Bari](https://www.poliba.it/) and it's shared under Apache 2.0. diff --git a/advertiser/.gitignore b/advertiser/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/advertiser/.gitignore @@ -0,0 +1 @@ +/build diff --git a/advertiser/build.gradle b/advertiser/build.gradle new file mode 100644 index 0000000..84ff51b --- /dev/null +++ b/advertiser/build.gradle @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + + + compileSdkVersion 28 + defaultConfig { + applicationId "com.wideverse.headlesswifimanager_advertiser" + minSdkVersion 21 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.core:core-ktx:1.1.0-alpha04' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' + implementation project(':headlesswifimanager') +} diff --git a/advertiser/proguard-rules.pro b/advertiser/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/advertiser/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/advertiser/src/main/AndroidManifest.xml b/advertiser/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e244e88 --- /dev/null +++ b/advertiser/src/main/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/advertiser/src/main/java/com/wideverse/headlesswifimanager_advertiser/MainActivity.kt b/advertiser/src/main/java/com/wideverse/headlesswifimanager_advertiser/MainActivity.kt new file mode 100644 index 0000000..2d7168b --- /dev/null +++ b/advertiser/src/main/java/com/wideverse/headlesswifimanager_advertiser/MainActivity.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_advertiser + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import com.wideverse.headlesswifimanager.interfaces.AdvertisingCallback +import com.wideverse.headlesswifimanager.HeadlessWifiManager +import java.lang.Exception + +const val TAG = "HEADLESS_ADVERTISER" +const val APP_ID = "headless_wifi_configurator" + + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + // Headless device starts Advertising as soon as connected + HeadlessWifiManager(applicationContext, APP_ID) + .startAdvertising(object: AdvertisingCallback { + + override fun onAdvertisingStarted() { + Log.d(TAG, "Successfully started Advertising.") + } + + override fun onError(e: Exception) { + Log.e(TAG, "Procedure failed") + e.printStackTrace() + } + + override fun onSuccess() { + Log.d(TAG, "Successfully connected to Wifi.") + } + }) + } +} diff --git a/advertiser/src/main/res/drawable-v24/ic_launcher_foreground.xml b/advertiser/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..44ce3cf --- /dev/null +++ b/advertiser/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + diff --git a/advertiser/src/main/res/drawable/ic_launcher_background.xml b/advertiser/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..3db51b1 --- /dev/null +++ b/advertiser/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/advertiser/src/main/res/layout/activity_main.xml b/advertiser/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..df0afdd --- /dev/null +++ b/advertiser/src/main/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + + + + + + + \ No newline at end of file diff --git a/advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..419eb95 --- /dev/null +++ b/advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..419eb95 --- /dev/null +++ b/advertiser/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/advertiser/src/main/res/mipmap-hdpi/ic_launcher.png b/advertiser/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..898f3ed59ac9f3248734a00e5902736c9367d455 GIT binary patch literal 2963 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 JPDHLkV1g@XpTGbB literal 0 HcmV?d00001 diff --git a/advertiser/src/main/res/mipmap-hdpi/ic_launcher_round.png b/advertiser/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..dffca3601eba7bf5f409bdd520820e2eb5122c75 GIT binary patch literal 4905 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 lV%Z2*hu);6rydA(}wUDXPCF_W1vnaRBK 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 literal 0 HcmV?d00001 diff --git a/advertiser/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/advertiser/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..14ed0af35023e4f1901cf03487b6c524257b8483 GIT binary patch literal 6895 zcmVBruHaWfboaZ^`J@5OTb59uN+UwfO z>5DKPj6xxy*f-15A^38Hcw8gS)fY>m7X^~)>WdY`i-Y7Ev5tB;lGU`#+aci!MOUUM zD}qsF_F|N>IHn{!fdYTV_wX|;<46$x9(d2I{>ArDOEMG+AD^=P{ywF-GrY99`C;pd zTVmI*ebJ{Z?*lK5{2OnL{2bsnz#klb&V^vTF8LL3idsEt+KcA+ISDVmw89n=b3!uh}YH8Am2dcyFwO zP>3sYL|70%XiHU}0Zo+(MxFf$fG{c^GK8Lk0nm!?MOUlH=$7@wQ=P+?afrb30+O<` ziTG*r2zL#G;JREn?w(KwKTW>kAG@~nvD;BDbNA6Sw3X7nOleNtO`EFE_iw7?Nk@V% z2nn}DI|Z-=FUSS{e!iMKGH%z#^FftGb+nGAxybACovek#YjQ#vb&d*p+t1kJZ`xQz z;u|ZlH|p$>-hl#GilOt>$n{u0Xl)T;>j-tlI@@Z?Wzp-=)#G34?74swCQ~ERfdKmc zFhPnTvx5a7>%ShCv+=IbEiP%zhTLzjnoMn+{p#7s56cR+1Ip9!b!Tb z`Sm7~BP+1z^;S0iG7&)FAn@&x7D5ZD8A|Rn^8#NH904lXb|d*p^Im_M3cx}s7!4)T z9gHH`t8+}w++;htxjC@gx{~KPlVjj*{S_ks3$9(+#6u-Jl&IAP3pu!CJwK#M5t6c_ z>9wdD74a&~(E(Zk#1U@ZTtm|Z&dTxVSzAiRZr?zO5>r03qKN!s*CrAGLWn8vUzShH zLj>)tEVfOD(e%jX+M_)bim*#E5_p?Gy16VcdB?_AS3UnYnfh>x4oMP&MNjS{^B>++6>|-QpN0X@X6L&Y0v_nr&QpJ?Nedk76e$t+1QRS1iuh%{F%%f!H-mR|< zQLG8Eng=h6w*&uot15mDdp?pMw_z>mzOGmllD0RJTU#1Lm&egEdG8hyS)~+JzIUCL zOasw+)T%|5zrIFI%imD16;(cBT?v`6d!z2=P1Pi}_cC zaY){_eM2i&Osq}6Oy>Y2JfPjfx74>{k`N|n!sM^n$$Li~8z=DouS%NFPq=6oaadk$ z0*u&FPkPm9z)j6IfM-M)d8(pgV+4M-S4t-d{CpIET*U$q-ZNqpnS{w$epknMM*J)< zPm6>bel7I#uL*$fN%fSIg0yd#CHM7kuV;h_C^iY@0i^Gty9+J2aLrPcO&e_I4V!m|%QLzX;!0D_phPA9;f z54Vuq!_U%`L{EsIT^4|j0x3HRvX(Vc4%<2x@Oh2+Dn;)>o2t)Xj~&>w&Vc`00uyVP z+rjjLt~xt1(^VjmUESy@cLz5nC)L@%fx;yxhQ-ro#ptR%A^-9B0u$XgK)sha_CY+|f}c==vHJ zIsE14R^;ECC&mE-m5-zZK z+8{Cl>U!wJC$s|y>+%=$e8oRsp!aOoBrJ@MF;SPkbU$$FNuOD87#(v%q_;vE<)g{{ z)}HI>svC+uv;Os$twg|H_&AuO>#CKsTo>rM<9BT$m9M@;K7t9+k|;62$@KkG-xKZ2 zhe^_oMi>opdhOmo+KXR&YGro*f{q}Ep3j$aj{uxYnw$E)-`r`v*$LKBT)@uM9ye4J z-Q#1bNUOU9;6>Q;!8^3)TN3u@@%O2>^UtqNkTbvkW<`=Kz-yfT?N{=`iBIXo`W%cP zOF@78`!8CjaFJ~gEr7rbg{*#HA!~+a`8W%{Bz>w?4Y=;y{O2FrCCt!4 zuy^g+qyHvTAKvPoK+M_<8JLnR5|X`g3r*75jg0vjI+5}2Tc>@aBLzSo8U5@X@4sm^ z5-ujt+fn`dMM}KeB4Jx*2>uVv&wPi8j_zvT3~}C%Z`$&>zV&72aX)=W3XlNt!|X?Q zQm^Au32^rJ-)S6xb54f}0OiA!vY*2j%^E_@&@x*=87F{e-s!CjZ|nOe1f`XR>1IGiFlvUuJSK*t=o+=Yf5Tc5TadL2IQF() zEi;A4K7Fc758(rGN!uFr7=1be_I@-cIEM1amN~NnsQVQ zGnAj7{i)NE&jag-b#>GhG`pj=Hqeb+VmN|mT#uW%u2aZ9WP0=nqgD1a!xX1#>7~!l<@*A zoYvP%oqLK3P?~FShX9z1Sqj6ovlDNLrBCj+nMZO-0B}XA0IJ;6%pJ)C?Fk@Zmdxqz ztUAO8CbdHVQ=%<(ai;xq23`ZNh1c{dOsDraC(;Gp_x{_&8?%}28UgCOUzsT>BkT#_$;_WV*qs7k zaPyN$mvj4DM~Poi24V76Q+NQ14?o+kc?17edH8v_RvLR<5W!E8Nw&XzRMg*N-BY$S zuzP*nCBWq5k(6tj0?eD4;4Tw{lUUiyM?|NRtpotF6fZvOQYu;~fC>eGYcU+!A^_gI z>|g&+Jh5H^5!z*f#wXumUx4XTZuC;;xMdO!D9;DmFW!WFarO)uTvuikAf~*Cy!Q2% z?KVMgd~=fYTB|S$Fu1;)-b?J?fAZ6hBmmb%3fCA#XxAj1GG?%S0g^}b05|kYcetUL z-fe4Y`Q-Vtqy|P!>5)U^_~}z_aa-{kcrCnU&C4&rJ`sE|B!wvbkd_OtElu>j6jNVj3Vxd?2fw$+FBYCS|S$=CYSc<5Xi_2*; z&gOy)`=+1ggA3j5q=$gF`8aHR>b`OQ}eQ6h8^930& zTfz6uT#6in{r9oABIe_L$ArY#I_=r^EJ;?q_OB~WfagCwZZ1HRKmdgU5x6DEkfO}< zfwzyo4LP-t+{?-ekO2Z@S_?o$$g;aAA0l1(9&md- z<=AWj7QQA=_Jw~#d#mJ4?b#K9JJqf<0gnCn1538001ANs_@tzj2-yZ49YM<%;c8eY z$FZH)D*9o-^{baHqyo6OF>A<%3Ni|8q&>{r+d^jT-r}%~5L31_lEnvhk3OrL;pn_Wlg^IkA4rJe+-a^UwY7R5qH&49$;zI8q6 zuFa?QWFa#_X%0VCHo0|kEkwel#20?HhOE_Boonzd$ROVHrqv>s49lswR{|TU1x4L9 zYWUdAHK)eyY$D^fHyXs|f^6qRnrJT@3q;P}(?aHg7lc1M1q}7Ow>ObxkL;#qWh{6p zNoJ@q2lV_2;LW5yv5(xor2$M!4PBBnq0SsoCnSIMQwPW-xK9!YXN?9Ewl1gu%s7*t+Bg35~wxOdVL z_!J6maK$|`wmvrlW(J|R4Qp6SZiZ11h`rAlpa;f+xk}ztOG1=6^mika+17v_cwJcm znb@*{glqHQ_Z$<{mdK^Ro{!{5S13qeX|4t2CTLg$Yx3A^XhS&(#Cr%31fKxLk>AE+jwroWIAJqGD8O53ik6ycRr{+uucnefYQ1B=j?lwCZCL0Z!rfHSi)rM z13-u*5X=u3)NR;&OIH(34)$~;+?LI^bTx53U>L*(G1V#y+YdHhk;R@Ll=i?+OkCd- z%3*SEKUbcW_h90>pZQtm|g{tib$ zTp&#%&A4L)t+45A(Dt7dVJl9s;bIyEC|u)|eC+Xd1+WujnF-*8d}{%+%uSDM1z{$R z&7_>g#s<0G`%Nz|CMXD((fWe2kIJa1h~| z1dux=-=+ZA>r1lqv|jhme3Ej-a^{v(vpkqY`fO7a6BRX#kuLv&l7`Q~y7ROYB*UHn z+5!+@oj?G`=>;nRoTL}fw?`M#BtWKv2$vOLIJmo103=_5DFBm)B`<7DKe~FO@{*5NG})#;LV$p z^ny_Ujoc~u*wc9ddR8e}^0QYE$@Iz9$PLF)hny$v0ZvsH#-G7`E%D3)bN6Cny)?Oo z+qSv+;8rB2z(RmV8v@wL?N9-lEd{Wj+o1w%wGhA#`MdzbHr2Go)TqJbTt%3<(;lIm zAUDzU378K1rVR-b78b-Utqt;cXu%;L^r5#m;S(UOxMfca@Vp&7^2Kf$-2R72FCZ2X z4Uz3AJnS1&!MHIBQ6xl$8R)*9=6bq&fnGYy#$XFui~gt_LO97NkaamPlJi zG}q~I`=rPHvkwCoH&ISlZaVxMHavs*`M}$I$W4lzSC%}s2RCQw@i<@HvgZtV*b$z$ z1usHku}*8?kXySDgM-1OS3 zUTf%8r$G=$z>}u%up?*XVrolC&vhjv5k$Ci$41h-vY7O&P;e-=MkR~*S`E2p?^e2R z2iI-Qp)^O8l4dnAv4*)FoLKDvZ9bYE?D@AANMDDx52qZkTzGY)>9HjOKPle;xH&j= z@eBOKOmjv`Hyzps*NFnc=^TJ|TSRUrK%GPVdOzN?a*|%a6f$NpF_~t|=CiIQ=k0*a z_gF9s&CV^f?WRfhqJP7Z2i@Zm5rN+@gx^9pm|1YoJ~}B;5wdmmL}=@&iPu5z8@0Jc zAb{iaf=vM&M7XvE5Rxy|@!k$I=PsOZhtM{&ZTGnpnJdqF)xt#!N9$N6F zgblJ1XdAJum&oim79o@gW2kW(w3Y;Pl=9zrpi`& z!mJaI$>Fh;R0Qh?H=tA~fP;NIicACUUhq}tw&EHtE`c(si%&^rOkR(5#=6rsU|XEx(9YvlOxt7`7r?j;Y@Ha zPS9~Uq=Rp`VM6r6xi!r4g~#X|fyA-jV9L%Fxb&&yzc@|W8V$kHtq`T!J->k$fwT9f zIY8D*dwEf&fqFE>)T?2)4Pu@N7f&9Xf6RBr>&*6g&&!c~>&O}H zr#}qk$lyMl5QDrSl9VKmNn_^Ee2iK3e)M7{i32${3oSk1TC7gGkDd~w?cAO{}c+|2tHX7 zU#BJGcQlcR%3^u|EI#sS6Kjh|H*En;OH2Zj6;&!Hp+#ASkepSggI6tnD`?^Do&Mky z_(gS3!Fy7-66*lojXxVy`EzxYFjw%47oscmr^CW}fN#x@ih)QBU|84q*gJzJCZ~13 zcV=bGip38P%u7EKDP8$aq&)5O$o!1&t}Dv=F{)U027y0E7G!>hpM_^Fehd{2TmRyarwi zugRJiU+!L#tDSf;g80yf8j!fq&|tdLATY2y^~;e|A@Du?49j3d&XV1QyT&!b+bIYy pii9&6o*bz{@b60mWOsVP{|BB8eXZ|AYE1wD002ovPDHLkV1li`I!yoo literal 0 HcmV?d00001 diff --git a/advertiser/src/main/res/mipmap-xxhdpi/ic_launcher.png b/advertiser/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b0907cac3bfd8fbfdc46e1108247f0a1055387ec GIT binary patch literal 6387 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 literal 0 HcmV?d00001 diff --git a/advertiser/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/advertiser/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..d8ae03154975f397f8ed1b84f2d4bf9783ecfa26 GIT binary patch literal 10413 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 XdJ+W}DiIkV00000NkvXXu0mjfKBlg6 literal 0 HcmV?d00001 diff --git a/advertiser/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/advertiser/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..2c18de9e66108411737e910f5c1972476f03ddbf GIT binary patch literal 9128 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 I20H400LcNok^lez literal 0 HcmV?d00001 diff --git a/advertiser/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/advertiser/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..beed3cdd2c32af5114a7dc70b9ef5b698eb8797e GIT binary patch literal 15132 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 literal 0 HcmV?d00001 diff --git a/advertiser/src/main/res/values/colors.xml b/advertiser/src/main/res/values/colors.xml new file mode 100644 index 0000000..1919c1f --- /dev/null +++ b/advertiser/src/main/res/values/colors.xml @@ -0,0 +1,22 @@ + + + + + #008577 + #00574B + #D81B60 + diff --git a/advertiser/src/main/res/values/strings.xml b/advertiser/src/main/res/values/strings.xml new file mode 100644 index 0000000..e5ecc44 --- /dev/null +++ b/advertiser/src/main/res/values/strings.xml @@ -0,0 +1,19 @@ + + + + Headless Wifi Advertiser + diff --git a/advertiser/src/main/res/values/styles.xml b/advertiser/src/main/res/values/styles.xml new file mode 100644 index 0000000..4f3b965 --- /dev/null +++ b/advertiser/src/main/res/values/styles.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..8ba4aa4 --- /dev/null +++ b/build.gradle @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.kotlin_version = '1.3.21' + repositories { + google() + jcenter() + + } + ext { + dokkaVersion = '0.9.17' + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.3.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:$dokkaVersion" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + + } +} + +allprojects { + repositories { + google() + jcenter() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/discoverer/.gitignore b/discoverer/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/discoverer/.gitignore @@ -0,0 +1 @@ +/build diff --git a/discoverer/build.gradle b/discoverer/build.gradle new file mode 100644 index 0000000..f915577 --- /dev/null +++ b/discoverer/build.gradle @@ -0,0 +1,69 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +android { + compileSdkVersion 28 + + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + + + defaultConfig { + applicationId "com.wideverse.headlesswifimanager_discoverer" + minSdkVersion 21 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + vectorDrawables.useSupportLibrary = true + + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation 'com.github.ybq:Android-SpinKit:1.2.0' + implementation "org.jetbrains.anko:anko:0.10.8" + implementation 'com.karumi:dexter:5.0.0' + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' + implementation project(':headlesswifimanager') + implementation 'androidx.cardview:cardview:1.0.0' +} diff --git a/discoverer/proguard-rules.pro b/discoverer/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/discoverer/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/discoverer/src/main/AndroidManifest.xml b/discoverer/src/main/AndroidManifest.xml new file mode 100644 index 0000000..134d8f3 --- /dev/null +++ b/discoverer/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/MainActivity.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/MainActivity.kt new file mode 100644 index 0000000..d89d756 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/MainActivity.kt @@ -0,0 +1,163 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer + +import android.Manifest +import android.os.Bundle +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.ViewModelProviders +import com.wideverse.headlesswifimanager.interfaces.DiscoveryCallback +import com.wideverse.headlesswifimanager.HeadlessWifiManager +import com.wideverse.headlesswifimanager.data.WifiScanResult +import com.wideverse.headlesswifimanager.interfaces.NetworkCallback +import com.karumi.dexter.Dexter +import com.wideverse.headlesswifimanager_discoverer.adapter.MainPagerAdapter +import com.wideverse.headlesswifimanager_discoverer.fragment.BaseFragment +import com.wideverse.headlesswifimanager_discoverer.fragment.OnFragmentWifiSelected +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_ADVERTISER_CONNECTED +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_SCANNING +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_WELCOME +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_WIFI_CONNECTING +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_WIFI_DONE +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_WIFI_ERROR +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_WIFI_LIST +import com.wideverse.headlesswifimanager_discoverer.viewmodel.MainViewModel +import kotlinx.android.synthetic.main.activity_main.* +import java.lang.Exception +import com.karumi.dexter.PermissionToken +import com.karumi.dexter.listener.PermissionDeniedResponse +import com.karumi.dexter.listener.PermissionGrantedResponse +import com.karumi.dexter.listener.PermissionRequest +import com.karumi.dexter.listener.single.PermissionListener + + +const val APP_ID = "headless_wifi_configurator" +const val TAG = "HEADLESS_DISCOVERER" + +class MainActivity : AppCompatActivity(), + BaseFragment.OnFragmentInteractionListener, + OnFragmentWifiSelected { + + lateinit var viewModel: MainViewModel + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Dexter.withActivity(this) + .withPermission(Manifest.permission.ACCESS_FINE_LOCATION) + .withListener(object : PermissionListener { + override fun onPermissionGranted(response: PermissionGrantedResponse) {/* ... */ + } + + override fun onPermissionDenied(response: PermissionDeniedResponse) {/* ... */ + } + + override fun onPermissionRationaleShouldBeShown( + permission: PermissionRequest, + token: PermissionToken + ) {/* ... */ + } + }).check() + setContentView(R.layout.activity_main) + + viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) + + viewModel.headlessWifiManager = HeadlessWifiManager(applicationContext, APP_ID) + + viewModel.pagerAdapter = + MainPagerAdapter(supportFragmentManager) + + mainPager.adapter = viewModel.pagerAdapter + + mainPager.setCurrentItem(VIEW_WELCOME, false) + } + + private fun initiateProcedure() { + mainPager.invalidate() + + // Set Scanning fragment at start + mainPager.setCurrentItem(VIEW_SCANNING, false) + + viewModel.headlessWifiManager + .startDiscovery(object : DiscoveryCallback { + override fun onDiscoveryStarted() { + Log.d(TAG, "Successfully started looking for nearby devices to configure") + mainPager.setCurrentItem(VIEW_SCANNING, false) + } + + override fun onDeviceFound(endpointId: String, deviceName: String) { + Log.d(TAG, "Trying to connect to $deviceName") + // Right now first device discovered is automatically + // targeted for connection + viewModel.headlessWifiManager.connectToEndpoint(endpointId) + // TODO: add here multi device support + } + + override fun onConnected() { + Log.d(TAG, "Sucessifully connected to a hub device") + Log.d(TAG, "Now waiting to get WiFi List from advertiser") + mainPager.setCurrentItem(VIEW_ADVERTISER_CONNECTED, false) + } + + override fun onNetworkListAvailable(results: List) { + Log.d(TAG, "Successfully made a connection. Wifi list is available.") + mainPager.setCurrentItem(VIEW_WIFI_LIST, false) + viewModel.pagerAdapter.getWifiFragment().setWifiScanList(results) + } + + override fun onError(e: Exception) { + mainPager.setCurrentItem(VIEW_WIFI_ERROR, false) + } + }) + } + + override fun onFragmentWifiSelected(result: WifiScanResult?) { + if (result != null) { + mainPager.setSlide(VIEW_WIFI_CONNECTING) + viewModel.headlessWifiManager.sendWifiCredentials(result, + object : NetworkCallback { + override fun onError(e: Exception) { + mainPager.setCurrentItem(VIEW_WIFI_ERROR, false) + } + + override fun onConnected(SSID: String) { + mainPager.setCurrentItem(VIEW_WIFI_DONE, false) + } + }) + } else { + cancelProcedure(false) + } + } + + override fun onFragmentInteraction(id: String) { + when (id) { + "welcomeButton" -> initiateProcedure() + "cancelButton" -> cancelProcedure(false) + "doneButton" -> cancelProcedure(true) + } + } + + private fun cancelProcedure(finish: Boolean) { + mainPager.setCurrentItem(VIEW_WELCOME, false) + viewModel.headlessWifiManager.abortProcedure() + + if (finish) { + finish() + } + } +} \ No newline at end of file diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/adapter/MainPagerAdapter.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/adapter/MainPagerAdapter.kt new file mode 100644 index 0000000..500b9ec --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/adapter/MainPagerAdapter.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.adapter + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import com.wideverse.headlesswifimanager_discoverer.fragment.* +import com.wideverse.headlesswifimanager_discoverer.helper.DiscovererViewPager.Companion.VIEW_WIFI_LIST + + +class MainPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { + + private val fragmentList: List = listOf( + WelcomeFragment(), + ScanningFragment(), + AdvertiserConnectedFragment(), + WifiSelectFragment(), + WifiConnectingFragment(), + DoneFragment(), + ErrorFragment()) + + fun getWifiFragment(): WifiSelectFragment = fragmentList[VIEW_WIFI_LIST] as WifiSelectFragment + + override fun getItem(position: Int) = fragmentList[position] + + override fun getCount() = 7 +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/AdvertiserConnectedFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/AdvertiserConnectedFragment.kt new file mode 100644 index 0000000..6f3780b --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/AdvertiserConnectedFragment.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.wideverse.headlesswifimanager_discoverer.R +import kotlinx.android.synthetic.main.view_scanning.view.* + +class AdvertiserConnectedFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.view_connected, container, false) + + view.cancelButton.setOnClickListener { + fragmentListener?.onFragmentInteraction("cancelButton") + } + + return view + } + + companion object { + @JvmStatic + fun newInstance() = + AdvertiserConnectedFragment() + } +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/BaseFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/BaseFragment.kt new file mode 100644 index 0000000..1173191 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/BaseFragment.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + + +import android.content.Context +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.LayoutRes + +@LayoutRes +private var customLayout: Int = -1 + +open class BaseFragment : Fragment() { + protected var fragmentListener: OnFragmentInteractionListener? = null + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(customLayout, container, false) + } + + override fun onAttach(context: Context) { + super.onAttach(context) + if (context is OnFragmentInteractionListener) { + fragmentListener = context + } else { + throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener") + } + } + + interface OnFragmentInteractionListener { + fun onFragmentInteraction(id: String) + } + + + companion object { + @JvmStatic + fun newInstance(@LayoutRes layout: Int): BaseFragment = + BaseFragment().apply { + customLayout = layout + } + } +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/DoneFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/DoneFragment.kt new file mode 100644 index 0000000..efe9baa --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/DoneFragment.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.wideverse.headlesswifimanager_discoverer.R +import kotlinx.android.synthetic.main.view_done.view.* + +class DoneFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.view_done, container, false) + + view.doneButton.setOnClickListener { + fragmentListener?.onFragmentInteraction("doneButton") + } + + return view + } + + companion object { + @JvmStatic + fun newInstance() = + DoneFragment() + } +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ErrorFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ErrorFragment.kt new file mode 100644 index 0000000..683e472 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ErrorFragment.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.wideverse.headlesswifimanager_discoverer.R +import kotlinx.android.synthetic.main.view_error.view.* + +class ErrorFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.view_error, container, false) + + view.retryButton.setOnClickListener { + fragmentListener?.onFragmentInteraction("cancelButton") + } + + return view + } + + companion object { + @JvmStatic + fun newInstance() = + ErrorFragment() + } +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/PasswordDialogFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/PasswordDialogFragment.kt new file mode 100644 index 0000000..6fc6218 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/PasswordDialogFragment.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.text.method.HideReturnsTransformationMethod +import android.text.method.PasswordTransformationMethod +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import com.wideverse.headlesswifimanager.data.WifiScanResult +import com.wideverse.headlesswifimanager_discoverer.R +import kotlinx.android.synthetic.main.dialog_password.view.* + +class PasswordDialogFragment: DialogFragment(){ + lateinit var listener: OnFragmentWifiSelected + var wifiSelected: WifiScanResult? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + try { + listener = context as OnFragmentWifiSelected + } catch (e: ClassCastException) { + throw ClassCastException((context.toString() + + " must implement NoticeDialogListener")) + } + } + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return activity?.let { + val builder = AlertDialog.Builder(it) + val inflater = requireActivity().layoutInflater + val view = inflater.inflate(R.layout.dialog_password, null) + view.passwordLabel.text = "Type the password for the network ${wifiSelected?.SSID}" + view.passwordCheckbox.setOnCheckedChangeListener { buttonView, isChecked -> + if (isChecked) { + // hide password + view.passwordEditText.transformationMethod = HideReturnsTransformationMethod.getInstance() + view.passwordEditText.moveCursorToVisibleOffset() + } else { + // show password + view.passwordEditText.transformationMethod = PasswordTransformationMethod.getInstance() + view.passwordEditText.moveCursorToVisibleOffset() + } + } + builder.setView(view) + // Add action button + .setPositiveButton("Confirm" + ) { dialog, id -> + var password = view.passwordEditText.text.toString() + wifiSelected?.password = password + listener.onFragmentWifiSelected(wifiSelected!!) + + + // sign in the user ... + } + .setNegativeButton( + "Cancel" + ) { dialog, id -> + getDialog().cancel() + //fragmentListener.onDialogNegativeClick(this) + + } + builder.create() + } ?: throw IllegalStateException("Activity cannot be null") + } +} \ No newline at end of file diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ScanningFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ScanningFragment.kt new file mode 100644 index 0000000..85c9b36 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/ScanningFragment.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.wideverse.headlesswifimanager_discoverer.R +import kotlinx.android.synthetic.main.view_scanning.view.* + +class ScanningFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.view_scanning, container, false) + + view.cancelButton.setOnClickListener { + fragmentListener?.onFragmentInteraction("cancelButton") + } + + return view + } + + companion object { + @JvmStatic + fun newInstance() = + ScanningFragment() + } +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WelcomeFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WelcomeFragment.kt new file mode 100644 index 0000000..c2007bc --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WelcomeFragment.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.wideverse.headlesswifimanager_discoverer.R +import kotlinx.android.synthetic.main.view_welcome.view.* + +class WelcomeFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.view_welcome, container, false) + + view.welcomeButton.setOnClickListener { + fragmentListener?.onFragmentInteraction("welcomeButton") + } + + return view + } + + + companion object { + @JvmStatic + fun newInstance() = + ScanningFragment() + } +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiConnectingFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiConnectingFragment.kt new file mode 100644 index 0000000..f120431 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiConnectingFragment.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +import com.wideverse.headlesswifimanager_discoverer.R +import kotlinx.android.synthetic.main.view_scanning.view.* + +class WifiConnectingFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.view_wificonnecting, container, false) + + view.cancelButton.setOnClickListener { + fragmentListener?.onFragmentInteraction("cancelButton") + } + + return view + } + + companion object { + @JvmStatic + fun newInstance() = + WifiConnectingFragment() + } +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiSelectFragment.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiSelectFragment.kt new file mode 100644 index 0000000..6e48a43 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/fragment/WifiSelectFragment.kt @@ -0,0 +1,164 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.fragment + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.ViewModelProviders +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.wideverse.headlesswifimanager.data.WifiScanResult +import com.wideverse.headlesswifimanager.helper.WifiHelper +import com.wideverse.headlesswifimanager_discoverer.R +import com.wideverse.headlesswifimanager_discoverer.viewmodel.WifiViewModel +import kotlinx.android.synthetic.main.fragment_wifi_select.view.* +import kotlinx.android.synthetic.main.view_item_wifi.view.* +import org.jetbrains.anko.okButton +import org.jetbrains.anko.sdk27.coroutines.onClick +import org.jetbrains.anko.support.v4.alert + +class WifiSelectFragment : BaseFragment(), OnFragmentWifiSelected { + lateinit var viewModel: WifiViewModel + private var wifiListener: OnFragmentWifiSelected? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + viewModel = ViewModelProviders.of(this).get(WifiViewModel::class.java) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + val view = inflater.inflate(R.layout.fragment_wifi_select, container, false) + + view.cancelButton.onClick { + fragmentListener?.onFragmentInteraction("cancelButton") + } + + viewModel.recyclerAdapter = WifiViewAdapter(viewModel.wifiList, wifiListener!!) + viewModel.recyclerLayout = LinearLayoutManager(inflater.context) + + view.wifiRecycler.layoutManager = viewModel.recyclerLayout + view.wifiRecycler.adapter = viewModel.recyclerAdapter + + // Inflate the layout for this fragment + return view + } + + + override fun onFragmentWifiSelected(result: WifiScanResult?) { + if (result == null) { + wifiListener?.onFragmentWifiSelected(null) + } else { + viewModel.selectedWifi = result + val passwordDialog = PasswordDialogFragment() + passwordDialog.wifiSelected = result + + if (result.protected) { + passwordDialog.show(fragmentManager, "passwordFragment") + } else { + wifiListener?.onFragmentWifiSelected(result) + } + } + } + + fun setWifiScanList(wifiList: List) { + if (wifiList.isEmpty()) { + alert("No Wi-Fi network found. Try again later.") { + okButton { + wifiListener?.onFragmentWifiSelected(null) + } + }.apply { + isCancelable = false + show() + } + } + + viewModel.wifiList = wifiList + + view?.wifiRecycler?.adapter = + WifiViewAdapter(viewModel.wifiList, this) + + view?.wifiRecycler?.invalidate() + } + + override fun onAttach(context: Context) { + super.onAttach(context) + if (context is OnFragmentWifiSelected) { + wifiListener = context + } else { + throw RuntimeException("$context must implement OnFragmentInteractionListener") + } + } + + override fun onDetach() { + super.onDetach() + wifiListener = null + } + + /*override fun onDialogPositiveClick(dialog: DialogFragment, password: String) { + selectedWifi?.password = password + if (selectedWifi != null){ + wifiListener?.onFragmentWifiSelected(selectedWifi!!) + } + + print("$TAG: $password") + } + + override fun onDialogNegativeClick(dialog: DialogFragment) { + }*/ +} + +interface OnFragmentWifiSelected { + fun onFragmentWifiSelected(result: WifiScanResult?) +} + +class WifiViewAdapter(private val wifiList: List, private val listener: OnFragmentWifiSelected) : + RecyclerView.Adapter() { + + class WifiListHolder(val view: View) : RecyclerView.ViewHolder(view) + + + // Create new views (invoked by the layout manager) + override fun onCreateViewHolder(parent: ViewGroup, + viewType: Int): WifiListHolder { + + val view = LayoutInflater.from(parent.context).inflate(R.layout.view_item_wifi, parent, false) + + return WifiListHolder(view) + } + + // Replace the contents of a view (invoked by the layout manager) + override fun onBindViewHolder(holder: WifiListHolder, position: Int) { + val currentWifi = wifiList[position] + holder.view.wifiRssiIcon.setImageResource(WifiHelper.getDrawableFromRSSI(currentWifi.level, currentWifi.protected)) + holder.view.wifiTitle.text = wifiList[position].SSID + + holder.view.wifiItem.setOnClickListener { + listener.onFragmentWifiSelected(wifiList[position]) + } + } + + // Return the size of your dataset (invoked by the layout manager) + override fun getItemCount() = wifiList.size +} \ No newline at end of file diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/helper/DiscovererViewPager.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/helper/DiscovererViewPager.kt new file mode 100644 index 0000000..3bda8b0 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/helper/DiscovererViewPager.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.helper + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import androidx.viewpager.widget.ViewPager + + +class DiscovererViewPager : ViewPager { + + companion object { + const val VIEW_WELCOME = 0 + const val VIEW_SCANNING = 1 + const val VIEW_ADVERTISER_CONNECTED = 2 + const val VIEW_WIFI_LIST = 3 + const val VIEW_WIFI_CONNECTING = 4 + const val VIEW_WIFI_DONE = 5 + const val VIEW_WIFI_ERROR = 6 + } + + fun setSlide(position: Int){ + this.currentItem = position + } + + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { + // Never allow swiping to switch between pages + return false + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + // Never allow swiping to switch between pages + return false + } +} \ No newline at end of file diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/MainViewModel.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/MainViewModel.kt new file mode 100644 index 0000000..19aa1d0 --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/MainViewModel.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.viewmodel + +import androidx.lifecycle.ViewModel +import com.wideverse.headlesswifimanager.HeadlessWifiManager +import com.wideverse.headlesswifimanager_discoverer.adapter.MainPagerAdapter + + +class MainViewModel: ViewModel() { + lateinit var headlessWifiManager: HeadlessWifiManager + lateinit var pagerAdapter: MainPagerAdapter +} diff --git a/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/WifiViewModel.kt b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/WifiViewModel.kt new file mode 100644 index 0000000..f33eabc --- /dev/null +++ b/discoverer/src/main/java/com/wideverse/headlesswifimanager_discoverer/viewmodel/WifiViewModel.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Wideverse + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.wideverse.headlesswifimanager_discoverer.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.recyclerview.widget.LinearLayoutManager +import com.wideverse.headlesswifimanager.data.WifiScanResult +import com.wideverse.headlesswifimanager_discoverer.fragment.WifiViewAdapter + +class WifiViewModel: ViewModel() { + var wifiList: List = ArrayList() + var selectedWifi: WifiScanResult? = null + lateinit var recyclerAdapter: WifiViewAdapter + lateinit var recyclerLayout: LinearLayoutManager +} \ No newline at end of file diff --git a/discoverer/src/main/res/drawable-v24/ic_launcher_foreground.xml b/discoverer/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..44ce3cf --- /dev/null +++ b/discoverer/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + diff --git a/discoverer/src/main/res/drawable/cancel.png b/discoverer/src/main/res/drawable/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..844c8a8c60582ed91552ca9126d78a3825a0a51f GIT binary patch literal 14838 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 E0Gd^V$^ZZW literal 0 HcmV?d00001 diff --git a/discoverer/src/main/res/drawable/ic_launcher_background.xml b/discoverer/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..3db51b1 --- /dev/null +++ b/discoverer/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/discoverer/src/main/res/drawable/ic_logo_nearby_48dp.xml b/discoverer/src/main/res/drawable/ic_logo_nearby_48dp.xml new file mode 100644 index 0000000..3d95876 --- /dev/null +++ b/discoverer/src/main/res/drawable/ic_logo_nearby_48dp.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/discoverer/src/main/res/layout/activity_main.xml b/discoverer/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..e9bc40e --- /dev/null +++ b/discoverer/src/main/res/layout/activity_main.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/discoverer/src/main/res/layout/dialog_password.xml b/discoverer/src/main/res/layout/dialog_password.xml new file mode 100644 index 0000000..69b30ef --- /dev/null +++ b/discoverer/src/main/res/layout/dialog_password.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/discoverer/src/main/res/layout/fragment_wifi_select.xml b/discoverer/src/main/res/layout/fragment_wifi_select.xml new file mode 100644 index 0000000..fc434e7 --- /dev/null +++ b/discoverer/src/main/res/layout/fragment_wifi_select.xml @@ -0,0 +1,58 @@ + + + + + + + + +