From a7c6f99c6fbb6fc3beb7a72c21b24003bdc07bdc Mon Sep 17 00:00:00 2001 From: kerwincui <164770707@qq.com> Date: Wed, 19 May 2021 15:46:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=89=E5=8D=93=E7=AB=AF?= =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/.gitignore | 16 + android/.idea/copyright/profiles_settings.xml | 7 + android/.idea/copyright/xuexiang.xml | 6 + android/LICENSE | 191 +++++ android/{移动端.txt => README.md} | 0 android/app/.gitignore | 1 + android/app/build.gradle | 131 ++++ android/app/channel | 25 + android/app/debug.jks | Bin 0 -> 2270 bytes android/app/multiple-channel.gradle | 10 + android/app/proguard-rules.pro | 269 +++++++ .../ExampleInstrumentedTest.java | 44 ++ android/app/src/main/AndroidManifest.xml | 147 ++++ android/app/src/main/assets/tips.json | 21 + .../app/src/main/ic_launcher-playstore.png | Bin 0 -> 31548 bytes .../src/main/java/com/kerwin/wumei/MyApp.java | 114 +++ .../wumei/activity/AddDeviceActivity.java | 410 +++++++++++ .../kerwin/wumei/activity/LoginActivity.java | 36 + .../kerwin/wumei/activity/MainActivity.java | 329 +++++++++ .../kerwin/wumei/activity/SplashActivity.java | 68 ++ .../broccoli/BroccoliRecyclerAdapter.java | 102 +++ .../BroccoliSimpleDelegateAdapter.java | 112 +++ .../base/delegate/BaseDelegateAdapter.java | 61 ++ .../base/delegate/SimpleDelegateAdapter.java | 64 ++ .../base/delegate/SingleDelegateAdapter.java | 72 ++ .../base/delegate/XDelegateAdapter.java | 300 ++++++++ .../adapter/entity/EspTouchViewModel.java | 31 + .../kerwin/wumei/adapter/entity/NewInfo.java | 199 +++++ .../com/kerwin/wumei/core/BaseActivity.java | 153 ++++ .../wumei/core/BaseContainerFragment.java | 123 ++++ .../com/kerwin/wumei/core/BaseFragment.java | 346 +++++++++ .../wumei/core/BaseSimpleListFragment.java | 284 ++++++++ .../kerwin/wumei/core/SimpleListAdapter.java | 80 +++ .../wumei/core/XPageTransferActivity.java | 56 ++ .../wumei/core/http/api/ApiService.java | 46 ++ .../core/http/callback/NoTipCallBack.java | 59 ++ .../wumei/core/http/callback/TipCallBack.java | 62 ++ .../callback/TipProgressLoadingCallBack.java | 70 ++ .../wumei/core/http/entity/TipInfo.java | 60 ++ .../http/loader/IProgressLoaderFactory.java | 50 ++ .../http/loader/MiniLoadingDialogLoader.java | 96 +++ .../loader/MiniProgressLoaderFactory.java | 41 ++ .../core/http/loader/ProgressLoader.java | 62 ++ .../subscriber/NoTipRequestSubscriber.java | 59 ++ .../TipProgressLoadingSubscriber.java | 75 ++ .../http/subscriber/TipRequestSubscriber.java | 64 ++ .../wumei/core/webview/AgentWebActivity.java | 127 ++++ .../wumei/core/webview/AgentWebFragment.java | 658 +++++++++++++++++ .../core/webview/BaseWebViewFragment.java | 66 ++ .../wumei/core/webview/FragmentKeyDown.java | 37 + .../core/webview/LollipopFixedWebView.java | 66 ++ .../core/webview/MiddlewareChromeClient.java | 49 ++ .../core/webview/MiddlewareWebViewClient.java | 146 ++++ .../wumei/core/webview/UIController.java | 56 ++ .../kerwin/wumei/core/webview/WebLayout.java | 61 ++ .../core/webview/WebViewInterceptDialog.java | 137 ++++ .../core/webview/XPageWebViewFragment.java | 677 ++++++++++++++++++ .../kerwin/wumei/fragment/AboutFragment.java | 66 ++ .../wumei/fragment/FeedbackFragment.java | 30 + .../kerwin/wumei/fragment/LoginFragment.java | 171 +++++ .../wumei/fragment/MessageFragment.java | 54 ++ .../wumei/fragment/SettingsFragment.java | 98 +++ .../fragment/device/AddDeviceFragment.java | 142 ++++ .../fragment/device/AddDeviceTwoFragment.java | 64 ++ .../wumei/fragment/device/DeviceFragment.java | 100 +++ .../fragment/device/EditDeviceFragment.java | 27 + .../FragmentStateViewPager2Adapter.java | 91 +++ .../wumei/fragment/device/GroupFragment.java | 27 + .../wumei/fragment/device/MultiPage.java | 44 ++ .../wumei/fragment/device/SceneFragment.java | 59 ++ .../fragment/device/ShareDeviceFragment.java | 29 + .../fragment/device/SimpleTabFragment.java | 255 +++++++ .../wumei/fragment/news/NewsFragment.java | 173 +++++ .../fragment/profile/ProfileFragment.java | 88 +++ .../kerwin/wumei/utils/DemoDataProvider.java | 154 ++++ .../com/kerwin/wumei/utils/MMKVUtils.java | 270 +++++++ .../java/com/kerwin/wumei/utils/NetUtils.java | 147 ++++ .../com/kerwin/wumei/utils/RandomUtils.java | 285 ++++++++ .../com/kerwin/wumei/utils/SettingUtils.java | 63 ++ .../com/kerwin/wumei/utils/TokenUtils.java | 100 +++ .../java/com/kerwin/wumei/utils/Utils.java | 175 +++++ .../com/kerwin/wumei/utils/XToastUtils.java | 161 +++++ .../wumei/utils/sdkinit/ANRWatchDogInit.java | 79 ++ .../kerwin/wumei/utils/sdkinit/UMengInit.java | 69 ++ .../wumei/utils/sdkinit/XBasicLibInit.java | 137 ++++ .../wumei/utils/sdkinit/XUpdateInit.java | 73 ++ .../service/JsonSerializationService.java | 66 ++ .../utils/update/CustomUpdateDownloader.java | 54 ++ .../update/CustomUpdateFailureListener.java | 59 ++ .../utils/update/CustomUpdateParser.java | 37 + .../wumei/utils/update/UpdateTipDialog.java | 75 ++ .../update/XHttpUpdateHttpServiceImpl.java | 111 +++ .../kerwin/wumei/widget/GuideTipsDialog.java | 208 ++++++ .../kerwin/wumei/widget/MaterialFooter.java | 124 ++++ ...selector_round_button_main_theme_color.xml | 24 + .../res/color/selector_tab_text_color.xml | 22 + .../app/src/main/res/drawable-hdpi/about.png | Bin 0 -> 5305 bytes .../app/src/main/res/drawable-hdpi/add.png | Bin 0 -> 2642 bytes .../src/main/res/drawable-hdpi/add_device.png | Bin 0 -> 15126 bytes .../src/main/res/drawable-hdpi/add_line.png | Bin 0 -> 16099 bytes .../src/main/res/drawable-hdpi/add_white.png | Bin 0 -> 2366 bytes .../app/src/main/res/drawable-hdpi/begin.png | Bin 0 -> 158191 bytes .../src/main/res/drawable-hdpi/category.png | Bin 0 -> 6520 bytes .../app/src/main/res/drawable-hdpi/device.png | Bin 0 -> 3353 bytes .../app/src/main/res/drawable-hdpi/down.png | Bin 0 -> 2319 bytes .../app/src/main/res/drawable-hdpi/group.png | Bin 0 -> 7278 bytes .../app/src/main/res/drawable-hdpi/hide.png | Bin 0 -> 7133 bytes .../src/main/res/drawable-hdpi/humidity.png | Bin 0 -> 6012 bytes .../src/main/res/drawable-hdpi/ic_comment.png | Bin 0 -> 978 bytes .../src/main/res/drawable-hdpi/ic_praise.png | Bin 0 -> 927 bytes .../app/src/main/res/drawable-hdpi/iot.png | Bin 0 -> 12468 bytes .../app/src/main/res/drawable-hdpi/light.png | Bin 0 -> 4958 bytes .../app/src/main/res/drawable-hdpi/logo.png | Bin 0 -> 3329 bytes .../main/res/drawable-hdpi/mobile_phone.png | Bin 0 -> 5482 bytes .../app/src/main/res/drawable-hdpi/name.png | Bin 0 -> 5169 bytes .../src/main/res/drawable-hdpi/no_wifi.png | Bin 0 -> 6379 bytes .../src/main/res/drawable-hdpi/offline.png | Bin 0 -> 8827 bytes .../app/src/main/res/drawable-hdpi/online.png | Bin 0 -> 8620 bytes .../src/main/res/drawable-hdpi/password.png | Bin 0 -> 5716 bytes .../app/src/main/res/drawable-hdpi/power.png | Bin 0 -> 7640 bytes .../app/src/main/res/drawable-hdpi/scene.png | Bin 0 -> 21435 bytes .../src/main/res/drawable-hdpi/sensors.png | Bin 0 -> 26994 bytes .../app/src/main/res/drawable-hdpi/share.png | Bin 0 -> 4715 bytes .../app/src/main/res/drawable-hdpi/show.png | Bin 0 -> 19481 bytes .../src/main/res/drawable-hdpi/state_a.png | Bin 0 -> 22883 bytes .../src/main/res/drawable-hdpi/state_b.png | Bin 0 -> 22810 bytes .../src/main/res/drawable-hdpi/switch_a.png | Bin 0 -> 20492 bytes .../src/main/res/drawable-hdpi/switch_b.png | Bin 0 -> 21791 bytes .../main/res/drawable-hdpi/switch_panel.png | Bin 0 -> 2905 bytes .../main/res/drawable-hdpi/temperature.png | Bin 0 -> 4571 bytes .../app/src/main/res/drawable-hdpi/time_a.png | Bin 0 -> 24735 bytes .../app/src/main/res/drawable-hdpi/time_b.png | Bin 0 -> 23893 bytes android/app/src/main/res/drawable-hdpi/up.png | Bin 0 -> 2298 bytes .../main/res/drawable-hdpi/water_valve.png | Bin 0 -> 4851 bytes .../app/src/main/res/drawable-hdpi/wifi.png | Bin 0 -> 6511 bytes .../res/drawable-v17/xui_config_bg_splash.xml | 34 + .../res/drawable-v21/xui_config_bg_splash.xml | 17 + .../drawable-v24/ic_launcher_foreground.xml | 34 + .../main/res/drawable-xxxhdpi/ic_web_back.png | Bin 0 -> 761 bytes .../res/drawable-xxxhdpi/ic_web_close.png | Bin 0 -> 416 bytes .../main/res/drawable-xxxhdpi/ic_web_more.png | Bin 0 -> 464 bytes .../bg_dialog_common_tip_corner_white.xml | 9 + .../res/drawable/ic_action_close_white.xml | 22 + .../src/main/res/drawable/ic_check_normal.xml | 9 + .../app/src/main/res/drawable/ic_checked.xml | 26 + .../src/main/res/drawable/ic_default_head.xml | 26 + .../res/drawable/ic_launcher_background.xml | 74 ++ .../src/main/res/drawable/ic_login_close.xml | 21 + .../app/src/main/res/drawable/ic_logo_app.xml | 29 + .../src/main/res/drawable/ic_menu_about.xml | 28 + .../src/main/res/drawable/ic_menu_issues.xml | 26 + .../src/main/res/drawable/ic_menu_news.xml | 28 + .../res/drawable/ic_menu_notifications.xml | 28 + .../src/main/res/drawable/ic_menu_person.xml | 28 + .../src/main/res/drawable/ic_menu_privacy.xml | 29 + .../src/main/res/drawable/ic_menu_search.xml | 28 + .../main/res/drawable/ic_menu_settings.xml | 28 + .../src/main/res/drawable/ic_menu_star.xml | 28 + .../main/res/drawable/ic_menu_trending.xml | 28 + .../app/src/main/res/drawable/ic_password.xml | 18 + .../app/src/main/res/drawable/ic_phone.xml | 4 + .../res/drawable/icon_arrow_right_grey.xml | 29 + .../src/main/res/drawable/icon_checkbox.xml | 9 + .../main/res/drawable/img_guide_tip_top.xml | 36 + .../main/res/layout/activity_agent_web.xml | 23 + .../app/src/main/res/layout/activity_main.xml | 26 + .../res/layout/adapter_button_top_item.xml | 51 ++ .../res/layout/adapter_common_grid_item.xml | 52 ++ .../adapter_device_card_view_list_item.xml | 211 ++++++ .../res/layout/adapter_item_simple_list_2.xml | 38 + .../adapter_news_card_view_list_item.xml | 172 +++++ .../main/res/layout/adapter_title_item.xml | 45 ++ .../src/main/res/layout/dialog_guide_tips.xml | 135 ++++ .../src/main/res/layout/fragment_about.xml | 74 ++ .../main/res/layout/fragment_add_device.xml | 172 +++++ .../res/layout/fragment_add_device_two.xml | 147 ++++ .../src/main/res/layout/fragment_agentweb.xml | 24 + .../src/main/res/layout/fragment_device.xml | 34 + .../main/res/layout/fragment_edit_device.xml | 14 + .../src/main/res/layout/fragment_feedback.xml | 14 + .../src/main/res/layout/fragment_group.xml | 14 + .../src/main/res/layout/fragment_login.xml | 203 ++++++ .../src/main/res/layout/fragment_message.xml | 14 + .../app/src/main/res/layout/fragment_news.xml | 52 ++ .../src/main/res/layout/fragment_profile.xml | 85 +++ .../main/res/layout/fragment_pulldown_web.xml | 30 + .../src/main/res/layout/fragment_scene.xml | 35 + .../src/main/res/layout/fragment_settings.xml | 75 ++ .../main/res/layout/fragment_share_device.xml | 14 + .../main/res/layout/fragment_simple_tab.xml | 57 ++ .../res/layout/include_head_view_banner.xml | 7 + .../res/layout/include_navigation_header.xml | 56 ++ .../main/res/layout/include_toolbar_web.xml | 77 ++ .../main/res/layout/layout_main_content.xml | 61 ++ android/app/src/main/res/menu/menu_drawer.xml | 47 ++ android/app/src/main/res/menu/menu_main.xml | 13 + .../main/res/menu/menu_navigation_bottom.xml | 39 + .../src/main/res/menu/menu_toolbar_web.xml | 43 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2285 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 3353 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4308 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1492 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 2109 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2636 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3293 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 4845 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6287 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5138 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 7935 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 9832 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 7300 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 11704 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 14152 bytes android/app/src/main/res/values/arrays.xml | 80 +++ android/app/src/main/res/values/colors.xml | 34 + android/app/src/main/res/values/dimens.xml | 16 + android/app/src/main/res/values/strings.xml | 103 +++ android/app/src/main/res/values/styles.xml | 64 ++ .../app/src/main/res/values/styles_widget.xml | 120 ++++ .../main/res/xml/network_security_config.xml | 21 + .../templateproject/ExampleUnitTest.java | 53 ++ android/app/x-library.gradle | 46 ++ android/build.gradle | 29 + android/esptouch/.gitignore | 1 + android/esptouch/README.md | 42 ++ android/esptouch/build.gradle | 31 + android/esptouch/proguard-rules.pro | 21 + android/esptouch/src/main/AndroidManifest.xml | 7 + .../iot/esptouch/EsptouchResult.java | 56 ++ .../espressif/iot/esptouch/EsptouchTask.java | 115 +++ .../iot/esptouch/IEsptouchListener.java | 11 + .../iot/esptouch/IEsptouchResult.java | 34 + .../espressif/iot/esptouch/IEsptouchTask.java | 61 ++ .../iot/esptouch/protocol/DataCode.java | 87 +++ .../iot/esptouch/protocol/DatumCode.java | 141 ++++ .../esptouch/protocol/EsptouchGenerator.java | 54 ++ .../iot/esptouch/protocol/GuideCode.java | 39 + .../iot/esptouch/protocol/TouchData.java | 22 + .../esptouch/security/ITouchEncryptor.java | 5 + .../iot/esptouch/security/TouchAES.java | 104 +++ .../esptouch/task/EsptouchTaskParameter.java | 165 +++++ .../iot/esptouch/task/ICodeData.java | 22 + .../iot/esptouch/task/IEsptouchGenerator.java | 17 + .../esptouch/task/IEsptouchTaskParameter.java | 156 ++++ .../iot/esptouch/task/__EsptouchTask.java | 351 +++++++++ .../iot/esptouch/task/__IEsptouchTask.java | 55 ++ .../iot/esptouch/udp/UDPSocketClient.java | 130 ++++ .../iot/esptouch/udp/UDPSocketServer.java | 149 ++++ .../espressif/iot/esptouch/util/ByteUtil.java | 323 +++++++++ .../com/espressif/iot/esptouch/util/CRC8.java | 63 ++ .../iot/esptouch/util/TouchNetUtil.java | 118 +++ android/gradle.properties | 24 + android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + android/gradlew | 172 +++++ android/gradlew.bat | 84 +++ android/settings.gradle | 1 + android/versions.gradle | 173 +++++ 260 files changed, 16889 insertions(+) create mode 100644 android/.gitignore create mode 100644 android/.idea/copyright/profiles_settings.xml create mode 100644 android/.idea/copyright/xuexiang.xml create mode 100644 android/LICENSE rename android/{移动端.txt => README.md} (100%) create mode 100644 android/app/.gitignore create mode 100644 android/app/build.gradle create mode 100644 android/app/channel create mode 100644 android/app/debug.jks create mode 100644 android/app/multiple-channel.gradle create mode 100644 android/app/proguard-rules.pro create mode 100644 android/app/src/androidTest/java/com/kerwin/templateproject/ExampleInstrumentedTest.java create mode 100644 android/app/src/main/AndroidManifest.xml create mode 100644 android/app/src/main/assets/tips.json create mode 100644 android/app/src/main/ic_launcher-playstore.png create mode 100644 android/app/src/main/java/com/kerwin/wumei/MyApp.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliRecyclerAdapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/BaseDelegateAdapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SimpleDelegateAdapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SingleDelegateAdapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/XDelegateAdapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/BaseActivity.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/BaseContainerFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/BaseFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/BaseSimpleListFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/SimpleListAdapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/XPageTransferActivity.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/callback/NoTipCallBack.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipCallBack.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipProgressLoadingCallBack.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/entity/TipInfo.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/loader/IProgressLoaderFactory.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniLoadingDialogLoader.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniProgressLoaderFactory.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/loader/ProgressLoader.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/NoTipRequestSubscriber.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipProgressLoadingSubscriber.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipRequestSubscriber.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebActivity.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/BaseWebViewFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/FragmentKeyDown.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/LollipopFixedWebView.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareChromeClient.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareWebViewClient.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/UIController.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/WebLayout.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/WebViewInterceptDialog.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/core/webview/XPageWebViewFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/EditDeviceFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/MultiPage.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/MMKVUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/NetUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/RandomUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/Utils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/XToastUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/ANRWatchDogInit.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/UMengInit.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XBasicLibInit.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/service/JsonSerializationService.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateDownloader.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateFailureListener.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateParser.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/update/UpdateTipDialog.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/update/XHttpUpdateHttpServiceImpl.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/widget/MaterialFooter.java create mode 100644 android/app/src/main/res/color/selector_round_button_main_theme_color.xml create mode 100644 android/app/src/main/res/color/selector_tab_text_color.xml create mode 100644 android/app/src/main/res/drawable-hdpi/about.png create mode 100644 android/app/src/main/res/drawable-hdpi/add.png create mode 100644 android/app/src/main/res/drawable-hdpi/add_device.png create mode 100644 android/app/src/main/res/drawable-hdpi/add_line.png create mode 100644 android/app/src/main/res/drawable-hdpi/add_white.png create mode 100644 android/app/src/main/res/drawable-hdpi/begin.png create mode 100644 android/app/src/main/res/drawable-hdpi/category.png create mode 100644 android/app/src/main/res/drawable-hdpi/device.png create mode 100644 android/app/src/main/res/drawable-hdpi/down.png create mode 100644 android/app/src/main/res/drawable-hdpi/group.png create mode 100644 android/app/src/main/res/drawable-hdpi/hide.png create mode 100644 android/app/src/main/res/drawable-hdpi/humidity.png create mode 100644 android/app/src/main/res/drawable-hdpi/ic_comment.png create mode 100644 android/app/src/main/res/drawable-hdpi/ic_praise.png create mode 100644 android/app/src/main/res/drawable-hdpi/iot.png create mode 100644 android/app/src/main/res/drawable-hdpi/light.png create mode 100644 android/app/src/main/res/drawable-hdpi/logo.png create mode 100644 android/app/src/main/res/drawable-hdpi/mobile_phone.png create mode 100644 android/app/src/main/res/drawable-hdpi/name.png create mode 100644 android/app/src/main/res/drawable-hdpi/no_wifi.png create mode 100644 android/app/src/main/res/drawable-hdpi/offline.png create mode 100644 android/app/src/main/res/drawable-hdpi/online.png create mode 100644 android/app/src/main/res/drawable-hdpi/password.png create mode 100644 android/app/src/main/res/drawable-hdpi/power.png create mode 100644 android/app/src/main/res/drawable-hdpi/scene.png create mode 100644 android/app/src/main/res/drawable-hdpi/sensors.png create mode 100644 android/app/src/main/res/drawable-hdpi/share.png create mode 100644 android/app/src/main/res/drawable-hdpi/show.png create mode 100644 android/app/src/main/res/drawable-hdpi/state_a.png create mode 100644 android/app/src/main/res/drawable-hdpi/state_b.png create mode 100644 android/app/src/main/res/drawable-hdpi/switch_a.png create mode 100644 android/app/src/main/res/drawable-hdpi/switch_b.png create mode 100644 android/app/src/main/res/drawable-hdpi/switch_panel.png create mode 100644 android/app/src/main/res/drawable-hdpi/temperature.png create mode 100644 android/app/src/main/res/drawable-hdpi/time_a.png create mode 100644 android/app/src/main/res/drawable-hdpi/time_b.png create mode 100644 android/app/src/main/res/drawable-hdpi/up.png create mode 100644 android/app/src/main/res/drawable-hdpi/water_valve.png create mode 100644 android/app/src/main/res/drawable-hdpi/wifi.png create mode 100644 android/app/src/main/res/drawable-v17/xui_config_bg_splash.xml create mode 100644 android/app/src/main/res/drawable-v21/xui_config_bg_splash.xml create mode 100644 android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_web_back.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_web_close.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_web_more.png create mode 100644 android/app/src/main/res/drawable/bg_dialog_common_tip_corner_white.xml create mode 100644 android/app/src/main/res/drawable/ic_action_close_white.xml create mode 100644 android/app/src/main/res/drawable/ic_check_normal.xml create mode 100644 android/app/src/main/res/drawable/ic_checked.xml create mode 100644 android/app/src/main/res/drawable/ic_default_head.xml create mode 100644 android/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 android/app/src/main/res/drawable/ic_login_close.xml create mode 100644 android/app/src/main/res/drawable/ic_logo_app.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_about.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_issues.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_news.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_notifications.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_person.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_privacy.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_search.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_settings.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_star.xml create mode 100644 android/app/src/main/res/drawable/ic_menu_trending.xml create mode 100644 android/app/src/main/res/drawable/ic_password.xml create mode 100644 android/app/src/main/res/drawable/ic_phone.xml create mode 100644 android/app/src/main/res/drawable/icon_arrow_right_grey.xml create mode 100644 android/app/src/main/res/drawable/icon_checkbox.xml create mode 100644 android/app/src/main/res/drawable/img_guide_tip_top.xml create mode 100644 android/app/src/main/res/layout/activity_agent_web.xml create mode 100644 android/app/src/main/res/layout/activity_main.xml create mode 100644 android/app/src/main/res/layout/adapter_button_top_item.xml create mode 100644 android/app/src/main/res/layout/adapter_common_grid_item.xml create mode 100644 android/app/src/main/res/layout/adapter_device_card_view_list_item.xml create mode 100644 android/app/src/main/res/layout/adapter_item_simple_list_2.xml create mode 100644 android/app/src/main/res/layout/adapter_news_card_view_list_item.xml create mode 100644 android/app/src/main/res/layout/adapter_title_item.xml create mode 100644 android/app/src/main/res/layout/dialog_guide_tips.xml create mode 100644 android/app/src/main/res/layout/fragment_about.xml create mode 100644 android/app/src/main/res/layout/fragment_add_device.xml create mode 100644 android/app/src/main/res/layout/fragment_add_device_two.xml create mode 100644 android/app/src/main/res/layout/fragment_agentweb.xml create mode 100644 android/app/src/main/res/layout/fragment_device.xml create mode 100644 android/app/src/main/res/layout/fragment_edit_device.xml create mode 100644 android/app/src/main/res/layout/fragment_feedback.xml create mode 100644 android/app/src/main/res/layout/fragment_group.xml create mode 100644 android/app/src/main/res/layout/fragment_login.xml create mode 100644 android/app/src/main/res/layout/fragment_message.xml create mode 100644 android/app/src/main/res/layout/fragment_news.xml create mode 100644 android/app/src/main/res/layout/fragment_profile.xml create mode 100644 android/app/src/main/res/layout/fragment_pulldown_web.xml create mode 100644 android/app/src/main/res/layout/fragment_scene.xml create mode 100644 android/app/src/main/res/layout/fragment_settings.xml create mode 100644 android/app/src/main/res/layout/fragment_share_device.xml create mode 100644 android/app/src/main/res/layout/fragment_simple_tab.xml create mode 100644 android/app/src/main/res/layout/include_head_view_banner.xml create mode 100644 android/app/src/main/res/layout/include_navigation_header.xml create mode 100644 android/app/src/main/res/layout/include_toolbar_web.xml create mode 100644 android/app/src/main/res/layout/layout_main_content.xml create mode 100644 android/app/src/main/res/menu/menu_drawer.xml create mode 100644 android/app/src/main/res/menu/menu_main.xml create mode 100644 android/app/src/main/res/menu/menu_navigation_bottom.xml create mode 100644 android/app/src/main/res/menu/menu_toolbar_web.xml create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/values/arrays.xml create mode 100644 android/app/src/main/res/values/colors.xml create mode 100644 android/app/src/main/res/values/dimens.xml create mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 android/app/src/main/res/values/styles.xml create mode 100644 android/app/src/main/res/values/styles_widget.xml create mode 100644 android/app/src/main/res/xml/network_security_config.xml create mode 100644 android/app/src/test/java/com/kerwin/templateproject/ExampleUnitTest.java create mode 100644 android/app/x-library.gradle create mode 100644 android/build.gradle create mode 100644 android/esptouch/.gitignore create mode 100644 android/esptouch/README.md create mode 100644 android/esptouch/build.gradle create mode 100644 android/esptouch/proguard-rules.pro create mode 100644 android/esptouch/src/main/AndroidManifest.xml create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchResult.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchTask.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchListener.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchResult.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchTask.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DataCode.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DatumCode.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/EsptouchGenerator.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/GuideCode.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/TouchData.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/security/ITouchEncryptor.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/security/TouchAES.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/task/EsptouchTaskParameter.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/task/ICodeData.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchGenerator.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchTaskParameter.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__EsptouchTask.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__IEsptouchTask.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketClient.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketServer.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/util/ByteUtil.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/util/CRC8.java create mode 100644 android/esptouch/src/main/java/com/espressif/iot/esptouch/util/TouchNetUtil.java create mode 100644 android/gradle.properties create mode 100644 android/gradle/wrapper/gradle-wrapper.jar create mode 100644 android/gradle/wrapper/gradle-wrapper.properties create mode 100644 android/gradlew create mode 100644 android/gradlew.bat create mode 100644 android/settings.gradle create mode 100644 android/versions.gradle diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 00000000..1afa24c5 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,16 @@ +*.iml +.gradle +/LocalRepository +/keystores +/local.properties +/.idea/caches +/.idea/codeStyles +/.idea/inspectionProfiles +/.idea/libraries +/.idea/dictionaries +/.idea/markdown-navigator +/.idea/*.xml +.DS_Store +/build +/captures +.externalNativeBuild \ No newline at end of file diff --git a/android/.idea/copyright/profiles_settings.xml b/android/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..066b2557 --- /dev/null +++ b/android/.idea/copyright/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/android/.idea/copyright/xuexiang.xml b/android/.idea/copyright/xuexiang.xml new file mode 100644 index 00000000..d785b8e0 --- /dev/null +++ b/android/.idea/copyright/xuexiang.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/android/LICENSE b/android/LICENSE new file mode 100644 index 00000000..44cc482b --- /dev/null +++ b/android/LICENSE @@ -0,0 +1,191 @@ +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: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +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 +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 2018 xuexiangjys + + 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. \ No newline at end of file diff --git a/android/移动端.txt b/android/README.md similarity index 100% rename from android/移动端.txt rename to android/README.md diff --git a/android/app/.gitignore b/android/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/android/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 00000000..603984ae --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,131 @@ +apply plugin: 'com.android.application' +apply plugin: 'img-optimizer' +//打包时,记得设置true启用 +if (isNeedPackage.toBoolean() && isUseBooster.toBoolean()) { + apply plugin: 'com.didiglobal.booster' +} + +android { + compileSdkVersion build_versions.target_sdk + buildToolsVersion build_versions.build_tools + + defaultConfig { + applicationId "com.kerwin.wumei" + minSdkVersion 17 + targetSdkVersion build_versions.target_sdk + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + multiDexEnabled true + vectorDrawables.useSupportLibrary = true + + javaCompileOptions { + annotationProcessorOptions { + arguments = [ moduleName : project.getName() ] + } + } + } + + signingConfigs { + if (isNeedPackage.toBoolean()) { + release { + storeFile file(app_release.storeFile) + storePassword app_release.storePassword + keyAlias app_release.keyAlias + keyPassword app_release.keyPassword + } + } + + debug { + storeFile file("./debug.jks") + storePassword "123456" + keyAlias "debug" + keyPassword "123456" + } + } + + buildTypes { + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + if (isNeedPackage.toBoolean()) { + signingConfig signingConfigs.release + + Properties properties = new Properties() + properties.load(project.rootProject.file('local.properties').newDataInputStream()) + def appID = properties.getProperty("APP_ID_UMENG") + if (appID != null) { + buildConfigField "String", "APP_ID_UMENG", appID + } else { + buildConfigField "String", "APP_ID_UMENG", '""' + } + } else { + signingConfig signingConfigs.debug + buildConfigField "String", "APP_ID_UMENG", '""' + } + } + + debug { + debuggable true + minifyEnabled false + + signingConfig signingConfigs.debug + buildConfigField "String", "APP_ID_UMENG", '""' + } + } + + lintOptions { + abortOnError false + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(path: ':esptouch') + testImplementation deps.junit + androidTestImplementation deps.runner + androidTestImplementation deps.espresso.core + + //分包 + implementation deps.androidx.multidex + + implementation 'com.alibaba.android:vlayout:1.2.36' + //下拉刷新 + implementation 'com.github.xuexiangjys.SmartRefreshLayout:refresh-header:1.1.5' + implementation 'com.github.xuexiangjys.SmartRefreshLayout:refresh-layout:1.1.5' + //WebView + implementation 'com.github.xuexiangjys.AgentWeb:agentweb-core:1.0.0' + implementation 'com.github.xuexiangjys.AgentWeb:agentweb-download:1.0.0'//选填 + //腾讯的键值对存储mmkv + implementation 'com.tencent:mmkv:1.0.22' + //屏幕适配AutoSize + implementation 'me.jessyan:autosize:1.1.2' + //umeng统计 + implementation 'com.umeng.umsdk:analytics:8.0.2' + implementation 'com.umeng.umsdk:common:2.0.2' + + //预加载占位控件 + implementation 'me.samlss:broccoli:1.0.0' + + implementation 'com.zzhoujay.richtext:richtext:3.0.8' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + + //ANR异常捕获 + implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0' + + //美团多渠道打包 + implementation 'com.meituan.android.walle:library:1.1.6' +} +//自动添加X-Library依赖 +apply from: 'x-library.gradle' +//walle多渠道打包 +apply from: 'multiple-channel.gradle' + + diff --git a/android/app/channel b/android/app/channel new file mode 100644 index 00000000..10c8afd1 --- /dev/null +++ b/android/app/channel @@ -0,0 +1,25 @@ +# 美团 +meituan +# 三星 +samsungapps +# 小米 +xiaomi +# 91助手 +91com +# 魅族 +meizu +# 豌豆荚 +wandou +# Google Play +googleplay +# 百度 +baidu +# 360 +360cn +# 应用宝 +myapp +# 华为 +huawei +# 蒲公英 +pgyer +github \ No newline at end of file diff --git a/android/app/debug.jks b/android/app/debug.jks new file mode 100644 index 0000000000000000000000000000000000000000..d49fb2b1706b01b3a04d10844d6b450d11319d52 GIT binary patch literal 2270 zcmc&#XIB#n7ED4&B#|IR>O%+*q>2eWf(QmFL3(>2hzNx8=pldsgoG+hArTNGMS_4d z5%5Tp;DR&-ED&6g-g_}3(w4Wo?;Q6R?1%X002P80R9`C9-cRe zUdPN&7kOO<0N@0oDBuGW0s>Qn0Kq^75HAqO2>?^Ti(;}V2jYdo%-;Q%ylf*wa7L?IUQ$<{wR^R!y!7OdB48Z)*BuWotgwd2n(q3)9QwxP5Itv~l zoz3jrQ`Lcd@NocI?))61MwmGt>Rna`yL>=AYe=+YBnVQAf#_$%9LMvg(cpi)Pe@SR zKPa|H2|2T0FG3pK;{J}&)?MQ=%Cz;n{PUwx&#L;Zxa&k+&eup{ne8dJXD-`CM-S>?cQnc4Lt^^F=s^FdBH7|r;?9bO zZ5Ezo{KJAjFz4~ud+&mYY?c=AQ}*cD9OH)YJh+QNSMC?Lxm&{W1Sl^qt9f-g#-ANi z%aAJ#`k=jPiQDM1PzGlaBJWgxH(C`gQ8>`7}uv0QfmpPMfFW4D35!3E2-;v2< zigl)XS2^N;Pj-aw%@fvYUb$7&3f@whn|9LOuFZUuQUUnw_R`nLsh~TlYP;5b z;!TmUo4GqIge3DudJ3s#tXk@l)X!qJfe)|i%Bky0&5xuaNa)gtUSHj-NBLp(@zPVl zFpNSpxngi4R3y#Fr@RF@kC(2mx2!Iq7$fg8@?g!51DjPkaZXR?0?qpA}S?>a&T zkE-#U-sGk?Sm#tc@6gpG0%R%O)wuf8jwLzwK2okn1d->M3I-i5+^`-BBVckXJyoDc zv%0X(cKK$1UbTxrx|}GTJDDbc_a7R)v7}R)&7c`Sc?i0rvN3-a7UNky=Yo@^4`08e zZ2fj(Wk5mFz`^pQq);gfN*#G@0vgEv5p>QMRNL<*p`P<8RxIEM)&e8QRkVQu`;jqT zX1c!9&YK7siLHPZmdPmh6O0AlnB@ZfH^u3ZQRD$uQ9xogS}K%a0?_y@@&D8#Ub{xVtm_E1o;gedwPVS6VkV<1(`ur=3nlui5zf zRFx!s$RUKp%dEUmJS;D=SLF?wC>zrc*D#yX_zt=2oQigtiGDaIf3d`=+4+{P`?8YB zvc>Lb;iDdrg)gdw5q#;09Q!5Lp^ny7aqE5k!SwgKdtrSqkVouD(ZqYT#E)6Px5NyF z7n@^Ve8u}JzT|c$?lhPAy2RccL#j#P6nJTmetXE!mpySs1&Q|x_!eAXu3nN5`#b8N zYov!hPia;OrqiMF6;cX1Swy{TKwKejoiAjYJb6f#C}+xaU~@*D2r7>@D@6ezFG;SJ z0(%?M7axqtxUXx{ROp>mm-&Uh8yV9t8mnT(L7Wo%4J{D@*kxw=S!cp-!BT{Fwz=88 z%0$%x729itF^!?cSGHTt`f_EEg0`2RMV7N-oPjl@PY94_^9cLiUsz}i37wI zjkI_U+J#NDM6O?8B&TxbXg#i)dVae*YRiO>A9BMmH*vuL|DRs`Ls=b#0RT91P!tX- ziUNu(iR)t?MqE>eJ?#WW^vX?U|5m%Ujwiw~-e;gVeE%~Y^Y87H!F|xxY znzNs%md{X1Ul#SHtu*oVlrxB~=)m7Xs0jC10i@I{N$SGYWy;1B-I#}HGyEcRWuz`)$(jm{eUA6t+_wrp2WYKx z)ZlkeaQjV{b0SO15J+&Qfx6cCFxqeYDoLV`fH0t-bInD?ShuEOxE? zO_`1j^VPl$&e`-q%uN6M7eDx`wJ|-9CVBlZ4@pJ71fgm8VY#S~c-oj+$KE#=%FVlK z{kMm#3>n_vB4$tk#`K3i7B>?8pEB literal 0 HcmV?d00001 diff --git a/android/app/multiple-channel.gradle b/android/app/multiple-channel.gradle new file mode 100644 index 00000000..5dc6dbf1 --- /dev/null +++ b/android/app/multiple-channel.gradle @@ -0,0 +1,10 @@ +apply plugin: 'walle' + +walle { + // 指定渠道包的输出路径 + apkOutputFolder = new File("${project.buildDir}/outputs/channels") + // 定制渠道包的APK的文件名称 + apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk' + // 渠道配置文件 + channelFile = new File("${project.getProjectDir()}/channel") +} \ No newline at end of file diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 00000000..2b565e20 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,269 @@ +#=========================================基础不变的混淆配置=========================================## +#指定代码的压缩级别 +-optimizationpasses 5 +#包名不混合大小写 +-dontusemixedcaseclassnames +#不去忽略非公共的库类 +-dontskipnonpubliclibraryclasses +# 指定不去忽略非公共的库的类的成员 +-dontskipnonpubliclibraryclassmembers +#优化 不优化输入的类文件 +-dontoptimize +#预校验 +-dontpreverify +#混淆时是否记录日志 +-verbose +# 混淆时所采用的算法 +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* +#保护注解 +-keepattributes *Annotation* +#忽略警告 +-ignorewarnings + +##记录生成的日志数据,gradle build时在本项目根目录输出## +#apk 包内所有 class 的内部结构 +-dump class_files.txt +#未混淆的类和成员 +-printseeds seeds.txt +#列出从 apk 中删除的代码 +-printusage unused.txt +#混淆前后的映射 +-printmapping mapping.txt +# 并保留源文件名为"Proguard"字符串,而非原始的类名 并保留行号 +-keepattributes SourceFile,LineNumberTable +########记录生成的日志数据,gradle build时 在本项目根目录输出-end##### + +#需要保留的东西 +# 保持哪些类不被混淆 +-keep public class * extends android.app.Fragment +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class * extends android.support.v4.** +-keep public class com.android.vending.licensing.ILicensingService + +#如果有引用v4包可以添加下面这行 +-keep public class * extends android.support.v4.app.Fragment + +##########JS接口类不混淆,否则执行不了 +-dontwarn com.android.JsInterface.** +-keep class com.android.JsInterface.** {*; } + +#极光推送和百度lbs android sdk一起使用proguard 混淆的问题#http的类被混淆后,导致apk定位失败,保持apache 的http类不被混淆就好了 +-dontwarn org.apache.** +-keep class org.apache.**{ *; } + +-keep public class * extends android.view.View { + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); + public void set*(...); + } + +#保持 native 方法不被混淆 +-keepclasseswithmembernames class * { + native ; +} + +#保持自定义控件类不被混淆 +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +#保持自定义控件类不被混淆 +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +#保持 Parcelable 不被混淆 +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +#保持 Serializable 不被混淆 +-keepnames class * implements java.io.Serializable + +#保持 Serializable 不被混淆并且enum 类也不被混淆 +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + !private ; + !private ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} + +#保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可 +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keepclassmembers class * { + public void *ButtonClicked(android.view.View); +} + +#不混淆资源类 +-keep class **.R$* {*;} + +#===================================混淆保护自己项目的部分代码以及引用的第三方jar包library=============================####### +#如果引用了v4或者v7包 +-dontwarn android.support.** + + +# AndroidX 防止混淆 +-dontwarn com.google.android.material.** +-dontnote com.google.android.material.** +-dontwarn androidx.** +-keep class com.google.android.material.** {*;} +-keep class androidx.** {*;} +-keep public class * extends androidx.** +-keep interface androidx.** {*;} +-keepclassmembers class * { + @androidx.annotation.Keep *; +} + +# zxing +-dontwarn com.google.zxing.** +-keep class com.google.zxing.**{*;} + +#SignalR推送 +-keep class microsoft.aspnet.signalr.** { *; } + +# 极光推送混淆 +-dontoptimize +-dontpreverify +-dontwarn cn.jpush.** +-keep class cn.jpush.** { *; } +-dontwarn cn.jiguang.** +-keep class cn.jiguang.** { *; } + +# 数据库框架OrmLite +-keepattributes *DatabaseField* +-keepattributes *DatabaseTable* +-keepattributes *SerializedName* +-keep class com.j256.** +-keepclassmembers class com.j256.** { *; } +-keep enum com.j256.** +-keepclassmembers enum com.j256.** { *; } +-keep interface com.j256.** +-keepclassmembers interface com.j256.** { *; } + +#XHttp2 +-keep class com.xuexiang.xhttp2.model.** { *; } +-keep class com.xuexiang.xhttp2.cache.model.** { *; } +-keep class com.xuexiang.xhttp2.cache.stategy.**{*;} +-keep class com.xuexiang.xhttp2.annotation.** { *; } + +#okhttp +-dontwarn com.squareup.okhttp3.** +-keep class com.squareup.okhttp3.** { *;} +-dontwarn okio.** +-dontwarn javax.annotation.Nullable +-dontwarn javax.annotation.ParametersAreNonnullByDefault +-dontwarn javax.annotation.** + +#如果用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错 +-keepattributes Signature +-keep class com.google.gson.stream.** { *; } +-keepattributes EnclosingMethod +-keep class org.xz_sale.entity.**{*;} +-keep class com.google.gson.** {*;} +-keep class com.google.**{*;} +-keep class sun.misc.Unsafe { *; } +-keep class com.google.gson.stream.** { *; } +-keep class com.google.gson.examples.android.model.** { *; } + +# Glide +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public class * extends com.bumptech.glide.module.AppGlideModule +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} + +# Retrofit +-dontwarn retrofit2.** +-keep class retrofit2.** { *; } +-keepattributes Exceptions + +# RxJava RxAndroid +-dontwarn sun.misc.** +-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { + long producerIndex; + long consumerIndex; +} +-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { + rx.internal.util.atomic.LinkedQueueNode producerNode; +} +-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { + rx.internal.util.atomic.LinkedQueueNode consumerNode; +} + +-dontwarn okio.** +-dontwarn javax.annotation.Nullable +-dontwarn javax.annotation.ParametersAreNonnullByDefault +-dontwarn javax.annotation.** + +# fastjson +-dontwarn com.alibaba.fastjson.** +-keep class com.alibaba.fastjson.** { *; } +-keepattributes Signature + +# xpage +-keep class com.xuexiang.xpage.annotation.** { *; } +-keep class com.xuexiang.xpage.config.** { *; } + +# xaop +-keep @com.xuexiang.xaop.annotation.* class * {*;} +-keep @org.aspectj.lang.annotation.* class * {*;} +-keep class * { + @com.xuexiang.xaop.annotation.* ; + @org.aspectj.lang.annotation.* ; +} +-keepclassmembers class * { + @com.xuexiang.xaop.annotation.* ; + @org.aspectj.lang.annotation.* ; +} + +# xrouter +-keep public class com.xuexiang.xrouter.routes.**{*;} +-keep class * implements com.xuexiang.xrouter.facade.template.ISyringe{*;} +# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口 +-keep interface * implements com.xuexiang.xrouter.facade.template.IProvider +# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现 +-keep class * implements com.xuexiang.xrouter.facade.template.IProvider + +# xupdate +-keep class com.xuexiang.xupdate.entity.** { *; } + +# xvideo +-keep class com.xuexiang.xvideo.jniinterface.** { *; } + +# xipc +-keep @com.xuexiang.xipc.annotation.* class * {*;} +-keep class * { + @com.xuexiang.xipc.annotation.* ; +} +-keepclassmembers class * { + @com.xuexiang.xipc.annotation.* ; +} + +# umeng统计 +-keep class com.umeng.** {*;} +-keepclassmembers class * { + public (org.json.JSONObject); +} +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class com.xuexiang.xui.widget.edittext.materialedittext.** { *; } diff --git a/android/app/src/androidTest/java/com/kerwin/templateproject/ExampleInstrumentedTest.java b/android/app/src/androidTest/java/com/kerwin/templateproject/ExampleInstrumentedTest.java new file mode 100644 index 00000000..10e93d68 --- /dev/null +++ b/android/app/src/androidTest/java/com/kerwin/templateproject/ExampleInstrumentedTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.kerwin.wumei", appContext.getPackageName()); + } +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..0893f1b7 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/assets/tips.json b/android/app/src/main/assets/tips.json new file mode 100644 index 00000000..969a4c43 --- /dev/null +++ b/android/app/src/main/assets/tips.json @@ -0,0 +1,21 @@ +{ + "Code": 0, + "Data": [ + { + "title": "微信公众号", + "content": "获取更多资讯内容,欢迎微信搜索公众号:「我的Android开源之旅」" + }, + { + "title": "关于作者", + "content": "点击关注作者,了解最新动态!
Github
\n知乎
\n掘金
简书
\n思否
\n哔哩哔哩
\n今日头条" + }, + { + "title": "赞助作者", + "content": "你的打赏是我维护的动力,点击此处支持我吧!" + }, + { + "title": "QQ交流群", + "content": "XUI开源交流1号群
XUI开源交流2号群
AndroidGitHub开源交流群
XUpdate官方交流群" + } + ] +} diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..a0b4b39c78d4fad57bf64c6f75b8819bbe5ad3ef GIT binary patch literal 31548 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 mBroadcastData; + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action == null) { + return; + } + + switch (action) { + case WifiManager.NETWORK_STATE_CHANGED_ACTION: + case LocationManager.PROVIDERS_CHANGED_ACTION: + mBroadcastData.setValue(action); + break; + } + } + }; + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + //解决4.x运行崩溃的问题 + MultiDex.install(this); + } + + @Override + public void onCreate() { + super.onCreate(); + initLibs(); + + app = this; + mBroadcastData = new MutableLiveData<>(); + IntentFilter filter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION); + } + registerReceiver(mReceiver, filter); + } + + @Override + public void onTerminate() { + super.onTerminate(); + unregisterReceiver(mReceiver); + } + + public static MyApp getInstance() { + return app; + } + + public void observeBroadcast(LifecycleOwner owner, Observer observer) { + mBroadcastData.observe(owner, observer); + } + + + /** + * 初始化基础库 + */ + private void initLibs() { + XBasicLibInit.init(this); + + XUpdateInit.init(this); + + //运营统计数据运行时不初始化 + if (!MyApp.isDebug()) { + UMengInit.init(this); + } + + //ANR监控 + ANRWatchDogInit.init(); + } + + + /** + * @return 当前app是否是调试开发模式 + */ + public static boolean isDebug() { + return BuildConfig.DEBUG; + } + + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java new file mode 100644 index 00000000..9b89c562 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java @@ -0,0 +1,410 @@ + +package com.kerwin.wumei.activity; + +import android.Manifest; +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.view.KeyEvent; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.core.location.LocationManagerCompat; + +import com.espressif.iot.esptouch.EsptouchTask; +import com.espressif.iot.esptouch.IEsptouchResult; +import com.espressif.iot.esptouch.IEsptouchTask; +import com.espressif.iot.esptouch.util.ByteUtil; +import com.espressif.iot.esptouch.util.TouchNetUtil; +import com.kerwin.wumei.R; +import com.kerwin.wumei.adapter.entity.EspTouchViewModel; +import com.kerwin.wumei.core.BaseActivity; +import com.kerwin.wumei.fragment.LoginFragment; +import com.kerwin.wumei.utils.NetUtils; +import com.xuexiang.xui.utils.KeyboardUtils; +import com.xuexiang.xui.utils.StatusBarUtils; +import com.xuexiang.xutil.display.Colors; + +import java.lang.ref.WeakReference; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + + +public class AddDeviceActivity extends BaseActivity { + + // begin esptouch ------------------------------------- + private static final String TAG = AddDeviceActivity.class.getSimpleName(); + private static final int REQUEST_PERMISSION = 0x01; + private EspTouchViewModel mViewModel; + private EsptouchAsyncTask4 mTask; + private WifiManager mWifiManager; + private List ssids; + private String selectedSSID; + + public String GetSelectedSSID(){ + return selectedSSID; + } + public List GetSsids(){ + return ssids; + } + public EspTouchViewModel GetMViewModel(){ + return mViewModel; + } + + public void executeEsptouch() { + EspTouchViewModel viewModel = mViewModel; + // byte[] ssid = viewModel.ssidBytes == null ? ByteUtil.getBytesByString(viewModel.ssid): viewModel.ssidBytes; + CharSequence ssidStr=mViewModel.ssidSpinner.getText(); + byte[] ssid= ByteUtil.getBytesByString(ssidStr.toString()); + CharSequence pwdStr = mViewModel.apPasswordEdit.getText(); + byte[] password = pwdStr == null ? null : ByteUtil.getBytesByString(pwdStr.toString()); + byte[] bssid = TouchNetUtil.parseBssid2bytes(viewModel.bssid); + byte[] broadcast = {(byte) (mViewModel.packageModeGroup.getCheckedRadioButtonId() == R.id.packageBroadcast? 1 : 0)}; + byte[] deviceCount = "1".getBytes(); + if (mTask != null) { + mTask.cancelEsptouch(); + } + mTask = new EsptouchAsyncTask4(this); + mTask.execute(ssid, bssid, password, deviceCount, broadcast); + } + + public void onWifiChanged() { + StateResult stateResult = check(); + mViewModel.message = stateResult.message; + mViewModel.ssid = stateResult.ssid; + mViewModel.ssidBytes = stateResult.ssidBytes; + mViewModel.bssid = stateResult.bssid; + mViewModel.confirmEnable = false; + if (stateResult.wifiConnected) { + mViewModel.confirmEnable = true; + if (stateResult.is5G) { + mViewModel.message = getString(R.string.esptouch1_wifi_5g_message); + } + } else { + if (mTask != null) { + mTask.cancelEsptouch(); + mTask = null; + new AlertDialog.Builder(AddDeviceActivity.this) + .setMessage(R.string.esptouch1_configure_wifi_change_message) + .setNegativeButton(android.R.string.cancel, null) + .show(); + } + } + mViewModel.invalidateAll(); + } + + protected static class StateResult { + public CharSequence message = null; + public boolean permissionGranted = false; + public boolean locationRequirement = false; + public boolean wifiConnected = false; + public boolean is5G = false; + public InetAddress address = null; + public String ssid = null; + public byte[] ssidBytes = null; + public String bssid = null; + } + + private StateResult check() { + StateResult result = checkPermission(); + if (!result.permissionGranted) { + return result; + } + result = checkLocation(); + result.permissionGranted = true; + if (result.locationRequirement) { + return result; + } + result = checkWifi(); + result.permissionGranted = true; + result.locationRequirement = false; + return result; + } + + protected StateResult checkWifi() { + StateResult result = new StateResult(); + result.wifiConnected = false; + WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + + // 获取wifi列表 + mWifiManager.startScan(); + List scanWifiList = mWifiManager.getScanResults(); + List wifiList = new ArrayList<>(); + ssids=new ArrayList<>(); + if (scanWifiList != null && scanWifiList.size() > 0) { + HashMap signalStrength = new HashMap(); + for (int i = 0; i < scanWifiList.size(); i++) { + ScanResult scanResult = scanWifiList.get(i); + Log.e(TAG, "搜索的wifi-ssid:" + scanResult.SSID); + if (!scanResult.SSID.isEmpty()) { + String key = scanResult.SSID + " " + scanResult.capabilities; + if (!signalStrength.containsKey(key)) { + signalStrength.put(key, i); + wifiList.add(scanResult); + ssids.add(scanResult.SSID); + } + } + } + } + + boolean connected = NetUtils.isWifiConnected(mWifiManager); + if (!connected) { + result.message = getString(R.string.esptouch_message_wifi_connection); + return result; + } + + String ssid = NetUtils.getSsidString(wifiInfo); + selectedSSID=ssid; + int ipValue = wifiInfo.getIpAddress(); + if (ipValue != 0) { + result.address = NetUtils.getAddress(wifiInfo.getIpAddress()); + } else { + result.address = NetUtils.getIPv4Address(); + if (result.address == null) { + result.address = NetUtils.getIPv6Address(); + } + } + + result.wifiConnected = true; + result.message = ""; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + result.is5G = NetUtils.is5G(wifiInfo.getFrequency()); + } + if (result.is5G) { + result.message = getString(R.string.esptouch_message_wifi_frequency); + } + result.ssid = ssid; + result.ssidBytes = NetUtils.getRawSsidBytesOrElse(wifiInfo, ssid.getBytes()); + result.bssid = wifiInfo.getBSSID(); + return result; + } + + protected StateResult checkLocation() { + StateResult result = new StateResult(); + result.locationRequirement = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + LocationManager manager = getSystemService(LocationManager.class); + boolean enable = manager != null && LocationManagerCompat.isLocationEnabled(manager); + if (!enable) { + result.message = getString(R.string.esptouch_message_location); + return result; + } + } + + result.locationRequirement = false; + return result; + } + + protected StateResult checkPermission() { + StateResult result = new StateResult(); + result.permissionGranted = false; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + boolean locationGranted = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED; + if (!locationGranted) { + String[] splits = getString(R.string.esptouch_message_permission).split("\n"); + if (splits.length != 2) { + throw new IllegalArgumentException("Invalid String @RES esptouch_message_permission"); + } + SpannableStringBuilder ssb = new SpannableStringBuilder(splits[0]); + ssb.append('\n'); + SpannableString clickMsg = new SpannableString(splits[1]); + ForegroundColorSpan clickSpan = new ForegroundColorSpan(0xFF0022FF); + clickMsg.setSpan(clickSpan, 0, clickMsg.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + ssb.append(clickMsg); + result.message = ssb; + return result; + } + } + + result.permissionGranted = true; + return result; + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == REQUEST_PERMISSION) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + onWifiChanged(); + } else { + new AlertDialog.Builder(this) + .setTitle(R.string.esptouch1_location_permission_title) + .setMessage(R.string.esptouch1_location_permission_message) + .setCancelable(false) + .setPositiveButton(android.R.string.ok, (dialog, which) -> finish()) + .show(); + } + + return; + } + + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + public static class EsptouchAsyncTask4 extends AsyncTask> { + private WeakReference mActivity; + private final Object mLock = new Object(); + private ProgressDialog mProgressDialog; + private AlertDialog mResultDialog; + private IEsptouchTask mEsptouchTask; + + EsptouchAsyncTask4(AddDeviceActivity activity) { + mActivity = new WeakReference<>(activity); + } + + public void cancelEsptouch() { + cancel(true); + if (mProgressDialog != null) { + mProgressDialog.dismiss(); + } + if (mResultDialog != null) { + mResultDialog.dismiss(); + } + if (mEsptouchTask != null) { + mEsptouchTask.interrupt(); + } + } + + @Override + protected void onPreExecute() { + Activity activity = mActivity.get(); + mProgressDialog = new ProgressDialog(activity); + mProgressDialog.setMessage(activity.getString(R.string.esptouch1_configuring_message)); + mProgressDialog.setCanceledOnTouchOutside(false); + mProgressDialog.setOnCancelListener(dialog -> { + synchronized (mLock) { + if (mEsptouchTask != null) { + mEsptouchTask.interrupt(); + } + } + }); + mProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, activity.getText(android.R.string.cancel), + (dialog, which) -> { + synchronized (mLock) { + if (mEsptouchTask != null) { + mEsptouchTask.interrupt(); + } + } + }); + mProgressDialog.show(); + } + + @Override + protected void onProgressUpdate(IEsptouchResult... values) { + Context context = mActivity.get(); + if (context != null) { + IEsptouchResult result = values[0]; + Log.i(TAG, "EspTouchResult: " + result); + String text = result.getBssid() + " is connected to the wifi"; + Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); + } + } + + @Override + protected List doInBackground(byte[]... params) { + AddDeviceActivity activity = mActivity.get(); + int taskResultCount; + synchronized (mLock) { + byte[] apSsid = params[0]; + byte[] apBssid = params[1]; + byte[] apPassword = params[2]; + byte[] deviceCountData = params[3]; + byte[] broadcastData = params[4]; + taskResultCount = deviceCountData.length == 0 ? -1 : Integer.parseInt(new String(deviceCountData)); + Context context = activity.getApplicationContext(); + mEsptouchTask = new EsptouchTask(apSsid, apBssid, apPassword, context); + mEsptouchTask.setPackageBroadcast(broadcastData[0] == 1); + mEsptouchTask.setEsptouchListener(this::publishProgress); + } + return mEsptouchTask.executeForResults(taskResultCount); + } + + @Override + protected void onPostExecute(List result) { + AddDeviceActivity activity = mActivity.get(); + activity.mTask = null; + mProgressDialog.dismiss(); + if (result == null) { + mResultDialog = new AlertDialog.Builder(activity) + .setMessage(R.string.esptouch1_configure_result_failed_port) + .setPositiveButton(android.R.string.ok, null) + .show(); + mResultDialog.setCanceledOnTouchOutside(false); + return; + } + + // check whether the task is cancelled and no results received + IEsptouchResult firstResult = result.get(0); + if (firstResult.isCancelled()) { + return; + } + // the task received some results including cancelled while + // executing before receiving enough results + + if (!firstResult.isSuc()) { + mResultDialog = new AlertDialog.Builder(activity) + .setMessage(R.string.esptouch1_configure_result_failed) + .setPositiveButton(android.R.string.ok, null) + .show(); + mResultDialog.setCanceledOnTouchOutside(false); + return; + } + + ArrayList resultMsgList = new ArrayList<>(result.size()); + for (IEsptouchResult touchResult : result) { + String message = activity.getString(R.string.esptouch1_configure_result_success_item, + touchResult.getBssid(), touchResult.getInetAddress().getHostAddress()); + resultMsgList.add(message); + } + CharSequence[] items = new CharSequence[resultMsgList.size()]; + mResultDialog = new AlertDialog.Builder(activity) + .setTitle(R.string.esptouch1_configure_result_success) + .setItems(resultMsgList.toArray(items), null) + .setPositiveButton(android.R.string.ok, null) + .show(); + mResultDialog.setCanceledOnTouchOutside(false); + } + } + + // end esptouch ---------------------------------------- + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mWifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); + mViewModel = new EspTouchViewModel(); + } + + @Override + protected boolean isSupportSlideBack() { + return true; + } + + @Override + protected void initStatusBarStyle() { + StatusBarUtils.initStatusBarStyle(this, false, Colors.WHITE); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java new file mode 100644 index 00000000..bab79c1c --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java @@ -0,0 +1,36 @@ + +package com.kerwin.wumei.activity; + +import android.os.Bundle; +import android.view.KeyEvent; + +import com.kerwin.wumei.core.BaseActivity; +import com.kerwin.wumei.fragment.LoginFragment; +import com.xuexiang.xui.utils.KeyboardUtils; +import com.xuexiang.xui.utils.StatusBarUtils; +import com.xuexiang.xutil.display.Colors; + + +public class LoginActivity extends BaseActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + openPage(LoginFragment.class, getIntent().getExtras()); + } + + @Override + protected boolean isSupportSlideBack() { + return false; + } + + @Override + protected void initStatusBarStyle() { + StatusBarUtils.initStatusBarStyle(this, false, Colors.WHITE); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java new file mode 100644 index 00000000..9c05b48f --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.activity; + +import android.Manifest; +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; +import androidx.core.location.LocationManagerCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.viewpager.widget.ViewPager; + +import com.espressif.iot.esptouch.EsptouchTask; +import com.espressif.iot.esptouch.IEsptouchResult; +import com.espressif.iot.esptouch.IEsptouchTask; +import com.espressif.iot.esptouch.util.ByteUtil; +import com.espressif.iot.esptouch.util.TouchNetUtil; +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.android.material.navigation.NavigationView; +import com.kerwin.wumei.R; +import com.kerwin.wumei.adapter.entity.EspTouchViewModel; +import com.kerwin.wumei.core.BaseActivity; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.fragment.AboutFragment; +import com.kerwin.wumei.fragment.FeedbackFragment; +import com.kerwin.wumei.fragment.MessageFragment; +import com.kerwin.wumei.fragment.SettingsFragment; +import com.kerwin.wumei.fragment.device.AddDeviceFragment; +import com.kerwin.wumei.fragment.device.GroupFragment; +import com.kerwin.wumei.fragment.device.SceneFragment; +import com.kerwin.wumei.fragment.device.ShareDeviceFragment; +import com.kerwin.wumei.fragment.news.NewsFragment; +import com.kerwin.wumei.fragment.profile.ProfileFragment; +import com.kerwin.wumei.fragment.device.DeviceFragment; +import com.kerwin.wumei.utils.NetUtils; +import com.kerwin.wumei.utils.Utils; +import com.kerwin.wumei.utils.XToastUtils; +import com.kerwin.wumei.widget.GuideTipsDialog; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.core.PageOption; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.adapter.FragmentAdapter; +import com.xuexiang.xui.adapter.simple.AdapterItem; +import com.xuexiang.xui.utils.ResUtils; +import com.xuexiang.xui.utils.ThemeUtils; +import com.xuexiang.xui.widget.imageview.RadiusImageView; +import com.xuexiang.xui.widget.popupwindow.popup.XUISimplePopup; +import com.xuexiang.xutil.XUtil; +import com.xuexiang.xutil.common.ClickUtils; +import com.xuexiang.xutil.common.CollectionUtils; +import com.xuexiang.xutil.display.Colors; + +import java.lang.ref.WeakReference; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import butterknife.BindView; + +public class MainActivity extends BaseActivity implements View.OnClickListener, ViewPager.OnPageChangeListener, BottomNavigationView.OnNavigationItemSelectedListener, ClickUtils.OnClick2ExitListener, Toolbar.OnMenuItemClickListener { + + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.view_pager) + ViewPager viewPager; + /** + * 底部导航栏 + */ + @BindView(R.id.bottom_navigation) + BottomNavigationView bottomNavigation; + /** + * 侧边栏 + */ + @BindView(R.id.nav_view) + NavigationView navView; + @BindView(R.id.drawer_layout) + DrawerLayout drawerLayout; + + private String[] mTitles; + + @Override + protected int getLayoutId() { + return R.layout.activity_main; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initViews(); + initListeners(); + } + + @Override + protected boolean isSupportSlideBack() { + return true; + } + + private void initViews() { + mTitles = ResUtils.getStringArray(R.array.home_titles); + toolbar.setTitle(mTitles[0]); + toolbar.inflateMenu(R.menu.menu_main); + toolbar.setOnMenuItemClickListener(this); + initHeader(); + + //主页内容填充 + BaseFragment[] fragments = new BaseFragment[]{ + new DeviceFragment(), + new SceneFragment(), + new NewsFragment(), + new ProfileFragment(), + }; + FragmentAdapter adapter = new FragmentAdapter<>(getSupportFragmentManager(), fragments); + viewPager.setOffscreenPageLimit(mTitles.length - 1); + viewPager.setAdapter(adapter); + + GuideTipsDialog.showTips(this); + } + + /** + * 侧边栏头部 + */ + private void initHeader() { + navView.setItemIconTintList(null); + View headerView = navView.getHeaderView(0); + LinearLayout navHeader = headerView.findViewById(R.id.nav_header); + RadiusImageView ivAvatar = headerView.findViewById(R.id.iv_avatar); + TextView tvAvatar = headerView.findViewById(R.id.tv_avatar); + TextView tvSign = headerView.findViewById(R.id.tv_sign); + + if (Utils.isColorDark(ThemeUtils.resolveColor(this, R.attr.colorAccent))) { + tvAvatar.setTextColor(Colors.WHITE); + tvSign.setTextColor(Colors.WHITE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ivAvatar.setImageTintList(ResUtils.getColors(R.color.xui_config_color_white)); + } + } else { + tvAvatar.setTextColor(ThemeUtils.resolveColor(this, R.attr.xui_config_color_title_text)); + tvSign.setTextColor(ThemeUtils.resolveColor(this, R.attr.xui_config_color_explain_text)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ivAvatar.setImageTintList(ResUtils.getColors(R.color.xui_config_color_gray_3)); + } + } + + // TODO: 2019-10-09 初始化数据 + ivAvatar.setImageResource(R.drawable.ic_default_head); + tvAvatar.setText("15208747707"); + tvSign.setText("物美点亮智慧生活..."); + navHeader.setOnClickListener(this); + } + + protected void initListeners() { + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); + drawerLayout.addDrawerListener(toggle); + toggle.syncState(); + + //侧边栏点击事件 + navView.setNavigationItemSelectedListener(menuItem -> { + switch (menuItem.getItemId()) { + case R.id.nav_add_device: + PageOption.to(AddDeviceFragment.class) //跳转的fragment + .setAnim(CoreAnim.slide) //页面转场动画 + .setRequestCode(100) //请求码,用于返回结果 + .setAddToBackStack(true) //是否加入堆栈 + .setNewActivity(true,AddDeviceActivity.class) //是否使用新的Activity打开 + .open(this); //打开页面进行跳转 + break; + case R.id.nav_settings: + openNewPage(SettingsFragment.class); + break; + case R.id.nav_about: + openNewPage(AboutFragment.class); + break; + case R.id.nav_message: + openNewPage(MessageFragment.class); + break; + case R.id.nav_share_device: + openNewPage(ShareDeviceFragment.class); + break; + case R.id.nav_group: + openNewPage(GroupFragment.class); + break; + default: + XToastUtils.toast("点击了:" + menuItem.getTitle()); + break; + } + return true; + }); + + //主页事件监听 + viewPager.addOnPageChangeListener(this); + bottomNavigation.setOnNavigationItemSelectedListener(this); + } + + + + + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.add_device: + PageOption.to(AddDeviceFragment.class) //跳转的fragment + .setAnim(CoreAnim.slide) //页面转场动画 + .setRequestCode(100) //请求码,用于返回结果 + .setAddToBackStack(true) //是否加入堆栈 + .setNewActivity(true, AddDeviceActivity.class) //是否使用新的Activity打开 + .open(this); //打开页面进行跳转 + break; + default: + break; + } + return false; + } + + @SingleClick + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.nav_header: + XToastUtils.toast("功能完善中..."); + break; + default: + break; + } + } + + //=============ViewPager===================// + + @Override + public void onPageScrolled(int i, float v, int i1) { + + } + + @Override + public void onPageSelected(int position) { + MenuItem item = bottomNavigation.getMenu().getItem(position); + toolbar.setTitle(item.getTitle()); + item.setChecked(true); + } + + @Override + public void onPageScrollStateChanged(int i) { + + } + + //================Navigation================// + + /** + * 底部导航栏点击事件 + * + * @param menuItem + * @return + */ + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { + int index = CollectionUtils.arrayIndexOf(mTitles, menuItem.getTitle()); + if (index != -1) { + toolbar.setTitle(menuItem.getTitle()); + viewPager.setCurrentItem(index, false); + return true; + } + return false; + } + + + /** + * 菜单、返回键响应 + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + ClickUtils.exitBy2Click(2000, this); + } + return true; + } + + @Override + public void onRetry() { + XToastUtils.toast("再按一次退出程序"); + } + + @Override + public void onExit() { + XUtil.exitApp(); + } + + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java new file mode 100644 index 00000000..9f9328e5 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java @@ -0,0 +1,68 @@ +package com.kerwin.wumei.activity; + +import android.view.KeyEvent; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.SettingUtils; +import com.kerwin.wumei.utils.TokenUtils; +import com.kerwin.wumei.utils.Utils; +import com.xuexiang.xui.utils.KeyboardUtils; +import com.xuexiang.xui.widget.activity.BaseSplashActivity; +import com.xuexiang.xutil.app.ActivityUtils; + +import me.jessyan.autosize.internal.CancelAdapt; + +/** + * 启动页【无需适配屏幕大小】 + * + */ +public class SplashActivity extends BaseSplashActivity implements CancelAdapt { + + @Override + protected long getSplashDurationMillis() { + return 500; + } + + /** + * activity启动后的初始化 + */ + @Override + protected void onCreateActivity() { + initSplashView(R.drawable.xui_config_bg_splash); + startSplash(false); + } + + + /** + * 启动页结束后的动作 + */ + @Override + protected void onSplashFinished() { + if (SettingUtils.isAgreePrivacy()) { + loginOrGoMainPage(); + } else { + Utils.showPrivacyDialog(this, (dialog, which) -> { + dialog.dismiss(); + SettingUtils.setIsAgreePrivacy(true); + loginOrGoMainPage(); + }); + } + } + + private void loginOrGoMainPage() { + if (TokenUtils.hasToken()) { + ActivityUtils.startActivity(MainActivity.class); + } else { + ActivityUtils.startActivity(LoginActivity.class); + } + finish(); + } + + /** + * 菜单、返回键响应 + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliRecyclerAdapter.java b/android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliRecyclerAdapter.java new file mode 100644 index 00000000..9a8df840 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliRecyclerAdapter.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.adapter.base.broccoli; + +import android.view.View; + +import androidx.annotation.NonNull; + +import com.xuexiang.xui.adapter.recyclerview.BaseRecyclerAdapter; +import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; +import com.xuexiang.xui.adapter.recyclerview.XRecyclerAdapter; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import me.samlss.broccoli.Broccoli; + +/** + * 使用Broccoli占位的基础适配器 + * + * @author XUE + * @since 2019/4/8 16:33 + */ +public abstract class BroccoliRecyclerAdapter extends BaseRecyclerAdapter { + /** + * 是否已经加载成功 + */ + private boolean mHasLoad = false; + private Map mBroccoliMap = new HashMap<>(); + + public BroccoliRecyclerAdapter(Collection collection) { + super(collection); + } + + @Override + protected void bindData(@NonNull RecyclerViewHolder holder, int position, T item) { + Broccoli broccoli = mBroccoliMap.get(holder.itemView); + if (broccoli == null) { + broccoli = new Broccoli(); + mBroccoliMap.put(holder.itemView, broccoli); + } + if (mHasLoad) { + broccoli.removeAllPlaceholders(); + + onBindData(holder, item, position); + } else { + onBindBroccoli(holder, broccoli); + broccoli.show(); + } + } + + /** + * 绑定控件 + * + * @param holder + * @param model + * @param position + */ + protected abstract void onBindData(RecyclerViewHolder holder, T model, int position); + + /** + * 绑定占位控件 + * + * @param broccoli + */ + protected abstract void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli); + + @Override + public XRecyclerAdapter refresh(Collection collection) { + mHasLoad = true; + return super.refresh(collection); + } + + /** + * 资源释放,防止内存泄漏 + */ + public void recycle() { + for (Broccoli broccoli : mBroccoliMap.values()) { + broccoli.removeAllPlaceholders(); + } + mBroccoliMap.clear(); + clear(); + } + + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.java b/android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.java new file mode 100644 index 00000000..ed722913 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.adapter.base.broccoli; + +import android.view.View; + +import androidx.annotation.NonNull; + +import com.alibaba.android.vlayout.LayoutHelper; +import com.kerwin.wumei.adapter.base.delegate.SimpleDelegateAdapter; +import com.kerwin.wumei.adapter.base.delegate.XDelegateAdapter; +import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import me.samlss.broccoli.Broccoli; + +/** + * 使用Broccoli占位的基础适配器 + * + * @author xuexiang + * @since 2021/1/9 4:52 PM + */ +public abstract class BroccoliSimpleDelegateAdapter extends SimpleDelegateAdapter { + + /** + * 是否已经加载成功 + */ + private boolean mHasLoad = false; + private Map mBroccoliMap = new HashMap<>(); + + public BroccoliSimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper) { + super(layoutId, layoutHelper); + } + + public BroccoliSimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, Collection list) { + super(layoutId, layoutHelper, list); + } + + public BroccoliSimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, T[] data) { + super(layoutId, layoutHelper, data); + } + + @Override + protected void bindData(@NonNull RecyclerViewHolder holder, int position, T item) { + Broccoli broccoli = mBroccoliMap.get(holder.itemView); + if (broccoli == null) { + broccoli = new Broccoli(); + mBroccoliMap.put(holder.itemView, broccoli); + } + if (mHasLoad) { + broccoli.removeAllPlaceholders(); + + onBindData(holder, item, position); + } else { + onBindBroccoli(holder, broccoli); + broccoli.show(); + } + } + + + /** + * 绑定控件 + * + * @param holder + * @param model + * @param position + */ + protected abstract void onBindData(RecyclerViewHolder holder, T model, int position); + + /** + * 绑定占位控件 + * + * @param holder + * @param broccoli + */ + protected abstract void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli); + + @Override + public XDelegateAdapter refresh(Collection collection) { + mHasLoad = true; + return super.refresh(collection); + } + + /** + * 资源释放,防止内存泄漏 + */ + public void recycle() { + for (Broccoli broccoli : mBroccoliMap.values()) { + broccoli.removeAllPlaceholders(); + } + mBroccoliMap.clear(); + clear(); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/BaseDelegateAdapter.java b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/BaseDelegateAdapter.java new file mode 100644 index 00000000..52c8fcda --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/BaseDelegateAdapter.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.adapter.base.delegate; + +import android.view.ViewGroup; + +import androidx.annotation.NonNull; + +import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; + +import java.util.Collection; + +/** + * 通用的DelegateAdapter适配器 + * + * @author xuexiang + * @since 2020/3/20 12:44 AM + */ +public abstract class BaseDelegateAdapter extends XDelegateAdapter { + + public BaseDelegateAdapter() { + super(); + } + + public BaseDelegateAdapter(Collection list) { + super(list); + } + + public BaseDelegateAdapter(T[] data) { + super(data); + } + + /** + * 适配的布局 + * + * @param viewType + * @return + */ + protected abstract int getItemLayoutId(int viewType); + + @NonNull + @Override + protected RecyclerViewHolder getViewHolder(@NonNull ViewGroup parent, int viewType) { + return new RecyclerViewHolder(inflateView(parent, getItemLayoutId(viewType))); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SimpleDelegateAdapter.java b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SimpleDelegateAdapter.java new file mode 100644 index 00000000..f0f280b0 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SimpleDelegateAdapter.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.adapter.base.delegate; + +import com.alibaba.android.vlayout.LayoutHelper; + +import java.util.Collection; + +/** + * 简易DelegateAdapter适配器 + * + * @author xuexiang + * @since 2020/3/20 12:55 AM + */ +public abstract class SimpleDelegateAdapter extends BaseDelegateAdapter { + + private int mLayoutId; + + private LayoutHelper mLayoutHelper; + + public SimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper) { + super(); + mLayoutId = layoutId; + mLayoutHelper = layoutHelper; + } + + public SimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, Collection list) { + super(list); + mLayoutId = layoutId; + mLayoutHelper = layoutHelper; + } + + public SimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, T[] data) { + super(data); + mLayoutId = layoutId; + mLayoutHelper = layoutHelper; + } + + @Override + protected int getItemLayoutId(int viewType) { + return mLayoutId; + } + + + @Override + public LayoutHelper onCreateLayoutHelper() { + return mLayoutHelper; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SingleDelegateAdapter.java b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SingleDelegateAdapter.java new file mode 100644 index 00000000..46b7329b --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/SingleDelegateAdapter.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.adapter.base.delegate; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; + +import com.alibaba.android.vlayout.DelegateAdapter; +import com.alibaba.android.vlayout.LayoutHelper; +import com.alibaba.android.vlayout.layout.SingleLayoutHelper; +import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; + +/** + * 单独布局的DelegateAdapter + * + * @author xuexiang + * @since 2020/3/20 1:04 AM + */ +public abstract class SingleDelegateAdapter extends DelegateAdapter.Adapter { + + private int mLayoutId; + + public SingleDelegateAdapter(int layoutId) { + mLayoutId = layoutId; + } + + @Override + public LayoutHelper onCreateLayoutHelper() { + return new SingleLayoutHelper(); + } + + /** + * 加载布局获取控件 + * + * @param parent 父布局 + * @param layoutId 布局ID + * @return + */ + protected View inflateView(ViewGroup parent, @LayoutRes int layoutId) { + return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); + } + + @NonNull + @Override + public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new RecyclerViewHolder(inflateView(parent, mLayoutId)); + } + + @Override + public int getItemCount() { + return 1; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/XDelegateAdapter.java b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/XDelegateAdapter.java new file mode 100644 index 00000000..86881382 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/base/delegate/XDelegateAdapter.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.adapter.base.delegate; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.alibaba.android.vlayout.DelegateAdapter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * 基础DelegateAdapter + * + * @author xuexiang + * @since 2020/3/20 12:17 AM + */ +public abstract class XDelegateAdapter extends DelegateAdapter.Adapter { + /** + * 数据源 + */ + protected final List mData = new ArrayList<>(); + /** + * 当前点击的条目 + */ + protected int mSelectPosition = -1; + + public XDelegateAdapter() { + + } + + public XDelegateAdapter(Collection list) { + if (list != null) { + mData.addAll(list); + } + } + + public XDelegateAdapter(T[] data) { + if (data != null && data.length > 0) { + mData.addAll(Arrays.asList(data)); + } + } + + /** + * 构建自定义的ViewHolder + * + * @param parent + * @param viewType + * @return + */ + @NonNull + protected abstract V getViewHolder(@NonNull ViewGroup parent, int viewType); + + /** + * 绑定数据 + * + * @param holder + * @param position 索引 + * @param item 列表项 + */ + protected abstract void bindData(@NonNull V holder, int position, T item); + + /** + * 加载布局获取控件 + * + * @param parent 父布局 + * @param layoutId 布局ID + * @return + */ + protected View inflateView(ViewGroup parent, @LayoutRes int layoutId) { + return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); + } + + @NonNull + @Override + public V onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return getViewHolder(parent, viewType); + } + + @Override + public void onBindViewHolder(@NonNull V holder, int position) { + bindData(holder, position, mData.get(position)); + } + + /** + * 获取列表项 + * + * @param position + * @return + */ + public T getItem(int position) { + return checkPosition(position) ? mData.get(position) : null; + } + + private boolean checkPosition(int position) { + return position >= 0 && position <= mData.size() - 1; + } + + public boolean isEmpty() { + return getItemCount() == 0; + } + + @Override + public int getItemCount() { + return mData.size(); + } + + /** + * @return 数据源 + */ + public List getData() { + return mData; + } + + /** + * 给指定位置添加一项 + * + * @param pos + * @param item + * @return + */ + public XDelegateAdapter add(int pos, T item) { + mData.add(pos, item); + notifyItemInserted(pos); + return this; + } + + /** + * 在列表末端增加一项 + * + * @param item + * @return + */ + public XDelegateAdapter add(T item) { + mData.add(item); + notifyItemInserted(mData.size() - 1); + return this; + } + + /** + * 删除列表中指定索引的数据 + * + * @param pos + * @return + */ + public XDelegateAdapter delete(int pos) { + mData.remove(pos); + notifyItemRemoved(pos); + return this; + } + + /** + * 刷新列表中指定位置的数据 + * + * @param pos + * @param item + * @return + */ + public XDelegateAdapter refresh(int pos, T item) { + mData.set(pos, item); + notifyItemChanged(pos); + return this; + } + + /** + * 刷新列表数据 + * + * @param collection + * @return + */ + public XDelegateAdapter refresh(Collection collection) { + if (collection != null) { + mData.clear(); + mData.addAll(collection); + mSelectPosition = -1; + notifyDataSetChanged(); + } + return this; + } + + /** + * 刷新列表数据 + * + * @param array + * @return + */ + public XDelegateAdapter refresh(T[] array) { + if (array != null && array.length > 0) { + mData.clear(); + mData.addAll(Arrays.asList(array)); + mSelectPosition = -1; + notifyDataSetChanged(); + } + return this; + } + + /** + * 加载更多 + * + * @param collection + * @return + */ + public XDelegateAdapter loadMore(Collection collection) { + if (collection != null) { + mData.addAll(collection); + notifyDataSetChanged(); + } + return this; + } + + /** + * 加载更多 + * + * @param array + * @return + */ + public XDelegateAdapter loadMore(T[] array) { + if (array != null && array.length > 0) { + mData.addAll(Arrays.asList(array)); + notifyDataSetChanged(); + } + return this; + } + + /** + * 添加一个 + * + * @param item + * @return + */ + public XDelegateAdapter load(T item) { + if (item != null) { + mData.add(item); + notifyDataSetChanged(); + } + return this; + } + + /** + * @return 当前列表的选中项 + */ + public int getSelectPosition() { + return mSelectPosition; + } + + /** + * 设置当前列表的选中项 + * + * @param selectPosition + * @return + */ + public XDelegateAdapter setSelectPosition(int selectPosition) { + mSelectPosition = selectPosition; + notifyDataSetChanged(); + return this; + } + + /** + * 获取当前列表选中项 + * + * @return 当前列表选中项 + */ + public T getSelectItem() { + return getItem(mSelectPosition); + } + + /** + * 清除数据 + */ + public void clear() { + if (!isEmpty()) { + mData.clear(); + mSelectPosition = -1; + notifyDataSetChanged(); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java new file mode 100644 index 00000000..fb4a2429 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java @@ -0,0 +1,31 @@ +package com.kerwin.wumei.adapter.entity; + +import android.widget.Button; +import android.widget.EditText; +import android.widget.RadioGroup; +import android.widget.TextView; + +import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner; + +public class EspTouchViewModel { + public MaterialSpinner ssidSpinner; + public EditText apPasswordEdit; + public EditText deviceCountEdit; + public RadioGroup packageModeGroup; + public TextView messageView; + public Button confirmBtn; + + public String ssid; + public byte[] ssidBytes; + public String bssid; + + public CharSequence message; + + public boolean confirmEnable; + + public void invalidateAll() { + ssidSpinner.setText(ssid); + messageView.setText(message); + confirmBtn.setEnabled(confirmEnable); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java new file mode 100644 index 00000000..165ed133 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.adapter.entity; + +/** + * 新闻信息 + * + * @author xuexiang + * @since 2019/4/7 下午12:07 + */ +public class NewInfo { + + /** + * 用户名 + */ + private String UserName = "kerwin"; + /** + * 标签 + */ + private String Tag; + /** + * 标题 + */ + private String Title; + /** + * 摘要 + */ + private String Summary; + + /** + * 图片 + */ + private String ImageUrl; + /** + * 点赞数 + */ + private int Praise; + /** + * 评论数 + */ + private int Comment; + /** + * 阅读量 + */ + private int Read; + /** + * 新闻的详情地址 + */ + private String DetailUrl; + + + public NewInfo() { + + } + + public NewInfo(String userName, String tag, String title, String summary, String imageUrl, int praise, int comment, int read, String detailUrl) { + UserName = userName; + Tag = tag; + Title = title; + Summary = summary; + ImageUrl = imageUrl; + Praise = praise; + Comment = comment; + Read = read; + DetailUrl = detailUrl; + } + + + public NewInfo(String tag, String title, String summary, String imageUrl, String detailUrl) { + Tag = tag; + Title = title; + Summary = summary; + ImageUrl = imageUrl; + DetailUrl = detailUrl; + } + + + public NewInfo(String tag, String title) { + Tag = tag; + Title = title; + + Praise = (int) (Math.random() * 100 + 5); + Comment = (int) (Math.random() * 50 + 5); + Read = (int) (Math.random() * 500 + 50); + } + + + + public String getUserName() { + return UserName; + } + + public NewInfo setUserName(String userName) { + UserName = userName; + return this; + } + + public String getTag() { + return Tag; + } + + public NewInfo setTag(String tag) { + Tag = tag; + return this; + } + + public String getTitle() { + return Title; + } + + public NewInfo setTitle(String title) { + Title = title; + return this; + } + + public String getSummary() { + return Summary; + } + + public NewInfo setSummary(String summary) { + Summary = summary; + return this; + } + + public String getImageUrl() { + return ImageUrl; + } + + public NewInfo setImageUrl(String imageUrl) { + ImageUrl = imageUrl; + return this; + } + + public int getPraise() { + return Praise; + } + + public NewInfo setPraise(int praise) { + Praise = praise; + return this; + } + + public int getComment() { + return Comment; + } + + public NewInfo setComment(int comment) { + Comment = comment; + return this; + } + + public int getRead() { + return Read; + } + + public NewInfo setRead(int read) { + Read = read; + return this; + } + + public String getDetailUrl() { + return DetailUrl; + } + + public NewInfo setDetailUrl(String detailUrl) { + DetailUrl = detailUrl; + return this; + } + + @Override + public String toString() { + return "NewInfo{" + + "UserName='" + UserName + '\'' + + ", Tag='" + Tag + '\'' + + ", Title='" + Title + '\'' + + ", Summary='" + Summary + '\'' + + ", ImageUrl='" + ImageUrl + '\'' + + ", Praise=" + Praise + + ", Comment=" + Comment + + ", Read=" + Read + + ", DetailUrl='" + DetailUrl + '\'' + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/BaseActivity.java b/android/app/src/main/java/com/kerwin/wumei/core/BaseActivity.java new file mode 100644 index 00000000..b6529fdd --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/BaseActivity.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core; + +import android.content.Context; +import android.os.Bundle; + +import com.xuexiang.xpage.base.XPageActivity; +import com.xuexiang.xpage.base.XPageFragment; +import com.xuexiang.xpage.core.CoreSwitchBean; +import com.xuexiang.xrouter.facade.service.SerializationService; +import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xui.utils.ResUtils; +import com.xuexiang.xui.widget.slideback.SlideBack; + +import butterknife.ButterKnife; +import butterknife.Unbinder; +import io.github.inflationx.viewpump.ViewPumpContextWrapper; + +/** + * 基础容器Activity + * + * @author XUE + * @since 2019/3/22 11:21 + */ +public class BaseActivity extends XPageActivity { + + Unbinder mUnbinder; + + @Override + protected void attachBaseContext(Context newBase) { + //注入字体 + super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase)); + } + + /** + * 是否支持侧滑返回 + */ + public static final String KEY_SUPPORT_SLIDE_BACK = "key_support_slide_back"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + initStatusBarStyle(); + super.onCreate(savedInstanceState); + mUnbinder = ButterKnife.bind(this); + + registerSlideBack(); + } + + /** + * 初始化状态栏的样式 + */ + protected void initStatusBarStyle() { + + } + + /** + * 打开fragment + * + * @param clazz 页面类 + * @param addToBackStack 是否添加到栈中 + * @return 打开的fragment对象 + */ + public T openPage(Class clazz, boolean addToBackStack) { + CoreSwitchBean page = new CoreSwitchBean(clazz) + .setAddToBackStack(addToBackStack); + return (T) openPage(page); + } + + /** + * 打开fragment + * + * @return 打开的fragment对象 + */ + public T openNewPage(Class clazz) { + CoreSwitchBean page = new CoreSwitchBean(clazz) + .setNewActivity(true); + return (T) openPage(page); + } + + /** + * 切换fragment + * + * @param clazz 页面类 + * @return 打开的fragment对象 + */ + public T switchPage(Class clazz) { + return openPage(clazz, false); + } + + /** + * 序列化对象 + * + * @param object + * @return + */ + public String serializeObject(Object object) { + return XRouter.getInstance().navigation(SerializationService.class).object2Json(object); + } + + @Override + protected void onRelease() { + mUnbinder.unbind(); + unregisterSlideBack(); + super.onRelease(); + } + + /** + * 注册侧滑回调 + */ + protected void registerSlideBack() { + if (isSupportSlideBack()) { + SlideBack.with(this) + .haveScroll(true) + .edgeMode(ResUtils.isRtl() ? SlideBack.EDGE_RIGHT : SlideBack.EDGE_LEFT) + .callBack(this::popPage) + .register(); + } + } + + /** + * 注销侧滑回调 + */ + protected void unregisterSlideBack() { + if (isSupportSlideBack()) { + SlideBack.unregister(this); + } + } + + /** + * @return 是否支持侧滑返回 + */ + protected boolean isSupportSlideBack() { + CoreSwitchBean page = getIntent().getParcelableExtra(CoreSwitchBean.KEY_SWITCH_BEAN); + return page == null || page.getBundle() == null || page.getBundle().getBoolean(KEY_SUPPORT_SLIDE_BACK, true); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/BaseContainerFragment.java b/android/app/src/main/java/com/kerwin/wumei/core/BaseContainerFragment.java new file mode 100644 index 00000000..29987cc1 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/BaseContainerFragment.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core; + +import android.content.res.Configuration; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; + +import com.umeng.analytics.MobclickAgent; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.base.XPageContainerListFragment; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.actionbar.TitleUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.kerwin.wumei.core.SimpleListAdapter.KEY_SUB_TITLE; +import static com.kerwin.wumei.core.SimpleListAdapter.KEY_TITLE; + +/** + * 修改列表样式为主副标题显示 + * + * @author xuexiang + * @since 2018/11/22 上午11:26 + */ +public abstract class BaseContainerFragment extends XPageContainerListFragment { + + @Override + protected void initPage() { + initTitle(); + initViews(); + initListeners(); + } + + protected TitleBar initTitle() { + return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), new View.OnClickListener() { + @Override + public void onClick(View v) { + popToBack(); + } + }); + } + + @Override + protected void initData() { + mSimpleData = initSimpleData(mSimpleData); + + List> data = new ArrayList<>(); + for (String content : mSimpleData) { + Map item = new HashMap<>(); + int index = content.indexOf("\n"); + if (index > 0) { + item.put(KEY_TITLE, String.valueOf(content.subSequence(0, index))); + item.put(KEY_SUB_TITLE, String.valueOf(content.subSequence(index + 1, content.length()))); + } else { + item.put(KEY_TITLE, content); + item.put(KEY_SUB_TITLE, ""); + } + data.add(item); + } + + getListView().setAdapter(new SimpleListAdapter(getContext(), data)); + initSimply(); + } + + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + onItemClick(view, position); + } + + @SingleClick + private void onItemClick(View view, int position) { + onItemClick(position); + } + + @Override + public void onDestroyView() { + getListView().setOnItemClickListener(null); + super.onDestroyView(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + //屏幕旋转时刷新一下title + super.onConfigurationChanged(newConfig); + ViewGroup root = (ViewGroup) getRootView(); + if (root.getChildAt(0) instanceof TitleBar) { + root.removeViewAt(0); + initTitle(); + } + } + + @Override + public void onResume() { + super.onResume(); + MobclickAgent.onPageStart(getPageName()); + } + + @Override + public void onPause() { + super.onPause(); + MobclickAgent.onPageEnd(getPageName()); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/BaseFragment.java b/android/app/src/main/java/com/kerwin/wumei/core/BaseFragment.java new file mode 100644 index 00000000..5441c502 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/BaseFragment.java @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core; + +import android.content.res.Configuration; +import android.os.Parcelable; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; + +import com.umeng.analytics.MobclickAgent; +import com.kerwin.wumei.core.http.loader.ProgressLoader; +import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader; +import com.xuexiang.xpage.base.XPageActivity; +import com.xuexiang.xpage.base.XPageFragment; +import com.xuexiang.xpage.core.PageOption; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xpage.utils.Utils; +import com.xuexiang.xrouter.facade.service.SerializationService; +import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.actionbar.TitleUtils; + +import java.io.Serializable; +import java.lang.reflect.Type; + +/** + * 基础fragment + * + * @author xuexiang + * @since 2018/5/25 下午3:44 + */ +public abstract class BaseFragment extends XPageFragment { + + private IProgressLoader mIProgressLoader; + + @Override + protected void initPage() { + initTitle(); + initViews(); + initListeners(); + } + + protected TitleBar initTitle() { + return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), v -> popToBack()); + } + + @Override + protected void initListeners() { + + } + + /** + * 获取进度条加载者 + * + * @return 进度条加载者 + */ + public IProgressLoader getProgressLoader() { + if (mIProgressLoader == null) { + mIProgressLoader = ProgressLoader.create(getContext()); + } + return mIProgressLoader; + } + + /** + * 获取进度条加载者 + * + * @param message + * @return 进度条加载者 + */ + public IProgressLoader getProgressLoader(String message) { + if (mIProgressLoader == null) { + mIProgressLoader = ProgressLoader.create(getContext(), message); + } else { + mIProgressLoader.updateMessage(message); + } + return mIProgressLoader; + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + //屏幕旋转时刷新一下title + super.onConfigurationChanged(newConfig); + ViewGroup root = (ViewGroup) getRootView(); + if (root.getChildAt(0) instanceof TitleBar) { + root.removeViewAt(0); + initTitle(); + } + } + + @Override + public void onDestroyView() { + if (mIProgressLoader != null) { + mIProgressLoader.dismissLoading(); + } + super.onDestroyView(); + } + + @Override + public void onResume() { + super.onResume(); + MobclickAgent.onPageStart(getPageName()); + } + + @Override + public void onPause() { + super.onPause(); + MobclickAgent.onPageEnd(getPageName()); + } + + //==============================页面跳转api===================================// + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param clazz 页面的类 + * @param + * @return + */ + public Fragment openNewPage(Class clazz) { + return new PageOption(clazz) + .setNewActivity(true) + .open(this); + } + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param pageName 页面名 + * @param + * @return + */ + public Fragment openNewPage(String pageName) { + return new PageOption(pageName) + .setAnim(CoreAnim.slide) + .setNewActivity(true) + .open(this); + } + + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param clazz 页面的类 + * @param containActivityClazz 页面容器 + * @param + * @return + */ + public Fragment openNewPage(Class clazz, @NonNull Class containActivityClazz) { + return new PageOption(clazz) + .setNewActivity(true) + .setContainActivityClazz(containActivityClazz) + .open(this); + } + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openNewPage(Class clazz, String key, Object value) { + PageOption option = new PageOption(clazz).setNewActivity(true); + return openPage(option, key, value); + } + + public Fragment openPage(PageOption option, String key, Object value) { + if (value instanceof Integer) { + option.putInt(key, (Integer) value); + } else if (value instanceof Float) { + option.putFloat(key, (Float) value); + } else if (value instanceof String) { + option.putString(key, (String) value); + } else if (value instanceof Boolean) { + option.putBoolean(key, (Boolean) value); + } else if (value instanceof Long) { + option.putLong(key, (Long) value); + } else if (value instanceof Double) { + option.putDouble(key, (Double) value); + } else if (value instanceof Parcelable) { + option.putParcelable(key, (Parcelable) value); + } else if (value instanceof Serializable) { + option.putSerializable(key, (Serializable) value); + } else { + option.putString(key, serializeObject(value)); + } + return option.open(this); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param addToBackStack 是否加入回退栈 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, boolean addToBackStack, String key, String value) { + return new PageOption(clazz) + .setAddToBackStack(addToBackStack) + .putString(key, value) + .open(this); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, String key, Object value) { + return openPage(clazz, true, key, value); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param addToBackStack 是否加入回退栈 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, boolean addToBackStack, String key, Object value) { + PageOption option = new PageOption(clazz).setAddToBackStack(addToBackStack); + return openPage(option, key, value); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, String key, String value) { + return new PageOption(clazz) + .putString(key, value) + .open(this); + } + + /** + * 打开页面,需要结果返回 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param requestCode 请求码 + * @param + * @return + */ + public Fragment openPageForResult(Class clazz, String key, Object value, int requestCode) { + PageOption option = new PageOption(clazz).setRequestCode(requestCode); + return openPage(option, key, value); + } + + /** + * 打开页面,需要结果返回 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param requestCode 请求码 + * @param + * @return + */ + public Fragment openPageForResult(Class clazz, String key, String value, int requestCode) { + return new PageOption(clazz) + .setRequestCode(requestCode) + .putString(key, value) + .open(this); + } + + /** + * 打开页面,需要结果返回 + * + * @param clazz 页面的类 + * @param requestCode 请求码 + * @param + * @return + */ + public Fragment openPageForResult(Class clazz, int requestCode) { + return new PageOption(clazz) + .setRequestCode(requestCode) + .open(this); + } + + /** + * 序列化对象 + * + * @param object 需要序列化的对象 + * @return 序列化结果 + */ + public String serializeObject(Object object) { + return XRouter.getInstance().navigation(SerializationService.class).object2Json(object); + } + + /** + * 反序列化对象 + * + * @param input 反序列化的内容 + * @param clazz 类型 + * @return 反序列化结果 + */ + public T deserializeObject(String input, Type clazz) { + return XRouter.getInstance().navigation(SerializationService.class).parseObject(input, clazz); + } + + + @Override + protected void hideCurrentPageSoftInput() { + if (getActivity() == null) { + return; + } + // 记住,要在xml的父布局加上android:focusable="true" 和 android:focusableInTouchMode="true" + Utils.hideSoftInputClearFocus(getActivity().getCurrentFocus()); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/BaseSimpleListFragment.java b/android/app/src/main/java/com/kerwin/wumei/core/BaseSimpleListFragment.java new file mode 100644 index 00000000..5474bb00 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/BaseSimpleListFragment.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core; + +import android.content.res.Configuration; +import android.os.Parcelable; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; + +import com.umeng.analytics.MobclickAgent; +import com.xuexiang.xpage.base.XPageActivity; +import com.xuexiang.xpage.base.XPageFragment; +import com.xuexiang.xpage.base.XPageSimpleListFragment; +import com.xuexiang.xpage.core.PageOption; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xrouter.facade.service.SerializationService; +import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.actionbar.TitleUtils; + +import java.io.Serializable; + +/** + * @author xuexiang + * @since 2018/12/29 下午12:41 + */ +public abstract class BaseSimpleListFragment extends XPageSimpleListFragment { + + @Override + protected void initPage() { + initTitle(); + initViews(); + initListeners(); + } + + protected TitleBar initTitle() { + return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), new View.OnClickListener() { + @Override + public void onClick(View v) { + popToBack(); + } + }); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + //屏幕旋转时刷新一下title + super.onConfigurationChanged(newConfig); + ViewGroup root = (ViewGroup) getRootView(); + if (root.getChildAt(0) instanceof TitleBar) { + root.removeViewAt(0); + initTitle(); + } + } + + @Override + public void onResume() { + super.onResume(); + MobclickAgent.onPageStart(getPageName()); + } + + @Override + public void onPause() { + super.onPause(); + MobclickAgent.onPageEnd(getPageName()); + } + + //==============================页面跳转api===================================// + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param clazz 页面的类 + * @param + * @return + */ + public Fragment openNewPage(Class clazz) { + return new PageOption(clazz) + .setNewActivity(true) + .open(this); + } + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param pageName 页面名 + * @param + * @return + */ + public Fragment openNewPage(String pageName) { + return new PageOption(pageName) + .setAnim(CoreAnim.slide) + .setNewActivity(true) + .open(this); + } + + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param clazz 页面的类 + * @param containActivityClazz 页面容器 + * @param + * @return + */ + public Fragment openNewPage(Class clazz, @NonNull Class containActivityClazz) { + return new PageOption(clazz) + .setNewActivity(true) + .setContainActivityClazz(containActivityClazz) + .open(this); + } + + /** + * 打开一个新的页面【建议只在主tab页使用】 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openNewPage(Class clazz, String key, Object value) { + PageOption option = new PageOption(clazz).setNewActivity(true); + return openPage(option, key, value); + } + + public Fragment openPage(PageOption option, String key, Object value) { + if (value instanceof Integer) { + option.putInt(key, (Integer) value); + } else if (value instanceof Float) { + option.putFloat(key, (Float) value); + } else if (value instanceof String) { + option.putString(key, (String) value); + } else if (value instanceof Boolean) { + option.putBoolean(key, (Boolean) value); + } else if (value instanceof Long) { + option.putLong(key, (Long) value); + } else if (value instanceof Double) { + option.putDouble(key, (Double) value); + } else if (value instanceof Parcelable) { + option.putParcelable(key, (Parcelable) value); + } else if (value instanceof Serializable) { + option.putSerializable(key, (Serializable) value); + } else { + option.putString(key, serializeObject(value)); + } + return option.open(this); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param addToBackStack 是否加入回退栈 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, boolean addToBackStack, String key, String value) { + return new PageOption(clazz) + .setAddToBackStack(addToBackStack) + .putString(key, value) + .open(this); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, String key, Object value) { + return openPage(clazz, true, key, value); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param addToBackStack 是否加入回退栈 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, boolean addToBackStack, String key, Object value) { + PageOption option = new PageOption(clazz).setAddToBackStack(addToBackStack); + return openPage(option, key, value); + } + + /** + * 打开页面 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param + * @return + */ + public Fragment openPage(Class clazz, String key, String value) { + return new PageOption(clazz) + .putString(key, value) + .open(this); + } + + /** + * 打开页面,需要结果返回 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param requestCode 请求码 + * @param + * @return + */ + public Fragment openPageForResult(Class clazz, String key, Object value, int requestCode) { + PageOption option = new PageOption(clazz).setRequestCode(requestCode); + return openPage(option, key, value); + } + + /** + * 打开页面,需要结果返回 + * + * @param clazz 页面的类 + * @param key 入参的键 + * @param value 入参的值 + * @param requestCode 请求码 + * @param + * @return + */ + public Fragment openPageForResult(Class clazz, String key, String value, int requestCode) { + return new PageOption(clazz) + .setRequestCode(requestCode) + .putString(key, value) + .open(this); + } + + /** + * 打开页面,需要结果返回 + * + * @param clazz 页面的类 + * @param requestCode 请求码 + * @param + * @return + */ + public Fragment openPageForResult(Class clazz, int requestCode) { + return new PageOption(clazz) + .setRequestCode(requestCode) + .open(this); + } + + /** + * 序列化对象 + * + * @param object 需要序列化的对象 + * @return 序列化结果 + */ + public String serializeObject(Object object) { + return XRouter.getInstance().navigation(SerializationService.class).object2Json(object); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/SimpleListAdapter.java b/android/app/src/main/java/com/kerwin/wumei/core/SimpleListAdapter.java new file mode 100644 index 00000000..c8d43cee --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/SimpleListAdapter.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core; + +import android.content.Context; +import android.view.View; +import android.widget.TextView; + +import com.kerwin.wumei.R; +import com.xuexiang.xui.adapter.listview.BaseListAdapter; +import com.xuexiang.xutil.common.StringUtils; + +import java.util.List; +import java.util.Map; + +/** + * 主副标题显示适配器 + * + * @author xuexiang + * @since 2018/12/19 上午12:19 + */ +public class SimpleListAdapter extends BaseListAdapter, SimpleListAdapter.ViewHolder> { + + public static final String KEY_TITLE = "key_title"; + public static final String KEY_SUB_TITLE = "key_sub_title"; + + public SimpleListAdapter(Context context, List> data) { + super(context, data); + } + + @Override + protected ViewHolder newViewHolder(View convertView) { + ViewHolder holder = new ViewHolder(); + holder.mTvTitle = convertView.findViewById(R.id.device_item_title); + holder.mTvSubTitle = convertView.findViewById(R.id.tv_sub_title); + return holder; + } + + @Override + protected int getLayoutId() { + return R.layout.adapter_item_simple_list_2; + } + + @Override + protected void convert(ViewHolder holder, Map item, int position) { + holder.mTvTitle.setText(item.get(KEY_TITLE)); + if (!StringUtils.isEmpty(item.get(KEY_SUB_TITLE))) { + holder.mTvSubTitle.setText(item.get(KEY_SUB_TITLE)); + holder.mTvSubTitle.setVisibility(View.VISIBLE); + } else { + holder.mTvSubTitle.setVisibility(View.GONE); + } + } + + public static class ViewHolder { + /** + * 标题 + */ + public TextView mTvTitle; + /** + * 副标题 + */ + public TextView mTvSubTitle; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/XPageTransferActivity.java b/android/app/src/main/java/com/kerwin/wumei/core/XPageTransferActivity.java new file mode 100644 index 00000000..b0343ccf --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/XPageTransferActivity.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core; + +import android.os.Bundle; + +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xrouter.annotation.AutoWired; +import com.xuexiang.xrouter.annotation.Router; +import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xutil.common.StringUtils; + +/** + * https://xuexiangjys.club/xpage/transfer?pageName=xxxxx&.... + * applink的中转 + * + * @author xuexiang + * @since 2019-07-06 9:37 + */ +@Router(path = "/xpage/transfer") +public class XPageTransferActivity extends BaseActivity { + + @AutoWired(name = "pageName") + String pageName; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + XRouter.getInstance().inject(this); + + if (!StringUtils.isEmpty(pageName)) { + if (openPage(pageName, getIntent().getExtras()) == null) { + XToastUtils.error("页面未找到!"); + finish(); + } + } else { + XToastUtils.error("页面未找到!"); + finish(); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java b/android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java new file mode 100644 index 00000000..efda7d0a --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.api; + +import com.kerwin.wumei.core.http.entity.TipInfo; +import com.xuexiang.xhttp2.model.ApiResult; + +import java.util.List; + +import io.reactivex.Observable; +import retrofit2.http.GET; + +/** + * @author xuexiang + * @since 2021/1/9 7:01 PM + */ +public class ApiService { + + /** + * 使用的是retrofit的接口定义 + */ + public interface IGetService { + + /** + * 获得小贴士 + */ + @GET("/xuexiangjys/Resource/raw/master/jsonapi/tips.json") + Observable>> getTips(); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/callback/NoTipCallBack.java b/android/app/src/main/java/com/kerwin/wumei/core/http/callback/NoTipCallBack.java new file mode 100644 index 00000000..ceaa7fbb --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/callback/NoTipCallBack.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.callback; + +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * 不带错误提示的网络请求回调 + * + * @author xuexiang + * @since 2019-11-18 23:02 + */ +public abstract class NoTipCallBack extends SimpleCallBack { + + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public NoTipCallBack() { + + } + + public NoTipCallBack(XHttpRequest req) { + this(req.getUrl()); + } + + public NoTipCallBack(String url) { + mUrl = url; + } + + @Override + public void onError(ApiException e) { + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipCallBack.java b/android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipCallBack.java new file mode 100644 index 00000000..10c4b1c2 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipCallBack.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.callback; + +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * 带错误toast提示的网络请求回调 + * + * @author xuexiang + * @since 2019-11-18 23:02 + */ +public abstract class TipCallBack extends SimpleCallBack { + + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public TipCallBack() { + + } + + public TipCallBack(XHttpRequest req) { + this(req.getUrl()); + } + + public TipCallBack(String url) { + mUrl = url; + } + + @Override + public void onError(ApiException e) { + XToastUtils.error(e); + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipProgressLoadingCallBack.java b/android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipProgressLoadingCallBack.java new file mode 100644 index 00000000..9fb26d4b --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/callback/TipProgressLoadingCallBack.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.callback; + +import androidx.annotation.NonNull; + +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xhttp2.callback.ProgressLoadingCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * 带错误toast提示和加载进度条的网络请求回调 + * + * @author xuexiang + * @since 2019-11-18 23:16 + */ +public abstract class TipProgressLoadingCallBack extends ProgressLoadingCallBack { + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public TipProgressLoadingCallBack(BaseFragment fragment) { + super(fragment.getProgressLoader()); + } + + public TipProgressLoadingCallBack(IProgressLoader iProgressLoader) { + super(iProgressLoader); + } + + public TipProgressLoadingCallBack(@NonNull XHttpRequest req, IProgressLoader iProgressLoader) { + this(req.getUrl(), iProgressLoader); + } + + public TipProgressLoadingCallBack(String url, IProgressLoader iProgressLoader) { + super(iProgressLoader); + mUrl = url; + } + + @Override + public void onError(ApiException e) { + super.onError(e); + XToastUtils.error(e); + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/entity/TipInfo.java b/android/app/src/main/java/com/kerwin/wumei/core/http/entity/TipInfo.java new file mode 100644 index 00000000..2aad9964 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/entity/TipInfo.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.entity; + +import androidx.annotation.Keep; + +/** + * @author xuexiang + * @since 2019-08-28 15:35 + */ +@Keep +public class TipInfo { + + /** + * title : 小贴士3 + * content :

欢迎关注我的微信公众号:我的Android开源之旅。


+ */ + + private String title; + private String content; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + @Override + public String toString() { + return "TipInfo{" + + "title='" + title + '\'' + + ", content='" + content + '\'' + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/loader/IProgressLoaderFactory.java b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/IProgressLoaderFactory.java new file mode 100644 index 00000000..0e5cd780 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/IProgressLoaderFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.loader; + +import android.content.Context; + +import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader; + +/** + * IProgressLoader的创建工厂实现接口 + * + * @author xuexiang + * @since 2019-11-18 23:17 + */ +public interface IProgressLoaderFactory { + + + /** + * 创建进度加载者 + * + * @param context + * @return + */ + IProgressLoader create(Context context); + + + /** + * 创建进度加载者 + * + * @param context + * @param message 默认提示 + * @return + */ + IProgressLoader create(Context context, String message); +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniLoadingDialogLoader.java b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniLoadingDialogLoader.java new file mode 100644 index 00000000..bb998aec --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniLoadingDialogLoader.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.loader; + +import android.content.Context; +import android.content.DialogInterface; + +import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader; +import com.xuexiang.xhttp2.subsciber.impl.OnProgressCancelListener; +import com.xuexiang.xui.widget.dialog.MiniLoadingDialog; + +/** + * 默认进度加载 + * + * @author xuexiang + * @since 2019-11-18 23:07 + */ +public class MiniLoadingDialogLoader implements IProgressLoader { + /** + * 进度loading弹窗 + */ + private MiniLoadingDialog mDialog; + /** + * 进度框取消监听 + */ + private OnProgressCancelListener mOnProgressCancelListener; + + public MiniLoadingDialogLoader(Context context) { + this(context, "请求中..."); + } + + public MiniLoadingDialogLoader(Context context, String msg) { + mDialog = new MiniLoadingDialog(context, msg); + } + + @Override + public boolean isLoading() { + return mDialog != null && mDialog.isShowing(); + } + + @Override + public void updateMessage(String msg) { + if (mDialog != null) { + mDialog.updateMessage(msg); + } + } + + @Override + public void showLoading() { + if (mDialog != null && !mDialog.isShowing()) { + mDialog.show(); + } + } + + @Override + public void dismissLoading() { + if (mDialog != null && mDialog.isShowing()) { + mDialog.dismiss(); + } + } + + @Override + public void setCancelable(boolean flag) { + mDialog.setCancelable(flag); + if (flag) { + mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialogInterface) { + if (mOnProgressCancelListener != null) { + mOnProgressCancelListener.onCancelProgress(); + } + } + }); + } + } + + @Override + public void setOnProgressCancelListener(OnProgressCancelListener listener) { + mOnProgressCancelListener = listener; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniProgressLoaderFactory.java b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniProgressLoaderFactory.java new file mode 100644 index 00000000..4694a5de --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/MiniProgressLoaderFactory.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.loader; + +import android.content.Context; + +import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader; + +/** + * 迷你加载框创建工厂 + * + * @author xuexiang + * @since 2019-11-18 23:23 + */ +public class MiniProgressLoaderFactory implements IProgressLoaderFactory { + + @Override + public IProgressLoader create(Context context) { + return new MiniLoadingDialogLoader(context); + } + + @Override + public IProgressLoader create(Context context, String message) { + return new MiniLoadingDialogLoader(context, message); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/loader/ProgressLoader.java b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/ProgressLoader.java new file mode 100644 index 00000000..da71eff6 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/loader/ProgressLoader.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.loader; + +import android.content.Context; + +import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader; + +/** + * 创建进度加载者 + * + * @author xuexiang + * @since 2019-07-02 12:51 + */ +public final class ProgressLoader { + + private ProgressLoader() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static IProgressLoaderFactory sIProgressLoaderFactory = new MiniProgressLoaderFactory(); + + public static void setIProgressLoaderFactory(IProgressLoaderFactory sIProgressLoaderFactory) { + ProgressLoader.sIProgressLoaderFactory = sIProgressLoaderFactory; + } + + /** + * 创建进度加载者 + * + * @param context + * @return + */ + public static IProgressLoader create(Context context) { + return sIProgressLoaderFactory.create(context); + } + + /** + * 创建进度加载者 + * + * @param context + * @param message 默认提示信息 + * @return + */ + public static IProgressLoader create(Context context, String message) { + return sIProgressLoaderFactory.create(context, message); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/NoTipRequestSubscriber.java b/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/NoTipRequestSubscriber.java new file mode 100644 index 00000000..114a4f78 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/NoTipRequestSubscriber.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.subscriber; + +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xhttp2.subsciber.BaseSubscriber; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * 不带错误toast提示的网络请求订阅,只存储错误的日志 + * + * @author xuexiang + * @since 2019-11-18 23:11 + */ +public abstract class NoTipRequestSubscriber extends BaseSubscriber { + + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public NoTipRequestSubscriber() { + + } + + public NoTipRequestSubscriber(XHttpRequest req) { + this(req.getUrl()); + } + + public NoTipRequestSubscriber(String url) { + mUrl = url; + } + + @Override + public void onError(ApiException e) { + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipProgressLoadingSubscriber.java b/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipProgressLoadingSubscriber.java new file mode 100644 index 00000000..ac05336b --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipProgressLoadingSubscriber.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.subscriber; + +import androidx.annotation.NonNull; + +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xhttp2.subsciber.ProgressLoadingSubscriber; +import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * 带错误toast提示和加载进度条的网络请求订阅 + * + * @author xuexiang + * @since 2019-11-18 23:11 + */ +public abstract class TipProgressLoadingSubscriber extends ProgressLoadingSubscriber { + + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public TipProgressLoadingSubscriber() { + super(); + } + + public TipProgressLoadingSubscriber(BaseFragment fragment) { + super(fragment.getProgressLoader()); + } + + public TipProgressLoadingSubscriber(IProgressLoader iProgressLoader) { + super(iProgressLoader); + } + + public TipProgressLoadingSubscriber(@NonNull XHttpRequest req) { + this(req.getUrl()); + } + + public TipProgressLoadingSubscriber(String url) { + super(); + mUrl = url; + } + + @Override + public void onError(ApiException e) { + super.onError(e); + XToastUtils.error(e); + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipRequestSubscriber.java b/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipRequestSubscriber.java new file mode 100644 index 00000000..050896d3 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/subscriber/TipRequestSubscriber.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.http.subscriber; + + +import androidx.annotation.NonNull; + +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xhttp2.subsciber.BaseSubscriber; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * 带错误toast提示的网络请求订阅 + * + * @author xuexiang + * @since 2019-11-18 23:10 + */ +public abstract class TipRequestSubscriber extends BaseSubscriber { + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public TipRequestSubscriber() { + + } + + public TipRequestSubscriber(@NonNull XHttpRequest req) { + this(req.getUrl()); + } + + public TipRequestSubscriber(String url) { + mUrl = url; + } + + + @Override + public void onError(ApiException e) { + XToastUtils.error(e); + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebActivity.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebActivity.java new file mode 100644 index 00000000..df21148a --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebActivity.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.KeyEvent; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentTransaction; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xrouter.facade.Postcard; +import com.xuexiang.xrouter.facade.callback.NavCallback; +import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xui.widget.slideback.SlideBack; + +/** + * 壳浏览器 + * + * @author xuexiang + * @since 2019/1/5 上午12:15 + */ +public class AgentWebActivity extends AppCompatActivity { + + /** + * 请求浏览器 + * + * @param url + */ + public static void goWeb(Context context, final String url) { + Intent intent = new Intent(context, AgentWebActivity.class); + intent.putExtra(AgentWebFragment.KEY_URL, url); + context.startActivity(intent); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_agent_web); + + SlideBack.with(this) + .haveScroll(true) + .callBack(this::finish) + .register(); + + Uri uri = getIntent().getData(); + if (uri != null) { + XRouter.getInstance().build(uri).navigation(this, new NavCallback() { + @Override + public void onArrival(Postcard postcard) { + finish(); + } + + @Override + public void onLost(Postcard postcard) { + loadUrl(uri.toString()); + } + }); + } else { + String url = getIntent().getStringExtra(AgentWebFragment.KEY_URL); + loadUrl(url); + } + } + + private void loadUrl(String url) { + if (url != null) { + openFragment(url); + } else { + XToastUtils.error("数据出错!"); + finish(); + } + } + + private AgentWebFragment mAgentWebFragment; + + private void openFragment(String url) { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.add(R.id.container_frame_layout, mAgentWebFragment = AgentWebFragment.getInstance(url)); + ft.commit(); + + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + AgentWebFragment agentWebFragment = mAgentWebFragment; + if (agentWebFragment != null) { + if (((FragmentKeyDown) agentWebFragment).onFragmentKeyDown(keyCode, event)) { + return true; + } else { + return super.onKeyDown(keyCode, event); + } + } + return super.onKeyDown(keyCode, event); + } + + + @Override + protected void onDestroy() { + SlideBack.unregister(this); + super.onDestroy(); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebFragment.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebFragment.java new file mode 100644 index 00000000..4459663a --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/AgentWebFragment.java @@ -0,0 +1,658 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebChromeClient; +import android.webkit.WebResourceError; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.appcompat.widget.PopupMenu; +import androidx.fragment.app.Fragment; + +import com.just.agentweb.action.PermissionInterceptor; +import com.just.agentweb.core.AgentWeb; +import com.just.agentweb.core.client.MiddlewareWebChromeBase; +import com.just.agentweb.core.client.MiddlewareWebClientBase; +import com.just.agentweb.core.client.WebListenerManager; +import com.just.agentweb.core.web.AbsAgentWebSettings; +import com.just.agentweb.core.web.AgentWebConfig; +import com.just.agentweb.core.web.IAgentWebSettings; +import com.just.agentweb.download.AgentWebDownloader; +import com.just.agentweb.download.DefaultDownloadImpl; +import com.just.agentweb.download.DownloadListenerAdapter; +import com.just.agentweb.download.DownloadingService; +import com.just.agentweb.utils.LogUtils; +import com.just.agentweb.widget.IWebLayout; +import com.kerwin.wumei.MyApp; +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xutil.net.JsonUtil; + +import java.util.HashMap; + +/** + * 通用WebView页面 + * + * @author xuexiang + * @since 2019/1/4 下午11:13 + */ +public class AgentWebFragment extends Fragment implements FragmentKeyDown { + public static final String KEY_URL = "com.xuexiang.xuidemo.base.webview.key_url"; + + private ImageView mBackImageView; + private View mLineView; + private ImageView mFinishImageView; + private TextView mTitleTextView; + private AgentWeb mAgentWeb; + private ImageView mMoreImageView; + private PopupMenu mPopupMenu; + public static final String TAG = AgentWebFragment.class.getSimpleName(); + private DownloadingService mDownloadingService; + + public static AgentWebFragment getInstance(String url) { + Bundle bundle = new Bundle(); + bundle.putString(KEY_URL, url); + return getInstance(bundle); + } + + public static AgentWebFragment getInstance(Bundle bundle) { + AgentWebFragment fragment = new AgentWebFragment(); + if (bundle != null) { + fragment.setArguments(bundle); + } + return fragment; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_agentweb, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mAgentWeb = AgentWeb.with(this) + //传入AgentWeb的父控件。 + .setAgentWebParent((LinearLayout) view, -1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)) + //设置进度条颜色与高度,-1为默认值,高度为2,单位为dp。 + .useDefaultIndicator(-1, 3) + //设置 IAgentWebSettings。 + .setAgentWebWebSettings(getSettings()) + //WebViewClient , 与 WebView 使用一致 ,但是请勿获取WebView调用setWebViewClient(xx)方法了,会覆盖AgentWeb DefaultWebClient,同时相应的中间件也会失效。 + .setWebViewClient(mWebViewClient) + //WebChromeClient + .setWebChromeClient(mWebChromeClient) + //设置WebChromeClient中间件,支持多个WebChromeClient,AgentWeb 3.0.0 加入。 + .useMiddlewareWebChrome(getMiddlewareWebChrome()) + //设置WebViewClient中间件,支持多个WebViewClient, AgentWeb 3.0.0 加入。 + .useMiddlewareWebClient(getMiddlewareWebClient()) + //权限拦截 2.0.0 加入。 + .setPermissionInterceptor(mPermissionInterceptor) + //严格模式 Android 4.2.2 以下会放弃注入对象 ,使用AgentWebView没影响。 + .setSecurityType(AgentWeb.SecurityType.STRICT_CHECK) + //自定义UI AgentWeb3.0.0 加入。 + .setAgentWebUIController(new UIController(getActivity())) + //参数1是错误显示的布局,参数2点击刷新控件ID -1表示点击整个布局都刷新, AgentWeb 3.0.0 加入。 + .setMainFrameErrorView(R.layout.agentweb_error_page, -1) + .setWebLayout(getWebLayout()) + .interceptUnkownUrl() + //创建AgentWeb。 + .createAgentWeb() + .ready()//设置 WebSettings。 + //WebView载入该url地址的页面并显示。 + .go(getUrl()); + + if (MyApp.isDebug()) { + AgentWebConfig.debug(); + } + + // 得到 AgentWeb 最底层的控件 + addBackgroundChild(mAgentWeb.getWebCreator().getWebParentLayout()); + + initView(view); + + // AgentWeb 没有把WebView的功能全面覆盖 ,所以某些设置 AgentWeb 没有提供,请从WebView方面入手设置。 + mAgentWeb.getWebCreator().getWebView().setOverScrollMode(WebView.OVER_SCROLL_NEVER); + } + + protected IWebLayout getWebLayout() { + return new WebLayout(getActivity()); + } + + protected void initView(View view) { + mBackImageView = view.findViewById(R.id.iv_back); + mLineView = view.findViewById(R.id.view_line); + mFinishImageView = view.findViewById(R.id.iv_finish); + mTitleTextView = view.findViewById(R.id.toolbar_title); + mBackImageView.setOnClickListener(mOnClickListener); + mFinishImageView.setOnClickListener(mOnClickListener); + mMoreImageView = view.findViewById(R.id.iv_more); + mMoreImageView.setOnClickListener(mOnClickListener); + pageNavigator(View.GONE); + } + + protected void addBackgroundChild(FrameLayout frameLayout) { + TextView textView = new TextView(frameLayout.getContext()); + textView.setText("技术由 AgentWeb 提供"); + textView.setTextSize(16); + textView.setTextColor(Color.parseColor("#727779")); + frameLayout.setBackgroundColor(Color.parseColor("#272b2d")); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2, -2); + params.gravity = Gravity.CENTER_HORIZONTAL; + final float scale = frameLayout.getContext().getResources().getDisplayMetrics().density; + params.topMargin = (int) (15 * scale + 0.5f); + frameLayout.addView(textView, 0, params); + } + + + private void pageNavigator(int tag) { + mBackImageView.setVisibility(tag); + mLineView.setVisibility(tag); + } + + private View.OnClickListener mOnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_back: + // true表示AgentWeb处理了该事件 + if (!mAgentWeb.back()) { + AgentWebFragment.this.getActivity().finish(); + } + break; + case R.id.iv_finish: + AgentWebFragment.this.getActivity().finish(); + break; + case R.id.iv_more: + showPoPup(v); + break; + default: + break; + + } + } + + }; + + //========================================// + + /** + * 权限申请拦截器 + */ + protected PermissionInterceptor mPermissionInterceptor = new PermissionInterceptor() { + /** + * PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。 + * @param url + * @param permissions + * @param action + * @return true 该Url对应页面请求权限进行拦截 ,false 表示不拦截。 + */ + @Override + public boolean intercept(String url, String[] permissions, String action) { + Log.i(TAG, "mUrl:" + url + " permission:" + JsonUtil.toJson(permissions) + " action:" + action); + return false; + } + }; + + //=====================下载============================// + + /** + * 更新于 AgentWeb 4.0.0,下载监听 + */ + protected DownloadListenerAdapter mDownloadListenerAdapter = new DownloadListenerAdapter() { + /** + * + * @param url 下载链接 + * @param userAgent UserAgent + * @param contentDisposition ContentDisposition + * @param mimetype 资源的媒体类型 + * @param contentLength 文件长度 + * @param extra 下载配置 , 用户可以通过 Extra 修改下载icon , 关闭进度条 , 是否强制下载。 + * @return true 表示用户处理了该下载事件 , false 交给 AgentWeb 下载 + */ + @Override + public boolean onStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength, AgentWebDownloader.Extra extra) { + LogUtils.i(TAG, "onStart:" + url); + // 是否开启断点续传 + extra.setOpenBreakPointDownload(true) + //下载通知的icon + .setIcon(R.drawable.ic_file_download_black_24dp) + // 连接的超时时间 + .setConnectTimeOut(6000) + // 以8KB位单位,默认60s ,如果60s内无法从网络流中读满8KB数据,则抛出异常 + .setBlockMaxTime(10 * 60 * 1000) + // 下载的超时时间 + .setDownloadTimeOut(Long.MAX_VALUE) + // 串行下载更节省资源哦 + .setParallelDownload(false) + // false 关闭进度通知 + .setEnableIndicator(true) + // 自定义请求头 + .addHeader("Cookie", "xx") + // 下载完成自动打开 + .setAutoOpen(true) + // 强制下载,不管网络网络类型 + .setForceDownload(true); + return false; + } + + /** + * + * 不需要暂停或者停止下载该方法可以不必实现 + * @param url + * @param downloadingService 用户可以通过 DownloadingService#shutdownNow 终止下载 + */ + @Override + public void onBindService(String url, DownloadingService downloadingService) { + super.onBindService(url, downloadingService); + mDownloadingService = downloadingService; + LogUtils.i(TAG, "onBindService:" + url + " DownloadingService:" + downloadingService); + } + + /** + * 回调onUnbindService方法,让用户释放掉 DownloadingService。 + * @param url + * @param downloadingService + */ + @Override + public void onUnbindService(String url, DownloadingService downloadingService) { + super.onUnbindService(url, downloadingService); + mDownloadingService = null; + LogUtils.i(TAG, "onUnbindService:" + url); + } + + /** + * + * @param url 下载链接 + * @param loaded 已经下载的长度 + * @param length 文件的总大小 + * @param usedTime 耗时 ,单位ms + * 注意该方法回调在子线程 ,线程名 AsyncTask #XX 或者 AgentWeb # XX + */ + @Override + public void onProgress(String url, long loaded, long length, long usedTime) { + int mProgress = (int) ((loaded) / Float.valueOf(length) * 100); + LogUtils.i(TAG, "onProgress:" + mProgress); + super.onProgress(url, loaded, length, usedTime); + } + + /** + * + * @param path 文件的绝对路径 + * @param url 下载地址 + * @param throwable 如果异常,返回给用户异常 + * @return true 表示用户处理了下载完成后续的事件 ,false 默认交给AgentWeb 处理 + */ + @Override + public boolean onResult(String path, String url, Throwable throwable) { + //下载成功 + if (null == throwable) { + //do you work + } else {//下载失败 + + } + // true 不会发出下载完成的通知 , 或者打开文件 + return false; + } + }; + + /** + * @return IAgentWebSettings + */ + public IAgentWebSettings getSettings() { + return new AbsAgentWebSettings() { + private AgentWeb mAgentWeb; + + @Override + protected void bindAgentWebSupport(AgentWeb agentWeb) { + this.mAgentWeb = agentWeb; + } + + /** + * AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库, + * 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 , + * 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter + * 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。 + * @param webView + * @param downloadListener + * @return WebListenerManager + */ + @Override + public WebListenerManager setDownloader(WebView webView, android.webkit.DownloadListener downloadListener) { + return super.setDownloader(webView, + DefaultDownloadImpl + .create(getActivity(), + webView, + mDownloadListenerAdapter, + mDownloadListenerAdapter, + this.mAgentWeb.getPermissionInterceptor())); + } + }; + } + + //===================WebChromeClient 和 WebViewClient===========================// + /** + * 页面空白,请检查scheme是否加上, scheme://host:port/path?query&query 。 + * + * @return mUrl + */ + public String getUrl() { + String target = ""; + Bundle bundle = getArguments(); + if (bundle != null) { + target = bundle.getString(KEY_URL); + } + + if (TextUtils.isEmpty(target)) { + target = "https://github.com/xuexiangjys"; + } + return target; + } + + protected WebChromeClient mWebChromeClient = new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + Log.i(TAG, "onProgressChanged:" + newProgress + " view:" + view); + } + + @Override + public void onReceivedTitle(WebView view, String title) { + super.onReceivedTitle(view, title); + if (mTitleTextView != null && !TextUtils.isEmpty(title)) { + if (title.length() > 10) { + title = title.substring(0, 10).concat("..."); + } + mTitleTextView.setText(title); + } + } + }; + + protected WebViewClient mWebViewClient = new WebViewClient() { + + private HashMap timer = new HashMap<>(); + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + super.onReceivedError(view, request, error); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + return shouldOverrideUrlLoading(view, request.getUrl() + ""); + } + + @Nullable + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + return super.shouldInterceptRequest(view, request); + } + + // + @Override + public boolean shouldOverrideUrlLoading(final WebView view, String url) { + //intent:// scheme的处理 如果返回false , 则交给 DefaultWebClient 处理 , 默认会打开该Activity , 如果Activity不存在则跳到应用市场上去. true 表示拦截 + //例如优酷视频播放 ,intent://play?...package=com.youku.phone;end; + //优酷想唤起自己应用播放该视频 , 下面拦截地址返回 true 则会在应用内 H5 播放 ,禁止优酷唤起播放该视频, 如果返回 false , DefaultWebClient 会根据intent 协议处理 该地址 , 首先匹配该应用存不存在 ,如果存在 , 唤起该应用播放 , 如果不存在 , 则跳到应用市场下载该应用 . + if (url.startsWith("intent://") && url.contains("com.youku.phone")) { + return true; + } + + return false; + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + Log.i(TAG, "mUrl:" + url + " onPageStarted target:" + getUrl()); + timer.put(url, System.currentTimeMillis()); + if (url.equals(getUrl())) { + pageNavigator(View.GONE); + } else { + pageNavigator(View.VISIBLE); + } + + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + if (timer.get(url) != null) { + long overTime = System.currentTimeMillis(); + Long startTime = timer.get(url); + Log.i(TAG, " page mUrl:" + url + " used time:" + (overTime - startTime)); + } + + } + + @Override + public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { + super.onReceivedHttpError(view, request, errorResponse); + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + super.onReceivedError(view, errorCode, description, failingUrl); + } + }; + + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + } + + + //========================菜单功能================================// + + /** + * 打开浏览器 + * + * @param targetUrl 外部浏览器打开的地址 + */ + private void openBrowser(String targetUrl) { + if (TextUtils.isEmpty(targetUrl) || targetUrl.startsWith("file://")) { + XToastUtils.toast(targetUrl + " 该链接无法使用浏览器打开。"); + return; + } + Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + Uri uri = Uri.parse(targetUrl); + intent.setData(uri); + startActivity(intent); + } + + + /** + * 显示更多菜单 + * + * @param view 菜单依附在该View下面 + */ + private void showPoPup(View view) { + if (mPopupMenu == null) { + mPopupMenu = new PopupMenu(getContext(), view); + mPopupMenu.inflate(R.menu.menu_toolbar_web); + mPopupMenu.setOnMenuItemClickListener(mOnMenuItemClickListener); + } + mPopupMenu.show(); + } + + /** + * 菜单事件 + */ + private PopupMenu.OnMenuItemClickListener mOnMenuItemClickListener = new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.refresh: + if (mAgentWeb != null) { + mAgentWeb.getUrlLoader().reload(); // 刷新 + } + return true; + + case R.id.copy: + if (mAgentWeb != null) { + toCopy(getContext(), mAgentWeb.getWebCreator().getWebView().getUrl()); + } + return true; + case R.id.default_browser: + if (mAgentWeb != null) { + openBrowser(mAgentWeb.getWebCreator().getWebView().getUrl()); + } + return true; + case R.id.share: + if (mAgentWeb != null) { + shareWebUrl(mAgentWeb.getWebCreator().getWebView().getUrl()); + } + return true; + default: + return false; + } + + } + }; + + /** + * 分享网页链接 + * + * @param url 网页链接 + */ + private void shareWebUrl(String url) { + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_TEXT, url); + shareIntent.setType("text/plain"); + //设置分享列表的标题,并且每次都显示分享列表 + startActivity(Intent.createChooser(shareIntent, "分享到")); + } + + + /** + * 复制字符串 + * + * @param context + * @param text + */ + private void toCopy(Context context, String text) { + ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + if (manager == null) { + return; + } + manager.setPrimaryClip(ClipData.newPlainText(null, text)); + } + + //===================生命周期管理===========================// + + @Override + public void onResume() { + mAgentWeb.getWebLifeCycle().onResume();//恢复 + super.onResume(); + } + + @Override + public void onPause() { + mAgentWeb.getWebLifeCycle().onPause(); //暂停应用内所有WebView , 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。 + super.onPause(); + } + + @Override + public boolean onFragmentKeyDown(int keyCode, KeyEvent event) { + return mAgentWeb.handleKeyEvent(keyCode, event); + } + + @Override + public void onDestroyView() { + mAgentWeb.getWebLifeCycle().onDestroy(); + super.onDestroyView(); + } + + //===================中间键===========================// + + + /** + * MiddlewareWebClientBase 是 AgentWeb 3.0.0 提供一个强大的功能, + * 如果用户需要使用 AgentWeb 提供的功能, 不想重写 WebClientView方 + * 法覆盖AgentWeb提供的功能,那么 MiddlewareWebClientBase 是一个 + * 不错的选择 。 + * + * @return + */ + protected MiddlewareWebClientBase getMiddlewareWebClient() { + return new MiddlewareWebViewClient() { + /** + * + * @param view + * @param url + * @return + */ + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + // 拦截 url,不执行 DefaultWebClient#shouldOverrideUrlLoading + if (url.startsWith("agentweb")) { + Log.i(TAG, "agentweb scheme ~"); + return true; + } + // 执行 DefaultWebClient#shouldOverrideUrlLoading + if (super.shouldOverrideUrlLoading(view, url)) { + return true; + } + // do you work + return false; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + return super.shouldOverrideUrlLoading(view, request); + } + }; + } + + protected MiddlewareWebChromeBase getMiddlewareWebChrome() { + return new MiddlewareChromeClient() { + }; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/BaseWebViewFragment.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/BaseWebViewFragment.java new file mode 100644 index 00000000..af3c0396 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/BaseWebViewFragment.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.view.KeyEvent; + +import com.just.agentweb.core.AgentWeb; +import com.kerwin.wumei.core.BaseFragment; + +/** + * 基础web + * + * @author xuexiang + * @since 2019/5/28 10:22 + */ +public abstract class BaseWebViewFragment extends BaseFragment { + + protected AgentWeb mAgentWeb; + + //===================生命周期管理===========================// + @Override + public void onResume() { + if (mAgentWeb != null) { + //恢复 + mAgentWeb.getWebLifeCycle().onResume(); + } + super.onResume(); + } + + @Override + public void onPause() { + if (mAgentWeb != null) { + //暂停应用内所有WebView , 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。 + mAgentWeb.getWebLifeCycle().onPause(); + } + super.onPause(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return mAgentWeb != null && mAgentWeb.handleKeyEvent(keyCode, event); + } + + @Override + public void onDestroyView() { + if (mAgentWeb != null) { + mAgentWeb.destroy(); + } + super.onDestroyView(); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/FragmentKeyDown.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/FragmentKeyDown.java new file mode 100644 index 00000000..7094fa6f --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/FragmentKeyDown.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.view.KeyEvent; + +/** + * + * + * @author xuexiang + * @since 2019/1/4 下午11:32 + */ +public interface FragmentKeyDown { + + /** + * fragment按键监听 + * @param keyCode + * @param event + * @return + */ + boolean onFragmentKeyDown(int keyCode, KeyEvent event); +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/LollipopFixedWebView.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/LollipopFixedWebView.java new file mode 100644 index 00000000..6f5ad0cb --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/LollipopFixedWebView.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Build; +import android.util.AttributeSet; +import android.webkit.WebView; + +/** + * 修复 Android 5.0 & 5.1 打开 WebView 闪退问题: + * 参阅 https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview + */ +@SuppressWarnings("unused") +public class LollipopFixedWebView extends WebView { + public LollipopFixedWebView(Context context) { + super(getFixedContext(context)); + } + + public LollipopFixedWebView(Context context, AttributeSet attrs) { + super(getFixedContext(context), attrs); + } + + public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) { + super(getFixedContext(context), attrs, defStyleAttr); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(getFixedContext(context), attrs, defStyleAttr, defStyleRes); + } + + public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) { + super(getFixedContext(context), attrs, defStyleAttr, privateBrowsing); + } + + public static Context getFixedContext(Context context) { + if (isLollipopWebViewBug()) { + // Avoid crashing on Android 5 and 6 (API level 21 to 23) + return context.createConfigurationContext(new Configuration()); + } + return context; + } + + public static boolean isLollipopWebViewBug() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT < Build.VERSION_CODES.M; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareChromeClient.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareChromeClient.java new file mode 100644 index 00000000..9babc825 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareChromeClient.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.util.Log; +import android.webkit.JsResult; +import android.webkit.WebView; + +import com.just.agentweb.core.client.MiddlewareWebChromeBase; + +/** + * WebChrome(WebChromeClient主要辅助WebView处理JavaScript的对话框、网站图片、网站title、加载进度等)中间件 + * 【浏览器】 + * @author xuexiang + * @since 2019/1/4 下午11:31 + */ +public class MiddlewareChromeClient extends MiddlewareWebChromeBase { + + public MiddlewareChromeClient() { + + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, JsResult result) { + Log.i("Info", "onJsAlert:" + url); + return super.onJsAlert(view, url, message, result); + } + + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + Log.i("Info", "onProgressChanged:"); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareWebViewClient.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareWebViewClient.java new file mode 100644 index 00000000..e4a46b61 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/MiddlewareWebViewClient.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.net.Uri; +import android.os.Build; +import android.util.Log; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebView; + +import androidx.annotation.RequiresApi; + +import com.just.agentweb.core.client.MiddlewareWebClientBase; +import com.kerwin.wumei.R; +import com.xuexiang.xui.utils.ResUtils; + +/** + * 【网络请求、加载】 + * WebClient(WebViewClient 这个类主要帮助WebView处理各种通知、url加载,请求时间的)中间件 + *

+ *

+ * 方法的执行顺序,例如下面用了7个中间件一个 WebViewClient + *

+ * .useMiddlewareWebClient(getMiddlewareWebClient()) // 1 + * .useMiddlewareWebClient(getMiddlewareWebClient()) // 2 + * .useMiddlewareWebClient(getMiddlewareWebClient()) // 3 + * .useMiddlewareWebClient(getMiddlewareWebClient()) // 4 + * .useMiddlewareWebClient(getMiddlewareWebClient()) // 5 + * .useMiddlewareWebClient(getMiddlewareWebClient()) // 6 + * .useMiddlewareWebClient(getMiddlewareWebClient()) // 7 + * DefaultWebClient // 8 + * .setWebViewClient(mWebViewClient) // 9 + *

+ *

+ * 典型的洋葱模型 + * 对象内部的方法执行顺序: 1->2->3->4->5->6->7->8->9->8->7->6->5->4->3->2->1 + *

+ *

+ * 中断中间件的执行, 删除super.methodName(...) 这行即可 + *

+ * 这里主要是做去广告的工作 + */ +public class MiddlewareWebViewClient extends MiddlewareWebClientBase { + + public MiddlewareWebViewClient() { + } + + private static int count = 1; + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + Log.i("Info", "MiddlewareWebViewClient -- > shouldOverrideUrlLoading:" + request.getUrl().toString() + " c:" + (count++)); + if (shouldOverrideUrlLoadingByApp(view, request.getUrl().toString())) { + return true; + } + return super.shouldOverrideUrlLoading(view, request); + + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Log.i("Info", "MiddlewareWebViewClient -- > shouldOverrideUrlLoading:" + url + " c:" + (count++)); + if (shouldOverrideUrlLoadingByApp(view, url)) { + return true; + } + return super.shouldOverrideUrlLoading(view, url); + } + + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, String url) { + url = url.toLowerCase(); + if (!hasAdUrl(url)) { + //正常加载 + return super.shouldInterceptRequest(view, url); + } else { + //含有广告资源屏蔽请求 + return new WebResourceResponse(null, null, null); + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + String url = request.getUrl().toString().toLowerCase(); + if (!hasAdUrl(url)) { + //正常加载 + return super.shouldInterceptRequest(view, request); + } else { + //含有广告资源屏蔽请求 + return new WebResourceResponse(null, null, null); + } + } + + /** + * 判断是否存在广告的链接 + * + * @param url + * @return + */ + private static boolean hasAdUrl(String url) { + String[] adUrls = ResUtils.getStringArray(R.array.adBlockUrl); + for (String adUrl : adUrls) { + if (url.contains(adUrl)) { + return true; + } + } + return false; + } + + + /** + * 根据url的scheme处理跳转第三方app的业务,true代表拦截,false代表不拦截 + */ + private boolean shouldOverrideUrlLoadingByApp(WebView webView, final String url) { + if (url.startsWith("http") || url.startsWith("https") || url.startsWith("ftp")) { + //不拦截http, https, ftp的请求 + Uri uri = Uri.parse(url); + if (uri != null && !(WebViewInterceptDialog.APP_LINK_HOST.equals(uri.getHost()) + //防止xui官网被拦截 + && url.contains("xpage"))) { + return false; + } + } + + WebViewInterceptDialog.show(url); + return true; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/UIController.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/UIController.java new file mode 100644 index 00000000..b5650e1e --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/UIController.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.app.Activity; +import android.os.Handler; +import android.util.Log; +import android.webkit.WebView; + +import com.just.agentweb.core.web.AgentWebUIControllerImplBase; + +import java.lang.ref.WeakReference; + +/** + * 如果你需要修改某一个AgentWeb 内部的某一个弹窗 ,请看下面的例子 + * 注意写法一定要参照 DefaultUIController 的写法 ,因为UI自由定制,但是回调的方式是固定的,并且一定要回调。 + * + * @author xuexiang + * @since 2019-10-30 23:18 + */ +public class UIController extends AgentWebUIControllerImplBase { + + private WeakReference mActivity; + + public UIController(Activity activity) { + mActivity = new WeakReference<>(activity); + } + + @Override + public void onShowMessage(String message, String from) { + super.onShowMessage(message, from); + Log.i(TAG, "message:" + message); + } + + @Override + public void onSelectItemsPrompt(WebView view, String url, String[] items, Handler.Callback callback) { + // 使用默认的UI + super.onSelectItemsPrompt(view, url, items, callback); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/WebLayout.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/WebLayout.java new file mode 100644 index 00000000..341683e3 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/WebLayout.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.app.Activity; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.webkit.WebView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.just.agentweb.widget.IWebLayout; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.kerwin.wumei.R; + +/** + * 定义支持下来回弹的WebView + * + * @author xuexiang + * @since 2019/1/5 上午2:01 + */ +public class WebLayout implements IWebLayout { + + private final SmartRefreshLayout mSmartRefreshLayout; + private WebView mWebView; + + public WebLayout(Activity activity) { + mSmartRefreshLayout = (SmartRefreshLayout) LayoutInflater.from(activity).inflate(R.layout.fragment_pulldown_web, null); + mWebView = mSmartRefreshLayout.findViewById(R.id.webView); + } + + @NonNull + @Override + public ViewGroup getLayout() { + return mSmartRefreshLayout; + } + + @Nullable + @Override + public WebView getWebView() { + return mWebView; + } + + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/WebViewInterceptDialog.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/WebViewInterceptDialog.java new file mode 100644 index 00000000..406e1753 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/WebViewInterceptDialog.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xui.utils.ResUtils; +import com.xuexiang.xui.widget.dialog.DialogLoader; +import com.xuexiang.xutil.XUtil; +import com.xuexiang.xutil.app.ActivityUtils; + +import java.net.URISyntaxException; + +/** + * WebView拦截提示 + * + * @author xuexiang + * @since 2019-10-21 9:51 + */ +public class WebViewInterceptDialog extends AppCompatActivity implements DialogInterface.OnDismissListener { + + private static final String KEY_INTERCEPT_URL = "key_intercept_url"; + + // TODO: 2019-10-30 这里修改你的applink + public static final String APP_LINK_HOST = "xuexiangjys.club"; + public static final String APP_LINK_ACTION = "com.xuexiang.xui.applink"; + + + /** + * 显示WebView拦截提示 + * + * @param url 需要拦截处理的url + */ + public static void show(String url) { + ActivityUtils.startActivity(WebViewInterceptDialog.class, KEY_INTERCEPT_URL, url); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + String url = getIntent().getStringExtra(KEY_INTERCEPT_URL); + + DialogLoader.getInstance().showConfirmDialog( + this, + getOpenTitle(url), + ResUtils.getString(R.string.lab_yes), + (dialog, which) -> { + dialog.dismiss(); + if (isAppLink(url)) { + openAppLink(this, url); + } else { + openApp(url); + } + }, + ResUtils.getString(R.string.lab_no), + (dialog, which) -> dialog.dismiss() + ).setOnDismissListener(this); + + } + + private String getOpenTitle(String url) { + String scheme = getScheme(url); + if ("mqqopensdkapi".equals(scheme)) { + return "是否允许页面打开\"QQ\"?"; + } else { + return ResUtils.getString(R.string.lab_open_third_app); + } + } + + private String getScheme(String url) { + try { + Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); + return intent.getScheme(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return ""; + } + + private boolean isAppLink(String url) { + Uri uri = Uri.parse(url); + return uri != null + && APP_LINK_HOST.equals(uri.getHost()) + && (url.startsWith("http") || url.startsWith("https")); + } + + + private void openApp(String url) { + Intent intent; + try { + intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); + XUtil.getContext().startActivity(intent); + } catch (Exception e) { + XToastUtils.error("您所打开的第三方App未安装!"); + } + } + + private void openAppLink(Context context, String url) { + try { + Intent intent = new Intent(APP_LINK_ACTION); + intent.setData(Uri.parse(url)); + context.startActivity(intent); + } catch (Exception e) { + XToastUtils.error("您所打开的第三方App未安装!"); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + finish(); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/core/webview/XPageWebViewFragment.java b/android/app/src/main/java/com/kerwin/wumei/core/webview/XPageWebViewFragment.java new file mode 100644 index 00000000..8e77e67a --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/core/webview/XPageWebViewFragment.java @@ -0,0 +1,677 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.core.webview; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebChromeClient; +import android.webkit.WebResourceError; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.PopupMenu; +import androidx.fragment.app.Fragment; + +import com.just.agentweb.action.PermissionInterceptor; +import com.just.agentweb.core.AgentWeb; +import com.just.agentweb.core.client.DefaultWebClient; +import com.just.agentweb.core.client.MiddlewareWebChromeBase; +import com.just.agentweb.core.client.MiddlewareWebClientBase; +import com.just.agentweb.core.client.WebListenerManager; +import com.just.agentweb.core.web.AbsAgentWebSettings; +import com.just.agentweb.core.web.AgentWebConfig; +import com.just.agentweb.core.web.IAgentWebSettings; +import com.just.agentweb.download.AgentWebDownloader; +import com.just.agentweb.download.DefaultDownloadImpl; +import com.just.agentweb.download.DownloadListenerAdapter; +import com.just.agentweb.download.DownloadingService; +import com.just.agentweb.widget.IWebLayout; +import com.kerwin.wumei.MyApp; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.base.XPageActivity; +import com.xuexiang.xpage.base.XPageFragment; +import com.xuexiang.xpage.core.PageOption; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xutil.common.logger.Logger; +import com.xuexiang.xutil.net.JsonUtil; + +import java.util.HashMap; + +import butterknife.BindView; +import butterknife.OnClick; + +/** + * 使用XPageFragment + * + * @author xuexiang + * @since 2019-05-26 18:15 + */ +@Page(params = {AgentWebFragment.KEY_URL}) +public class XPageWebViewFragment extends BaseFragment { + + @BindView(R.id.iv_back) + AppCompatImageView mIvBack; + @BindView(R.id.view_line) + View mLineView; + @BindView(R.id.toolbar_title) + TextView mTvTitle; + + protected AgentWeb mAgentWeb; + private PopupMenu mPopupMenu; + + private DownloadingService mDownloadingService; + + /** + * 打开网页 + * + * @param xPageActivity + * @param url + * @return + */ + public static Fragment openUrl(XPageActivity xPageActivity, String url) { + return PageOption.to(XPageWebViewFragment.class) + .putString(AgentWebFragment.KEY_URL, url) + .open(xPageActivity); + } + + /** + * 打开网页 + * + * @param fragment + * @param url + * @return + */ + public static Fragment openUrl(XPageFragment fragment, String url) { + return PageOption.to(XPageWebViewFragment.class) + .setNewActivity(true) + .putString(AgentWebFragment.KEY_URL, url) + .open(fragment); + } + + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_agentweb; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + mAgentWeb = AgentWeb.with(this) + //传入AgentWeb的父控件。 + .setAgentWebParent((LinearLayout) getRootView(), -1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)) + //设置进度条颜色与高度,-1为默认值,高度为2,单位为dp。 + .useDefaultIndicator(-1, 3) + //设置 IAgentWebSettings。 + .setAgentWebWebSettings(getSettings()) + //WebViewClient , 与 WebView 使用一致 ,但是请勿获取WebView调用setWebViewClient(xx)方法了,会覆盖AgentWeb DefaultWebClient,同时相应的中间件也会失效。 + .setWebViewClient(mWebViewClient) + //WebChromeClient + .setWebChromeClient(mWebChromeClient) + //设置WebChromeClient中间件,支持多个WebChromeClient,AgentWeb 3.0.0 加入。 + .useMiddlewareWebChrome(getMiddlewareWebChrome()) + //设置WebViewClient中间件,支持多个WebViewClient, AgentWeb 3.0.0 加入。 + .useMiddlewareWebClient(getMiddlewareWebClient()) + //权限拦截 2.0.0 加入。 + .setPermissionInterceptor(mPermissionInterceptor) + //严格模式 Android 4.2.2 以下会放弃注入对象 ,使用AgentWebView没影响。 + .setSecurityType(AgentWeb.SecurityType.STRICT_CHECK) + //自定义UI AgentWeb3.0.0 加入。 + .setAgentWebUIController(new UIController(getActivity())) + //参数1是错误显示的布局,参数2点击刷新控件ID -1表示点击整个布局都刷新, AgentWeb 3.0.0 加入。 + .setMainFrameErrorView(R.layout.agentweb_error_page, -1) + .setWebLayout(getWebLayout()) + //打开其他页面时,弹窗质询用户前往其他应用 AgentWeb 3.0.0 加入。 + .setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.DISALLOW) + //拦截找不到相关页面的Url AgentWeb 3.0.0 加入。 + .interceptUnkownUrl() + //创建AgentWeb。 + .createAgentWeb() + .ready()//设置 WebSettings。 + //WebView载入该url地址的页面并显示。 + .go(getUrl()); + + if (MyApp.isDebug()) { + AgentWebConfig.debug(); + } + + pageNavigator(View.GONE); + // 得到 AgentWeb 最底层的控件 + addBackgroundChild(mAgentWeb.getWebCreator().getWebParentLayout()); + + // AgentWeb 没有把WebView的功能全面覆盖 ,所以某些设置 AgentWeb 没有提供,请从WebView方面入手设置。 + mAgentWeb.getWebCreator().getWebView().setOverScrollMode(WebView.OVER_SCROLL_NEVER); + } + + protected IWebLayout getWebLayout() { + return new WebLayout(getActivity()); + } + + protected void addBackgroundChild(FrameLayout frameLayout) { + TextView textView = new TextView(frameLayout.getContext()); + textView.setText("技术由 AgentWeb 提供"); + textView.setTextSize(16); + textView.setTextColor(Color.parseColor("#727779")); + frameLayout.setBackgroundColor(Color.parseColor("#272b2d")); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2, -2); + params.gravity = Gravity.CENTER_HORIZONTAL; + final float scale = frameLayout.getContext().getResources().getDisplayMetrics().density; + params.topMargin = (int) (15 * scale + 0.5f); + frameLayout.addView(textView, 0, params); + } + + + private void pageNavigator(int tag) { + //返回的导航按钮 + mIvBack.setVisibility(tag); + mLineView.setVisibility(tag); + } + + @SingleClick + @OnClick({R.id.iv_back, R.id.iv_finish, R.id.iv_more}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.iv_back: + // true表示AgentWeb处理了该事件 + if (!mAgentWeb.back()) { + popToBack(); + } + break; + case R.id.iv_finish: + popToBack(); + break; + case R.id.iv_more: + showPoPup(view); + break; + default: + break; + } + } + + //=====================下载============================// + + /** + * 更新于 AgentWeb 4.0.0,下载监听 + */ + protected DownloadListenerAdapter mDownloadListenerAdapter = new DownloadListenerAdapter() { + /** + * + * @param url 下载链接 + * @param userAgent UserAgent + * @param contentDisposition ContentDisposition + * @param mimeType 资源的媒体类型 + * @param contentLength 文件长度 + * @param extra 下载配置 , 用户可以通过 Extra 修改下载icon , 关闭进度条 , 是否强制下载。 + * @return true 表示用户处理了该下载事件 , false 交给 AgentWeb 下载 + */ + @Override + public boolean onStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength, AgentWebDownloader.Extra extra) { + Logger.i("onStart:" + url); + // 是否开启断点续传 + extra.setOpenBreakPointDownload(true) + //下载通知的icon + .setIcon(R.drawable.ic_file_download_black_24dp) + // 连接的超时时间 + .setConnectTimeOut(6000) + // 以8KB位单位,默认60s ,如果60s内无法从网络流中读满8KB数据,则抛出异常 + .setBlockMaxTime(10 * 60 * 1000) + // 下载的超时时间 + .setDownloadTimeOut(Long.MAX_VALUE) + // 串行下载更节省资源哦 + .setParallelDownload(false) + // false 关闭进度通知 + .setEnableIndicator(true) + // 自定义请求头 + .addHeader("Cookie", "xx") + // 下载完成自动打开 + .setAutoOpen(true) + // 强制下载,不管网络网络类型 + .setForceDownload(true); + return false; + } + + /** + * + * 不需要暂停或者停止下载该方法可以不必实现 + * @param url + * @param downloadingService 用户可以通过 DownloadingService#shutdownNow 终止下载 + */ + @Override + public void onBindService(String url, DownloadingService downloadingService) { + super.onBindService(url, downloadingService); + mDownloadingService = downloadingService; + Logger.i("onBindService:" + url + " DownloadingService:" + downloadingService); + } + + /** + * 回调onUnbindService方法,让用户释放掉 DownloadingService。 + * @param url + * @param downloadingService + */ + @Override + public void onUnbindService(String url, DownloadingService downloadingService) { + super.onUnbindService(url, downloadingService); + mDownloadingService = null; + Logger.i("onUnbindService:" + url); + } + + /** + * + * @param url 下载链接 + * @param loaded 已经下载的长度 + * @param length 文件的总大小 + * @param usedTime 耗时 ,单位ms + * 注意该方法回调在子线程 ,线程名 AsyncTask #XX 或者 AgentWeb # XX + */ + @Override + public void onProgress(String url, long loaded, long length, long usedTime) { + int mProgress = (int) ((loaded) / (float) length * 100); + Logger.i("onProgress:" + mProgress); + super.onProgress(url, loaded, length, usedTime); + } + + /** + * + * @param path 文件的绝对路径 + * @param url 下载地址 + * @param throwable 如果异常,返回给用户异常 + * @return true 表示用户处理了下载完成后续的事件 ,false 默认交给AgentWeb 处理 + */ + @Override + public boolean onResult(String path, String url, Throwable throwable) { + //下载成功 + if (null == throwable) { + //do you work + } else {//下载失败 + + } + // true 不会发出下载完成的通知 , 或者打开文件 + return false; + } + }; + + /** + * 下载服务设置 + * + * @return IAgentWebSettings + */ + public IAgentWebSettings getSettings() { + return new AbsAgentWebSettings() { + private AgentWeb mAgentWeb; + + @Override + protected void bindAgentWebSupport(AgentWeb agentWeb) { + this.mAgentWeb = agentWeb; + } + + /** + * AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库, + * 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 , + * 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter + * 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。 + * @param webView + * @param downloadListener + * @return WebListenerManager + */ + @Override + public WebListenerManager setDownloader(WebView webView, android.webkit.DownloadListener downloadListener) { + return super.setDownloader(webView, + DefaultDownloadImpl + .create(getActivity(), + webView, + mDownloadListenerAdapter, + mDownloadListenerAdapter, + mAgentWeb.getPermissionInterceptor())); + } + }; + } + + //===================WebChromeClient 和 WebViewClient===========================// + + /** + * 页面空白,请检查scheme是否加上, scheme://host:port/path?query&query 。 + * + * @return mUrl + */ + public String getUrl() { + String target = ""; + Bundle bundle = getArguments(); + if (bundle != null) { + target = bundle.getString(AgentWebFragment.KEY_URL); + } + + if (TextUtils.isEmpty(target)) { + target = "https://github.com/xuexiangjys"; + } + return target; + } + + /** + * 和浏览器相关,包括和JS的交互 + */ + protected WebChromeClient mWebChromeClient = new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + //网页加载进度 + } + @Override + public void onReceivedTitle(WebView view, String title) { + super.onReceivedTitle(view, title); + if (mTvTitle != null && !TextUtils.isEmpty(title)) { + if (title.length() > 10) { + title = title.substring(0, 10).concat("..."); + } + mTvTitle.setText(title); + } + } + }; + + /** + * 和网页url加载相关,统计加载时间 + */ + protected WebViewClient mWebViewClient = new WebViewClient() { + private HashMap mTimer = new HashMap<>(); + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + super.onReceivedError(view, request, error); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + return shouldOverrideUrlLoading(view, request.getUrl() + ""); + } + + @Nullable + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + return super.shouldInterceptRequest(view, request); + } + @Override + public boolean shouldOverrideUrlLoading(final WebView view, String url) { + //intent:// scheme的处理 如果返回false , 则交给 DefaultWebClient 处理 , 默认会打开该Activity , 如果Activity不存在则跳到应用市场上去. true 表示拦截 + //例如优酷视频播放 ,intent://play?...package=com.youku.phone;end; + //优酷想唤起自己应用播放该视频 , 下面拦截地址返回 true 则会在应用内 H5 播放 ,禁止优酷唤起播放该视频, 如果返回 false , DefaultWebClient 会根据intent 协议处理 该地址 , 首先匹配该应用存不存在 ,如果存在 , 唤起该应用播放 , 如果不存在 , 则跳到应用市场下载该应用 . + if (url.startsWith("intent://") && url.contains("com.youku.phone")) { + return true; + } + return false; + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + mTimer.put(url, System.currentTimeMillis()); + if (url.equals(getUrl())) { + pageNavigator(View.GONE); + } else { + pageNavigator(View.VISIBLE); + } + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + if (mTimer.get(url) != null) { + long overTime = System.currentTimeMillis(); + Long startTime = mTimer.get(url); + //统计页面的使用时长 + Logger.i(" page mUrl:" + url + " used time:" + (overTime - startTime)); + } + } + + @Override + public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { + super.onReceivedHttpError(view, request, errorResponse); + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + super.onReceivedError(view, errorCode, description, failingUrl); + } + }; + + //=====================菜单========================// + + /** + * 显示更多菜单 + * + * @param view 菜单依附在该View下面 + */ + private void showPoPup(View view) { + if (mPopupMenu == null) { + mPopupMenu = new PopupMenu(getContext(), view); + mPopupMenu.inflate(R.menu.menu_toolbar_web); + mPopupMenu.setOnMenuItemClickListener(mOnMenuItemClickListener); + } + mPopupMenu.show(); + } + + /** + * 菜单事件 + */ + private PopupMenu.OnMenuItemClickListener mOnMenuItemClickListener = new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.refresh: + if (mAgentWeb != null) { + mAgentWeb.getUrlLoader().reload(); // 刷新 + } + return true; + case R.id.copy: + if (mAgentWeb != null) { + toCopy(getContext(), mAgentWeb.getWebCreator().getWebView().getUrl()); + } + return true; + case R.id.default_browser: + if (mAgentWeb != null) { + openBrowser(mAgentWeb.getWebCreator().getWebView().getUrl()); + } + return true; + case R.id.share: + if (mAgentWeb != null) { + shareWebUrl(mAgentWeb.getWebCreator().getWebView().getUrl()); + } + return true; + default: + return false; + } + + } + }; + + /** + * 打开浏览器 + * + * @param targetUrl 外部浏览器打开的地址 + */ + private void openBrowser(String targetUrl) { + if (TextUtils.isEmpty(targetUrl) || targetUrl.startsWith("file://")) { + XToastUtils.toast(targetUrl + " 该链接无法使用浏览器打开。"); + return; + } + Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + Uri uri = Uri.parse(targetUrl); + intent.setData(uri); + startActivity(intent); + } + + /** + * 分享网页链接 + * + * @param url 网页链接 + */ + private void shareWebUrl(String url) { + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_TEXT, url); + shareIntent.setType("text/plain"); + //设置分享列表的标题,并且每次都显示分享列表 + startActivity(Intent.createChooser(shareIntent, "分享到")); + } + + /** + * 复制字符串 + * + * @param context + * @param text + */ + private void toCopy(Context context, String text) { + ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + if (manager == null) { + return; + } + manager.setPrimaryClip(ClipData.newPlainText(null, text)); + } + + //===================生命周期管理===========================// + + @Override + public void onResume() { + if (mAgentWeb != null) { + mAgentWeb.getWebLifeCycle().onResume();//恢复 + } + super.onResume(); + } + + @Override + public void onPause() { + if (mAgentWeb != null) { + mAgentWeb.getWebLifeCycle().onPause(); //暂停应用内所有WebView , 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。 + } + super.onPause(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return mAgentWeb != null && mAgentWeb.handleKeyEvent(keyCode, event); + } + + @Override + public void onDestroyView() { + if (mAgentWeb != null) { + mAgentWeb.destroy(); + } + super.onDestroyView(); + } + + + //===================中间键===========================// + + + /** + * MiddlewareWebClientBase 是 AgentWeb 3.0.0 提供一个强大的功能, + * 如果用户需要使用 AgentWeb 提供的功能, 不想重写 WebClientView方 + * 法覆盖AgentWeb提供的功能,那么 MiddlewareWebClientBase 是一个 + * 不错的选择 。 + * + * @return + */ + protected MiddlewareWebClientBase getMiddlewareWebClient() { + return new MiddlewareWebViewClient() { + /** + * + * @param view + * @param url + * @return + */ + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + // 拦截 url,不执行 DefaultWebClient#shouldOverrideUrlLoading + if (url.startsWith("agentweb")) { + return true; + } + // 执行 DefaultWebClient#shouldOverrideUrlLoading + if (super.shouldOverrideUrlLoading(view, url)) { + return true; + } + // do you work + return false; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + return super.shouldOverrideUrlLoading(view, request); + } + }; + } + + protected MiddlewareWebChromeBase getMiddlewareWebChrome() { + return new MiddlewareChromeClient() { + }; + } + + /** + * 权限申请拦截器 + */ + protected PermissionInterceptor mPermissionInterceptor = new PermissionInterceptor() { + /** + * PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。 + * @param url + * @param permissions + * @param action + * @return true 该Url对应页面请求权限进行拦截 ,false 表示不拦截。 + */ + @Override + public boolean intercept(String url, String[] permissions, String action) { + Logger.i("mUrl:" + url + " permission:" + JsonUtil.toJson(permissions) + " action:" + action); + return false; + } + }; + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java new file mode 100644 index 00000000..0ea94321 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.fragment; + +import android.widget.TextView; + +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.core.webview.AgentWebActivity; +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.widget.grouplist.XUIGroupListView; +import com.xuexiang.xutil.app.AppUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import butterknife.BindView; + + +@Page(name = "关于") +public class AboutFragment extends BaseFragment { + + @BindView(R.id.tv_version) + TextView mVersionTextView; + @BindView(R.id.about_list) + XUIGroupListView mAboutGroupListView; + @BindView(R.id.tv_copyright) + TextView mCopyrightTextView; + + @Override + protected int getLayoutId() { + return R.layout.fragment_about; + } + + @Override + protected void initViews() { + mVersionTextView.setText(String.format("版本号:%s", AppUtils.getAppVersionName())); + + XUIGroupListView.newSection(getContext()) + .addItemView(mAboutGroupListView.createItemView(getResources().getString(R.string.about_item_homepage)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_project_github))) + .addItemView(mAboutGroupListView.createItemView(getResources().getString(R.string.about_item_author_github)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_author_github))) + .addItemView(mAboutGroupListView.createItemView("版本"), v -> XToastUtils.toast("版本升级")) + .addTo(mAboutGroupListView); + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy", Locale.CHINA); + String currentYear = dateFormat.format(new Date()); + mCopyrightTextView.setText(String.format(getResources().getString(R.string.about_copyright), currentYear)); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java new file mode 100644 index 00000000..fec81e94 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java @@ -0,0 +1,30 @@ +package com.kerwin.wumei.fragment; + +import android.widget.TextView; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.core.webview.AgentWebActivity; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.widget.grouplist.XUIGroupListView; +import com.xuexiang.xutil.app.AppUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import butterknife.BindView; + +@Page(name = "意见反馈") +public class FeedbackFragment extends BaseFragment { + + @Override + protected int getLayoutId() { + return R.layout.fragment_feedback; + } + + @Override + protected void initViews() { + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java new file mode 100644 index 00000000..683c09f9 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.fragment; + +import android.graphics.Color; +import android.view.View; + +import com.kerwin.wumei.activity.MainActivity; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.RandomUtils; +import com.kerwin.wumei.utils.SettingUtils; +import com.kerwin.wumei.utils.TokenUtils; +import com.kerwin.wumei.utils.Utils; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.utils.CountDownButtonHelper; +import com.xuexiang.xui.utils.ResUtils; +import com.xuexiang.xui.utils.ThemeUtils; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.button.roundbutton.RoundButton; +import com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText; +import com.xuexiang.xutil.app.ActivityUtils; + +import butterknife.BindView; +import butterknife.OnClick; + + +/** + * 登录页面 + * + * @author xuexiang + * @since 2019-11-17 22:15 + */ +@Page(anim = CoreAnim.none) +public class LoginFragment extends BaseFragment { + + @BindView(R.id.et_phone_number) + MaterialEditText etPhoneNumber; + @BindView(R.id.et_verify_code) + MaterialEditText etVerifyCode; + @BindView(R.id.btn_get_verify_code) + RoundButton btnGetVerifyCode; + + private CountDownButtonHelper mCountDownHelper; + + @Override + protected int getLayoutId() { + return R.layout.fragment_login; + } + + @Override + protected TitleBar initTitle() { + TitleBar titleBar = super.initTitle() + .setImmersive(true); + titleBar.setBackgroundColor(Color.TRANSPARENT); + titleBar.setTitle(""); + titleBar.setLeftImageDrawable(ResUtils.getVectorDrawable(getContext(), R.drawable.ic_login_close)); + titleBar.setActionTextColor(ThemeUtils.resolveColor(getContext(), R.attr.colorAccent)); + titleBar.addAction(new TitleBar.TextAction(R.string.title_jump_login) { + @Override + public void performAction(View view) { + onLoginSuccess(); + } + }); + return titleBar; + } + + @Override + protected void initViews() { + mCountDownHelper = new CountDownButtonHelper(btnGetVerifyCode, 60); + + //隐私政策弹窗 + if (!SettingUtils.isAgreePrivacy()) { + Utils.showPrivacyDialog(getContext(), (dialog, which) -> { + dialog.dismiss(); + SettingUtils.setIsAgreePrivacy(true); + }); + } + } + + @SingleClick + @OnClick({R.id.btn_get_verify_code, R.id.btn_login, R.id.tv_other_login, R.id.tv_forget_password, R.id.tv_user_protocol, R.id.tv_privacy_protocol}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.btn_get_verify_code: + if (etPhoneNumber.validate()) { + getVerifyCode(etPhoneNumber.getEditValue()); + } + break; + case R.id.btn_login: + if (etPhoneNumber.validate()) { + if (etVerifyCode.validate()) { + loginByVerifyCode(etPhoneNumber.getEditValue(), etVerifyCode.getEditValue()); + } + } + break; + case R.id.tv_other_login: + XToastUtils.info("其他登录方式"); + break; + case R.id.tv_forget_password: + XToastUtils.info("忘记密码"); + break; + case R.id.tv_user_protocol: + XToastUtils.info("用户协议"); + break; + case R.id.tv_privacy_protocol: + XToastUtils.info("隐私政策"); + break; + default: + break; + } + } + + /** + * 获取验证码 + */ + private void getVerifyCode(String phoneNumber) { + // TODO: 2020/8/29 这里只是界面演示而已 + XToastUtils.warning("只是演示,验证码请随便输"); + mCountDownHelper.start(); + } + + /** + * 根据验证码登录 + * + * @param phoneNumber 手机号 + * @param verifyCode 验证码 + */ + private void loginByVerifyCode(String phoneNumber, String verifyCode) { + // TODO: 2020/8/29 这里只是界面演示而已 + onLoginSuccess(); + } + + /** + * 登录成功的处理 + */ + private void onLoginSuccess() { + String token = RandomUtils.getRandomNumbersAndLetters(16); + if (TokenUtils.handleLoginSuccess(token)) { + popToBack(); + ActivityUtils.startActivity(MainActivity.class); + } + } + + @Override + public void onDestroyView() { + if (mCountDownHelper != null) { + mCountDownHelper.recycle(); + } + super.onDestroyView(); + } +} + diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java new file mode 100644 index 00000000..d5fecd09 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java @@ -0,0 +1,54 @@ +package com.kerwin.wumei.fragment; + +import android.view.View; +import android.widget.TextView; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.core.webview.AgentWebActivity; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.grouplist.XUIGroupListView; +import com.xuexiang.xutil.app.AppUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import butterknife.BindView; + + +@Page(name = "消息") +public class MessageFragment extends BaseFragment { + + @Override + protected int getLayoutId() { + return R.layout.fragment_message; + } + + @Override + protected TitleBar initTitle() { + com.xuexiang.xui.widget.actionbar.TitleBar titleBar = super.initTitle(); + titleBar.setCenterClickListener(new View.OnClickListener() { + @SingleClick + @Override + public void onClick(View view) { + + } + }); + titleBar.addAction(new com.xuexiang.xui.widget.actionbar.TitleBar.TextAction("菜单") { + @SingleClick + @Override + public void performAction(View view) { + + } + }); + return titleBar; + } + + @Override + protected void initViews() { + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java new file mode 100644 index 00000000..0e3ccd6c --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.fragment; + +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.TokenUtils; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.widget.dialog.DialogLoader; +import com.xuexiang.xui.widget.textview.supertextview.SuperTextView; +import com.xuexiang.xutil.XUtil; + +import butterknife.BindView; + +/** + * @author xuexiang + * @since 2019-10-15 22:38 + */ +@Page(name = "设置") +public class SettingsFragment extends BaseFragment implements SuperTextView.OnSuperTextViewClickListener { + + @BindView(R.id.menu_common) + SuperTextView menuCommon; + @BindView(R.id.menu_privacy) + SuperTextView menuPrivacy; + @BindView(R.id.menu_push) + SuperTextView menuPush; + @BindView(R.id.menu_helper) + SuperTextView menuHelper; + @BindView(R.id.menu_change_account) + SuperTextView menuChangeAccount; + @BindView(R.id.menu_logout) + SuperTextView menuLogout; + + @Override + protected int getLayoutId() { + return R.layout.fragment_settings; + } + + @Override + protected void initViews() { + menuCommon.setOnSuperTextViewClickListener(this); + menuPrivacy.setOnSuperTextViewClickListener(this); + menuPush.setOnSuperTextViewClickListener(this); + menuHelper.setOnSuperTextViewClickListener(this); + menuChangeAccount.setOnSuperTextViewClickListener(this); + menuLogout.setOnSuperTextViewClickListener(this); + } + + @SingleClick + @Override + public void onClick(SuperTextView superTextView) { + switch (superTextView.getId()) { + case R.id.menu_common: + case R.id.menu_privacy: + case R.id.menu_push: + case R.id.menu_helper: + XToastUtils.toast(superTextView.getLeftString()); + break; + case R.id.menu_change_account: + XToastUtils.toast(superTextView.getCenterString()); + break; + case R.id.menu_logout: + DialogLoader.getInstance().showConfirmDialog( + getContext(), + getString(R.string.lab_logout_confirm), + getString(R.string.lab_yes), + (dialog, which) -> { + dialog.dismiss(); + XUtil.getActivityLifecycleHelper().exit(); + TokenUtils.handleLogoutSuccess(); + }, + getString(R.string.lab_no), + (dialog, which) -> dialog.dismiss() + ); + break; + default: + break; + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java new file mode 100644 index 00000000..8c9af48d --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java @@ -0,0 +1,142 @@ +package com.kerwin.wumei.fragment.device; + +import android.Manifest; +import android.os.Build; +import android.text.method.HideReturnsTransformationMethod; +import android.text.method.PasswordTransformationMethod; +import android.util.Log; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.kerwin.wumei.MyApp; +import com.kerwin.wumei.R; +import com.kerwin.wumei.activity.AddDeviceActivity; +import com.kerwin.wumei.activity.MainActivity; +import com.kerwin.wumei.adapter.entity.EspTouchViewModel; +import com.kerwin.wumei.core.BaseFragment; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.core.PageOption; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner; + +import java.util.List; + +import butterknife.BindView; + + +@Page(name = "WIFI网络配置") +public class AddDeviceFragment extends BaseFragment { + @BindView(R.id.advance_frame_layout) + FrameLayout advanceFrameLayout; + @BindView(R.id.advance_linear_layout) + LinearLayout advanceLinearLayout; + @BindView(R.id.advance_icon) + AppCompatImageView advanceIcon; + @BindView(R.id.wifi_password_icon) + AppCompatImageView wifiPasswordIcon; + + private static final String TAG = AddDeviceFragment.class.getSimpleName(); + private static final int REQUEST_PERMISSION = 0x01; + private EspTouchViewModel mViewModel; + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_add_device; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + + //智能配网 + mViewModel = ((AddDeviceActivity)this.getActivity()).GetMViewModel(); + mViewModel.ssidSpinner = findViewById(R.id.ssid_spinner); + mViewModel.apPasswordEdit = findViewById(R.id.wifi_password_txt); + mViewModel.packageModeGroup = findViewById(R.id.packageModeGroup); + mViewModel.messageView = findViewById(R.id.messageView); + mViewModel.confirmBtn = findViewById(R.id.add_device_next_btn); + mViewModel.confirmBtn.setOnClickListener(v -> + { + // ((AddDeviceActivity)this.getActivity()).executeEsptouch(); + PageOption.to(AddDeviceTwoFragment.class) //跳转的fragment + .setAnim(CoreAnim.slide) //页面转场动画 + .setRequestCode(100) //请求码,用于返回结果 + .setAddToBackStack(true) //是否加入堆栈 + .putString("device_mac","0908070605040306") + .open(this); //打开页面进行跳转 + }); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}; + requestPermissions(permissions, REQUEST_PERMISSION); + } + + MyApp.getInstance().observeBroadcast(this, broadcast -> { + Log.d(TAG, "onCreate: Broadcast=" + broadcast); + ((AddDeviceActivity)this.getActivity()).onWifiChanged(); + + List ssids=((AddDeviceActivity)this.getActivity()).GetSsids(); + if(ssids!=null && ssids.size()>0){ + Log.e(TAG, "进入数据绑定 " ); + mViewModel.ssidSpinner.setItems(ssids); + // ssidSpinner.setOnItemSelectedListener((spinner, position, id, item) -> SnackbarUtils.Long(spinner, "Clicked " + item).show()); + // ssidSpinner.setOnNothingSelectedListener(spinner -> SnackbarUtils.Long(spinner, "Nothing selected").show()); + String ssid=((AddDeviceActivity)this.getActivity()).GetSelectedSSID(); + if(ssid!=null && ssid.length()>0 && ssids.contains(ssid)) { + mViewModel.ssidSpinner.setSelectedItem(ssid); + } + } + }); + + + } + + @Override + protected void initListeners() { + //单击高级设置项 + advanceFrameLayout.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view) { + int visible=advanceLinearLayout.getVisibility(); + if(visible!=0) { + advanceLinearLayout.setVisibility(View.VISIBLE); + advanceIcon.setImageDrawable(getResources().getDrawable((R.drawable.up))); + }else{ + advanceLinearLayout.setVisibility(View.GONE); + advanceIcon.setImageDrawable(getResources().getDrawable((R.drawable.down))); + } + } + }); + + //显示和隐藏密码 + wifiPasswordIcon.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view){ + if(wifiPasswordIcon.getTag()==null) return; + if(wifiPasswordIcon.getTag().toString().equals("show")){ + wifiPasswordIcon.setImageDrawable(getResources().getDrawable((R.drawable.hide))); + wifiPasswordIcon.setTag("hide"); + mViewModel.apPasswordEdit.setTransformationMethod(PasswordTransformationMethod.getInstance()); + }else{ + wifiPasswordIcon.setImageDrawable(getResources().getDrawable((R.drawable.show))); + wifiPasswordIcon.setTag("show"); + mViewModel.apPasswordEdit.setTransformationMethod(HideReturnsTransformationMethod.getInstance()); + } + } + }); + + + + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java new file mode 100644 index 00000000..9003ba42 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java @@ -0,0 +1,64 @@ +package com.kerwin.wumei.fragment.device; + +import android.Manifest; +import android.os.Build; +import android.os.Bundle; +import android.text.method.HideReturnsTransformationMethod; +import android.text.method.PasswordTransformationMethod; +import android.util.Log; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.kerwin.wumei.MyApp; +import com.kerwin.wumei.R; +import com.kerwin.wumei.activity.AddDeviceActivity; +import com.kerwin.wumei.activity.MainActivity; +import com.kerwin.wumei.adapter.entity.EspTouchViewModel; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner; + +import java.util.List; + +import butterknife.BindView; + + +@Page(name = "设备信息") +public class AddDeviceTwoFragment extends BaseFragment { + + + /** + * 布局的资源id + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_add_device_two; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + + Bundle arguments = getArguments(); + String mac = arguments.getString("device_mac"); + XToastUtils.toast("设备MAC:" + mac); + + + } + + @Override + protected void initListeners() { + + + + + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java new file mode 100644 index 00000000..84b2a353 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java @@ -0,0 +1,100 @@ +package com.kerwin.wumei.fragment.device; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; +import androidx.viewpager2.widget.ViewPager2; + +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.adapter.simple.AdapterItem; +import com.xuexiang.xui.utils.WidgetUtils; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.popupwindow.popup.XUISimplePopup; +import com.xuexiang.xutil.display.ViewUtils; + +import butterknife.BindView; +import butterknife.OnClick; + +import static com.google.android.material.tabs.TabLayout.MODE_SCROLLABLE; + +@Page(name = "设备") +public class DeviceFragment extends BaseFragment implements TabLayout.OnTabSelectedListener{ + @BindView(R.id.tab_layout) + TabLayout tabLayout; + @BindView(R.id.view_pager) + ViewPager2 viewPager; + + private boolean mIsShowNavigationView; + private FragmentStateViewPager2Adapter mAdapter; + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { +// mAdapter.addFragment(2, SimpleTabFragment.newInstance("动态加入"), "动态加入"); +// mAdapter.removeFragment(2); +// mAdapter.notifyDataSetChanged(); + + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_device; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + mAdapter = new FragmentStateViewPager2Adapter(this); + tabLayout.setTabMode(MODE_SCROLLABLE); + tabLayout.addOnTabSelectedListener(this); + viewPager.setAdapter(mAdapter); + // 设置缓存的数量 + viewPager.setOffscreenPageLimit(1); + new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(mAdapter.getPageTitle(position))).attach(); + + // 动态加载选项卡内容 + for (String page : MultiPage.getPageNames()) { + mAdapter.addFragment(SimpleTabFragment.newInstance(page), page); + } + mAdapter.notifyDataSetChanged(); + viewPager.setCurrentItem(0, false); + WidgetUtils.setTabLayoutTextFont(tabLayout); + } + + + @Override + public void onTabSelected(TabLayout.Tab tab) { + XToastUtils.toast("选中了:" + tab.getText()); + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/EditDeviceFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/EditDeviceFragment.java new file mode 100644 index 00000000..a05602ba --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/EditDeviceFragment.java @@ -0,0 +1,27 @@ +package com.kerwin.wumei.fragment.device; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.xuexiang.xpage.annotation.Page; + +@Page(name = "分享设备") +public class EditDeviceFragment extends BaseFragment { + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_edit_device; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java new file mode 100644 index 00000000..b0a75892 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java @@ -0,0 +1,91 @@ +package com.kerwin.wumei.fragment.device; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author xuexiang + * @since 2020/5/21 1:27 AM + */ +public class FragmentStateViewPager2Adapter extends FragmentStateAdapter { + + private List mFragmentList = new ArrayList<>(); + + private List mTitleList = new ArrayList<>(); + + private List mIds = new ArrayList<>(); + + private AtomicLong mAtomicLong = new AtomicLong(0); + + public FragmentStateViewPager2Adapter(@NonNull Fragment fragment) { + super(fragment); + } + + @NonNull + @Override + public Fragment createFragment(int position) { + return mFragmentList.get(position); + } + + public FragmentStateViewPager2Adapter addFragment(Fragment fragment, String title) { + if (fragment != null) { + mFragmentList.add(fragment); + mTitleList.add(title); + mIds.add(getAtomicGeneratedId()); + } + return this; + } + + public FragmentStateViewPager2Adapter addFragment(int index, Fragment fragment, String title) { + if (fragment != null && index >= 0 && index <= mFragmentList.size()) { + mFragmentList.add(index, fragment); + mTitleList.add(index, title); + mIds.add(index, getAtomicGeneratedId()); + } + return this; + } + + public FragmentStateViewPager2Adapter removeFragment(int index) { + if (index >= 0 && index < mFragmentList.size()) { + mFragmentList.remove(index); + mTitleList.remove(index); + mIds.remove(index); + } + return this; + } + + private long getAtomicGeneratedId() { + return mAtomicLong.incrementAndGet(); + } + + @Override + public int getItemCount() { + return mFragmentList.size(); + } + + public void clear() { + mFragmentList.clear(); + mTitleList.clear(); + mIds.clear(); + notifyDataSetChanged(); + } + + public CharSequence getPageTitle(int position) { + return mTitleList.get(position); + } + + @Override + public long getItemId(int position) { + return mIds.get(position); + } + + @Override + public boolean containsItem(long itemId) { + return mIds.contains(itemId); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java new file mode 100644 index 00000000..d85115e1 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java @@ -0,0 +1,27 @@ +package com.kerwin.wumei.fragment.device; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.xuexiang.xpage.annotation.Page; + +@Page(name = "分组管理") +public class GroupFragment extends BaseFragment { + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_group; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/MultiPage.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/MultiPage.java new file mode 100644 index 00000000..c59f1e15 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/MultiPage.java @@ -0,0 +1,44 @@ +package com.kerwin.wumei.fragment.device;/* + + +/** + * @author xuexiang + * @since 2018/12/26 下午11:49 + */ +public enum MultiPage { + + 全部(0), + 浇灌(1), + 一楼(2), + 二楼(3), + 三楼(4), + 走廊(5); + + private final int position; + + MultiPage(int pos) { + position = pos; + } + + public static MultiPage getPage(int position) { + return MultiPage.values()[position]; + } + + public static int size() { + return MultiPage.values().length; + } + + public static String[] getPageNames() { + MultiPage[] pages = MultiPage.values(); + String[] pageNames = new String[pages.length]; + for (int i = 0; i < pages.length; i++) { + pageNames[i] = pages[i].name(); + } + return pageNames; + } + + public int getPosition() { + return position; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java new file mode 100644 index 00000000..b07a69b8 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java @@ -0,0 +1,59 @@ +package com.kerwin.wumei.fragment.device; + +import android.Manifest; +import android.os.Build; +import android.text.method.HideReturnsTransformationMethod; +import android.text.method.PasswordTransformationMethod; +import android.util.Log; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.kerwin.wumei.MyApp; +import com.kerwin.wumei.R; +import com.kerwin.wumei.activity.MainActivity; +import com.kerwin.wumei.adapter.entity.EspTouchViewModel; +import com.kerwin.wumei.core.BaseFragment; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner; + +import java.util.List; + +import butterknife.BindView; + + +@Page(anim = CoreAnim.none) +public class SceneFragment extends BaseFragment { + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_scene; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { } + + @Override + protected void initListeners() { } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java new file mode 100644 index 00000000..964c66e2 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java @@ -0,0 +1,29 @@ +package com.kerwin.wumei.fragment.device; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.widget.actionbar.TitleBar; + +@Page(name = "分享设备") +public class ShareDeviceFragment extends BaseFragment { + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_share_device; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java new file mode 100644 index 00000000..965e7d08 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java @@ -0,0 +1,255 @@ +package com.kerwin.wumei.fragment.device; + +import android.content.Context; +import android.graphics.Point; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Vibrator; +import android.text.method.HideReturnsTransformationMethod; +import android.text.method.PasswordTransformationMethod; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.cardview.widget.CardView; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + +import com.alibaba.android.vlayout.DelegateAdapter; +import com.alibaba.android.vlayout.LayoutHelper; +import com.alibaba.android.vlayout.VirtualLayoutManager; +import com.alibaba.android.vlayout.layout.GridLayoutHelper; +import com.alibaba.android.vlayout.layout.LinearLayoutHelper; +import com.alibaba.android.vlayout.layout.StaggeredGridLayoutHelper; +import com.alibaba.android.vlayout.layout.StickyLayoutHelper; +import com.kerwin.wumei.R; +import com.kerwin.wumei.adapter.base.broccoli.BroccoliSimpleDelegateAdapter; +import com.kerwin.wumei.adapter.base.delegate.SimpleDelegateAdapter; +import com.kerwin.wumei.adapter.base.delegate.SingleDelegateAdapter; +import com.kerwin.wumei.adapter.entity.NewInfo; +import com.kerwin.wumei.utils.DemoDataProvider; +import com.kerwin.wumei.utils.RandomUtils; +import com.kerwin.wumei.utils.Utils; +import com.kerwin.wumei.utils.XToastUtils; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.xuexiang.xrouter.annotation.AutoWired; +import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; +import com.xuexiang.xui.adapter.simple.AdapterItem; +import com.xuexiang.xui.widget.banner.widget.banner.SimpleImageBanner; +import com.xuexiang.xui.widget.button.SwitchIconView; +import com.xuexiang.xui.widget.imageview.ImageLoader; +import com.xuexiang.xui.widget.imageview.RadiusImageView; +import com.xuexiang.xui.widget.textview.supertextview.SuperButton; + +import java.util.ArrayList; +import java.util.Collection; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import me.samlss.broccoli.Broccoli; + +import static com.xuexiang.xui.utils.Utils.getScreenWidth; +import static com.xuexiang.xutil.display.DensityUtils.dip2px; + +/** + * @author xuexiang + * @since 2020/4/21 12:24 AM + */ +public class SimpleTabFragment extends Fragment { + private static final String TAG = "SimpleTabFragment"; + + private static final String KEY_TITLE = "title"; + +// @BindView(R.id.tv_title) +// TextView tvTitle; +// @BindView(R.id.tv_explain) +// TextView tvExplain; + + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.refreshLayout) + SmartRefreshLayout refreshLayout; +// @BindView(R.id.item_card_view) +// CardView itemCardView; + + private Unbinder mUnbinder; + + private SimpleDelegateAdapter mNewsAdapter; + + @AutoWired(name = KEY_TITLE) + String title; + + + public static SimpleTabFragment newInstance(String title) { + Bundle args = new Bundle(); + args.putString(KEY_TITLE, title); + SimpleTabFragment fragment = new SimpleTabFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + Log.e(TAG, "onAttach:" + title); + } + + @Override + public void onDetach() { + super.onDetach(); + Log.e(TAG, "onDetach:" + title); + } + + @Override + public void onResume() { + super.onResume(); + Log.e(TAG, "onResume:" + title); + } + + @Override + public void onStop() { + super.onStop(); + Log.e(TAG, "onStop:" + title); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + XRouter.getInstance().inject(this); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_simple_tab, container, false); + mUnbinder = ButterKnife.bind(this, view); + initView(); + return view; + } + + private void initView() { +// int randomNumber = RandomUtils.getRandom(10, 100); +// Log.e(TAG, "initView, random number:" + randomNumber + ", " + title); +// tvTitle.setText(String.format("这个是%s页面的内容", title)); +// tvExplain.setText(String.format("这个是页面随机生成的数字:%d", randomNumber)); + + + VirtualLayoutManager virtualLayoutManager = new VirtualLayoutManager(getContext()); + recyclerView.setLayoutManager(virtualLayoutManager); + RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool(); + recyclerView.setRecycledViewPool(viewPool); + viewPool.setMaxRecycledViews(0, 10); + + //顶部按钮 +// SingleDelegateAdapter buttonAdapter = new SingleDelegateAdapter(R.layout.adapter_button_top_item) { +// @Override +// public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { +// SuperButton superButton = holder.findViewById(R.id.device_item_all_open); +// } +// }; + + // 设备 + FragmentActivity activity=this.getActivity(); + mNewsAdapter = new BroccoliSimpleDelegateAdapter(R.layout.adapter_device_card_view_list_item, new StaggeredGridLayoutHelper(2,0), DemoDataProvider.getEmptyNewInfo()) { + @Override + protected void onBindData(RecyclerViewHolder holder, NewInfo model, int position) { + + //设置item宽度,适配屏幕分辨率 +// CardView view=holder.findViewById(R.id.device_item_card_view); +// int widthPixels = getScreenWidth(activity); +// int space=dip2px(40); //间隙=左边距+右边距+中间间隔 +// ViewGroup.LayoutParams cardViewParams=view.getLayoutParams(); +// cardViewParams.width=(widthPixels-space)/2; + + //设置开关按钮 + SwitchIconView switchIconView=holder.findViewById(R.id.device_item_switch_button); + holder.click(R.id.device_item_switch_button, v -> { + Vibrator vibrator = (Vibrator) activity.getSystemService(activity.VIBRATOR_SERVICE); + vibrator.vibrate(100); + switchIconView.switchState(); + }); + + AppCompatImageView stateView=holder.findViewById(R.id.device_item_state_icon); + stateView.setImageDrawable(getResources().getDrawable((R.drawable.state_a))); + + + if (model != null) { +// holder.text(R.id.tv_user_name, model.getUserName()); +// holder.text(R.id.tv_tag, model.getTag()); +// holder.text(R.id.tv_title, model.getTitle()); +// holder.text(R.id.tv_summary, model.getSummary()); +// holder.text(R.id.tv_praise, model.getPraise() == 0 ? "点赞" : String.valueOf(model.getPraise())); +// holder.text(R.id.tv_comment, model.getComment() == 0 ? "评论" : String.valueOf(model.getComment())); +// holder.text(R.id.tv_read, "阅读量 " + model.getRead()); +// holder.image(R.id.iv_image, model.getImageUrl()); +// +// holder.click(R.id.card_view, v -> Utils.goWeb(getContext(), model.getDetailUrl())); + } + } + + @Override + protected void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli) { +// broccoli.addPlaceholders( +// holder.findView(R.id.device_item_title), +// holder.findView(R.id.device_item_title_icon), +// holder.findView(R.id.device_item_time), +// holder.findView(R.id.device_item_time_icon), +// holder.findView(R.id.device_item_temperature), +// holder.findView(R.id.device_item_humidity), +// holder.findView(R.id.device_item_wifi), +// holder.findView(R.id.device_item_wifi_icon), +// holder.findView(R.id.device_item_state), +// holder.findView(R.id.device_item_state_icon), +// holder.findView(R.id.device_item_switch_button) +// ); + } + }; + + DelegateAdapter delegateAdapter = new DelegateAdapter(virtualLayoutManager); + delegateAdapter.addAdapter(mNewsAdapter); + recyclerView.setAdapter(delegateAdapter); + + + //下拉刷新 + refreshLayout.setOnRefreshListener(refreshLayout -> { + // TODO: 2020-02-25 这里只是模拟了网络请求 + refreshLayout.getLayout().postDelayed(() -> { + mNewsAdapter.refresh(DemoDataProvider.getDemoNewInfos()); + refreshLayout.finishRefresh(); + }, 1000); + }); + //上拉加载 + refreshLayout.setOnLoadMoreListener(refreshLayout -> { + // TODO: 2020-02-25 这里只是模拟了网络请求 + refreshLayout.getLayout().postDelayed(() -> { + mNewsAdapter.loadMore(DemoDataProvider.getDemoNewInfos()); + refreshLayout.finishLoadMore(); + }, 1000); + }); + refreshLayout.autoRefresh();//第一次进入触发自动刷新,演示效果 + } + + + @Override + public void onDestroyView() { + if (mUnbinder != null) { + mUnbinder.unbind(); + } + super.onDestroyView(); + Log.e(TAG, "onDestroyView:" + title); + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java new file mode 100644 index 00000000..21358614 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java @@ -0,0 +1,173 @@ +package com.kerwin.wumei.fragment.news; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.alibaba.android.vlayout.DelegateAdapter; +import com.alibaba.android.vlayout.VirtualLayoutManager; +import com.alibaba.android.vlayout.layout.GridLayoutHelper; +import com.alibaba.android.vlayout.layout.LinearLayoutHelper; +import com.kerwin.wumei.adapter.base.broccoli.BroccoliSimpleDelegateAdapter; +import com.kerwin.wumei.adapter.base.delegate.SimpleDelegateAdapter; +import com.kerwin.wumei.adapter.base.delegate.SingleDelegateAdapter; +import com.kerwin.wumei.adapter.entity.NewInfo; +import com.kerwin.wumei.core.BaseFragment; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.kerwin.wumei.R; +import com.kerwin.wumei.utils.DemoDataProvider; +import com.kerwin.wumei.utils.Utils; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; +import com.xuexiang.xui.adapter.simple.AdapterItem; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.banner.widget.banner.SimpleImageBanner; +import com.xuexiang.xui.widget.imageview.ImageLoader; +import com.xuexiang.xui.widget.imageview.RadiusImageView; + +import butterknife.BindView; +import me.samlss.broccoli.Broccoli; + +@Page(anim = CoreAnim.none) +public class NewsFragment extends BaseFragment { + + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.refreshLayout) + SmartRefreshLayout refreshLayout; + + private SimpleDelegateAdapter mNewsAdapter; + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_news; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + VirtualLayoutManager virtualLayoutManager = new VirtualLayoutManager(getContext()); + recyclerView.setLayoutManager(virtualLayoutManager); + RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool(); + recyclerView.setRecycledViewPool(viewPool); + viewPool.setMaxRecycledViews(0, 10); + + //轮播条 + SingleDelegateAdapter bannerAdapter = new SingleDelegateAdapter(R.layout.include_head_view_banner) { + @Override + public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { + SimpleImageBanner banner = holder.findViewById(R.id.sib_simple_usage); + banner.setSource(DemoDataProvider.getBannerList()) + .setOnItemClickListener((view, item, position1) -> XToastUtils.toast("headBanner position--->" + position1)).startScroll(); + } + }; + + //九宫格菜单 + GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4); + gridLayoutHelper.setPadding(0, 16, 0, 0); + gridLayoutHelper.setVGap(10); + gridLayoutHelper.setHGap(0); + SimpleDelegateAdapter commonAdapter = new SimpleDelegateAdapter(R.layout.adapter_common_grid_item, gridLayoutHelper, DemoDataProvider.getGridItems(getContext())) { + @Override + protected void bindData(@NonNull RecyclerViewHolder holder, int position, AdapterItem item) { + if (item != null) { + RadiusImageView imageView = holder.findViewById(R.id.riv_item); + imageView.setCircle(true); + ImageLoader.get().loadImage(imageView, item.getIcon()); + holder.text(R.id.device_item_title, item.getTitle().toString().substring(0, 1)); + holder.text(R.id.tv_sub_title, item.getTitle()); + + holder.click(R.id.ll_container, v -> XToastUtils.toast("点击了:" + item.getTitle())); + } + } + }; + + //动态的标题 + SingleDelegateAdapter titleAdapter = new SingleDelegateAdapter(R.layout.adapter_title_item) { + @Override + public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { + holder.text(R.id.device_item_title, "动态"); + holder.text(R.id.tv_action, "更多"); + holder.click(R.id.tv_action, v -> XToastUtils.toast("更多")); + } + }; + + // 动态 + mNewsAdapter = new BroccoliSimpleDelegateAdapter(R.layout.adapter_news_card_view_list_item, new LinearLayoutHelper(), DemoDataProvider.getEmptyNewInfo()) { + @Override + protected void onBindData(RecyclerViewHolder holder, NewInfo model, int position) { + if (model != null) { + holder.text(R.id.tv_user_name, model.getUserName()); + holder.text(R.id.tv_tag, model.getTag()); + holder.text(R.id.device_item_title, model.getTitle()); + holder.text(R.id.tv_summary, model.getSummary()); + holder.text(R.id.tv_praise, model.getPraise() == 0 ? "点赞" : String.valueOf(model.getPraise())); + holder.text(R.id.tv_comment, model.getComment() == 0 ? "评论" : String.valueOf(model.getComment())); + holder.text(R.id.tv_read, "阅读量 " + model.getRead()); + holder.image(R.id.iv_image, model.getImageUrl()); + + holder.click(R.id.card_view, v -> Utils.goWeb(getContext(), model.getDetailUrl())); + } + } + + @Override + protected void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli) { + broccoli.addPlaceholders( + holder.findView(R.id.tv_user_name), + holder.findView(R.id.tv_tag), + holder.findView(R.id.device_item_title), + holder.findView(R.id.tv_summary), + holder.findView(R.id.tv_praise), + holder.findView(R.id.tv_comment), + holder.findView(R.id.tv_read), + holder.findView(R.id.iv_image) + ); + } + }; + + DelegateAdapter delegateAdapter = new DelegateAdapter(virtualLayoutManager); + delegateAdapter.addAdapter(bannerAdapter); + delegateAdapter.addAdapter(commonAdapter); + delegateAdapter.addAdapter(titleAdapter); + delegateAdapter.addAdapter(mNewsAdapter); + + recyclerView.setAdapter(delegateAdapter); + } + + @Override + protected void initListeners() { + //下拉刷新 + refreshLayout.setOnRefreshListener(refreshLayout -> { + // TODO: 2020-02-25 这里只是模拟了网络请求 + refreshLayout.getLayout().postDelayed(() -> { + mNewsAdapter.refresh(DemoDataProvider.getDemoNewInfos()); + refreshLayout.finishRefresh(); + }, 1000); + }); + //上拉加载 + refreshLayout.setOnLoadMoreListener(refreshLayout -> { + // TODO: 2020-02-25 这里只是模拟了网络请求 + refreshLayout.getLayout().postDelayed(() -> { + mNewsAdapter.loadMore(DemoDataProvider.getDemoNewInfos()); + refreshLayout.finishLoadMore(); + }, 1000); + }); + refreshLayout.autoRefresh();//第一次进入触发自动刷新,演示效果 + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java new file mode 100644 index 00000000..50a7bc22 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java @@ -0,0 +1,88 @@ +package com.kerwin.wumei.fragment.profile; + +import android.graphics.drawable.ColorDrawable; + +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.R; +import com.kerwin.wumei.fragment.AboutFragment; +import com.kerwin.wumei.fragment.FeedbackFragment; +import com.kerwin.wumei.fragment.MessageFragment; +import com.kerwin.wumei.fragment.SettingsFragment; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xpage.utils.Utils; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.imageview.RadiusImageView; +import com.xuexiang.xui.widget.textview.supertextview.SuperTextView; + +import butterknife.BindView; + +@Page(anim = CoreAnim.none) +public class ProfileFragment extends BaseFragment implements SuperTextView.OnSuperTextViewClickListener { + @BindView(R.id.riv_head_pic) + RadiusImageView rivHeadPic; + @BindView(R.id.menu_settings) + SuperTextView menuSettings; + @BindView(R.id.menu_about) + SuperTextView menuAbout; + @BindView(R.id.menu_feedback) + SuperTextView menuFeedback; + @BindView(R.id.menu_message) + SuperTextView menuMessage; + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_profile; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + + } + + @Override + protected void initListeners() { + menuSettings.setOnSuperTextViewClickListener(this); + menuAbout.setOnSuperTextViewClickListener(this); + menuFeedback.setOnSuperTextViewClickListener(this); + menuMessage.setOnSuperTextViewClickListener(this); + } + + @SingleClick + @Override + public void onClick(SuperTextView view) { + switch(view.getId()) { + case R.id.menu_settings: + openNewPage(SettingsFragment.class); + break; + case R.id.menu_about: + openNewPage(AboutFragment.class); + break; + case R.id.menu_message: + openNewPage(MessageFragment.class); + break; + case R.id.menu_feedback: + openNewPage(FeedbackFragment.class); + break; + default: + break; + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java b/android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java new file mode 100644 index 00000000..9597d62f --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils; + +import android.content.Context; +import android.graphics.drawable.Drawable; + +import com.kerwin.wumei.adapter.entity.NewInfo; +import com.kerwin.wumei.R; +import com.xuexiang.xaop.annotation.MemoryCache; +import com.xuexiang.xui.adapter.simple.AdapterItem; +import com.xuexiang.xui.utils.ResUtils; +import com.xuexiang.xui.widget.banner.widget.banner.BannerItem; + +import java.util.ArrayList; +import java.util.List; + +/** + * 演示数据 + * + * @author xuexiang + * @since 2018/11/23 下午5:52 + */ +public class DemoDataProvider { + + public static String[] titles = new String[]{ + "伪装者:胡歌演绎'痞子特工'", + "无心法师:生死离别!月牙遭虐杀", + "花千骨:尊上沦为花千骨", + "综艺饭:胖轩偷看夏天洗澡掀波澜", + "碟中谍4:阿汤哥高塔命悬一线,超越不可能", + }; + + public static String[] urls = new String[]{//640*360 360/640=0.5625 + "http://photocdn.sohu.com/tvmobilemvms/20150907/144160323071011277.jpg",//伪装者:胡歌演绎"痞子特工" + "http://photocdn.sohu.com/tvmobilemvms/20150907/144158380433341332.jpg",//无心法师:生死离别!月牙遭虐杀 + "http://photocdn.sohu.com/tvmobilemvms/20150907/144160286644953923.jpg",//花千骨:尊上沦为花千骨 + "http://photocdn.sohu.com/tvmobilemvms/20150902/144115156939164801.jpg",//综艺饭:胖轩偷看夏天洗澡掀波澜 + "http://photocdn.sohu.com/tvmobilemvms/20150907/144159406950245847.jpg",//碟中谍4:阿汤哥高塔命悬一线,超越不可能 + }; + + @MemoryCache + public static List getBannerList() { + List list = new ArrayList<>(); + for (int i = 0; i < urls.length; i++) { + BannerItem item = new BannerItem(); + item.imgUrl = urls[i]; + item.title = titles[i]; + + list.add(item); + } + return list; + } + + /** + * 用于占位的空信息 + * + * @return + */ + @MemoryCache + public static List getDemoNewInfos() { + List list = new ArrayList<>(); + list.add(new NewInfo("源码", "Android源码分析--Android系统启动") + .setSummary("其实Android系统的启动最主要的内容无非是init、Zygote、SystemServer这三个进程的启动,他们一起构成的铁三角是Android系统的基础。") + .setDetailUrl("https://juejin.im/post/5c6fc0cdf265da2dda694f05") + .setImageUrl("https://user-gold-cdn.xitu.io/2019/2/22/16914891cd8a950a?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + + list.add(new NewInfo("Android UI", "XUI 一个简洁而优雅的Android原生UI框架,解放你的双手") + .setSummary("涵盖绝大部分的UI组件:TextView、Button、EditText、ImageView、Spinner、Picker、Dialog、PopupWindow、ProgressBar、LoadingView、StateLayout、FlowLayout、Switch、Actionbar、TabBar、Banner、GuideView、BadgeView、MarqueeView、WebView、SearchView等一系列的组件和丰富多彩的样式主题。\n") + .setDetailUrl("https://juejin.im/post/5c3ed1dae51d4543805ea48d") + .setImageUrl("https://user-gold-cdn.xitu.io/2019/1/16/1685563ae5456408?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + + list.add(new NewInfo("面试", "写给即将面试的你") + .setSummary("最近由于公司业务发展,需要招聘技术方面的人才,由于我在技术方面比较熟悉,技术面的任务就交给我了。今天我要分享的就和面试有关,主要包含技术面的流程、经验和建议,避免大家在今后的面试过程中走一些弯路,帮助即将需要跳槽面试的人。") + .setDetailUrl("https://juejin.im/post/5ca4df966fb9a05e4e58320c") + .setImageUrl("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1554629219186&di=6cdab5cfceaae1f7e6d78dbe79104c9f&imgtype=0&src=http%3A%2F%2Fimg.qinxue365.com%2Fuploads%2Fallimg%2F1902%2F4158-1Z22FZ64E00.jpg")); + + list.add(new NewInfo("Android", "XUpdate 一个轻量级、高可用性的Android版本更新框架") + .setSummary("XUpdate 一个轻量级、高可用性的Android版本更新框架。本框架借鉴了AppUpdate中的部分思想和UI界面,将版本更新中的各部分环节抽离出来,形成了如下几个部分:") + .setDetailUrl("https://juejin.im/post/5b480b79e51d45190905ef44") + .setImageUrl("https://user-gold-cdn.xitu.io/2018/7/13/16492d9b7877dc21?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + + list.add(new NewInfo("Android/HTTP", "XHttp2 一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp进行组装") + .setSummary("一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装。还不赶紧点击使用说明文档,体验一下吧!") + .setDetailUrl("https://juejin.im/post/5b6b9b49e51d4576b828978d") + .setImageUrl("https://user-gold-cdn.xitu.io/2018/8/9/1651c568a7e30e02?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + list.add(new NewInfo("Android/HTTP", "XHttp2 一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp进行组装") + .setSummary("一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装。还不赶紧点击使用说明文档,体验一下吧!") + .setDetailUrl("https://juejin.im/post/5b6b9b49e51d4576b828978d") + .setImageUrl("https://user-gold-cdn.xitu.io/2018/8/9/1651c568a7e30e02?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + list.add(new NewInfo("Android/HTTP", "XHttp2 一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp进行组装") + .setSummary("一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装。还不赶紧点击使用说明文档,体验一下吧!") + .setDetailUrl("https://juejin.im/post/5b6b9b49e51d4576b828978d") + .setImageUrl("https://user-gold-cdn.xitu.io/2018/8/9/1651c568a7e30e02?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + list.add(new NewInfo("Android/HTTP", "XHttp2 一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp进行组装") + .setSummary("一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装。还不赶紧点击使用说明文档,体验一下吧!") + .setDetailUrl("https://juejin.im/post/5b6b9b49e51d4576b828978d") + .setImageUrl("https://user-gold-cdn.xitu.io/2018/8/9/1651c568a7e30e02?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + list.add(new NewInfo("Android/HTTP", "XHttp2 一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp进行组装") + .setSummary("一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装。还不赶紧点击使用说明文档,体验一下吧!") + .setDetailUrl("https://juejin.im/post/5b6b9b49e51d4576b828978d") + .setImageUrl("https://user-gold-cdn.xitu.io/2018/8/9/1651c568a7e30e02?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + list.add(new NewInfo("Android/HTTP", "XHttp2 一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp进行组装") + .setSummary("一个功能强悍的网络请求库,使用RxJava2 + Retrofit2 + OKHttp组合进行封装。还不赶紧点击使用说明文档,体验一下吧!") + .setDetailUrl("https://juejin.im/post/5b6b9b49e51d4576b828978d") + .setImageUrl("https://user-gold-cdn.xitu.io/2018/8/9/1651c568a7e30e02?imageView2/0/w/1280/h/960/format/webp/ignore-error/1")); + return list; + } + + public static List getGridItems(Context context) { + return getGridItems(context, R.array.grid_titles_entry, R.array.grid_icons_entry); + } + + + private static List getGridItems(Context context, int titleArrayId, int iconArrayId) { + List list = new ArrayList<>(); + String[] titles = ResUtils.getStringArray(titleArrayId); + Drawable[] icons = ResUtils.getDrawableArray(context, iconArrayId); + for (int i = 0; i < titles.length; i++) { + list.add(new AdapterItem(titles[i], icons[i])); + } + return list; + } + + /** + * 用于占位的空信息 + * + * @return + */ + @MemoryCache + public static List getEmptyNewInfo() { + List list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + list.add(new NewInfo()); + } + return list; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/MMKVUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/MMKVUtils.java new file mode 100644 index 00000000..c0a7acc3 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/MMKVUtils.java @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils; + + +import android.content.Context; +import android.os.Parcelable; + +import com.tencent.mmkv.MMKV; + +import java.util.Set; + +/** + * MMKV工具类 + * + * @author xuexiang + * @since 2019-07-04 10:20 + */ +public final class MMKVUtils { + + private MMKVUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static MMKV sMMKV; + + /** + * 初始化 + * + * @param context + */ + public static void init(Context context) { + MMKV.initialize(context.getApplicationContext()); + sMMKV = MMKV.defaultMMKV(); + } + + public static MMKV getsMMKV() { + if (sMMKV == null) { + sMMKV = MMKV.defaultMMKV(); + } + return sMMKV; + } + + //=======================================键值保存==================================================// + + /** + * 保存键值 + * + * @param key + * @param value + * @return + */ + public static boolean put(String key, Object value) { + if (value instanceof Integer) { + return getsMMKV().encode(key, (Integer) value); + } else if (value instanceof Float) { + return getsMMKV().encode(key, (Float) value); + } else if (value instanceof String) { + return getsMMKV().encode(key, (String) value); + } else if (value instanceof Boolean) { + return getsMMKV().encode(key, (Boolean) value); + } else if (value instanceof Long) { + return getsMMKV().encode(key, (Long) value); + } else if (value instanceof Double) { + return getsMMKV().encode(key, (Double) value); + } else if (value instanceof Parcelable) { + return getsMMKV().encode(key, (Parcelable) value); + } else if (value instanceof byte[]) { + return getsMMKV().encode(key, (byte[]) value); + } else if (value instanceof Set) { + return getsMMKV().encode(key, (Set) value); + } + return false; + } + + + //=======================================键值获取==================================================// + + /** + * 获取键值 + * + * @param key + * @param defaultValue + * @return + */ + public static Object get(String key, Object defaultValue) { + if (defaultValue instanceof Integer) { + return getsMMKV().decodeInt(key, (Integer) defaultValue); + } else if (defaultValue instanceof Float) { + return getsMMKV().decodeFloat(key, (Float) defaultValue); + } else if (defaultValue instanceof String) { + return getsMMKV().decodeString(key, (String) defaultValue); + } else if (defaultValue instanceof Boolean) { + return getsMMKV().decodeBool(key, (Boolean) defaultValue); + } else if (defaultValue instanceof Long) { + return getsMMKV().decodeLong(key, (Long) defaultValue); + } else if (defaultValue instanceof Double) { + return getsMMKV().decodeDouble(key, (Double) defaultValue); + } else if (defaultValue instanceof byte[]) { + return getsMMKV().decodeBytes(key); + } else if (defaultValue instanceof Set) { + return getsMMKV().decodeStringSet(key, (Set) defaultValue); + } + return null; + } + + + /** + * 根据key获取boolean值 + * + * @param key + * @param defValue + * @return + */ + public static boolean getBoolean(String key, boolean defValue) { + try { + return getsMMKV().getBoolean(key, defValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defValue; + } + + /** + * 根据key获取long值 + * + * @param key + * @param defValue + * @return + */ + public static long getLong(String key, long defValue) { + try { + return getsMMKV().getLong(key, defValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defValue; + } + + /** + * 根据key获取float值 + * + * @param key + * @param defValue + * @return + */ + public static float getFloat(String key, float defValue) { + try { + return getsMMKV().getFloat(key, defValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defValue; + } + + /** + * 根据key获取String值 + * + * @param key + * @param defValue + * @return + */ + public static String getString(String key, String defValue) { + try { + return getsMMKV().getString(key, defValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defValue; + } + + /** + * 根据key获取int值 + * + * @param key + * @param defValue + * @return + */ + public static int getInt(String key, int defValue) { + try { + return getsMMKV().getInt(key, defValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defValue; + } + + + /** + * 根据key获取double值 + * + * @param key + * @param defValue + * @return + */ + public static double getDouble(String key, double defValue) { + try { + return getsMMKV().decodeDouble(key, defValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defValue; + } + + + /** + * 获取对象 + * + * @param key + * @param tClass 类型 + * @param + * @return + */ + public static T getObject(String key, Class tClass) { + return getsMMKV().decodeParcelable(key, tClass); + } + + /** + * 获取对象 + * + * @param key + * @param tClass 类型 + * @param + * @return + */ + public static T getObject(String key, Class tClass, T defValue) { + try { + return getsMMKV().decodeParcelable(key, tClass, defValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defValue; + } + + + /** + * 判断键值对是否存在 + * + * @param key 键 + * @return 键值对是否存在 + */ + public static boolean containsKey(String key) { + return getsMMKV().containsKey(key); + } + + /** + * 清除指定键值对 + * + * @param key 键 + */ + public static void remove(String key) { + getsMMKV().remove(key).apply(); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/NetUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/NetUtils.java new file mode 100644 index 00000000..21cbff26 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/NetUtils.java @@ -0,0 +1,147 @@ +package com.kerwin.wumei.utils; + +import android.net.DhcpInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; + +public class NetUtils { + public static boolean isWifiConnected(WifiManager wifiManager) { + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + return wifiInfo != null + && wifiInfo.getNetworkId() != -1 + && !"".equals(wifiInfo.getSSID()); + } + + public static byte[] getRawSsidBytes(WifiInfo info) { + try { + Method method = info.getClass().getMethod("getWifiSsid"); + method.setAccessible(true); + Object wifiSsid = method.invoke(info); + if (wifiSsid == null) { + return null; + } + method = wifiSsid.getClass().getMethod("getOctets"); + method.setAccessible(true); + return (byte[]) method.invoke(wifiSsid); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | NullPointerException e) { + e.printStackTrace(); + } + return null; + } + + public static byte[] getRawSsidBytesOrElse(WifiInfo info, byte[] orElse) { + byte[] raw = getRawSsidBytes(info); + return raw != null ? raw : orElse; + } + + public static String getSsidString(WifiInfo info) { + String ssid = info.getSSID(); + if (ssid.startsWith("\"") && ssid.endsWith("\"")) { + ssid = ssid.substring(1, ssid.length() - 1); + } + return ssid; + } + + public static InetAddress getBroadcastAddress(WifiManager wifi) { + DhcpInfo dhcp = wifi.getDhcpInfo(); + if (dhcp != null) { + int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask; + byte[] quads = new byte[4]; + for (int k = 0; k < 4; k++) { + quads[k] = (byte) ((broadcast >> k * 8) & 0xFF); + } + try { + return InetAddress.getByAddress(quads); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + } + + try { + return InetAddress.getByName("255.255.255.255"); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + // Impossible arrive here + return null; + } + + public static boolean is5G(int frequency) { + return frequency > 4900 && frequency < 5900; + } + + public static InetAddress getAddress(int ipAddress) { + byte[] ip = new byte[]{ + (byte) (ipAddress & 0xff), + (byte) ((ipAddress >> 8) & 0xff), + (byte) ((ipAddress >> 16) & 0xff), + (byte) ((ipAddress >> 24) & 0xff) + }; + + try { + return InetAddress.getByAddress(ip); + } catch (UnknownHostException e) { + e.printStackTrace(); + // Impossible arrive here + return null; + } + } + + private static InetAddress getAddress(boolean isIPv4) { + try { + Enumeration enums = NetworkInterface.getNetworkInterfaces(); + while (enums.hasMoreElements()) { + NetworkInterface ni = enums.nextElement(); + Enumeration addrs = ni.getInetAddresses(); + while (addrs.hasMoreElements()) { + InetAddress address = addrs.nextElement(); + if (!address.isLoopbackAddress()) { + if (isIPv4 && address instanceof Inet4Address) { + return address; + } + if (!isIPv4 && address instanceof Inet6Address) { + return address; + } + } + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + return null; + } + + public static InetAddress getIPv4Address() { + return getAddress(true); + } + + public static InetAddress getIPv6Address() { + return getAddress(false); + } + + /** + * @param bssid the bssid like aa:bb:cc:dd:ee:ff + * @return byte array converted from bssid + */ + public static byte[] convertBssid2Bytes(String bssid) { + String[] bssidSplits = bssid.split(":"); + if (bssidSplits.length != 6) { + throw new IllegalArgumentException("Invalid bssid format"); + } + byte[] result = new byte[bssidSplits.length]; + for (int i = 0; i < bssidSplits.length; i++) { + result[i] = (byte) Integer.parseInt(bssidSplits[i], 16); + } + return result; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/RandomUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/RandomUtils.java new file mode 100644 index 00000000..44833c4f --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/RandomUtils.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils; + +import android.graphics.Color; +import android.text.TextUtils; + +import java.util.Random; + +/** + *

+ *     desc   : Random Utils
+ *     author : xuexiang
+ *     time   : 2018/4/28 上午12:41
+ * 
+ *
    + * Shuffling algorithm + *
  • {@link #shuffle(Object[])} Shuffling algorithm, Randomly permutes the specified array using a default source of + * randomness
  • + *
  • {@link #shuffle(Object[], int)} Shuffling algorithm, Randomly permutes the specified array
  • + *
  • {@link #shuffle(int[])} Shuffling algorithm, Randomly permutes the specified int array using a default source of + * randomness
  • + *
  • {@link #shuffle(int[], int)} Shuffling algorithm, Randomly permutes the specified int array
  • + *
+ *
    + * get random int + *
  • {@link #getRandom(int)} get random int between 0 and max
  • + *
  • {@link #getRandom(int, int)} get random int between min and max
  • + *
+ *
    + * get random numbers or letters + *
  • {@link #getRandomCapitalLetters(int)} get a fixed-length random string, its a mixture of uppercase letters
  • + *
  • {@link #getRandomLetters(int)} get a fixed-length random string, its a mixture of uppercase and lowercase letters + *
  • + *
  • {@link #getRandomLowerCaseLetters(int)} get a fixed-length random string, its a mixture of lowercase letters
  • + *
  • {@link #getRandomNumbers(int)} get a fixed-length random string, its a mixture of numbers
  • + *
  • {@link #getRandomNumbersAndLetters(int)} get a fixed-length random string, its a mixture of uppercase, lowercase + * letters and numbers
  • + *
  • {@link #getRandom(String, int)} get a fixed-length random string, its a mixture of chars in source
  • + *
  • {@link #getRandom(char[], int)} get a fixed-length random string, its a mixture of chars in sourceChar
  • + *
+ * + */ +public final class RandomUtils { + + public static final String NUMBERS_AND_LETTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public static final String NUMBERS = "0123456789"; + public static final String LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public static final String LOWER_CASE_LETTERS = "abcdefghijklmnopqrstuvwxyz"; + + /** + * Don't let anyone instantiate this class. + */ + private RandomUtils() { + throw new Error("Do not need instantiate!"); + } + + /** + * 在数字和英文字母中获取一个定长的随机字符串 + * + * @param length 长度 + * @return 随机字符串 + * @see RandomUtils#getRandom(String source, int length) + */ + public static String getRandomNumbersAndLetters(int length) { + return getRandom(NUMBERS_AND_LETTERS, length); + } + + /** + * 在数字中获取一个定长的随机字符串 + * + * @param length 长度 + * @return 随机数字符串 + * @see RandomUtils#getRandom(String source, int length) + */ + public static String getRandomNumbers(int length) { + return getRandom(NUMBERS, length); + } + + /** + * 在英文字母中获取一个定长的随机字符串 + * + * @param length 长度 + * @return 随机字母字符串 + * @see RandomUtils#getRandom(String source, int length) + */ + public static String getRandomLetters(int length) { + return getRandom(LETTERS, length); + } + + /** + * 在大写英文字母中获取一个定长的随机字符串 + * + * @param length 长度 + * @return 随机字符串 只包含大写字母 + * @see RandomUtils#getRandom(String source, int length) + */ + public static String getRandomCapitalLetters(int length) { + return getRandom(CAPITAL_LETTERS, length); + } + + /** + * 在小写英文字母中获取一个定长的随机字符串 + * + * @param length 长度 + * @return 随机字符串 只包含小写字母 + * @see RandomUtils#getRandom(String source, int length) + */ + public static String getRandomLowerCaseLetters(int length) { + return getRandom(LOWER_CASE_LETTERS, length); + } + + /** + * 在一个字符数组源中获取一个定长的随机字符串 + * + * @param source 源字符串 + * @param length 长度 + * @return
    + *
  • if source is null or empty, return null
  • + *
  • else see {@link RandomUtils#getRandom(char[] sourceChar, int length)}
  • + *
+ */ + public static String getRandom(String source, int length) { + return TextUtils.isEmpty(source) ? null : getRandom(source.toCharArray(), length); + } + + /** + * 在一个字符数组源中获取一个定长的随机字符串 + * + * @param sourceChar 字符数组源 + * @param length 长度 + * @return
    + *
  • if sourceChar is null or empty, return null
  • + *
  • if length less than 0, return null
  • + *
+ */ + public static String getRandom(char[] sourceChar, int length) { + if (sourceChar == null || sourceChar.length == 0 || length < 0) { + return null; + } + + StringBuilder str = new StringBuilder(length); + Random random = new Random(); + for (int i = 0; i < length; i++) { + str.append(sourceChar[random.nextInt(sourceChar.length)]); + } + return str.toString(); + } + + /** + * get random int between 0 and max + * + * @param max 最大随机数 + * @return
    + *
  • if max <= 0, return 0
  • + *
  • else return random int between 0 and max
  • + *
+ */ + public static int getRandom(int max) { + return getRandom(0, max); + } + + /** + * get random int between min and max + * + * @param min 最小随机数 + * @param max 最大随机数 + * @return
    + *
  • if min > max, return 0
  • + *
  • if min == max, return min
  • + *
  • else return random int between min and max
  • + *
+ */ + public static int getRandom(int min, int max) { + if (min > max) { + return 0; + } + if (min == max) { + return min; + } + return min + new Random().nextInt(max - min); + } + + /** + * 获取随机颜色 + * + * @return + */ + public static int getRandomColor() { + Random random = new Random(); + int r = random.nextInt(256); + int g = random.nextInt(256); + int b = random.nextInt(256); + return Color.rgb(r, g, b); + } + + /** + * 随机打乱数组中的内容 + * + * @param objArray + * @return + */ + public static boolean shuffle(Object[] objArray) { + if (objArray == null) { + return false; + } + + return shuffle(objArray, getRandom(objArray.length)); + } + + /** + * 随机打乱数组中的内容 + * + * @param objArray + * @param shuffleCount + * @return + */ + public static boolean shuffle(Object[] objArray, int shuffleCount) { + int length; + if (objArray == null || shuffleCount < 0 || (length = objArray.length) < shuffleCount) { + return false; + } + + for (int i = 1; i <= shuffleCount; i++) { + int random = getRandom(length - i); + Object temp = objArray[length - i]; + objArray[length - i] = objArray[random]; + objArray[random] = temp; + } + return true; + } + + /** + * 随机打乱数组中的内容 + * + * @param intArray + * @return + */ + public static int[] shuffle(int[] intArray) { + if (intArray == null) { + return null; + } + + return shuffle(intArray, getRandom(intArray.length)); + } + + /** + * 随机打乱数组中的内容 + * + * @param intArray + * @param shuffleCount + * @return + */ + public static int[] shuffle(int[] intArray, int shuffleCount) { + int length; + if (intArray == null || shuffleCount < 0 || (length = intArray.length) < shuffleCount) { + return null; + } + + int[] out = new int[shuffleCount]; + for (int i = 1; i <= shuffleCount; i++) { + int random = getRandom(length - i); + out[i - 1] = intArray[random]; + int temp = intArray[length - i]; + intArray[length - i] = intArray[random]; + intArray[random] = temp; + } + return out; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java new file mode 100644 index 00000000..cab09bb4 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils; + + +/** + * SharedPreferences管理工具基类 + * + * @author xuexiang + * @since 2018/11/27 下午5:16 + */ +public final class SettingUtils { + + private SettingUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final String IS_FIRST_OPEN_KEY = "is_first_open_key"; + + private static final String IS_AGREE_PRIVACY_KEY = "is_agree_privacy_key"; + + /** + * 是否是第一次启动 + */ + public static boolean isFirstOpen() { + return MMKVUtils.getBoolean(IS_FIRST_OPEN_KEY, true); + } + + /** + * 设置是否是第一次启动 + */ + public static void setIsFirstOpen(boolean isFirstOpen) { + MMKVUtils.put(IS_FIRST_OPEN_KEY, isFirstOpen); + } + + /** + * @return 是否同意隐私政策 + */ + public static boolean isAgreePrivacy() { + return MMKVUtils.getBoolean(IS_AGREE_PRIVACY_KEY, false); + } + + public static void setIsAgreePrivacy(boolean isAgreePrivacy) { + MMKVUtils.put(IS_AGREE_PRIVACY_KEY, isAgreePrivacy); + } + + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java new file mode 100644 index 00000000..b4897847 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils; + +import android.content.Context; + +import com.kerwin.wumei.activity.LoginActivity; +import com.umeng.analytics.MobclickAgent; +import com.xuexiang.xutil.app.ActivityUtils; +import com.xuexiang.xutil.common.StringUtils; + +/** + * Token管理工具 + * + * @author xuexiang + * @since 2019-11-17 22:37 + */ +public final class TokenUtils { + + private static String sToken; + + private static final String KEY_TOKEN = "com.xuexiang.templateproject.utils.KEY_TOKEN"; + + private TokenUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final String KEY_PROFILE_CHANNEL = "github"; + + /** + * 初始化Token信息 + */ + public static void init(Context context) { + MMKVUtils.init(context); + sToken = MMKVUtils.getString(KEY_TOKEN, ""); + } + + public static void setToken(String token) { + sToken = token; + MMKVUtils.put(KEY_TOKEN, token); + } + + public static void clearToken() { + sToken = null; + MMKVUtils.remove(KEY_TOKEN); + } + + public static String getToken() { + return sToken; + } + + public static boolean hasToken() { + return MMKVUtils.containsKey(KEY_TOKEN); + } + + /** + * 处理登录成功的事件 + * + * @param token 账户信息 + */ + public static boolean handleLoginSuccess(String token) { + if (!StringUtils.isEmpty(token)) { + XToastUtils.success("登录成功!"); + MobclickAgent.onProfileSignIn(KEY_PROFILE_CHANNEL, token); + setToken(token); + return true; + } else { + XToastUtils.error("登录失败!"); + return false; + } + } + + /** + * 处理登出的事件 + */ + public static void handleLogoutSuccess() { + MobclickAgent.onProfileSignOff(); + //登出时,清除账号信息 + clearToken(); + XToastUtils.success("登出成功!"); + //跳转到登录页 + ActivityUtils.startActivity(LoginActivity.class); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/Utils.java b/android/app/src/main/java/com/kerwin/wumei/utils/Utils.java new file mode 100644 index 00000000..a4298e05 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/Utils.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.view.View; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; + +import com.kerwin.wumei.core.webview.AgentWebActivity; +import com.kerwin.wumei.core.webview.AgentWebFragment; +import com.kerwin.wumei.R; +import com.xuexiang.xui.utils.ResUtils; +import com.xuexiang.xui.widget.dialog.DialogLoader; +import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction; +import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog; +import com.xuexiang.xutil.XUtil; + +/** + * 工具类 + * + * @author xuexiang + * @since 2020-02-23 15:12 + */ +public final class Utils { + + private Utils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 这里填写你的应用隐私政策网页地址 + */ + private static final String PRIVACY_URL = "https://gitee.com/xuexiangjys/TemplateAppProject/raw/master/LICENSE"; + + /** + * 显示隐私政策的提示 + * + * @param context + * @param submitListener 同意的监听 + * @return + */ + public static Dialog showPrivacyDialog(Context context, MaterialDialog.SingleButtonCallback submitListener) { + MaterialDialog dialog = new MaterialDialog.Builder(context).title(R.string.title_reminder).autoDismiss(false).cancelable(false) + .positiveText(R.string.lab_agree).onPositive((dialog1, which) -> { + if (submitListener != null) { + submitListener.onClick(dialog1, which); + } else { + dialog1.dismiss(); + } + }) + .negativeText(R.string.lab_disagree).onNegative(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { + dialog.dismiss(); + DialogLoader.getInstance().showConfirmDialog(context, ResUtils.getString(R.string.title_reminder), String.format(ResUtils.getString(R.string.content_privacy_explain_again), ResUtils.getString(R.string.app_name)), ResUtils.getString(R.string.lab_look_again), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + showPrivacyDialog(context, submitListener); + } + }, ResUtils.getString(R.string.lab_still_disagree), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + DialogLoader.getInstance().showConfirmDialog(context, ResUtils.getString(R.string.content_think_about_it_again), ResUtils.getString(R.string.lab_look_again), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + showPrivacyDialog(context, submitListener); + } + }, ResUtils.getString(R.string.lab_exit_app), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + XUtil.exitApp(); + } + }); + } + }); + } + }).build(); + dialog.setContent(getPrivacyContent(context)); + //开始响应点击事件 + dialog.getContentView().setMovementMethod(LinkMovementMethod.getInstance()); + dialog.show(); + return dialog; + } + + /** + * @return 隐私政策说明 + */ + private static SpannableStringBuilder getPrivacyContent(Context context) { + SpannableStringBuilder stringBuilder = new SpannableStringBuilder() + .append(" 欢迎来到").append(ResUtils.getString(R.string.app_name)).append("!\n") + .append(" 我们深知个人信息对你的重要性,也感谢你对我们的信任。\n") + .append(" 为了更好地保护你的权益,同时遵守相关监管的要求,我们将通过"); + stringBuilder.append(getPrivacyLink(context, PRIVACY_URL)) + .append("向你说明我们会如何收集、存储、保护、使用及对外提供你的信息,并说明你享有的权利。\n") + .append(" 更多详情,敬请查阅") + .append(getPrivacyLink(context, PRIVACY_URL)) + .append("全文。"); + return stringBuilder; + } + + /** + * @param context 隐私政策的链接 + * @return + */ + private static SpannableString getPrivacyLink(Context context, String privacyUrl) { + String privacyName = String.format(ResUtils.getString(R.string.lab_privacy_name), ResUtils.getString(R.string.app_name)); + SpannableString spannableString = new SpannableString(privacyName); + spannableString.setSpan(new ClickableSpan() { + @Override + public void onClick(@NonNull View widget) { + goWeb(context, privacyUrl); + } + }, 0, privacyName.length(), Spanned.SPAN_MARK_MARK); + return spannableString; + } + + + /** + * 请求浏览器 + * + * @param url + */ + public static void goWeb(Context context, final String url) { + Intent intent = new Intent(context, AgentWebActivity.class); + intent.putExtra(AgentWebFragment.KEY_URL, url); + context.startActivity(intent); + } + + + /** + * 是否是深色的颜色 + * + * @param color + * @return + */ + public static boolean isColorDark(@ColorInt int color) { + double darkness = + 1 + - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) + / 255; + return darkness >= 0.382; + } + + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/XToastUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/XToastUtils.java new file mode 100644 index 00000000..86820b82 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/XToastUtils.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils; + +import androidx.annotation.MainThread; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; + +import com.xuexiang.xui.XUI; +import com.xuexiang.xui.widget.toast.XToast; + +/** + * xtoast 工具类 + * + * @author xuexiang + * @since 2019-06-30 19:04 + */ +public final class XToastUtils { + + + private XToastUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + static { + XToast.Config.get() + .setAlpha(200) + .allowQueue(false); + } + + //======普通土司=======// + + @MainThread + public static void toast(@NonNull CharSequence message) { + XToast.normal(XUI.getContext(), message).show(); + } + + @MainThread + public static void toast(@StringRes int message) { + XToast.normal(XUI.getContext(), message).show(); + } + + @MainThread + public static void toast(@NonNull CharSequence message, int duration) { + XToast.normal(XUI.getContext(), message, duration).show(); + } + + @MainThread + public static void toast(@StringRes int message, int duration) { + XToast.normal(XUI.getContext(), message, duration).show(); + } + + //======错误【红色】=======// + + @MainThread + public static void error(@NonNull Throwable throwable) { + XToast.error(XUI.getContext(), throwable.getMessage()).show(); + } + + @MainThread + public static void error(@NonNull CharSequence message) { + XToast.error(XUI.getContext(), message).show(); + } + + @MainThread + public static void error(@StringRes int message) { + XToast.error(XUI.getContext(), message).show(); + } + + @MainThread + public static void error(@NonNull CharSequence message, int duration) { + XToast.error(XUI.getContext(), message, duration).show(); + } + + @MainThread + public static void error(@StringRes int message, int duration) { + XToast.error(XUI.getContext(), message, duration).show(); + } + + //======成功【绿色】=======// + + @MainThread + public static void success(@NonNull CharSequence message) { + XToast.success(XUI.getContext(), message).show(); + } + + @MainThread + public static void success(@StringRes int message) { + XToast.success(XUI.getContext(), message).show(); + } + + @MainThread + public static void success(@NonNull CharSequence message, int duration) { + XToast.success(XUI.getContext(), message, duration).show(); + } + + @MainThread + public static void success(@StringRes int message, int duration) { + XToast.success(XUI.getContext(), message, duration).show(); + } + + //======信息【蓝色】=======// + + @MainThread + public static void info(@NonNull CharSequence message) { + XToast.info(XUI.getContext(), message).show(); + } + + @MainThread + public static void info(@StringRes int message) { + XToast.info(XUI.getContext(), message).show(); + } + + @MainThread + public static void info(@NonNull CharSequence message, int duration) { + XToast.info(XUI.getContext(), message, duration).show(); + } + + @MainThread + public static void info(@StringRes int message, int duration) { + XToast.info(XUI.getContext(), message, duration).show(); + } + + //=======警告【黄色】======// + + @MainThread + public static void warning(@NonNull CharSequence message) { + XToast.warning(XUI.getContext(), message).show(); + } + + @MainThread + public static void warning(@StringRes int message) { + XToast.warning(XUI.getContext(), message).show(); + } + + @MainThread + public static void warning(@NonNull CharSequence message, int duration) { + XToast.warning(XUI.getContext(), message, duration).show(); + } + + @MainThread + public static void warning(@StringRes int message, int duration) { + XToast.warning(XUI.getContext(), message, duration).show(); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/ANRWatchDogInit.java b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/ANRWatchDogInit.java new file mode 100644 index 00000000..11427a6c --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/ANRWatchDogInit.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.sdkinit; + +import com.github.anrwatchdog.ANRWatchDog; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * ANR看门狗监听器初始化 + * + * @author xuexiang + * @since 2020-02-18 15:08 + */ +public final class ANRWatchDogInit { + + private static final String TAG = "ANRWatchDog"; + + private ANRWatchDogInit() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * ANR看门狗 + */ + private static ANRWatchDog sANRWatchDog; + + /** + * ANR监听触发的时间 + */ + private static final int ANR_DURATION = 4000; + + + /** + * ANR静默处理【就是不处理,直接记录一下日志】 + */ + private final static ANRWatchDog.ANRListener SILENT_LISTENER = error -> Logger.eTag(TAG, error); + + /** + * ANR自定义处理【可以是记录日志用于上传】 + */ + private final static ANRWatchDog.ANRListener CUSTOM_LISTENER = error -> { + Logger.eTag(TAG, "Detected Application Not Responding!", error); + //这里进行ANR的捕获后的操作 + + throw error; + }; + + public static void init() { + //这里设置监听的间隔为2秒 + sANRWatchDog = new ANRWatchDog(2000); + sANRWatchDog.setANRInterceptor(duration -> { + long ret = ANR_DURATION - duration; + if (ret > 0) { + Logger.wTag(TAG, "Intercepted ANR that is too short (" + duration + " ms), postponing for " + ret + " ms."); + } + //当返回是0或者负数时,就会触发ANR监听回调 + return ret; + }).setANRListener(SILENT_LISTENER).start(); + } + + public static ANRWatchDog getANRWatchDog() { + return sANRWatchDog; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/UMengInit.java b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/UMengInit.java new file mode 100644 index 00000000..6a8b198d --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/UMengInit.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.sdkinit; + +import android.app.Application; +import android.content.Context; + +import com.kerwin.wumei.BuildConfig; +import com.kerwin.wumei.MyApp; +import com.meituan.android.walle.WalleChannelReader; +import com.umeng.analytics.MobclickAgent; +import com.umeng.commonsdk.UMConfigure; + +/** + * UMeng 统计 SDK初始化 + * + * @author xuexiang + * @since 2019-06-18 15:49 + */ +public final class UMengInit { + + private UMengInit() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static String DEFAULT_CHANNEL_ID = "github"; + + /** + * 初始化UmengSDK + */ + public static void init(Application application) { + //设置LOG开关,默认为false + UMConfigure.setLogEnabled(MyApp.isDebug()); + //初始化组件化基础库, 注意: 即使您已经在AndroidManifest.xml中配置过appkey和channel值,也需要在App代码中调用初始化接口(如需要使用AndroidManifest.xml中配置好的appkey和channel值,UMConfigure.init调用中appkey和channel参数请置为null)。 + //第二个参数是appkey,最后一个参数是pushSecret + //这里BuildConfig.APP_ID_UMENG是根据local.properties中定义的APP_ID_UMENG生成的,只是运行看效果的话,可以不初始化该SDK + UMConfigure.init(application, BuildConfig.APP_ID_UMENG, getChannel(application), UMConfigure.DEVICE_TYPE_PHONE, ""); + //统计SDK是否支持采集在子进程中打点的自定义事件,默认不支持 + //支持多进程打点 + UMConfigure.setProcessEvent(true); + MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO); + } + + + /** + * 获取渠道信息 + * + * @param context + * @return + */ + public static String getChannel(final Context context) { + return WalleChannelReader.getChannel(context, DEFAULT_CHANNEL_ID); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XBasicLibInit.java b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XBasicLibInit.java new file mode 100644 index 00000000..b7e32a24 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XBasicLibInit.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.sdkinit; + +import android.app.Application; + +import com.kerwin.wumei.MyApp; +import com.kerwin.wumei.core.BaseActivity; +import com.kerwin.wumei.utils.TokenUtils; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.XAOP; +import com.xuexiang.xhttp2.XHttpSDK; +import com.xuexiang.xpage.PageConfig; +import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xui.XUI; +import com.xuexiang.xutil.XUtil; +import com.xuexiang.xutil.common.StringUtils; + +/** + * X系列基础库初始化 + * + * @author xuexiang + * @since 2019-06-30 23:54 + */ +public final class XBasicLibInit { + + private XBasicLibInit() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 初始化基础库SDK + */ + public static void init(Application application) { + //工具类 + initXUtil(application); + + //网络请求框架 + initXHttp2(application); + + //页面框架 + initXPage(application); + + //切片框架 + initXAOP(application); + + //UI框架 + initXUI(application); + + //路由框架 + initRouter(application); + } + + /** + * 初始化XUtil工具类 + */ + private static void initXUtil(Application application) { + XUtil.init(application); + XUtil.debug(MyApp.isDebug()); + TokenUtils.init(application); + } + + /** + * 初始化XHttp2 + */ + private static void initXHttp2(Application application) { + //初始化网络请求框架,必须首先执行 + XHttpSDK.init(application); + //需要调试的时候执行 + if (MyApp.isDebug()) { + XHttpSDK.debug(); + } +// XHttpSDK.debug(new CustomLoggingInterceptor()); //设置自定义的日志打印拦截器 + //设置网络请求的全局基础地址 + XHttpSDK.setBaseUrl("https://gitee.com/"); +// //设置动态参数添加拦截器 +// XHttpSDK.addInterceptor(new CustomDynamicInterceptor()); +// //请求失效校验拦截器 +// XHttpSDK.addInterceptor(new CustomExpiredInterceptor()); + } + + /** + * 初始化XPage页面框架 + */ + private static void initXPage(Application application) { + PageConfig.getInstance() + .debug(MyApp.isDebug() ? "PageLog" : null) + .setContainActivityClazz(BaseActivity.class) + .init(application); + } + + /** + * 初始化XAOP + */ + private static void initXAOP(Application application) { + XAOP.init(application); + XAOP.debug(MyApp.isDebug()); + //设置动态申请权限切片 申请权限被拒绝的事件响应监听 + XAOP.setOnPermissionDeniedListener(permissionsDenied -> XToastUtils.error("权限申请被拒绝:" + StringUtils.listToString(permissionsDenied, ","))); + } + + /** + * 初始化XUI框架 + */ + private static void initXUI(Application application) { + XUI.init(application); + XUI.debug(MyApp.isDebug()); + } + + /** + * 初始化路由框架 + */ + private static void initRouter(Application application) { + // 这两行必须写在init之前,否则这些配置在init过程中将无效 + if (MyApp.isDebug()) { + XRouter.openLog(); // 打印日志 + XRouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) + } + XRouter.init(application); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java new file mode 100644 index 00000000..a092c277 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.sdkinit; + +import android.app.Application; +import android.content.Context; + +import com.kerwin.wumei.MyApp; +import com.kerwin.wumei.utils.update.CustomUpdateDownloader; +import com.kerwin.wumei.utils.update.CustomUpdateFailureListener; +import com.kerwin.wumei.utils.update.XHttpUpdateHttpServiceImpl; +import com.xuexiang.xupdate.XUpdate; +import com.xuexiang.xupdate.utils.UpdateUtils; + +/** + * XUpdate 版本更新 SDK 初始化 + * + * @author xuexiang + * @since 2019-06-18 15:51 + */ +public final class XUpdateInit { + + private XUpdateInit() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 应用版本更新的检查地址 + */ + private static final String KEY_UPDATE_URL = ""; + + public static void init(Application application) { + XUpdate.get() + .debug(MyApp.isDebug()) + //默认设置只在wifi下检查版本更新 + .isWifiOnly(false) + //默认设置使用get请求检查版本 + .isGet(true) + //默认设置非自动模式,可根据具体使用配置 + .isAutoMode(false) + //设置默认公共请求参数 + .param("versionCode", UpdateUtils.getVersionCode(application)) + .param("appKey", application.getPackageName()) + //这个必须设置!实现网络请求功能。 + .setIUpdateHttpService(new XHttpUpdateHttpServiceImpl()) + .setIUpdateDownLoader(new CustomUpdateDownloader()) + //这个必须初始化 + .init(application); + } + + /** + * 进行版本更新检查 + */ + public static void checkUpdate(Context context, boolean needErrorTip) { + XUpdate.newBuild(context).updateUrl(KEY_UPDATE_URL).update(); + XUpdate.get().setOnUpdateFailureListener(new CustomUpdateFailureListener(needErrorTip)); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/service/JsonSerializationService.java b/android/app/src/main/java/com/kerwin/wumei/utils/service/JsonSerializationService.java new file mode 100644 index 00000000..dbfe7328 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/service/JsonSerializationService.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.service; + +import android.content.Context; + +import com.xuexiang.xrouter.annotation.Router; +import com.xuexiang.xrouter.facade.service.SerializationService; +import com.xuexiang.xutil.net.JsonUtil; + +import java.lang.reflect.Type; + +/** + * @author XUE + * @since 2019/3/27 16:39 + */ +@Router(path = "/service/json") +public class JsonSerializationService implements SerializationService { + /** + * 对象序列化为json + * + * @param instance obj + * @return json string + */ + @Override + public String object2Json(Object instance) { + return JsonUtil.toJson(instance); + } + + /** + * json反序列化为对象 + * + * @param input json string + * @param clazz object type + * @return instance of object + */ + @Override + public T parseObject(String input, Type clazz) { + return JsonUtil.fromJson(input, clazz); + } + + /** + * 进程初始化的方法 + * + * @param context 上下文 + */ + @Override + public void init(Context context) { + + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateDownloader.java b/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateDownloader.java new file mode 100644 index 00000000..4cc9fef7 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateDownloader.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.update; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.xuexiang.xupdate.entity.UpdateEntity; +import com.xuexiang.xupdate.proxy.impl.DefaultUpdateDownloader; +import com.xuexiang.xupdate.service.OnFileDownloadListener; +import com.xuexiang.xutil.app.ActivityUtils; + +/** + * 重写DefaultUpdateDownloader,在取消下载时,弹出提示 + * + * @author xuexiang + * @since 2019-06-14 23:47 + */ +public class CustomUpdateDownloader extends DefaultUpdateDownloader { + + private boolean mIsStartDownload; + + @Override + public void startDownload(@NonNull UpdateEntity updateEntity, @Nullable OnFileDownloadListener downloadListener) { + super.startDownload(updateEntity, downloadListener); + mIsStartDownload = true; + + } + + @Override + public void cancelDownload() { + super.cancelDownload(); + if (mIsStartDownload) { + mIsStartDownload = false; + ActivityUtils.startActivity(UpdateTipDialog.class); + } + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateFailureListener.java b/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateFailureListener.java new file mode 100644 index 00000000..001d391b --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateFailureListener.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.update; + +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xupdate.entity.UpdateError; +import com.xuexiang.xupdate.listener.OnUpdateFailureListener; + +/** + * 自定义版本更新提示 + * + * @author xuexiang + * @since 2019/4/15 上午12:01 + */ +public class CustomUpdateFailureListener implements OnUpdateFailureListener { + + /** + * 是否需要错误提示 + */ + private boolean mNeedErrorTip; + + public CustomUpdateFailureListener() { + this(true); + } + + public CustomUpdateFailureListener(boolean needErrorTip) { + mNeedErrorTip = needErrorTip; + } + + /** + * 更新失败 + * + * @param error 错误 + */ + @Override + public void onFailure(UpdateError error) { + if (mNeedErrorTip) { + XToastUtils.error(error); + } + if (error.getCode() == UpdateError.ERROR.DOWNLOAD_FAILED) { + UpdateTipDialog.show("Github被墙无法下载,是否考虑切换蒲公英下载?"); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateParser.java b/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateParser.java new file mode 100644 index 00000000..ae504a3d --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/update/CustomUpdateParser.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.update; + +import com.xuexiang.xupdate.entity.UpdateEntity; +import com.xuexiang.xupdate.proxy.impl.AbstractUpdateParser; + +/** + * 版本更新信息自定义json解析器 + * + * @author xuexiang + * @since 2020-02-18 13:01 + */ +public class CustomUpdateParser extends AbstractUpdateParser { + + @Override + public UpdateEntity parseJson(String json) throws Exception { + // TODO: 2020-02-18 这里填写你需要自定义的json格式 + return null; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/update/UpdateTipDialog.java b/android/app/src/main/java/com/kerwin/wumei/utils/update/UpdateTipDialog.java new file mode 100644 index 00000000..0b907086 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/update/UpdateTipDialog.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.update; + +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.xuexiang.xui.widget.dialog.DialogLoader; +import com.xuexiang.xupdate.XUpdate; + +/** + * 版本更新提示弹窗 + * + * @author xuexiang + * @since 2019-06-15 00:06 + */ +public class UpdateTipDialog extends AppCompatActivity implements DialogInterface.OnDismissListener { + + public static final String KEY_CONTENT = "com.xuexiang.templateproject.utils.update.KEY_CONTENT"; + + /** + * 显示版本更新重试提示弹窗 + * + * @param content + */ + public static void show(String content) { + Intent intent = new Intent(XUpdate.getContext(), UpdateTipDialog.class); + intent.putExtra(KEY_CONTENT, content); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + XUpdate.getContext().startActivity(intent); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String content = getIntent().getStringExtra(KEY_CONTENT); + if (TextUtils.isEmpty(content)) { + content = "Github下载速度太慢了,是否考虑切换蒲公英下载?"; + } + + DialogLoader.getInstance().showConfirmDialog(this, content, "是", (dialog, which) -> { + dialog.dismiss(); +// Utils.goWeb(UpdateTipDialog.this, "这里填写你应用下载页面的链接"); + }, "否") + .setOnDismissListener(this); + + } + + @Override + public void onDismiss(DialogInterface dialog) { + finish(); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/update/XHttpUpdateHttpServiceImpl.java b/android/app/src/main/java/com/kerwin/wumei/utils/update/XHttpUpdateHttpServiceImpl.java new file mode 100644 index 00000000..b1bf60cb --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/update/XHttpUpdateHttpServiceImpl.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.utils.update; + +import androidx.annotation.NonNull; + +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.XHttpSDK; +import com.xuexiang.xhttp2.callback.DownloadProgressCallBack; +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xupdate.proxy.IUpdateHttpService; +import com.xuexiang.xutil.file.FileUtils; +import com.xuexiang.xutil.net.JsonUtil; + +import java.util.Map; + +/** + * XHttp2实现的请求更新 + * + * @author xuexiang + * @since 2018/8/12 上午11:46 + */ +public class XHttpUpdateHttpServiceImpl implements IUpdateHttpService { + + @Override + public void asyncGet(@NonNull String url, @NonNull Map params, @NonNull final IUpdateHttpService.Callback callBack) { + XHttp.get(url) + .params(params) + .keepJson(true) + .execute(new SimpleCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + callBack.onSuccess(response); + } + @Override + public void onError(ApiException e) { + callBack.onError(e); + } + }); + } + + @Override + public void asyncPost(@NonNull String url, @NonNull Map params, @NonNull final IUpdateHttpService.Callback callBack) { + XHttp.post(url) + .upJson(JsonUtil.toJson(params)) + .keepJson(true) + .execute(new SimpleCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + callBack.onSuccess(response); + } + + @Override + public void onError(ApiException e) { + callBack.onError(e); + } + }); + } + + @Override + public void download(@NonNull String url, @NonNull String path, @NonNull String fileName, @NonNull final IUpdateHttpService.DownloadCallback callback) { + XHttpSDK.addRequest(url, XHttp.downLoad(url) + .savePath(path) + .saveName(fileName) + .isUseBaseUrl(false) + .execute(new DownloadProgressCallBack() { + @Override + public void onStart() { + callback.onStart(); + } + + @Override + public void onError(ApiException e) { + callback.onError(e); + } + + @Override + public void update(long downLoadSize, long totalSize, boolean done) { + callback.onProgress(downLoadSize / (float) totalSize, totalSize); + } + + @Override + public void onComplete(String path) { + callback.onSuccess(FileUtils.getFileByPath(path)); + } + })); + } + + @Override + public void cancelDownload(@NonNull String url) { + XToastUtils.info("已取消更新"); + XHttpSDK.cancelRequest(url); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java b/android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java new file mode 100644 index 00000000..4e44f4cb --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.widget; + +import android.content.Context; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatCheckBox; + +import com.kerwin.wumei.core.http.api.ApiService; +import com.kerwin.wumei.core.http.callback.NoTipCallBack; +import com.kerwin.wumei.core.http.entity.TipInfo; +import com.kerwin.wumei.utils.MMKVUtils; +import com.xuexiang.constant.TimeConstants; +import com.kerwin.wumei.R; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.cache.model.CacheMode; +import com.xuexiang.xhttp2.request.CustomRequest; +import com.xuexiang.xui.widget.dialog.BaseDialog; +import com.xuexiang.xutil.app.AppUtils; +import com.zzhoujay.richtext.RichText; + +import java.util.List; + +/** + * 小贴士弹窗 + * + * @author xuexiang + * @since 2019-08-22 17:02 + */ +public class GuideTipsDialog extends BaseDialog implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { + + private static final String KEY_IS_IGNORE_TIPS = "com.xuexiang.templateproject.widget.key_is_ignore_tips_"; + + private List mTips; + private int mIndex = -1; + + private TextView mTvPrevious; + private TextView mTvNext; + + private TextView mTvTitle; + private TextView mTvContent; + + /** + * 显示提示 + * + * @param context 上下文 + */ + public static void showTips(final Context context) { + if (!isIgnoreTips()) { + CustomRequest request = XHttp.custom().cacheMode(CacheMode.FIRST_CACHE).cacheTime(TimeConstants.DAY).cacheKey("getTips"); + request.apiCall(request.create(ApiService.IGetService.class).getTips(), new NoTipCallBack>() { + @Override + public void onSuccess(List response) throws Throwable { + if (response != null && response.size() > 0) { + new GuideTipsDialog(context, response).show(); + } + } + }); + } + } + + public GuideTipsDialog(Context context, @NonNull List tips) { + super(context, R.layout.dialog_guide_tips); + initViews(); + updateTips(tips); + } + + /** + * 初始化弹窗 + */ + private void initViews() { + mTvTitle = findViewById(R.id.device_item_title); + mTvContent = findViewById(R.id.tv_content); + AppCompatCheckBox cbIgnore = findViewById(R.id.cb_ignore); + ImageView ivClose = findViewById(R.id.iv_close); + + mTvPrevious = findViewById(R.id.tv_previous); + mTvNext = findViewById(R.id.tv_next); + + if (cbIgnore != null) { + cbIgnore.setOnCheckedChangeListener(this); + } + if (ivClose != null) { + ivClose.setOnClickListener(this); + } + mTvPrevious.setOnClickListener(this); + mTvNext.setOnClickListener(this); + mTvPrevious.setEnabled(false); + mTvNext.setEnabled(true); + setCancelable(false); + setCanceledOnTouchOutside(true); + } + + /** + * 更新提示信息 + * + * @param tips 提示信息 + */ + private void updateTips(List tips) { + mTips = tips; + if (mTips != null && mTips.size() > 0 && mTvContent != null) { + mIndex = 0; + showRichText(mTips.get(mIndex)); + } + } + + /** + * 切换提示信息 + * + * @param index 索引 + */ + private void switchTipInfo(int index) { + if (mTips != null && mTips.size() > 0 && mTvContent != null) { + if (index >= 0 && index <= mTips.size() - 1) { + showRichText(mTips.get(index)); + if (index == 0) { + mTvPrevious.setEnabled(false); + mTvNext.setEnabled(true); + } else if (index == mTips.size() - 1) { + mTvPrevious.setEnabled(true); + mTvNext.setEnabled(false); + } else { + mTvPrevious.setEnabled(true); + mTvNext.setEnabled(true); + } + } + } + } + + /** + * 显示富文本 + * + * @param tipInfo 提示信息 + */ + private void showRichText(TipInfo tipInfo) { + mTvTitle.setText(tipInfo.getTitle()); + RichText.fromHtml(tipInfo.getContent()) + .bind(this) + .into(mTvContent); + } + + + @SingleClick(300) + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.iv_close: + dismiss(); + break; + case R.id.tv_previous: + if (mIndex > 0) { + mIndex--; + switchTipInfo(mIndex); + } + break; + case R.id.tv_next: + if (mIndex < mTips.size() - 1) { + mIndex++; + switchTipInfo(mIndex); + } + break; + default: + break; + } + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + setIsIgnoreTips(isChecked); + } + + @Override + public void onDetachedFromWindow() { + RichText.clear(this); + super.onDetachedFromWindow(); + } + + + public static boolean setIsIgnoreTips(boolean isIgnore) { + return MMKVUtils.put(KEY_IS_IGNORE_TIPS + AppUtils.getAppVersionCode(), isIgnore); + } + + public static boolean isIgnoreTips() { + return MMKVUtils.getBoolean(KEY_IS_IGNORE_TIPS + AppUtils.getAppVersionCode(), false); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/widget/MaterialFooter.java b/android/app/src/main/java/com/kerwin/wumei/widget/MaterialFooter.java new file mode 100644 index 00000000..d134f1e4 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/widget/MaterialFooter.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.wumei.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ProgressBar; + +import androidx.annotation.NonNull; + +import com.scwang.smartrefresh.layout.api.RefreshFooter; +import com.scwang.smartrefresh.layout.api.RefreshKernel; +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.constant.RefreshState; +import com.scwang.smartrefresh.layout.constant.SpinnerStyle; +import com.scwang.smartrefresh.layout.util.DensityUtil; + +/** + * Material风格的上拉加载 + * + * @author xuexiang + * @since 2019-08-03 11:14 + */ +public class MaterialFooter extends ProgressBar implements RefreshFooter { + + public MaterialFooter(Context context) { + this(context, null); + } + + public MaterialFooter(Context context, AttributeSet attrs) { + super(context, attrs); + initView(); + } + + private void initView() { + setVisibility(GONE); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); + setPadding(0, DensityUtil.dp2px(10), 0, DensityUtil.dp2px(10)); + setLayoutParams(params); + } + + @Override + public boolean setNoMoreData(boolean noMoreData) { + return false; + } + + @NonNull + @Override + public View getView() { + return this; + } + + @NonNull + @Override + public SpinnerStyle getSpinnerStyle() { + //指定为平移,不能null + return SpinnerStyle.Translate; + } + + + @Override + public void onStartAnimator(@NonNull RefreshLayout refreshLayout, int height, int maxDragHeight) { + setVisibility(VISIBLE); + } + + @Override + public int onFinish(@NonNull RefreshLayout refreshLayout, boolean success) { + setVisibility(GONE); + return 100; + } + + @Override + public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) { + + } + + @Override + public void setPrimaryColors(int... colors) { + + } + + @Override + public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) { + + } + + @Override + public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) { + + } + + @Override + public void onReleased(@NonNull RefreshLayout refreshLayout, int height, int maxDragHeight) { + + } + + @Override + public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) { + + } + + @Override + public boolean isSupportHorizontalDrag() { + return false; + } + +} diff --git a/android/app/src/main/res/color/selector_round_button_main_theme_color.xml b/android/app/src/main/res/color/selector_round_button_main_theme_color.xml new file mode 100644 index 00000000..16fd2c79 --- /dev/null +++ b/android/app/src/main/res/color/selector_round_button_main_theme_color.xml @@ -0,0 +1,24 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/color/selector_tab_text_color.xml b/android/app/src/main/res/color/selector_tab_text_color.xml new file mode 100644 index 00000000..b7628149 --- /dev/null +++ b/android/app/src/main/res/color/selector_tab_text_color.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable-hdpi/about.png b/android/app/src/main/res/drawable-hdpi/about.png new file mode 100644 index 0000000000000000000000000000000000000000..53886015c75f23e380b259c0d7fc1e200c572beb GIT binary patch literal 5305 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/add.png b/android/app/src/main/res/drawable-hdpi/add.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c4d4e3bcd29bc1e00d9c13d299ab3da6fb8846 GIT binary patch literal 2642 zcmeH}=~I(e8^%)z_yiRbs0a%35F$|!v;wjk44?#&AS56~wvi=(lubaEusu)##U!L` zN&_w-l9WX)h*$zxQ7C9BVX-U?3I>FTL`W1_!kbS2g?{PG`{A53bI;soxn|Dwy9&<` zUAC+3R)fJ{+g%CHUW&En?*XVP=6c_TDi};n$JH56P6=FKxz`3zc3z&0t#dCm-Smlmd8GfVXfv1xy8MY@@{v4!&7wJYR<(xbE5s5}TNP~T?#k@Cms-9u4L zkSWmu6u6qy)ZT2Jr6w3gjlboXq&M3kM)HKUB}xf6Qhc*D+)fD)(DvLla)jZHG%Q|4yWC`f=YC=( zPg|?x7$E8nMWn7cmKQFl91!K0<=Sk`5h8|$S%APUOqIPa8;raY^3ebQdypm9i_2gT z`x@<8zT#d^XTneVDFMu*wp#iS4BCdjt`ms>31jbkses~Kcv$#IJ&xiT=iG`my5gmdLve2?DlT>KSuWS=^Vt9IJ{~bhlL|nU3Lyt&ag3)lb}G zBoyvM{WCd5ecHT{eoD4C#4_xVQ8vgG<{vY?@wEP^aBMB_)N;KKM{nA{xX`qa%nxYB3Ax=v>V^bnms@K7?`2n6Ev&|Vx3r*H z94RszJirtV^4d<$_DMH8x zBk>c(t5(j)EY1iGIKOYFZ$20=L1Ae8)FV)ZXX`F>ft}apWnij*Xbgp~V=IY~7GV4B+}gYvm-p-WquNgU%&2Whb|~32kSvyPh9@R$NT3>Q@KB$9he>)Y?K-YjKri0 z_11^>WOCXA&Go#8zp+fa8?_(*?jXYEuSUP}_-Q1zNa^WY6|ShMO!UMv z?}^4H_8wo}&ckWbLdT#IH)hPM+w11`fL6+Z9MV~0?e&0d-A5wvZCTXaRWp}O4>#_r zNkdD02DL(y?v~{r%2Vx>jDE;=d)TL+yFDDTv6Z$Bue&%eL5D523xI;k6) zu2`p*N-2fmw^#6hic@Sk`8u5;`L85Dvvu1BzQBeE_ha{?Z{P;I|ZjFRY&P`A3BKc875Q>+_w33 z%|=OS*#uiNDz}=QPC>rSvRU_bZ#_pZ!9Fj30dM)!FN0J=O(0vjFv`0~j<{q+i(4vtv z?8)6*`pIE_c)%p!5)LXlQdVvz+Bny}oa7!Sj;|{Kr+eO9J_i!~3IG2;|C)Imvp6{0 zyk9>qk~$w0d-meHSu;N84>;b7P5t)jj8D0Hi`c)pD(N4)!-)KZwP9aKv)^^El!w{{ z@w!z3fuVo@NOLB!Z}ch4@57K&T7%qCaG#jLNz}#**c+GX`}Rm>Oa2O@QPU)umZfa;A5Ul21ofsTK3renv{W@#Go%kIaaJ;AfGOEtD>L9f zw5ex3_khH%7 zQK;bWl*E^xrQp3oh!IACp~9yjGP$C>S#+II0sD_N!?!Lq$YXopKq7eNETzewddq1` zsad`vp|~pqsH{5tS?mnM+rF8Wa1^4sdsM6?p|e4jBtB&j0rqgPFE(ryNr<>&-8QEP zPJ@~=nJfS#V5z#oL?z(C9O7aJQ4ypxaq6+QU%^MEd96WMg>ne}d@B|Vicb4=qEYiJ g_*@?SX(jRXWM6WQA<=6crO1jf*AqnN2FGCNe?1ngDgXcg literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/add_device.png b/android/app/src/main/res/drawable-hdpi/add_device.png new file mode 100644 index 0000000000000000000000000000000000000000..be4d52be3edeccabda3b3a3d2fdbf566c4e7f0d3 GIT binary patch literal 15126 zcmeI3Z-^9S9LMJ>&pJ6Rk`$2~Rs|(z=ijcoGwiOOyJvUdde?d4-HXuKnP=}NcW2g_ zS$FSV9Uf&Cm}DP>gzJ_TSvIyH6Jyy?GXP zXMWH3`Tc$~pXd4gcHYc^!L84CcP;CpD5|@^FEs>@wEKO$6aLzhlXu|Zi9+9~O;HP; zcE26ek$0C;lyqJn9&tv}TV&PD2NliCfM7XafU_wowxL{5)ZM_LGhj?N;(^;IPX%aQ ziwAau(_Ffc1mk+&qy@H3ZXH%9cdL>X*pTRom1P(p4;+Oq=W~WFm*W91t_;uJVKzW} zQ=HxLK#!Y{9!U?*77_?CW!anmvFakEXzy4*G~T$6OVp1bAs=JPF6+fMIZh@gtJrKdeSQ2^`^ zu+5^Sg5JIGR#vvUdq>YU7H3u@S803gpscrXbCrslw-qWY6odCFCoP~jrZsGuxkP1` z4b~9S$t1mIhi+(Q$zB^{(b9;-Bk_qp5P%wDO9R(DTX|U<<}rjBO11X4W^9 zoHTQ$1uqLE#2DLZ*yrVKGP&Qd9mP;Ve<}e7g1WBB(Tp0F1S!L;k0==?k_`bSDyj;T z0a0Gegm^xj&3X{iX}^0@=#;4z-9o8`)?nzYBxXcj6q%3!vWylA@r;sDBTO_L&8`63Uy^K8S5*oswdKo-w#5{-Mk(0cU%lkz=ge^K<%tum-lW_rX?RZYA`9E8uTO z|H}$A_O3dv7-K+7u(fSl8<^XoRhDvgJ=NMkbN$8K{~sCFF5E|oS2M6@G>tVfSLTnn zHJB@U^CJQWKP>P5R$cuv>N<*d^~iBEn3b4=S{D9Bt?56RM7trSd&_dF59bh0k^Hk&>-HQ#Ms* zy>~s#lg1rA%&15#k^}*QHwi90A4Da%5FmJy;KK7kRDufuf;R~+JRd|QxDX(Cli@s=hq;H#M>_zvcRKbH)^_cv*^ZzxSsldCCeYMP?%{soV}QB;wm zs2jT|N`8l;mY8qtJiQsto#{{Y43{t6`sw4BH}Q)*uMFJSwSUt~AARuE#uWoI3orG| zB;I2$yngA^ebWoSD@xO^B~O39oge*u|GE{ct{-~)lXdpF7hjlq?DHot9JqUP+0>5v zy(coGp<}PyKAXS4xcfup*)InJ@v~stG~P}Y&ptx9GU;- tp=XXS`eW6!@x#?SY~R$$dAH_MufB13Cb;^{0(di2fA7}RiA}rq{S83&cEbPw literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/add_line.png b/android/app/src/main/res/drawable-hdpi/add_line.png new file mode 100644 index 0000000000000000000000000000000000000000..5736045918fc99c8c8c73cc4590178088c321b77 GIT binary patch literal 16099 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 R4xs-c3_CP}(HN4n?+??c4~hT) literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/begin.png b/android/app/src/main/res/drawable-hdpi/begin.png new file mode 100644 index 0000000000000000000000000000000000000000..3b88998e65eed881c4ca55d28f0532081f7b8791 GIT binary patch literal 158191 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/category.png b/android/app/src/main/res/drawable-hdpi/category.png new file mode 100644 index 0000000000000000000000000000000000000000..496f8c045190680db0d39aa67ab865cb50cc3ecc GIT binary patch literal 6520 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/device.png b/android/app/src/main/res/drawable-hdpi/device.png new file mode 100644 index 0000000000000000000000000000000000000000..90278fc7c9dbb576687c2f490f495a839c966122 GIT binary patch literal 3353 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 IE(e%@1K#P$y8r+H literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/group.png b/android/app/src/main/res/drawable-hdpi/group.png new file mode 100644 index 0000000000000000000000000000000000000000..4e6645601622b54b5c18ee17c6b1ec8c9ef6f64b GIT binary patch literal 7278 zcmchcWmFW-*T)xJU@2Lo77$n(>6V6tC6w;&Mi4|&5SFD&7HKKzMWh5pdg%p}?(S3? zY5nti|Ga))%*>hjoHO^%J#%L6%r{m?OO=#}jtBq%kUmp`>)p55{|X5IzOFQ>$^!r% zi#>zG3<9ivTLxu5Hcb1MyO&4U$ zAox9MB!whUuwSFJnbRgU8rH+f!wvn2jgBXS!zszT&m)0&EO8OfN-Ks!F8t0NaL32b zn;Je1AkQ;c@@O&F5-y?+?Xul4# zW~N#Bm{cMDwJfBGmS06sWqIPoQ}Zbjn8DAopEtNCv7=-wv!8y{PYs&msPk@wPQCd| zd+Y43S;6b*1?nY7Qd{CXzKGzyI0&*^@?7>Sg>66HWoUP~xQgY) z18?)o6rsHz_1sD*iPDB>YclmVtz4>TDN?Dn2j5xI8`YCG6_uJ0Bs{B4E=11lg!p@a zn~$n)S^}>nPNz!hE=~W8cDtbxs^+!9hEU?M2XWtnG?b7bDiSM?c zM?Tzf!E`44m}Q88=;r!i3KQL6J^N;eo9{5VTVO#sB;}%8qNiFd``wNB41Ng`b(|Ieu*os1le!upS~m^5eAZ{n5-CwZ$!7%i3pa_DXt8zn7oiKK*60U9QcP} z7x&<;=z^)K@NvX_kfSCqg(Xdi+}(I{)lr4x>kPiKY!xXLPpYhO4^#|JGF-ouO=@hD z7h?~P-!+L>JTCOb6?XWgf~tGCS#{{dRSJ&8ofCT#G(CziL5%PIrc*S()C_*Y`vRQ3 ztxf{nRj`U|zMh=dBfs z9EBpco7xYi0NiIb&E46g$e00UuN#qtso_$Ii8kO9iPxLB!AaCOu2FNBQ^2tO)iJk(QL?cZog4Dv z4DD1ZqO5T&VmKG2iN~Hg>vD`e)b7 z1cKqZlPCv_Jwqw}_CbBt3GmUwK$=|@5q%>bX*J1=lfMm{Kz66utwmL))sG8<^6G3n zr7s(c{kJ*!&5A9By!SD6EV#DfG@j7(gMVJF8M3+3W#LKd^+#ui}2x&hF^ z$Bzv+DJ)RzQ{(9OqG?ssBmZ?>fA*O4K8A=bHB#a2NcbPgITb=bxI?}!U zep5ml9@*%()v=p6Aryg(ILCm2##%w~wNT{QNjt_@0N`Q;iB3p>DUjm&NP`}5jr+pR z`qaVAe)u+)fR$yWgl#V!@QfK_t*G^qczM6iNd~yPo`LDWLwt^V$sevj55?>Y&2tyP z*F_}h$zXKUKPZYxUy`h|U@{5@xotE5&JZOA5VCyE5>w;(@$;~s*^A!78LD;@bxHW; z#?{WR_I)#X!e%)L%!qdi;BIu&v6&!;2iUcR19QnlxLgP(-OKse#G_*J&sXmm zZ|dnI`M}U7!YU2vMm{2=Hy{=n(MA*9t$ysaGU8YjoTgJ?a-Furs>Z62{By8{1QU9l zIGZ2>x>Q8$up|slmov2W-av};p(*hJWuU^>9TFqa`A#vgkCM0v)j`^cGi2KAs$lY} zOU#ZPVWzz8)-n`~8+OAcG;kIP{?Z12&yGEqu3B$ZGAQNyQ0*!bzVXdN%vdiGe!piL z=QnxZS6gCmK0SDPJx__VC4jZ~q}!ye3fyH;TmL%PK{Q@x(RbF6mYCnk0!x_DBEF85 zdkf6Ep6hAp%uzfONz7ub>k7(k;)>-OS4S;2TgKxAzI)rw1`rlcfn!4T3b+NvwNZ=J zmK?cOla?sC*02;J!^jav;OyyF^q;Siu-I%|f%BN^dJrp}v$kuDpv1n#$fWL!i;-e6J= zBC=EG77nTQ_<6Fs`=ja(`bhQVSUAp9btFU~{uZhNC}jr30i`VQL&L zNeMJj=P**(^PE0EfA-AoFiyj1eMX@*SvC9VA$-#csZVopGgx%BNE^eA!)!1Shz23q zZ#>)F8nhXT?4^;vzc(JMIV~_UOwcZ``#zo#IO1#(i<|oiT!!(`Uh-fV;Oze-+2_i* z`6SrEvD3eR0)Go{u_h(fSH3KA$ecT@ynX(ivhx$mJ5c`7U#h4(eEI;3SU#D(Ij9+) z%`)a>mud!ojg)J9!ge~Q6-$iy;;&(LWPkYe1!nlHTNP|x9E0WTdwmOe_v(kzQdLix z-9%&Ar^c42P6d7DMd*1K9coPR8Uw&kr{FX-oBO11#hWm-w-a$jQ*C*+Wh8Mwg>C)5UgfRZ&3_Uzz&At@eJ;e9aQiktsXy-M=o zIbV^lO^w^38^>%_?t^dqYCFs84-aF#D}@(sF0Z_pV+y?~SU4`O;<4rxLW&pN#a?g3 z&OM=Pq-$Iyeu_M0hX9B|WE%}Uk`4(XBf8ZC!|8X5ucz z7|+uwE^fc`JRq8gMhQ~Xm)hgS?Y|!A?X2fuQ+B~JhoHl+$@)uPmU2xfd?mVC1Tz6{ zUG&oGC|JI0STFe_qa@p7)nb)LInurxO<{?fzMo*-TUed-9{D=Ye~PtiLW^zFhmV)U zCN<>oGfj%s4bYeuT1T3~Ayz-KT9^Ezc5YIT_2#6}5Z8njzA2LH@Mw2BuM55#`rXi= znMJJB-L)BW3gi7N>JxhAu{)QF(|-PU;Tt|Vk(78K5|re4$77tMK>?rTbOF~UW*pYM zBuoqDC52{RPwEG?vk`T8c75E3y`*yVRaGyk?wK>SQFjn!qNFe7rX;WIS{6d^xL8D9 zmrISqP*JLd$U?MxXK?8r#(7Hn0$bftbY@r*Lb<7hx?H)8;_zz|n5O;I;2wYbQb2lT z^7(q=CyT!HyYXNR8W`QsN8yB4SkjT+)pGfS7Vm&7xK0T1XwpuXM(0@*Aq%pcCY547q5rKz4lu1M zs%}5nJQk^$mS|b%YT)_R5}bW ziQ<-}#0h#^D4fz^i8s=BMoa4Y%mEl<72$ZTr$$;E_mvFBG0ph}{Z%6C&wG<(P)S0C z*XNQ~p*cjG13rrJ0ZhLlxYTN);gOZ4LJ`WbBIw)jr<+_Li-)%vMu!rVw`;||W>p`P zP-lMIME}tdt<$24P{wu0g;bO78q>#(POsSIo*e4xqn-^@z>6&fhwvO$qkmb#{}D$) zpMMk?9R?H%z9K=HQ$Uk=f=rOpU0)|kuY%C*+TdfUo)%yN+xXJ?B0OOqRa62gX?{S< zcT{0}Oed&C!j`ev(H^E|#;adr_5fQ;4hZ-%RyLP&d=NO?QRH{br(iPOm~8xa}!Hi?7OiX9a^5T8lEY@uVYP56EL# z$t17EXBzkHc;&gYE^@%D1}A$r>6J?L1>yS-K7S;b6Vz!)ZN<}983pq=W0U_J%Duv4 z%x8R+M<5g7#&1^g4^F*%KBPB@^Wz;EdHV;omS&0=Wv80PLKaLtH8osaS}6ZX%Z{{7 z%mT)xts}G|i3rXfZ?j*o{D`$gAf*=ENL4 zoxH1eN0d`xR}|%E8CQ>dOv51s@{#A-46vB?E`%z(ZLXxl+tVz4 zh1+=py>dQn}0%=6jG29K}t2VjydNb`tC5XqbBTTQ6?9D#x&s>u#3p z{V{p>7IK;izRe=Dv;@U-rc!gAmymz`{ug9ay^Z_kxk@|HEjc)TOGzN1ir0uV2@wF; zTrlCOJSK;GMn7Sftz|cPd+RQ7pn@2BiD&gKWP1=*N3HVYY=M%@{IQ|U=;*F#IVK^H zZ_9*T-cW4)KKu4&kR`&=_0vCl1JT0|AZsV07RL?F5vDKK;U$(8=+5l?%lxelg1RG2 z35jeam*loh`Byk~Oaa$u%HwY+tglfU2g4f`XIqUjB_5_y5MLQTsY^~+3&IR3-k-gp zJT7}7wSSmr)t+2U&4uE-fT=#=N1Bns=&W{jQ}|<8_P!7mc4zC!QE6rm|M6?dW1!qf zO$=R_&(brN71mrV%@j~wGMg0MuIy(kXIJZTNzOo;-lm{E5dA*6zc>sE=F=8am922n ziHH9*#~2lA6xO3ZRA8fn5~ascuWl(~1pZFCObVTY;TqBZC4u7;glSaeB+?lRP376#1_q-VvCoN12Y1(}1Qi*4=gaewR!_R*cyfjlFl z<&dH><=YOi;@!g@n-&|(S>iVDe&H0BVqXcgKd!nRLFb*VV!l&T^SOV}1#4};EGIj) znlbjPH(WNF%degWeDy{9{2N(5nkqV@fM1Fxk*P4YB6cdPZr==4jFeT)sf8s)_Rx1c zk^KAoJ25|>!5pRzb7vJF(V8}F!}B14Da^&7=jxvWXbkin`|n{od{l=hCFD>n$=Dd& zgmn(I-bnexev7`qyB#pPFxXk%zq9D3(>UYSxW2ArQ<1dDOJmwjxeugLvmX(55AWt6 zW0mt8hyBjO>W=lNtXx^9^*g-hZu(C|j!AmD2UGt%spnk6+34h}%Fe&F$$eLzBVvb!N;WeyZ5r@;Hq@Cit;&-pwqf=rO3OaX zefIV__)TlCa2ULcv@~%hwq!=}K4UOfo4s{Xa3WzM*Zs!;;5*74W17gsA_FG)0?XvX zpI1OarFkD!>&?aY#@dWs00X7EBV+AhfwiclGNoS{`dCQDPZ^$is~!#YT)*EB5bWQg z@|i|@#W9vK&;Ncxc>j%_w=+(jE@3M_f;FxR_0cKETKt1`OAFrtUAxWEZ*}-L!iv@+ zZKOQT2x|28=5Q;qg?QiE9n=eZxW@4vU(sCMfoZGCU7j%i{pQNx2I+BnV`BP4j;i7Q zsg5&QkwIM8GUJ>;9yO|s86q+`omSNuv#9T;W=z?qs9pN7Rj8Sn7&-74)^kB$gC3jt z9E*Nmlg&*PsPCOSdMDBvm2Lh)9vNc-|B2?$AxM9k9##1IjBi%=lcKz#@T(pM0sKRD ztLCNc-G4+b!OR0e|6sAQx+S$s1eSL%D%t_vG@-RaI`h1f`2s-+ZrVsu#huNr4O9H1 z(C8T12#{s$<8&Je4`Sv8v*PGwE`r1>`RWm~-Bj`~%SFF*1GJ!$hT*jSVJ;82&m;{w z3imubk)nkHQ|}12yA`eUU6~nGX3c;s@1$_vY-HICGDf=YBEK>e@=S{-tPO7LbU<^` z+`+}<&6d*iDB`QG&JJ=lH%<(XPXCp;3xOWP`pTP1!0Nh{kXz!%xGC0XT}SOzP@X2| z2R@|6qaIUyY-G!Ig6#?n%%_w!u_+&!b%vWy^uAkyDxWRQ?BWYj?+;LYXeol*dPVmT4As|HHZyHJEX>iKP7#CR)oG*fp@o^Wr*^Wm zU7cK>c%PNgBdj>vY%@oVG6Z!FVwXvH6b9mNEMDUOh`PkJ(sxo$SsP-;Zd^xf2QqDm zI*`N@5LrifYiSPm;F2N73~Y0w1#J`8-XHZ8iY;EW{q$jk`B6A3SoaG0h3(21xOQLs z_#s+@{gzQ$_ze{0>3qeFq0{@rJlVi>O!mtH3F7sT14O_)XuA^RVH<{qTo#?S$=ate z1)t`NwL6YgpxKq87DNrenSR&4i=&#Sekf@w&g8W~VI;m$M$3e^b4t zs}30nw<5c&+|y)#(E)bg{);EqA5=D7r_4>KGnLQPp7TeX>xjqZSf@#9{-iNr=8-kV zpFL=Qul6NKm|;k{j6h@izZgCoam3mmJFpJF5#9o4%75AxKeCS;0CY>O!{m$VgnPjb zrCIg4zJT-nen>jpRNp^3qhtra8Q;J>(fdMMZzDzAm;`19YmLc|&xMR-2rUdSYqrO0 zn2!h>Jo{-1(X@q&*@M<-V7mV4wJO%VHP(H0Oq{|V%KqiU-BpdGRCGvSZoT4f2Ne6B z(k>SAaL=;-_y-ScN_pTpNcohX-1Ytky@uv7J=?JH&OP2Qk(b<3AN3%$$(%@)JK0v| zR;5M4bJJO>3F>B!-P+Y1=9;{73rYj5ZkSI}(Ka6^#!Ual zUct1QGXG`$yr2>|O~k0$fXgh;6)m*D3vMH-`buek7L-=tWZ1wQ^Dc`|LJ4YC+%@r% z-iKbW7LfMR_m1uyKQ%^732a$2T~QJrdAl2@8K*HHVz9##_uD7pjS_fqoHskm4zgmu z_Vj1GPO|LcPbv!BD5ww)t%;^UJ57~)G`MS(lRK!A-VgYv3-lxAURfG@8uR-M=gXpE zCSBJwqMXU_+GEVtVX}=`&CF@a58nI@uWcbY>zkJRC(DLQI#2va6%3e7)Q1RobEPn` zab0XWz5II#SLRgJlIkP<^Act?t{F<=+2H!=s>*wn&4Ok8+XsqegC8a2I7;9|8v=3m zz5Pzvhti)zEL60C=}&Q!@70`Gk^)_n}N3@DX(7}6~4uO7}?*ErNxAK-ocfwX5S1j*! OM8Gp;EqIlp4f222K!JAv literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/hide.png b/android/app/src/main/res/drawable-hdpi/hide.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fd6047a8a791c8032cc7e88b7f2e8569d3dad7 GIT binary patch literal 7133 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 z zL5SrmWC~b+#jj8RQFf;A1}rYhkmwMCXgJ~iJ#hqlJ7p>&LJ6a7k{$Bg*r>Shi1a85 zSt!I-7@IYSB@s(AR)|oc3~V{#O3$^D$U>rvBm+eYLLA?+lDKO+;Bb_-wo;50lQ6Iy zQ_+Yc4S>Aia5!{kGlhT#)p#g>f->j*>2I|;z4URO^3{Ie1!8CIm2MNtsAcwBj2t)Bm><6s!w)u+2 z06y`66}$=@!pWv4UcyTAYr)6o3#~a&&(as~z zyj=P0{J48RIk|`X>V%VbxGI1C@?kh`chsGBKYPBa_m{`=2Ezu=W3Q%*ZykyFJN^W@ z++|(ZOz$y0TaptGK76{h{(jq>%0Jx_cBWq&yRCoE`{NhJA9_23`z?EOW`=Z^qVDYL zcXz9!{U7RHSHo|SBA1241++A-j^8MlC+V=TVeYeI*LHN`Cu?}IIrZDBKq`S=7%ow~}m)<30at>;zGmdKk0jXU-Z4=nN){ozCX73pd&&Iqe3_seOs1TR=Q zcc-oUgY1`L^SzSdl!d0C;Ui%9Vui0jE1o%$APxZUoJN4-Ec~zd> Z(LGU0?EZFJAq;}MC*!lvI6;x#X;^) z4C~Ixyaci{0(?ST-3xr?ui8BihU)+S2ebFgU%eZM=C0a3XTy-7B()Y~2vB_fn*BhlA&Pu+%+fK}1y{BhKSvN2O%1eU$f*HL3g&$!0 zlj6|O&3p6jXU3AvdOJS_J^Ni;!Tgg$?8gknHa2#acMqjE%=^eXd);}X+#Zb`(_d_9 zc5e^x|1$T+`|qvWjtDxN<_j73-6}Zu__>JgaqBa0y7qF`O-wksE5vnyC-;@;s#6Aj zQ!cL0zHXu3ar*X$eRKG>^6WJRMthK_i(`nz>Do!5(+?Slv~X{^@JQ#KPWRf~U~umK z{VV76CZx#~sn6BFH2HL4>aU;w{(Pw1JZE9WiK_FGPq!bK9>S#LcEB#i_1xzMZ{-91 z(nfL2)n9BL9%IxDcbLd`hDj|*$DwW3`sD&b9$ODfEqiI1OMCZ~x!6EV`(nk6Uitl;_V ztJQw1_`+qJ8zx>_aO~WdkgHqUFZjFV?p^z9yG&xmOb3w{$&8ZXVzy^ww>@|~ z+Jh61dpNH!E%$jK;9&h)D k{r39u;^zopr0BsKRT>t<8 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/iot.png b/android/app/src/main/res/drawable-hdpi/iot.png new file mode 100644 index 0000000000000000000000000000000000000000..365f333eb43e6d5887371afe5323af9898dc40f7 GIT binary patch literal 12468 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 aMe(YsOJ0ZTqWhYg0aPDrDU~X`2>c&ASx71X literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/logo.png b/android/app/src/main/res/drawable-hdpi/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5daf5e036f3b4f2b0809428f7a802498bfabeb GIT binary patch literal 3329 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 IT_X1X585i=ssI20 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/mobile_phone.png b/android/app/src/main/res/drawable-hdpi/mobile_phone.png new file mode 100644 index 0000000000000000000000000000000000000000..042f612a20f8a50e7fba6fc241f5d82adcd0b820 GIT binary patch literal 5482 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/name.png b/android/app/src/main/res/drawable-hdpi/name.png new file mode 100644 index 0000000000000000000000000000000000000000..c84024bf481f99c5b5facbda401b46ce697b9f68 GIT binary patch literal 5169 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/no_wifi.png b/android/app/src/main/res/drawable-hdpi/no_wifi.png new file mode 100644 index 0000000000000000000000000000000000000000..ee5f41cd7829f1cec974be2467cd37997aa846a0 GIT binary patch literal 6379 zcmc(kRaBH;^!I0mE`dQ1L}5S}>28UUkU@G7X&AagLK=n!sX;&*1VOry5|A9EhLY}3 zDM6(Bo!@)&UcI;f|HTvQIeVXHpS8}~dw)MCMoUAPg7hIN005v+fh!_#&+q?T#Dute zrG8Z|06<@-qWJukkLjNrij+sXsr`3nC&O$Z%_>?ktDsh}Ot}*ZpSDj4@-B9_E>_<2 z!CMNpj7+Om|5h4eol~7dMlb!UvLiZsau{I3+ zI$N!EcfWK1A9`fKT-{p!)g?#Rme@mX`DW$pneLMA3Dfg?+OYfddO)zVB2XI{K!8t` z@wlK9pOhFPB%=rfD*i%otZD)!!_Ftw+bjxD0C4gP)r{NwRIux9sHvbf3=pI8sYopt zXMgKSQ=QHMLG>1nBRVG4Qk2@$& zZ|_klH`EG>P?T|S+5eS7&jCe`57ta_>dbIv$}6<4IJ-nkHYSATxk$2euEx6rDDrYO zn1*?z(-TB-OXwp7Q^xy2`8SB_v$Wqa1nn)zFhsv!fcLDM*MHx zyzhu8rejCXEci(Y7o$ZcX|JS42h=8M`!|*`lH`(e=e_`IsilAV zqCZTH^zVLgmIX*Hh$M#iN*oJ+eP~I7K7ycfu#~{WFuSL7rwN{|Ka&80mK%n&u;GG} z#{zWCIvGs5PWFJt3KPLf=P2rCOfJ~gMEyC@@sy;tb91H)sX^dcvhxD0@70O zC7gb@U7hm=?dj&1Bs79=0M<6e@2}pg99%l@Gn)${B&c$w&qTiJTrmrBXmIV zmn0HBA7)1Z`22#aW9H%fg9lWHEdVT@WyhId@8AX}5go{x`;Gn8;PF4_+OnXM*>`vr zbd^yzni|3Abb?(lpsBC6>!IT`u*c5gt`04IzjP<77qSPijVquk=)i zQ9jC<4LDiv^pQ2ACVjE-Ftce4uC_;bekS`Bs&$h9)dpas&3ccuQiF)sB(Meup zY=*Y-ok;Qk%@A>J5f_ajIyo8vW2;5(d+@4yTk53wLSpqRqpuSTn( z;O$uB95`+Y&PkqAXV4L=3_BT{pC|bf(v{IT^*PU>Z&B3kV8L<_oNwj`>HuHF`}^$p zJ|}u>T(E+pEk0UI-MJUqBar>O0hMwN7Q5WEQ0Nj%!=|{^#6U#6OU`)h z2O0(1-2?o#eK+$+x9*N2-F02abIW0sF$A@wHaqh3-#)(2*^kl~ zlSt}#K=exg-w8h2TYnMt_f7)SFJn($HYRM>O$1H5tvbvky%nkCHaQ$ zrY_V$-PTu39Mb9PydJA1bDusr_6%61X|i-*bx9C)+Ea6V9{%W(;uD`I?40hU2tt?S zsHAUG&Uqerci-=rubnwPezfpPBfD?4{u3VgA4It5w$)Mm)bww++wTA{JG@{b`(;AU zg$*@HHbF`K{k3-TY{P-;C+^PBuWg?zoqebBI1=tdKq|Dwo6$d_`24pO04BsW9xAWL z!%%4%b|Z)VSmS!PwQhH%WJ*;!Nf`cn2la@Zy zdh1CXAX~?Pg3l@&j=tDJtpj>gL$ohe_pOKD)QtT0mm4N&rHUg1KGG}Aj2Y7@z=(1i zRi8T-xkr*l+rRxrK|wJ??q6t?4?_%0M`rD+n$_8;WobMRs`q&P25C<&{-m?BI;Iwy zELKtD5pl^PGc$LUSh!V>Y;#s*0jU&88Ffjw>@(hlzQnu3XZ?NA+7zCbdBDb~*YxF! zH1%7)$~1k2179;Dh-6nM!TXx8hDGNyu8ZfHrTl3R1owu3QZhfx1%e2=xvKTpP5TQe z&yvr`ltA-#^p4#To$4YC7!+1lMVgmImY^9bIVNcKcJn0rJAH%Z&{27~~d z7&=wpE4$)B&HdBZPcl!ZTax|^N?eX$k*)$0Q%xGnWj);cGJI~EmrBMa8&NLWWNd!p z`)*GO_-oLL{eYlcH{*CB>#6YZKkpS3xhVqZ_&j}=eT}{mqyhsv4zzz7^N$2o;{T1& z!i)%*1(=Uc{rU3;Pip-N)cc!#N^yf0?&(<{X|Wj_n1}qO3up*V_g+rabhFTvYTs0T z&VEQ9ZP4%!Sr`WWAgn@6I;{^Ms!Q-|Sus_5X+p5d(cbg>25CrpoEzf^lX~{-Zum22 zAV9XN3EeZ^{4CkQ{^X(2ezU(WkKbudj!f}FVRn7Y=@1`bN47eH-c{v1E#xBL;L+=2 z6F~63_&9#hSNhWl$bk_t8;fTVDN9f5o&_e-XoaIuJQ3vkuc)Nr|MNR?o#-WR<;rsCFh?ll5rSeg*I0LK=qf}3 zRpVmPm;`$rx5$N`Q5bwSvn^+Ht;ELXk|FfZoL0+d?KfmA-}Dnh(czVD)*IfN{&Z#G z?o5_`$)ATc=O)3$Rr+wkAbiVMdzwn{lUW=pIu#_83Et~BA81pE7y^p9m^T-8!&W`vK5q+WbZUlE*s zQ5%M`yOB!U^2o5NKdp`odj~<|>k4Gv+Kji-#qrzGn|!m#l>>v_U52mi0l`1eod&@5 ziN=&eugA6B(bTl?Y#ExlM&(K;&B9wa=~cQfv%()e(km^l1Afujt9uDx)b!e$Mb8PwM@UKoXphQpbjetE246~!XG56~PsJPM7^BjjuVcW8(9j$#VP_gGg+ z2oDfinzNl%(4t&BXOp^e@THQda#j7=C&dQpPPG+FHt7tNhstd_nitoX7ZrO^fkXr^ zCo=_l1me>0dP_t$erKt^p5nBD8R!g<*f(g9)_Lr?NdSHf%;I`|eED{hEk z0fBJa+ZDA|Yg2VDaf>m*a4Rh!=;k~0s*3RQGab&2L%*$`-yaTJtau@BQiqzb)z#->o5T0Dm_(F#x%oBP-E(w_NkE*5)Y zJ8zY!Guq48$#lr`!JsDlk6(YlpQKLlh9bjk@2K5VD!8dLFZGf}W1vUt%kr|_Tr2Db z=WzCu)lKu-ChlL{nAWh{!8xx@SoYT)uKZsi_OdjTR5eq4lQ(mXHkF#^J9IET=@6^J z_s5W~j*I5G{zc=FKq=1?@w@~7>iB;bWu=Fwjn=9`f(DB!W-U29u#`KOx2^$NLN`fK!9

RmT6tY(5ld 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 G?Ee5BOxzy; literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/online.png b/android/app/src/main/res/drawable-hdpi/online.png new file mode 100644 index 0000000000000000000000000000000000000000..1381977c52679ab08fc2a0b8fd4f4e66974d8ae5 GIT binary patch literal 8620 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 b+~J|zqkdCt+{EEdVF1)sw3V9_ZKD1UO&J#G literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/password.png b/android/app/src/main/res/drawable-hdpi/password.png new file mode 100644 index 0000000000000000000000000000000000000000..6beb822ba53f9913e7663b0082875299d976ba76 GIT binary patch literal 5716 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 ZdX@xjVW6uobz2P3ziq5rd&@EQe*gj4<4*tp literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/power.png b/android/app/src/main/res/drawable-hdpi/power.png new file mode 100644 index 0000000000000000000000000000000000000000..023d19ddbb2ed2e434010728a081c37e350f42f6 GIT binary patch literal 7640 zcmXweby!s2_w@xv9eQR6Nr9oeq;qiSl8_iu28LEZTH0VhkdBf1NQiVvNGl;Rf=DBs z($WHg@A!S6-+i8Y?|jS^}r}LEehWVnwtdP^i(WA?oePo9T@<(0vHyTJe4MOs7IvQGNpoq{lbLv)Vpwb15g&n$g-S z_hcVGdoJf((P(Rbx>I)+Fm$$#&kjA+@Dip0p(-Zs7mvzC;HW_nB!GPYkVy)Ns&?b> ziq|cde|i4UKh3=v;oRJTJ7+|Opu!BBPPu?`&F*OC_}&Zu7NztUPAT(Psk4s9XIWp@ zb)iOJuZWEx8qylOg@F|Qz(UMZ3f9;jPD8N~Ym1Qf9L&2FjXy%gfZL^Sd_#27F5$7RiZQAv&doFl*f z+}|d9-c2)cX=$lVY1o}(84k#n%HA__(S3woPkYGFpsA@DZsMYAB3&sBO3Ls=DpCTg z&Q+=2<*%B*0E;@9_F56qvov08NP4`Mw*atXmVwKz$?LckQTANu!Cwz+%P5zMHFc|8 zdNqpa8h_zXkfU>lE^W}KD(f;9M94xO&C8{d5g)hWfp`mX)?l-Ao7@c>I?$sWKi z9;9(-m5t9-jBbWd0Lt^sw0o7Q5Q_5u^pbD2l8O^zp9<5>d{`uyPh)HkoNw~0EL2Z7Q$ar(#~xS$yE^+=0; zB68YXg2e$u5sByoBJ^6b;q6FXz@8LplTkV2TTl0fU8lqe%a`}qri_mm-#W`+GSyb5 z2IGp&yMP0&MfpdcKT0u1G7~Lk!+ZVcUbDCFyJP5mcD6A_6_7w$=rCziMC_{HTY>@d zBv4UdnCeh^2-JREGG5%Szj2cF%#48$4V7C!o)DSX(CbL}uORrvn5r;VUKB*Q9x#ck zJvgxJ!AC)CPLss)fWd`XmJp(jBwPX;A6ey*8ax6ka|0pvjarI?8*A)F3BQBt8}Zhl zBPPOxePfVxzTZm`$BuHB`|~#+A-8uSOh??oo!@rr;ejeRzkVGdyL}-fLySzl4Efr2 zui~W3sNu*bA-ygP0xsu;_owGs4W<#ClV+6PFw5f0`hbc^+mTo9tB>nPDAHZHWyN`8 zIc>Xe3v8{2+*n<56akH(!ij;Q;VzCzO;3ny23DkR<_Dg1`Lky2ozE9r!<<6gCQ*Dv z1{&S&TMEyIj>-w1Fo_eN#EctaKr#6~&&nwRf?0`eK#-AP0Ww*dDCCA*`-a-Y9M=#j zQAx6&HT{NmEgUl}Pn1?XyOCS&e)A4zPnNh;-A_`CZK9dZTT?Jxdk!<4E4=CzROTkl zOun_Z%Pj3-k*ML*Y)S}RGu}y2=%;B(iDmMq5r(5rVRQRg>_(Nd+m}+^bNdi2W`eIZ zJ3dBS!m*B)`@Zr4#1Xn&Ij2A6LtWXc8%A7MMhwl)+X)L@2*JbTDGjr!qE+b$S2U`9q<;C`tbC!aDqwR1@oU2N z_!yb^p2r>oO>L81-tz``vwQi7O3~2JaFy~rjTX$@19pO3ma z`zBS(zan*uBtlVX)_E@fb$i|5%}8e=dl6_w9n?TAQIx1N+A~$2FgQRVv<%@Sg5-X*)pUl5$izS z-3vqV*NegjM$wH;cjiuVp-nSKt>otA76&FH)qw}g<}V-eg(q4Yz0Ku_Z#y`{D^4v6!Z|!WdM?F&T$`|1h{od&`_h=uBLQK;+mrQcierye*K!ickkZe*T5=| zow7zVWGfsTb!HG9wSQ^nygs@eZ;F{$ktRIOzP_ez<9gHY2#K`Sh2^uWvK|D8vPhKn zR8coO4e$5kof*+0n=yoh*eB^Unto$pw;Qj4K5Lr#kMDH1{~|y2<3=NNWF&?(zdqe0 zN@ZZSl_|j9O1%HU>Oe?xYdUtqV0@4&!vf`AVkuHTXfp^V(oBqt(62l-K^~tMg3ir> z%#2pifM{Xj*X#{iP9g!+(5oUTLb|Ic${S>Tbn@Hlgciycu(1xdxm&$@XYJrxQN(1L z-*mp*^rnTojL1Grv~68AG1qguCog&72@y2MT{n@9Bm%kL+<*qn<7(j z;?4s#Q%j(k0;LaIxYLcd9FQN#Zd5XUv&uZb>SYLW@bGlv(3-R_8Y{sD$^rQI)4zL~ z2k~|iy?UkHt*rm5RszoMc3Fiju_00C0wjs{=9{qrjl`cNye}}$1uUVc*!uU|w{OENE-8>i*_?uyp9{sGi{d~rT89EaqE<}XT%byH=hW1cpa!8K z&R?mdfC(Mf75|6w))X65wL9+?;#chEFFrv;v+{ZSUrEgTLj3uJc(@@1WNx4hsi-%N z4$dHPXNer2yFDvF!xjAI_|Mz7QBT(7;qtCJgfewa0=2V66sI&hs=p57HNSJoF3q(+ znNYY$Z<&h=e;9Xuvg?=`YF>qp(wwkU0GI zTcYJhf$;ZHm*n7ntd3?(F$Jdh-k4qg%MOp-N77lEPjh)!OKs5W)C_15HeT%hF7M(OO-U$Jo+l7*&(MGkI)*7(^7FkBonc@yCk8y`PHwla$UV`+6B z+oz<4yhN9cGi~|G=fui7ZTA`yplz#vi}1sp8hw603AindVCH@M`yi+!?wl4K_kd%< ztgPO>cr>ZFPmreB!tFq#U_`Z|{<%`Zy>yWVkiBmI8_97iArd4bS?#D)=mxIYtXc-z{BHzY}E9 z-z)GVQq>4d43uH}1m5Yn3&#k~e=i$$YEHoYMYKEIs5Q6X>3UjE2UUTAKB;@3UAF&~ zz~naEHP5EX+P(qDwpQ;mgFcC_?3{*%lS+nj7*xV1wR72Fi49#BU^;K#SxRKc6A0+A z-+$&^{k1HhCH+~?DhUiP!Nl;LqT}~3A3LnGIg;riQYDYh)<}&rg!aN+?lRT=*lnOq z&TCjpV=mVMA-Z>c)bwu{6JT=5=w{#a+l`(ji^%OWFk&k?`pf_x8{Zi(fH%OA2<{Sz z!Vuju!$-E`6(1CGs!-bsz#{g;0pEY^erga)_m1+2-Xb@cq@82jxmLDu(U>vvPmAow zyOokhJ55jcd_+i~Yoh+^@wmV940U%aIg7?_L%g-Kt#4HRH3q{K27G|`Tl&xut?U%k zwji*m1in^D_5fS!8*({EbUFDYt?Ux8{9qPYGs5Jq{7 zfyU~I`0#KhKBP^2Jx3gLP7iPAH1Wzcd33^P&3}SIhKTWI-JJefSI^OxE^K96>o#6G zHR_9UXZ$_6E-UbuGyl}|iqNFqML!Q%9S=hyqkH}QKa=vd2KL4={$=DfkKA4XmGr>e zhn3D|H)91Wr(iNJsBHp?c|kDM)_J`M&k`3G*LRD?MLMerfnT|E_$hhX#Ki(&Z!Gn$bm=>#RLQ;SCT;S0!nYid6 zVn2Olj;mp!4yfvi zZC=mrIhmZ@a~CeAv_nlGc1QQ@XhxL1E7j$l zC(qncf=%-cpRr?Yl!dIDyf$q7r`6qFm|ooQjqPu79et-?_o)3G6SJ4waNgdbkzert zw>Wt(`?kJP_i#(eBeu__qUt8Fy*lKS2Tr=0gc$9Za0uLSOiQa>ZTce~hoy&PLAEb2UPEEt&@ z=K0Y!aiIoam6}E7K%WtLVRFAKhFr|uYAw6BOtAR(2x!wxm zfQC+D4qYpTi6W*#+NGPx`0Acx+g;EZ6Tw8ltOutR5v~Gy!-_Onv-vMEku#k!$LUax zLO`$bFo&kHXFAu6lv#*3uK4(<1RPSEk-2DsEWIr*=@Cv z6O6Q>3*n-Y;ldSAhQd3@5IYFSuCX5Benkn$el=@f^+_?vdlVXl1f7!sA=Rr?JmTR{ zs5XM3>|MPr6;Q(*Z#Hm~*OvoonK4VqT_^`Xk7goH- z&c!oN4$`hb(AywHA|FScv70h{;35QrunBpIyUmC;_zcB+Cyx;00V-jWricU!)s^}_)3b>R=BF-4mTmo`N1oup}IHp%U zK(DXFi8t!$LOxoggtYyj3`>@+h>_7OhO8;A_40xB|DR_n>4l4%_LEhi}qez3zlTyz9(2>nAx}KaQ@4i>0UeqQkXm>nF zo-=anNi|IT$!~mKzCTLoRW(=Ne}6Sgi;MklFnSEs0&%i1dZ|cj-v1O*Zah&mWr`I zkF-gBz(6;B+s@PHWR>jw-lkUOt4Gz@0cVPjsWJ2Su7x|4hM84J*j_HBVEJ(Odc&h1 z%3kjm=DDxzl#JFaGYHx0BHd}ATqsO`@#li&h{_8;%=I0~JV`>}@6&~NN@v~TSiTKC zXcG86T1@?qIx2jx>EceG{V(;R+A-kgXhi9(NEUWu=RMrhGCNLSV*v9@cfjFEy1&Gc zWpAc#F#P|>t+98>cR%)Iiip+>kNMW~Kend~$;T-T9<+ghBJgXQnP%Pc{Tjj}S5Q#U zL13`|(kq5M`Sn34z`pRcNZx!YYhothv|hkQq9QsHt8XE`3ll_Pc3)wsfzIC?{*yc$ zUiBM61U_B^myZ9&?qx;jZrcPr-NqC1E=BFnQ%tUcxKDt{(bjQ3V1FaKjEw*akuz=X$95mX&7>-Y|y0ey;0c<1`x6}2B%*<`Zi6_ zeErR0&`7@e)4NQR@z_`#P0l4BDDa%=AZ~T#XRbnCrMqAh(hz$7=42`4iqG@08WmaB zH?bpD!r2U+m--2OpB!?aHGGuXok<+AQ_@7A(8-PTHEW%c<|Qj`LAZx{9n((tYt*Dn z$9A#-s&26hQnmri2VbPQ8Qy(1)S(tTa?k%39CMaDv+pM?JF`vuR601gyw1p;kaNlvq$i+4bAk|71>H4!*mEpYkfx8B}d;wBQ^BdbmQ&SIi()K8K3M2yxG;4mtIA{D=*I>-Uo3HKs!8O&(ocpAMN_K_6i*0pxC{v-==5Qi5hR9mUX)XEH$#Mx|&c3d#6@Ec$u zHsSom2e3Flc`nT#frB99eudiUQcV}$lnaVhH3o5Qctb#`$I8s-crdIjAv+SAF~hJ- zP`cXKJMqp;=)#a79$}Lx$k9^PH)ZQ5i{+aOyjex8krrnhxEWqUsIrtV#QE((d4$3@7pz+y4zJ^7T z=26H&;r_y_{8kpvzqJ2-1#%m=Mx)Q&=5Dge_8IE88`||tiyjhUE*8G{p_JSDmLw9*N0$O(yAk} zl_!S8paDhDH~D)rKRfOU(IOn*7x38!iF&_19Dj4^J+Byx-EgE!W1c*JU3vR8`-nnJ z$TeN^D$L-UVBlW+7^F$O6w#q970=Hvz=ddT=P#N)m`lCc{NAlrmM807)e9c2n z$nB3F{H|0_IefKQzi_+qSoD1^`%F-Af-+Lo)Ld{iMKjAhvQE}8ZrrKRzrQ9;jrO>>ucIwuuf4kr!~6iuSa9|D z*761Gk3lUaZ+QEV_FQFu2uw$r9@;a`+y8WeYkS|4gFt2^)6Y_zlq@qgwKJ00ZO%d$ zRP@MVn{~`L^|5!Qw4HbX3wjX3u*d!Thaz*EA|952v*j-PAY4H#Y)!3+!hZ)_4y1C z^wt8w1-E;Nds?5Nzwk2Pd)_5F2p`E(J%9{2;zuvW;v#&d895wi; zl`B3mFQ}f;PeF5^2q-y%Ytu~3%o!_{plBSIy)N3rWhDdp;iA9&JPz~Q$e@G+c$u>j zO-(p!Ch}t<2{Sgp;%Cr26#u7Lz>pT%szTAFK(vS<%-9~B*56(rOzZA5-?=m2G2()E zUguo91+|+e|EB&i8W$dk4d^p09<@}Gm%lj5pE5%#upnTsb?T-S!O(>`>|^2x8IsQO z=K_cH3t&LSew|I?h?*cdaZz;tZwe?BIg?~jHyy$cAFv%H%H3e?#3#c|uAg=&Kj3Y< zf&vx^SnBA9d{1e%|8L4D;Bz?4u?S8c@gQg!_i_xJ;Sc>2{EzJ-u#&i-KLKZd^?wV~ zD^UWqx=PnsxI9F6@!HvQcSC>D5tq9YjX!p4;;c*RXa3&OUm@ADxk{raOl$#dbpvFj Intjy&1CqQ|%m4rY literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/scene.png b/android/app/src/main/res/drawable-hdpi/scene.png new file mode 100644 index 0000000000000000000000000000000000000000..c5efd44dabeb5f39d7e23c0e17949124ff9061ae GIT binary patch literal 21435 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/show.png b/android/app/src/main/res/drawable-hdpi/show.png new file mode 100644 index 0000000000000000000000000000000000000000..d4bbcbb8ea18125403b6f50466cc766183991cdb GIT binary patch literal 19481 zcmeI4c{r47{Qt+6U1X0K3^A5j?1QmurYvD>IjUhsrZAe3eH~@rW>ASz(JGQQMN+mQ zQ5;edi6kwyEGd0Qb!twhbLRK`UEe=vu4~L^?)&}z-1qakmwBG&x*lm;9XAOJtQP

#7Z0KiC|fbk6Vbg)PG5rcHF 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 S&4;W1ybEpXXj5smlkz{}W!5GD literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/state_a.png b/android/app/src/main/res/drawable-hdpi/state_a.png new file mode 100644 index 0000000000000000000000000000000000000000..f59728ab7b6bcd3cba5012479900f93c0433ffd2 GIT binary patch literal 22883 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/state_b.png b/android/app/src/main/res/drawable-hdpi/state_b.png new file mode 100644 index 0000000000000000000000000000000000000000..e48af22c4300134d9d235913a0cd0178b742cb1d GIT binary patch literal 22810 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 F{{m}fb2b0~ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/switch_a.png b/android/app/src/main/res/drawable-hdpi/switch_a.png new file mode 100644 index 0000000000000000000000000000000000000000..3c03311fcad80523814c16624893cf390fa47067 GIT binary patch literal 20492 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/switch_panel.png b/android/app/src/main/res/drawable-hdpi/switch_panel.png new file mode 100644 index 0000000000000000000000000000000000000000..20780d846bb8c092b7dea2867a25ce4adae61061 GIT binary patch literal 2905 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 NEKF@osxNv({|D}oOMn0X literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/time_a.png b/android/app/src/main/res/drawable-hdpi/time_a.png new file mode 100644 index 0000000000000000000000000000000000000000..3948fa557dbf6ce469eff75b3cd60113891de167 GIT binary patch literal 24735 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 Mt8IjRiE()JKY>N2$^ZZW literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/wifi.png b/android/app/src/main/res/drawable-hdpi/wifi.png new file mode 100644 index 0000000000000000000000000000000000000000..aeeb154de3b96a4d9cf915f07c128559aa1c6c78 GIT binary patch literal 6511 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 DaWgFV literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-v17/xui_config_bg_splash.xml b/android/app/src/main/res/drawable-v17/xui_config_bg_splash.xml new file mode 100644 index 00000000..be312207 --- /dev/null +++ b/android/app/src/main/res/drawable-v17/xui_config_bg_splash.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable-v21/xui_config_bg_splash.xml b/android/app/src/main/res/drawable-v21/xui_config_bg_splash.xml new file mode 100644 index 00000000..a068a128 --- /dev/null +++ b/android/app/src/main/res/drawable-v21/xui_config_bg_splash.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..1f6bb290 --- /dev/null +++ b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_web_back.png b/android/app/src/main/res/drawable-xxxhdpi/ic_web_back.png new file mode 100644 index 0000000000000000000000000000000000000000..8bb3cf89457fe16651a87a1f33e88c006e2d5530 GIT binary patch literal 761 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4T z;_2(k{*YCiOO|u~(aZaR@{FD?jv*Dd-rhRx#Z)MA{Nw)~me?)sA3pKvdgWfuo}#(7 zx-qOV_UxMUOi|ZqTRYx;kJ^?Y%_8a|{$z{BiGS{Ejh*HC=e`dTu(MD5)4cdt#;j$T zQ1tD7GvkkpDbbI5?{mlZ7G%HpV^DMcq1eSAjuo5OSa$e|?BiZ7RzLZ+i?jiAnPHxA zt9{FlzjxHQ_Va%<22%DtKUjf+@-6AV4{N{p!YF=Cr%ux8j@GFLnO(JuKnhxac!CtT z|1sI#d8l8ZZr*K|hwTrpKFV)6z4n*w{npa%|7x$_%$!{NZHb`$!Q4e3ggfld0I9_t z^BX{Ym+=G&-m{ou|IpzU%bx}1@wZxPwEb>0 zm*t7)GSy{m*RDU*w}q3{B+>gy{JaAPm}Xr#y!MlI;)L5S^EYVx;99`B$&Oi6IjDe{ z-+(Rmj*#zV69{^{zM9=+idXw`$%o;<^r2ef8c~vxSdwa$T$Bo=7>o=I&2na*SN8&+|Ac@@Rcty?J$Ffv zUoZpns@1kRHjmjD*T%m(Bf!AGsNm`17!q;#?KNAzCI=CggbkZiikPyrv!$i9rK_c- zwe=H{mWyxrCUN7ZUV6m8#DV@Ai>Hw}3^BvgtHJa{9<)+ux1!JR{M|2V+~qn}33GG&cmA95sXgP~ zT$QNxeu8h0F61bEKKXlC>Gx^Bn{PEfky~CCxYK{Nr^7j^qFEC^PnvV$$r<(Kr#{}P i@~d6({poA>SKR6=RF?l(*~JSCLIzJ)KbLh*2~7Z!`?;9_ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_web_more.png b/android/app/src/main/res/drawable-xxxhdpi/ic_web_more.png new file mode 100644 index 0000000000000000000000000000000000000000..6ecc004c262c4f5fe994bb93ee92db80dd93d337 GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy%50(?ST-3xsFQx9}3{T>B0S+XR^ zFPP!Oh5!MF3kC`e4-TwPI6qzJk_;1u*Z#~u;5T? zq+ZPOg1?)ue+}5def!Xhb0QZvtZa=}{j>c+>51D28 q-re>ew>)0tJ$H@oR>e;689ZJ6T-G@yGywo13jB`% literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable/bg_dialog_common_tip_corner_white.xml b/android/app/src/main/res/drawable/bg_dialog_common_tip_corner_white.xml new file mode 100644 index 00000000..dbcadadd --- /dev/null +++ b/android/app/src/main/res/drawable/bg_dialog_common_tip_corner_white.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/ic_action_close_white.xml b/android/app/src/main/res/drawable/ic_action_close_white.xml new file mode 100644 index 00000000..266e01fa --- /dev/null +++ b/android/app/src/main/res/drawable/ic_action_close_white.xml @@ -0,0 +1,22 @@ + + + + diff --git a/android/app/src/main/res/drawable/ic_check_normal.xml b/android/app/src/main/res/drawable/ic_check_normal.xml new file mode 100644 index 00000000..ac01f1f4 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_check_normal.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/ic_checked.xml b/android/app/src/main/res/drawable/ic_checked.xml new file mode 100644 index 00000000..9961d244 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_checked.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/android/app/src/main/res/drawable/ic_default_head.xml b/android/app/src/main/res/drawable/ic_default_head.xml new file mode 100644 index 00000000..f68423ec --- /dev/null +++ b/android/app/src/main/res/drawable/ic_default_head.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..ca3826a4 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_login_close.xml b/android/app/src/main/res/drawable/ic_login_close.xml new file mode 100644 index 00000000..4d90015b --- /dev/null +++ b/android/app/src/main/res/drawable/ic_login_close.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/android/app/src/main/res/drawable/ic_logo_app.xml b/android/app/src/main/res/drawable/ic_logo_app.xml new file mode 100644 index 00000000..89557fa2 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_logo_app.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_about.xml b/android/app/src/main/res/drawable/ic_menu_about.xml new file mode 100644 index 00000000..1f7d30f0 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_about.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_issues.xml b/android/app/src/main/res/drawable/ic_menu_issues.xml new file mode 100644 index 00000000..1614cdba --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_issues.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_news.xml b/android/app/src/main/res/drawable/ic_menu_news.xml new file mode 100644 index 00000000..9a7ddff3 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_news.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_notifications.xml b/android/app/src/main/res/drawable/ic_menu_notifications.xml new file mode 100644 index 00000000..9c92f095 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_notifications.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_person.xml b/android/app/src/main/res/drawable/ic_menu_person.xml new file mode 100644 index 00000000..3bd07cf2 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_person.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_privacy.xml b/android/app/src/main/res/drawable/ic_menu_privacy.xml new file mode 100644 index 00000000..9184e2e9 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_privacy.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_search.xml b/android/app/src/main/res/drawable/ic_menu_search.xml new file mode 100644 index 00000000..9dba080c --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_search.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_settings.xml b/android/app/src/main/res/drawable/ic_menu_settings.xml new file mode 100644 index 00000000..ee77a3e7 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_settings.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_star.xml b/android/app/src/main/res/drawable/ic_menu_star.xml new file mode 100644 index 00000000..e7b7c616 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_star.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_menu_trending.xml b/android/app/src/main/res/drawable/ic_menu_trending.xml new file mode 100644 index 00000000..df83f283 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_menu_trending.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_password.xml b/android/app/src/main/res/drawable/ic_password.xml new file mode 100644 index 00000000..716e402a --- /dev/null +++ b/android/app/src/main/res/drawable/ic_password.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/ic_phone.xml b/android/app/src/main/res/drawable/ic_phone.xml new file mode 100644 index 00000000..56cf551f --- /dev/null +++ b/android/app/src/main/res/drawable/ic_phone.xml @@ -0,0 +1,4 @@ + + + diff --git a/android/app/src/main/res/drawable/icon_arrow_right_grey.xml b/android/app/src/main/res/drawable/icon_arrow_right_grey.xml new file mode 100644 index 00000000..964e9b20 --- /dev/null +++ b/android/app/src/main/res/drawable/icon_arrow_right_grey.xml @@ -0,0 +1,29 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/icon_checkbox.xml b/android/app/src/main/res/drawable/icon_checkbox.xml new file mode 100644 index 00000000..bd2960a2 --- /dev/null +++ b/android/app/src/main/res/drawable/icon_checkbox.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/img_guide_tip_top.xml b/android/app/src/main/res/drawable/img_guide_tip_top.xml new file mode 100644 index 00000000..6c787f8f --- /dev/null +++ b/android/app/src/main/res/drawable/img_guide_tip_top.xml @@ -0,0 +1,36 @@ + + + + + + + diff --git a/android/app/src/main/res/layout/activity_agent_web.xml b/android/app/src/main/res/layout/activity_agent_web.xml new file mode 100644 index 00000000..f02c1073 --- /dev/null +++ b/android/app/src/main/res/layout/activity_agent_web.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..088aa83b --- /dev/null +++ b/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/adapter_button_top_item.xml b/android/app/src/main/res/layout/adapter_button_top_item.xml new file mode 100644 index 00000000..d7c9fabb --- /dev/null +++ b/android/app/src/main/res/layout/adapter_button_top_item.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/adapter_common_grid_item.xml b/android/app/src/main/res/layout/adapter_common_grid_item.xml new file mode 100644 index 00000000..7b2513a4 --- /dev/null +++ b/android/app/src/main/res/layout/adapter_common_grid_item.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/adapter_device_card_view_list_item.xml b/android/app/src/main/res/layout/adapter_device_card_view_list_item.xml new file mode 100644 index 00000000..2d97ef8a --- /dev/null +++ b/android/app/src/main/res/layout/adapter_device_card_view_list_item.xml @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/adapter_item_simple_list_2.xml b/android/app/src/main/res/layout/adapter_item_simple_list_2.xml new file mode 100644 index 00000000..94c4c2be --- /dev/null +++ b/android/app/src/main/res/layout/adapter_item_simple_list_2.xml @@ -0,0 +1,38 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/adapter_news_card_view_list_item.xml b/android/app/src/main/res/layout/adapter_news_card_view_list_item.xml new file mode 100644 index 00000000..b6cb55cb --- /dev/null +++ b/android/app/src/main/res/layout/adapter_news_card_view_list_item.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/adapter_title_item.xml b/android/app/src/main/res/layout/adapter_title_item.xml new file mode 100644 index 00000000..cabe173d --- /dev/null +++ b/android/app/src/main/res/layout/adapter_title_item.xml @@ -0,0 +1,45 @@ + + + + + + + + + diff --git a/android/app/src/main/res/layout/dialog_guide_tips.xml b/android/app/src/main/res/layout/dialog_guide_tips.xml new file mode 100644 index 00000000..59d2a3d3 --- /dev/null +++ b/android/app/src/main/res/layout/dialog_guide_tips.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_about.xml b/android/app/src/main/res/layout/fragment_about.xml new file mode 100644 index 00000000..a70c8934 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_about.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_add_device.xml b/android/app/src/main/res/layout/fragment_add_device.xml new file mode 100644 index 00000000..1bc283d9 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_add_device.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_add_device_two.xml b/android/app/src/main/res/layout/fragment_add_device_two.xml new file mode 100644 index 00000000..30f3d5ab --- /dev/null +++ b/android/app/src/main/res/layout/fragment_add_device_two.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_agentweb.xml b/android/app/src/main/res/layout/fragment_agentweb.xml new file mode 100644 index 00000000..cf1b5a9a --- /dev/null +++ b/android/app/src/main/res/layout/fragment_agentweb.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/android/app/src/main/res/layout/fragment_device.xml b/android/app/src/main/res/layout/fragment_device.xml new file mode 100644 index 00000000..7376c75e --- /dev/null +++ b/android/app/src/main/res/layout/fragment_device.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_edit_device.xml b/android/app/src/main/res/layout/fragment_edit_device.xml new file mode 100644 index 00000000..3aba826a --- /dev/null +++ b/android/app/src/main/res/layout/fragment_edit_device.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_feedback.xml b/android/app/src/main/res/layout/fragment_feedback.xml new file mode 100644 index 00000000..87f71d42 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_feedback.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_group.xml b/android/app/src/main/res/layout/fragment_group.xml new file mode 100644 index 00000000..ebfaaf34 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_group.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_login.xml b/android/app/src/main/res/layout/fragment_login.xml new file mode 100644 index 00000000..36e05ea0 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_login.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_message.xml b/android/app/src/main/res/layout/fragment_message.xml new file mode 100644 index 00000000..a80e943e --- /dev/null +++ b/android/app/src/main/res/layout/fragment_message.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_news.xml b/android/app/src/main/res/layout/fragment_news.xml new file mode 100644 index 00000000..8e90cecf --- /dev/null +++ b/android/app/src/main/res/layout/fragment_news.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_profile.xml b/android/app/src/main/res/layout/fragment_profile.xml new file mode 100644 index 00000000..2761c921 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_profile.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_pulldown_web.xml b/android/app/src/main/res/layout/fragment_pulldown_web.xml new file mode 100644 index 00000000..012b5dbd --- /dev/null +++ b/android/app/src/main/res/layout/fragment_pulldown_web.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/android/app/src/main/res/layout/fragment_scene.xml b/android/app/src/main/res/layout/fragment_scene.xml new file mode 100644 index 00000000..c7094c94 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_scene.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_settings.xml b/android/app/src/main/res/layout/fragment_settings.xml new file mode 100644 index 00000000..7b9e3b71 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_settings.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_share_device.xml b/android/app/src/main/res/layout/fragment_share_device.xml new file mode 100644 index 00000000..ebfaaf34 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_share_device.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_simple_tab.xml b/android/app/src/main/res/layout/fragment_simple_tab.xml new file mode 100644 index 00000000..f92614ad --- /dev/null +++ b/android/app/src/main/res/layout/fragment_simple_tab.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/include_head_view_banner.xml b/android/app/src/main/res/layout/include_head_view_banner.xml new file mode 100644 index 00000000..c0e18903 --- /dev/null +++ b/android/app/src/main/res/layout/include_head_view_banner.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/include_navigation_header.xml b/android/app/src/main/res/layout/include_navigation_header.xml new file mode 100644 index 00000000..0d9c6f43 --- /dev/null +++ b/android/app/src/main/res/layout/include_navigation_header.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/include_toolbar_web.xml b/android/app/src/main/res/layout/include_toolbar_web.xml new file mode 100644 index 00000000..1393456a --- /dev/null +++ b/android/app/src/main/res/layout/include_toolbar_web.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/layout_main_content.xml b/android/app/src/main/res/layout/layout_main_content.xml new file mode 100644 index 00000000..8c91e4c1 --- /dev/null +++ b/android/app/src/main/res/layout/layout_main_content.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/menu/menu_drawer.xml b/android/app/src/main/res/menu/menu_drawer.xml new file mode 100644 index 00000000..d64611b8 --- /dev/null +++ b/android/app/src/main/res/menu/menu_drawer.xml @@ -0,0 +1,47 @@ + + + +

+ + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/menu/menu_main.xml b/android/app/src/main/res/menu/menu_main.xml new file mode 100644 index 00000000..ca5df9e8 --- /dev/null +++ b/android/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/menu/menu_navigation_bottom.xml b/android/app/src/main/res/menu/menu_navigation_bottom.xml new file mode 100644 index 00000000..1b16294c --- /dev/null +++ b/android/app/src/main/res/menu/menu_navigation_bottom.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + diff --git a/android/app/src/main/res/menu/menu_toolbar_web.xml b/android/app/src/main/res/menu/menu_toolbar_web.xml new file mode 100644 index 00000000..207ca500 --- /dev/null +++ b/android/app/src/main/res/menu/menu_toolbar_web.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..c4a603d4 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..c4a603d4 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..33700913c7c9029fc2a4ee05f79561b0c0306ab2 GIT binary patch literal 2285 zcmV+P)n}tw{i;MFp7c*k^7Q`LL>Qm0f72N=Z=PsKh?N=Vuj;(_CNop7zjS|JcmMCj zvceUvaD^*eeqS7CC38Zc3_hKZmCW&h{kvD#H}?&C@IS0XGuY~3#>(Ruu@`-2V@lrp zVB41pgXCP8#C5F1|1Fmrvu)kU|E7K{w>lNpDJMv-{7j@QyDjtnk96tTJ;5rDRhw|y-KK=D@R z{7HJl00IP`x*cWffoNW8OD><}(2UsCrN0f29&nU2S-DCh=c~5XX7WiAyBD=|99@>@$4mh~fF03_m)P z`1Xm!cf3se#B0RweQfwh#PEh)hW|1+AOO{TlK8oW5)nnE(eP=m;pXEN6z9BZ^1RQR z#9w`H_@NoZi5bMpJ~g~k0Q+2Q(N@Ec%_8nD$M^ndxLtYx06P6C;!&9r5yhq8IQFFg z(MqDKT94B6Yb6n1If6K2gI=@aJHt!18D6^G*uVkg30a0OA4dF#UOop1Jdv`>aM96N za2)$~zu|i%5)xb>)$C2YFdM08xb0NpZm$z}o}+|4eU0HMtBK(C{NOm8YERPnF2KZ!i(th?W zRiVGhb)V$MUN?QM;nSW9K&ydBXz{YvE^a4}Ml=%6kk;T5DGFD89$gh9ouEg)COF+ku7aEUifAnU{4HFio}KSrIWpOJV((&P^`!cbXfeHIH6DUR!VM6l^$9)NgBSx@Ag{_~$`B0;q;? zN75U_`#n-!a9E`p-16_qWLL_+1dcmWP%T5{kWzCudP)Sb6+5&@D{8 z6{1fPDVE4W-SS;w*}(CZ0^qCDpC+CmBz?qFfp6VyxY@Yq{;f&@gvdc3JjV{PGCnT+oWl%;8(GaCj#@!|FA!DPK5>*Bu#_cCQ0ZZblv_M3(8oVuw>%Dj6}HS}GIa^#b}+IvCephg&M`71T{G(E-$RvdH5`DTGUJy?M2U)_Z8#u=n*5G7sHkmFBf-ES zNXL1bj12_3f3y*ZN{lmbK1QkN_|alGlSnT>zUjprfZzZ|60K6S$XlFa_@WnxPc4}* zUp-3g)(KjDUob$ybL^yET7bHbH5pz?%Dx8(#MvlW=gM&<1!Y}n8Lk_x5plsl1qf{f z(r3fhh6gSpeqK1NpF|y|gdlyqc5LmJ$4)Wd0hF^_NpzUJKC=(;#1+INm+GJ^X+GJ` zp~A*aX(Xa5*gDN{%T(-^>PQ5D;z|gl% zUQIvQge=`n#jdOSIKbXl7!ZIy%TotXOxkV7a^l|e6cp@@&5^q01yQxjhH01INTSBE zKMmBL3xw`IjtFv!Lf->~ng;t0zF&%X&PZD3FdsHGLIcsq!<(o zn}t`6)LmG}Jc>bQD&Tv79CJ7bA3DG;1{&E1XOP{qfn)9$koJjmr>@dI3bP*&Hwb;i zQoRxfhAg3&_Mt4pG63kE@kGsginRZ7k3O#TBS1(WIEv9jW!m;!W0Se> z07B(_qe%2U>88@G%~Tz&gr89iKg1aV6aw`71gJyq@8G){n=0^KjgEQ2jUeaiQ0=!= zB*pfO3;Y-A+N?<{KS1q1eCVf}b&muodh{!qoeS7%F{`WXYp3gI>qWDyyO+(g?#j%t?piiC%I?gJe(rr; z)^jT3p7!JW8TNY@A8cR5C)>9MH=JCN|Gf}rozt|YJk}SxNUX8gr9QXDCBD?N>Rn#T z_OartX?2OF+5%P`xoKTr8+?E-@Tn43TtF;b;R;u{e6juyZ2IA?+JxHg00000NkvXX Hu0mjf32s-Z literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..376ec27ac5f4643d2b3f20db657a2ff955906c73 GIT binary patch literal 3353 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..a8435da533eb89e293e43037c6beec0c5949639e GIT binary patch literal 4308 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f36004ee5895fd4952e77602e3552a5e4a5d98cc GIT binary patch literal 1492 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ec5df43bba374f1422b4be7b82ebed6b51449f GIT binary patch literal 6287 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 FV1h%r5IFz< literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..587b5908456157e3f82651f1f0416be3e4b296bb GIT binary patch literal 5138 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..8b1d00f687b54775acbe4bdfa4f17401de8e9270 GIT binary patch literal 7935 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..1ab8200bd6ce0296208b558eceaae81c165efdf1 GIT binary patch literal 9832 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 O00007cJ4dB!cL@MTs_|CDB9l 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

+ * Smart Config v2.4 support the API + * + * @return the IEsptouchResult + */ + IEsptouchResult executeForResult() throws RuntimeException; + + /** + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will + * be thrown Execute the Esptouch Task and return the result + *

+ * Smart Config v2.4 support the API + *

+ * It will be blocked until the client receive result count >= expectTaskResultCount. + * If it fail, it will return one fail result will be returned in the list. + * If it is cancelled while executing, + * if it has received some results, all of them will be returned in the list. + * if it hasn't received any results, one cancel result will be returned in the list. + * + * @param expectTaskResultCount the expect result count(if expectTaskResultCount <= 0, + * expectTaskResultCount = Integer.MAX_VALUE) + * @return the list of IEsptouchResult + */ + List executeForResults(int expectTaskResultCount) throws RuntimeException; + + /** + * check whether the task is cancelled by user + * + * @return whether the task is cancelled by user + */ + boolean isCancelled(); + + /** + * Set broadcast or multicast when post configure info + * + * @param broadcast true is broadcast, false is multicast + */ + void setPackageBroadcast(boolean broadcast); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DataCode.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DataCode.java new file mode 100644 index 00000000..ada4cce1 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DataCode.java @@ -0,0 +1,87 @@ +package com.espressif.iot.esptouch.protocol; + +import com.espressif.iot.esptouch.task.ICodeData; +import com.espressif.iot.esptouch.util.ByteUtil; +import com.espressif.iot.esptouch.util.CRC8; + +/** + * one data format:(data code should have 2 to 65 data) + *

+ * control byte high 4 bits low 4 bits + * 1st 9bits: 0x0 crc(high) data(high) + * 2nd 9bits: 0x1 sequence header + * 3rd 9bits: 0x0 crc(low) data(low) + *

+ * sequence header: 0,1,2,... + * + * @author afunx + */ +public class DataCode implements ICodeData { + + public static final int DATA_CODE_LEN = 6; + + private static final int INDEX_MAX = 127; + + private final byte mSeqHeader; + private final byte mDataHigh; + private final byte mDataLow; + // the crc here means the crc of the data and sequence header be transformed + // it is calculated by index and data to be transformed + private final byte mCrcHigh; + private final byte mCrcLow; + + /** + * Constructor of DataCode + * + * @param u8 the character to be transformed + * @param index the index of the char + */ + public DataCode(char u8, int index) { + if (index > INDEX_MAX) { + throw new RuntimeException("index > INDEX_MAX"); + } + byte[] dataBytes = ByteUtil.splitUint8To2bytes(u8); + mDataHigh = dataBytes[0]; + mDataLow = dataBytes[1]; + CRC8 crc8 = new CRC8(); + crc8.update(ByteUtil.convertUint8toByte(u8)); + crc8.update(index); + byte[] crcBytes = ByteUtil.splitUint8To2bytes((char) crc8.getValue()); + mCrcHigh = crcBytes[0]; + mCrcLow = crcBytes[1]; + mSeqHeader = (byte) index; + } + + @Override + public byte[] getBytes() { + byte[] dataBytes = new byte[DATA_CODE_LEN]; + dataBytes[0] = 0x00; + dataBytes[1] = ByteUtil.combine2bytesToOne(mCrcHigh, mDataHigh); + dataBytes[2] = 0x01; + dataBytes[3] = mSeqHeader; + dataBytes[4] = 0x00; + dataBytes[5] = ByteUtil.combine2bytesToOne(mCrcLow, mDataLow); + return dataBytes; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + byte[] dataBytes = getBytes(); + for (int i = 0; i < DATA_CODE_LEN; i++) { + String hexString = ByteUtil.convertByte2HexString(dataBytes[i]); + sb.append("0x"); + if (hexString.length() == 1) { + sb.append("0"); + } + sb.append(hexString).append(" "); + } + return sb.toString(); + } + + @Override + public char[] getU8s() { + throw new RuntimeException("DataCode don't support getU8s()"); + } + +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DatumCode.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DatumCode.java new file mode 100644 index 00000000..4cfeafbe --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/DatumCode.java @@ -0,0 +1,141 @@ +package com.espressif.iot.esptouch.protocol; + +import com.espressif.iot.esptouch.security.ITouchEncryptor; +import com.espressif.iot.esptouch.task.ICodeData; +import com.espressif.iot.esptouch.util.ByteUtil; +import com.espressif.iot.esptouch.util.CRC8; + +import java.net.InetAddress; +import java.util.LinkedList; + +public class DatumCode implements ICodeData { + + // define by the Esptouch protocol, all of the datum code should add 1 at last to prevent 0 + private static final int EXTRA_LEN = 40; + private static final int EXTRA_HEAD_LEN = 5; + + private final LinkedList mDataCodes; + + /** + * Constructor of DatumCode + * + * @param apSsid the Ap's ssid + * @param apBssid the Ap's bssid + * @param apPassword the Ap's password + * @param ipAddress the ip address of the phone or pad + * @param encryptor null use origin data, not null use encrypted data + */ + public DatumCode(byte[] apSsid, byte[] apBssid, byte[] apPassword, + InetAddress ipAddress, ITouchEncryptor encryptor) { + // Data = total len(1 byte) + apPwd len(1 byte) + SSID CRC(1 byte) + + // BSSID CRC(1 byte) + TOTAL XOR(1 byte)+ ipAddress(4 byte) + apPwd + apSsid apPwdLen <= + // 105 at the moment + + // total xor + char totalXor = 0; + + char apPwdLen = (char) apPassword.length; + CRC8 crc = new CRC8(); + crc.update(apSsid); + char apSsidCrc = (char) crc.getValue(); + + crc.reset(); + crc.update(apBssid); + char apBssidCrc = (char) crc.getValue(); + + char apSsidLen = (char) apSsid.length; + + byte[] ipBytes = ipAddress.getAddress(); + int ipLen = ipBytes.length; + + char totalLen = (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen); + + // build data codes + mDataCodes = new LinkedList<>(); + mDataCodes.add(new DataCode(totalLen, 0)); + totalXor ^= totalLen; + mDataCodes.add(new DataCode(apPwdLen, 1)); + totalXor ^= apPwdLen; + mDataCodes.add(new DataCode(apSsidCrc, 2)); + totalXor ^= apSsidCrc; + mDataCodes.add(new DataCode(apBssidCrc, 3)); + totalXor ^= apBssidCrc; + // ESPDataCode 4 is null + for (int i = 0; i < ipLen; ++i) { + char c = ByteUtil.convertByte2Uint8(ipBytes[i]); + totalXor ^= c; + mDataCodes.add(new DataCode(c, i + EXTRA_HEAD_LEN)); + } + + for (int i = 0; i < apPassword.length; i++) { + char c = ByteUtil.convertByte2Uint8(apPassword[i]); + totalXor ^= c; + mDataCodes.add(new DataCode(c, i + EXTRA_HEAD_LEN + ipLen)); + } + + // totalXor will xor apSsidChars no matter whether the ssid is hidden + for (int i = 0; i < apSsid.length; i++) { + char c = ByteUtil.convertByte2Uint8(apSsid[i]); + totalXor ^= c; + mDataCodes.add(new DataCode(c, i + EXTRA_HEAD_LEN + ipLen + apPwdLen)); + } + + // add total xor last + mDataCodes.add(4, new DataCode(totalXor, 4)); + + // add bssid + int bssidInsertIndex = EXTRA_HEAD_LEN; + for (int i = 0; i < apBssid.length; i++) { + int index = totalLen + i; + char c = ByteUtil.convertByte2Uint8(apBssid[i]); + DataCode dc = new DataCode(c, index); + if (bssidInsertIndex >= mDataCodes.size()) { + mDataCodes.add(dc); + } else { + mDataCodes.add(bssidInsertIndex, dc); + } + bssidInsertIndex += 4; + } + } + + @Override + public byte[] getBytes() { + byte[] datumCode = new byte[mDataCodes.size() * DataCode.DATA_CODE_LEN]; + int index = 0; + for (DataCode dc : mDataCodes) { + for (byte b : dc.getBytes()) { + datumCode[index++] = b; + } + } + return datumCode; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + byte[] dataBytes = getBytes(); + for (byte dataByte : dataBytes) { + String hexString = ByteUtil.convertByte2HexString(dataByte); + sb.append("0x"); + if (hexString.length() == 1) { + sb.append("0"); + } + sb.append(hexString).append(" "); + } + return sb.toString(); + } + + @Override + public char[] getU8s() { + byte[] dataBytes = getBytes(); + int len = dataBytes.length / 2; + char[] dataU8s = new char[len]; + byte high, low; + for (int i = 0; i < len; i++) { + high = dataBytes[i * 2]; + low = dataBytes[i * 2 + 1]; + dataU8s[i] = (char) (ByteUtil.combine2bytesToU16(high, low) + EXTRA_LEN); + } + return dataU8s; + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/EsptouchGenerator.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/EsptouchGenerator.java new file mode 100644 index 00000000..a928efb9 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/EsptouchGenerator.java @@ -0,0 +1,54 @@ +package com.espressif.iot.esptouch.protocol; + +import com.espressif.iot.esptouch.security.ITouchEncryptor; +import com.espressif.iot.esptouch.task.IEsptouchGenerator; +import com.espressif.iot.esptouch.util.ByteUtil; + +import java.net.InetAddress; + +public class EsptouchGenerator implements IEsptouchGenerator { + + private final byte[][] mGcBytes2; + private final byte[][] mDcBytes2; + + /** + * Constructor of EsptouchGenerator, it will cost some time(maybe a bit + * much) + * + * @param apSsid the Ap's ssid + * @param apBssid the Ap's bssid + * @param apPassword the Ap's password + * @param inetAddress the phone's or pad's local ip address allocated by Ap + */ + public EsptouchGenerator(byte[] apSsid, byte[] apBssid, byte[] apPassword, InetAddress inetAddress, + ITouchEncryptor encryptor) { + // generate guide code + GuideCode gc = new GuideCode(); + char[] gcU81 = gc.getU8s(); + mGcBytes2 = new byte[gcU81.length][]; + + for (int i = 0; i < mGcBytes2.length; i++) { + mGcBytes2[i] = ByteUtil.genSpecBytes(gcU81[i]); + } + + // generate data code + DatumCode dc = new DatumCode(apSsid, apBssid, apPassword, inetAddress, encryptor); + char[] dcU81 = dc.getU8s(); + mDcBytes2 = new byte[dcU81.length][]; + + for (int i = 0; i < mDcBytes2.length; i++) { + mDcBytes2[i] = ByteUtil.genSpecBytes(dcU81[i]); + } + } + + @Override + public byte[][] getGCBytes2() { + return mGcBytes2; + } + + @Override + public byte[][] getDCBytes2() { + return mDcBytes2; + } + +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/GuideCode.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/GuideCode.java new file mode 100644 index 00000000..a49bea2f --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/GuideCode.java @@ -0,0 +1,39 @@ +package com.espressif.iot.esptouch.protocol; + +import com.espressif.iot.esptouch.task.ICodeData; +import com.espressif.iot.esptouch.util.ByteUtil; + +public class GuideCode implements ICodeData { + + public static final int GUIDE_CODE_LEN = 4; + + @Override + public byte[] getBytes() { + throw new RuntimeException("DataCode don't support getBytes()"); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + char[] dataU8s = getU8s(); + for (int i = 0; i < GUIDE_CODE_LEN; i++) { + String hexString = ByteUtil.convertU8ToHexString(dataU8s[i]); + sb.append("0x"); + if (hexString.length() == 1) { + sb.append("0"); + } + sb.append(hexString).append(" "); + } + return sb.toString(); + } + + @Override + public char[] getU8s() { + char[] guidesU8s = new char[GUIDE_CODE_LEN]; + guidesU8s[0] = 515; + guidesU8s[1] = 514; + guidesU8s[2] = 513; + guidesU8s[3] = 512; + return guidesU8s; + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/TouchData.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/TouchData.java new file mode 100644 index 00000000..f96afaf0 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/protocol/TouchData.java @@ -0,0 +1,22 @@ +package com.espressif.iot.esptouch.protocol; + +import com.espressif.iot.esptouch.util.ByteUtil; + +public class TouchData { + private final byte[] mData; + + public TouchData(String string) { + mData = ByteUtil.getBytesByString(string); + } + + public TouchData(byte[] data) { + if (data == null) { + throw new NullPointerException("data can't be null"); + } + mData = data; + } + + public byte[] getData() { + return mData; + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/security/ITouchEncryptor.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/security/ITouchEncryptor.java new file mode 100644 index 00000000..9a8f463f --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/security/ITouchEncryptor.java @@ -0,0 +1,5 @@ +package com.espressif.iot.esptouch.security; + +public interface ITouchEncryptor { + byte[] encrypt(byte[] src); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/security/TouchAES.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/security/TouchAES.java new file mode 100644 index 00000000..bc7c6ae4 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/security/TouchAES.java @@ -0,0 +1,104 @@ +package com.espressif.iot.esptouch.security; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class TouchAES implements ITouchEncryptor { + private static final String TRANSFORMATION_DEFAULT = "AES/ECB/PKCS5Padding"; + + private final byte[] mKey; + private final byte[] mIV; + private final String mTransformation; + private Cipher mEncryptCipher; + private Cipher mDecryptCipher; + + public TouchAES(byte[] key) { + this(key, null, TRANSFORMATION_DEFAULT); + } + + public TouchAES(byte[] key, String transformation) { + this(key, null, transformation); + } + + public TouchAES(byte[] key, byte[] iv) { + this(key, iv, TRANSFORMATION_DEFAULT); + } + + public TouchAES(byte[] key, byte[] iv, String transformation) { + mKey = key; + mIV = iv; + mTransformation = transformation; + + mEncryptCipher = createEncryptCipher(); + mDecryptCipher = createDecryptCipher(); + } + + private Cipher createEncryptCipher() { + try { + Cipher cipher = Cipher.getInstance(mTransformation); + + SecretKeySpec secretKeySpec = new SecretKeySpec(mKey, "AES"); + if (mIV == null) { + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); + } else { + IvParameterSpec parameterSpec = new IvParameterSpec(mIV); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, parameterSpec); + } + + return cipher; + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException + e) { + e.printStackTrace(); + } + + return null; + } + + private Cipher createDecryptCipher() { + try { + Cipher cipher = Cipher.getInstance(mTransformation); + + SecretKeySpec secretKeySpec = new SecretKeySpec(mKey, "AES"); + if (mIV == null) { + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); + } else { + IvParameterSpec parameterSpec = new IvParameterSpec(mIV); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, parameterSpec); + } + + return cipher; + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException + e) { + e.printStackTrace(); + } + + return null; + } + + public byte[] encrypt(byte[] content) { + try { + return mEncryptCipher.doFinal(content); + } catch (BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + } + return null; + } + + public byte[] decrypt(byte[] content) { + try { + return mDecryptCipher.doFinal(content); + } catch (BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + } + + return null; + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/EsptouchTaskParameter.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/EsptouchTaskParameter.java new file mode 100644 index 00000000..7ea80864 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/EsptouchTaskParameter.java @@ -0,0 +1,165 @@ +package com.espressif.iot.esptouch.task; + +public class EsptouchTaskParameter implements IEsptouchTaskParameter { + + private static int _datagramCount = 0; + private long mIntervalGuideCodeMillisecond; + private long mIntervalDataCodeMillisecond; + private long mTimeoutGuideCodeMillisecond; + private long mTimeoutDataCodeMillisecond; + private int mTotalRepeatTime; + private int mEsptouchResultOneLen; + private int mEsptouchResultMacLen; + private int mEsptouchResultIpLen; + private int mEsptouchResultTotalLen; + private int mPortListening; + private int mTargetPort; + private int mWaitUdpReceivingMilliseond; + private int mWaitUdpSendingMillisecond; + private int mThresholdSucBroadcastCount; + private int mExpectTaskResultCount; + private boolean mBroadcast = true; + + public EsptouchTaskParameter() { + mIntervalGuideCodeMillisecond = 8; + mIntervalDataCodeMillisecond = 8; + mTimeoutGuideCodeMillisecond = 2000; + mTimeoutDataCodeMillisecond = 4000; + mTotalRepeatTime = 1; + mEsptouchResultOneLen = 1; + mEsptouchResultMacLen = 6; + mEsptouchResultIpLen = 4; + mEsptouchResultTotalLen = 1 + 6 + 4; + mPortListening = 18266; + mTargetPort = 7001; + mWaitUdpReceivingMilliseond = 15000; + mWaitUdpSendingMillisecond = 45000; + mThresholdSucBroadcastCount = 1; + mExpectTaskResultCount = 1; + } + + // the range of the result should be 1-100 + private static int __getNextDatagramCount() { + return 1 + (_datagramCount++) % 100; + } + + @Override + public long getIntervalGuideCodeMillisecond() { + return mIntervalGuideCodeMillisecond; + } + + @Override + public long getIntervalDataCodeMillisecond() { + return mIntervalDataCodeMillisecond; + } + + @Override + public long getTimeoutGuideCodeMillisecond() { + return mTimeoutGuideCodeMillisecond; + } + + @Override + public long getTimeoutDataCodeMillisecond() { + return mTimeoutDataCodeMillisecond; + } + + @Override + public long getTimeoutTotalCodeMillisecond() { + return mTimeoutGuideCodeMillisecond + mTimeoutDataCodeMillisecond; + } + + @Override + public int getTotalRepeatTime() { + return mTotalRepeatTime; + } + + @Override + public int getEsptouchResultOneLen() { + return mEsptouchResultOneLen; + } + + @Override + public int getEsptouchResultMacLen() { + return mEsptouchResultMacLen; + } + + @Override + public int getEsptouchResultIpLen() { + return mEsptouchResultIpLen; + } + + @Override + public int getEsptouchResultTotalLen() { + return mEsptouchResultTotalLen; + } + + @Override + public int getPortListening() { + return mPortListening; + } + + // target hostname is : 234.1.1.1, 234.2.2.2, 234.3.3.3 to 234.100.100.100 + @Override + public String getTargetHostname() { + if (mBroadcast) { + return "255.255.255.255"; + } else { + int count = __getNextDatagramCount(); + return "234." + count + "." + count + "." + count; + } + } + + @Override + public int getTargetPort() { + return mTargetPort; + } + + @Override + public int getWaitUdpReceivingMillisecond() { + return mWaitUdpReceivingMilliseond; + } + + @Override + public int getWaitUdpSendingMillisecond() { + return mWaitUdpSendingMillisecond; + } + + @Override + public int getWaitUdpTotalMillisecond() { + return mWaitUdpReceivingMilliseond + mWaitUdpSendingMillisecond; + } + + @Override + public void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond) { + if (waitUdpTotalMillisecond < mWaitUdpReceivingMilliseond + + getTimeoutTotalCodeMillisecond()) { + // if it happen, even one turn about sending udp broadcast can't be + // completed + throw new IllegalArgumentException( + "waitUdpTotalMillisecod is invalid, " + + "it is less than mWaitUdpReceivingMilliseond + getTimeoutTotalCodeMillisecond()"); + } + mWaitUdpSendingMillisecond = waitUdpTotalMillisecond + - mWaitUdpReceivingMilliseond; + } + + @Override + public int getThresholdSucBroadcastCount() { + return mThresholdSucBroadcastCount; + } + + @Override + public int getExpectTaskResultCount() { + return this.mExpectTaskResultCount; + } + + @Override + public void setExpectTaskResultCount(int expectTaskResultCount) { + this.mExpectTaskResultCount = expectTaskResultCount; + } + + @Override + public void setBroadcast(boolean broadcast) { + mBroadcast = broadcast; + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/ICodeData.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/ICodeData.java new file mode 100644 index 00000000..64e9c9b5 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/ICodeData.java @@ -0,0 +1,22 @@ +package com.espressif.iot.esptouch.task; + +/** + * the class used to represent some code to be transformed by UDP socket should implement the interface + * + * @author afunx + */ +public interface ICodeData { + /** + * Get the byte[] to be transformed. + * + * @return the byte[] to be transfromed + */ + byte[] getBytes(); + + /** + * Get the char[](u8[]) to be transfromed. + * + * @return the char[](u8) to be transformed + */ + char[] getU8s(); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchGenerator.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchGenerator.java new file mode 100644 index 00000000..07c8981f --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchGenerator.java @@ -0,0 +1,17 @@ +package com.espressif.iot.esptouch.task; + +public interface IEsptouchGenerator { + /** + * Get guide code by the format of byte[][] + * + * @return guide code by the format of byte[][] + */ + byte[][] getGCBytes2(); + + /** + * Get data code by the format of byte[][] + * + * @return data code by the format of byte[][] + */ + byte[][] getDCBytes2(); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchTaskParameter.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchTaskParameter.java new file mode 100644 index 00000000..f40e9535 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/IEsptouchTaskParameter.java @@ -0,0 +1,156 @@ +package com.espressif.iot.esptouch.task; + +public interface IEsptouchTaskParameter { + + /** + * get interval millisecond for guide code(the time between each guide code sending) + * + * @return interval millisecond for guide code(the time between each guide code sending) + */ + long getIntervalGuideCodeMillisecond(); + + /** + * get interval millisecond for data code(the time between each data code sending) + * + * @return interval millisecond for data code(the time between each data code sending) + */ + long getIntervalDataCodeMillisecond(); + + /** + * get timeout millisecond for guide code(the time how much the guide code sending) + * + * @return timeout millisecond for guide code(the time how much the guide code sending) + */ + long getTimeoutGuideCodeMillisecond(); + + /** + * get timeout millisecond for data code(the time how much the data code sending) + * + * @return timeout millisecond for data code(the time how much the data code sending) + */ + long getTimeoutDataCodeMillisecond(); + + /** + * get timeout millisecond for total code(guide code and data code altogether) + * + * @return timeout millisecond for total code(guide code and data code altogether) + */ + long getTimeoutTotalCodeMillisecond(); + + /** + * get total repeat time for executing esptouch task + * + * @return total repeat time for executing esptouch task + */ + int getTotalRepeatTime(); + + /** + * the length of the Esptouch result 1st byte is the total length of ssid and + * password, the other 6 bytes are the device's bssid + */ + + /** + * get esptouchResult length of one + * + * @return length of one + */ + int getEsptouchResultOneLen(); + + /** + * get esptouchResult length of mac + * + * @return length of mac + */ + int getEsptouchResultMacLen(); + + /** + * get esptouchResult length of ip + * + * @return length of ip + */ + int getEsptouchResultIpLen(); + + /** + * get esptouchResult total length + * + * @return total length + */ + int getEsptouchResultTotalLen(); + + /** + * get port for listening(used by server) + * + * @return port for listening(used by server) + */ + int getPortListening(); + + /** + * get target hostname + * + * @return target hostame(used by client) + */ + String getTargetHostname(); + + /** + * get target port + * + * @return target port(used by client) + */ + int getTargetPort(); + + /** + * get millisecond for waiting udp receiving(receiving without sending) + * + * @return millisecond for waiting udp receiving(receiving without sending) + */ + int getWaitUdpReceivingMillisecond(); + + /** + * get millisecond for waiting udp sending(sending including receiving) + * + * @return millisecond for waiting udep sending(sending including receiving) + */ + int getWaitUdpSendingMillisecond(); + + /** + * get millisecond for waiting udp sending and receiving + * + * @return millisecond for waiting udp sending and receiving + */ + int getWaitUdpTotalMillisecond(); + + /** + * set the millisecond for waiting udp sending and receiving + * + * @param waitUdpTotalMillisecond the millisecond for waiting udp sending and receiving + */ + void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond); + + /** + * get the threshold for how many correct broadcast should be received + * + * @return the threshold for how many correct broadcast should be received + */ + int getThresholdSucBroadcastCount(); + + /** + * get the count of expect task results + * + * @return the count of expect task results + */ + int getExpectTaskResultCount(); + + /** + * set the count of expect task results + * + * @param expectTaskResultCount the count of expect task results + */ + void setExpectTaskResultCount(int expectTaskResultCount); + + /** + * Set broadcast or multicast + * + * @param broadcast true is broadcast, false is multicast + */ + void setBroadcast(boolean broadcast); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__EsptouchTask.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__EsptouchTask.java new file mode 100644 index 00000000..0ffa7812 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__EsptouchTask.java @@ -0,0 +1,351 @@ +package com.espressif.iot.esptouch.task; + +import android.content.Context; +import android.os.Looper; +import android.util.Log; + +import com.espressif.iot.esptouch.EsptouchResult; +import com.espressif.iot.esptouch.IEsptouchListener; +import com.espressif.iot.esptouch.IEsptouchResult; +import com.espressif.iot.esptouch.IEsptouchTask; +import com.espressif.iot.esptouch.protocol.EsptouchGenerator; +import com.espressif.iot.esptouch.protocol.TouchData; +import com.espressif.iot.esptouch.security.ITouchEncryptor; +import com.espressif.iot.esptouch.udp.UDPSocketClient; +import com.espressif.iot.esptouch.udp.UDPSocketServer; +import com.espressif.iot.esptouch.util.ByteUtil; +import com.espressif.iot.esptouch.util.TouchNetUtil; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +public class __EsptouchTask implements __IEsptouchTask { + /** + * one indivisible data contain 3 9bits info + */ + private static final int ONE_DATA_LEN = 3; + + private static final String TAG = "__EsptouchTask"; + + private final UDPSocketClient mSocketClient; + private final UDPSocketServer mSocketServer; + private final byte[] mApSsid; + private final byte[] mApPassword; + private final byte[] mApBssid; + private final ITouchEncryptor mEncryptor; + private final Context mContext; + private final List mEsptouchResultList; + private volatile boolean mIsSuc = false; + private volatile boolean mIsInterrupt = false; + private volatile boolean mIsExecuted = false; + private AtomicBoolean mIsCancelled; + private IEsptouchTaskParameter mParameter; + private volatile Map mBssidTaskSucCountMap; + private IEsptouchListener mEsptouchListener; + private Thread mTask; + + public __EsptouchTask(Context context, TouchData apSsid, TouchData apBssid, TouchData apPassword, + ITouchEncryptor encryptor, IEsptouchTaskParameter parameter) { + Log.i(TAG, "Welcome Esptouch " + IEsptouchTask.ESPTOUCH_VERSION); + mContext = context; + mEncryptor = encryptor; + mApSsid = apSsid.getData(); + mApPassword = apPassword.getData(); + mApBssid = apBssid.getData(); + mIsCancelled = new AtomicBoolean(false); + mSocketClient = new UDPSocketClient(); + mParameter = parameter; + mSocketServer = new UDPSocketServer(mParameter.getPortListening(), + mParameter.getWaitUdpTotalMillisecond(), context); + mEsptouchResultList = new ArrayList<>(); + mBssidTaskSucCountMap = new HashMap<>(); + } + + private void __putEsptouchResult(boolean isSuc, String bssid, InetAddress inetAddress) { + synchronized (mEsptouchResultList) { + // check whether the result receive enough UDP response + boolean isTaskSucCountEnough = false; + Integer count = mBssidTaskSucCountMap.get(bssid); + if (count == null) { + count = 0; + } + ++count; + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "__putEsptouchResult(): count = " + count); + } + mBssidTaskSucCountMap.put(bssid, count); + isTaskSucCountEnough = count >= mParameter + .getThresholdSucBroadcastCount(); + if (!isTaskSucCountEnough) { + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "__putEsptouchResult(): count = " + count + + ", isn't enough"); + } + return; + } + // check whether the result is in the mEsptouchResultList already + boolean isExist = false; + for (IEsptouchResult esptouchResultInList : mEsptouchResultList) { + if (esptouchResultInList.getBssid().equals(bssid)) { + isExist = true; + break; + } + } + // only add the result who isn't in the mEsptouchResultList + if (!isExist) { + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "__putEsptouchResult(): put one more result " + + "bssid = " + bssid + " , address = " + inetAddress); + } + final IEsptouchResult esptouchResult = new EsptouchResult(isSuc, + bssid, inetAddress); + mEsptouchResultList.add(esptouchResult); + if (mEsptouchListener != null) { + mEsptouchListener.onEsptouchResultAdded(esptouchResult); + } + } + } + } + + private List __getEsptouchResultList() { + synchronized (mEsptouchResultList) { + if (mEsptouchResultList.isEmpty()) { + EsptouchResult esptouchResultFail = new EsptouchResult(false, + null, null); + esptouchResultFail.setIsCancelled(mIsCancelled.get()); + mEsptouchResultList.add(esptouchResultFail); + } + + return mEsptouchResultList; + } + } + + private synchronized void __interrupt() { + if (!mIsInterrupt) { + mIsInterrupt = true; + mSocketClient.interrupt(); + mSocketServer.interrupt(); + // interrupt the current Thread which is used to wait for udp response + if (mTask != null) { + mTask.interrupt(); + mTask = null; + } + } + } + + @Override + public void interrupt() { + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "interrupt()"); + } + mIsCancelled.set(true); + __interrupt(); + } + + private void __listenAsyn(final int expectDataLen) { + mTask = new Thread() { + public void run() { + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "__listenAsyn() start"); + } + long startTimestamp = System.currentTimeMillis(); +// byte[] apSsidAndPassword = ByteUtil.getBytesByString(mApSsid +// + mApPassword); + byte expectOneByte = (byte) (mApSsid.length + mApPassword.length + 9); + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "expectOneByte: " + expectOneByte); + } + byte receiveOneByte = -1; + byte[] receiveBytes = null; + while (mEsptouchResultList.size() < mParameter + .getExpectTaskResultCount() && !mIsInterrupt) { + receiveBytes = mSocketServer + .receiveSpecLenBytes(expectDataLen); + if (receiveBytes != null) { + receiveOneByte = receiveBytes[0]; + } else { + receiveOneByte = -1; + } + if (receiveOneByte == expectOneByte) { + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "receive correct broadcast"); + } + // change the socket's timeout + long consume = System.currentTimeMillis() + - startTimestamp; + int timeout = (int) (mParameter + .getWaitUdpTotalMillisecond() - consume); + if (timeout < 0) { + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "esptouch timeout"); + } + break; + } else { + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "mSocketServer's new timeout is " + + timeout + " milliseconds"); + } + mSocketServer.setSoTimeout(timeout); + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "receive correct broadcast"); + } + if (receiveBytes != null) { + String bssid = ByteUtil.parseBssid( + receiveBytes, + mParameter.getEsptouchResultOneLen(), + mParameter.getEsptouchResultMacLen()); + InetAddress inetAddress = TouchNetUtil + .parseInetAddr( + receiveBytes, + mParameter + .getEsptouchResultOneLen() + + mParameter + .getEsptouchResultMacLen(), + mParameter + .getEsptouchResultIpLen()); + __putEsptouchResult(true, bssid, inetAddress); + } + } + } else { + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "receive rubbish message, just ignore"); + } + } + } + mIsSuc = mEsptouchResultList.size() >= mParameter + .getExpectTaskResultCount(); + __EsptouchTask.this.__interrupt(); + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "__listenAsyn() finish"); + } + } + }; + mTask.start(); + } + + private boolean __execute(IEsptouchGenerator generator) { + + long startTime = System.currentTimeMillis(); + long currentTime = startTime; + long lastTime = currentTime - mParameter.getTimeoutTotalCodeMillisecond(); + + byte[][] gcBytes2 = generator.getGCBytes2(); + byte[][] dcBytes2 = generator.getDCBytes2(); + + int index = 0; + while (!mIsInterrupt) { + if (currentTime - lastTime >= mParameter.getTimeoutTotalCodeMillisecond()) { + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "send gc code "); + } + // send guide code + while (!mIsInterrupt + && System.currentTimeMillis() - currentTime < mParameter + .getTimeoutGuideCodeMillisecond()) { + mSocketClient.sendData(gcBytes2, + mParameter.getTargetHostname(), + mParameter.getTargetPort(), + mParameter.getIntervalGuideCodeMillisecond()); + // check whether the udp is send enough time + if (System.currentTimeMillis() - startTime > mParameter.getWaitUdpSendingMillisecond()) { + break; + } + } + lastTime = currentTime; + } else { + mSocketClient.sendData(dcBytes2, index, ONE_DATA_LEN, + mParameter.getTargetHostname(), + mParameter.getTargetPort(), + mParameter.getIntervalDataCodeMillisecond()); + index = (index + ONE_DATA_LEN) % dcBytes2.length; + } + currentTime = System.currentTimeMillis(); + // check whether the udp is send enough time + if (currentTime - startTime > mParameter.getWaitUdpSendingMillisecond()) { + break; + } + } + + return mIsSuc; + } + + private void __checkTaskValid() { + // !!!NOTE: the esptouch task could be executed only once + if (this.mIsExecuted) { + throw new IllegalStateException( + "the Esptouch task could be executed only once"); + } + this.mIsExecuted = true; + } + + @Override + public IEsptouchResult executeForResult() throws RuntimeException { + return executeForResults(1).get(0); + } + + @Override + public boolean isCancelled() { + return this.mIsCancelled.get(); + } + + @Override + public List executeForResults(int expectTaskResultCount) + throws RuntimeException { + __checkTaskValid(); + + mParameter.setExpectTaskResultCount(expectTaskResultCount); + + if (__IEsptouchTask.DEBUG) { + Log.d(TAG, "execute()"); + } + if (Looper.myLooper() == Looper.getMainLooper()) { + throw new RuntimeException( + "Don't call the esptouch Task at Main(UI) thread directly."); + } + InetAddress localInetAddress = TouchNetUtil.getLocalInetAddress(mContext); + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "localInetAddress: " + localInetAddress); + } + // generator the esptouch byte[][] to be transformed, which will cost + // some time(maybe a bit much) + IEsptouchGenerator generator = new EsptouchGenerator(mApSsid, mApBssid, + mApPassword, localInetAddress, mEncryptor); + // listen the esptouch result asyn + __listenAsyn(mParameter.getEsptouchResultTotalLen()); + boolean isSuc = false; + for (int i = 0; i < mParameter.getTotalRepeatTime(); i++) { + isSuc = __execute(generator); + if (isSuc) { + return __getEsptouchResultList(); + } + } + + if (!mIsInterrupt) { + // wait the udp response without sending udp broadcast + try { + Thread.sleep(mParameter.getWaitUdpReceivingMillisecond()); + } catch (InterruptedException e) { + // receive the udp broadcast or the user interrupt the task + if (this.mIsSuc) { + return __getEsptouchResultList(); + } else { + this.__interrupt(); + return __getEsptouchResultList(); + } + } + this.__interrupt(); + } + + return __getEsptouchResultList(); + } + + @Override + public void setEsptouchListener(IEsptouchListener esptouchListener) { + mEsptouchListener = esptouchListener; + } + +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__IEsptouchTask.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__IEsptouchTask.java new file mode 100644 index 00000000..216e09b9 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/task/__IEsptouchTask.java @@ -0,0 +1,55 @@ +package com.espressif.iot.esptouch.task; + +import com.espressif.iot.esptouch.IEsptouchListener; +import com.espressif.iot.esptouch.IEsptouchResult; + +import java.util.List; + +/** + * IEsptouchTask defined the task of esptouch should offer. INTERVAL here means + * the milliseconds of interval of the step. REPEAT here means the repeat times + * of the step. + * + * @author afunx + */ +public interface __IEsptouchTask { + + /** + * Turn on or off the log. + */ + static final boolean DEBUG = true; + + /** + * set the esptouch listener, when one device is connected to the Ap, it will be called back + * + * @param esptouchListener when one device is connected to the Ap, it will be called back + */ + void setEsptouchListener(IEsptouchListener esptouchListener); + + /** + * Interrupt the Esptouch Task when User tap back or close the Application. + */ + void interrupt(); + + /** + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will + * be thrown Execute the Esptouch Task and return the result + * + * @return the IEsptouchResult + * @throws RuntimeException + */ + IEsptouchResult executeForResult() throws RuntimeException; + + /** + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will + * be thrown Execute the Esptouch Task and return the result + * + * @param expectTaskResultCount the expect result count(if expectTaskResultCount <= 0, + * expectTaskResultCount = Integer.MAX_VALUE) + * @return the list of IEsptouchResult + * @throws RuntimeException + */ + List executeForResults(int expectTaskResultCount) throws RuntimeException; + + boolean isCancelled(); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketClient.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketClient.java new file mode 100644 index 00000000..7ca7880e --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketClient.java @@ -0,0 +1,130 @@ +package com.espressif.iot.esptouch.udp; + +import android.util.Log; + +import com.espressif.iot.esptouch.task.__IEsptouchTask; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; + +/** + * this class is used to help send UDP data according to length + * + * @author afunx + */ +public class UDPSocketClient { + + private static final String TAG = "UDPSocketClient"; + private DatagramSocket mSocket; + private volatile boolean mIsStop; + private volatile boolean mIsClosed; + + public UDPSocketClient() { + try { + this.mSocket = new DatagramSocket(); + this.mIsStop = false; + this.mIsClosed = false; + } catch (SocketException e) { + if (__IEsptouchTask.DEBUG) { + Log.w(TAG, "SocketException"); + } + e.printStackTrace(); + } + } + + @Override + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + + public void interrupt() { + if (__IEsptouchTask.DEBUG) { + Log.i(TAG, "USPSocketClient is interrupt"); + } + this.mIsStop = true; + } + + /** + * close the UDP socket + */ + public synchronized void close() { + if (!this.mIsClosed) { + this.mSocket.close(); + this.mIsClosed = true; + } + } + + /** + * send the data by UDP + * + * @param data the data to be sent + * @param targetPort the port of target + * @param interval the milliseconds to between each UDP sent + */ + public void sendData(byte[][] data, String targetHostName, int targetPort, + long interval) { + sendData(data, 0, data.length, targetHostName, targetPort, interval); + } + + + /** + * send the data by UDP + * + * @param data the data to be sent + * @param offset the offset which data to be sent + * @param count the count of the data + * @param targetPort the port of target + * @param interval the milliseconds to between each UDP sent + */ + public void sendData(byte[][] data, int offset, int count, + String targetHostName, int targetPort, long interval) { + if ((data == null) || (data.length <= 0)) { + if (__IEsptouchTask.DEBUG) { + Log.w(TAG, "sendData(): data == null or length <= 0"); + } + return; + } + for (int i = offset; !mIsStop && i < offset + count; i++) { + if (data[i].length == 0) { + continue; + } + try { + InetAddress targetInetAddress = InetAddress.getByName(targetHostName); + DatagramPacket localDatagramPacket = new DatagramPacket( + data[i], data[i].length, targetInetAddress, targetPort); + this.mSocket.send(localDatagramPacket); + } catch (UnknownHostException e) { + if (__IEsptouchTask.DEBUG) { + Log.w(TAG, "sendData(): UnknownHostException"); + } + e.printStackTrace(); + mIsStop = true; + break; + } catch (IOException e) { + if (__IEsptouchTask.DEBUG) { + Log.w(TAG, "sendData(): IOException, but just ignore it"); + } + // for the Ap will make some troubles when the phone send too many UDP packets, + // but we don't expect the UDP packet received by others, so just ignore it + } + try { + Thread.sleep(interval); + } catch (InterruptedException e) { + e.printStackTrace(); + if (__IEsptouchTask.DEBUG) { + Log.w(TAG, "sendData is Interrupted"); + } + mIsStop = true; + break; + } + } + if (mIsStop) { + close(); + } + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketServer.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketServer.java new file mode 100644 index 00000000..049f3ffc --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/udp/UDPSocketServer.java @@ -0,0 +1,149 @@ +package com.espressif.iot.esptouch.udp; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.util.Log; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.util.Arrays; + +public class UDPSocketServer { + private static final String TAG = "UDPSocketServer"; + private DatagramSocket mServerSocket; + private Context mContext; + private WifiManager.MulticastLock mLock; + private volatile boolean mIsClosed; + + /** + * Constructor of UDP Socket Server + * + * @param port the Socket Server port + * @param socketTimeout the socket read timeout + * @param context the context of the Application + */ + public UDPSocketServer(int port, int socketTimeout, Context context) { + this.mContext = context; + try { + this.mServerSocket = new DatagramSocket(null); + this.mServerSocket.setReuseAddress(true); + this.mServerSocket.bind(new InetSocketAddress(port)); + this.mServerSocket.setSoTimeout(socketTimeout); + } catch (IOException e) { + Log.w(TAG, "IOException"); + e.printStackTrace(); + } + this.mIsClosed = false; + WifiManager manager = (WifiManager) mContext.getApplicationContext() + .getSystemService(Context.WIFI_SERVICE); + mLock = manager.createMulticastLock("test wifi"); + Log.d(TAG, "mServerSocket is created, socket read timeout: " + + socketTimeout + ", port: " + port); + } + + private synchronized void acquireLock() { + if (mLock != null && !mLock.isHeld()) { + mLock.acquire(); + } + } + + private synchronized void releaseLock() { + if (mLock != null && mLock.isHeld()) { + try { + mLock.release(); + } catch (Throwable th) { + // ignoring this exception, probably wakeLock was already released + } + } + } + + /** + * Set the socket timeout in milliseconds + * + * @param timeout the timeout in milliseconds or 0 for no timeout. + * @return true whether the timeout is set suc + */ + public boolean setSoTimeout(int timeout) { + try { + this.mServerSocket.setSoTimeout(timeout); + return true; + } catch (SocketException e) { + e.printStackTrace(); + } + return false; + } + + /** + * Receive one byte from the port and convert it into String + * + * @return + */ + public byte receiveOneByte() { + Log.d(TAG, "receiveOneByte() entrance"); + try { + acquireLock(); + DatagramPacket packet = new DatagramPacket(new byte[1], 1); + mServerSocket.receive(packet); + Log.d(TAG, "receive: " + (packet.getData()[0])); + return packet.getData()[0]; + } catch (Exception e) { + e.printStackTrace(); + } + return -1; + } + + /** + * Receive specific length bytes from the port and convert it into String + * 21,24,-2,52,-102,-93,-60 + * 15,18,fe,34,9a,a3,c4 + * + * @return + */ + public byte[] receiveSpecLenBytes(int len) { + Log.d(TAG, "receiveSpecLenBytes() entrance: len = " + len); + try { + acquireLock(); + DatagramPacket packet = new DatagramPacket(new byte[64], 64); + mServerSocket.receive(packet); + byte[] recDatas = Arrays.copyOf(packet.getData(), packet.getLength()); + Log.d(TAG, "received len : " + recDatas.length); + for (int i = 0; i < recDatas.length; i++) { + Log.w(TAG, "recDatas[" + i + "]:" + recDatas[i]); + } + Log.w(TAG, "receiveSpecLenBytes: " + new String(recDatas)); + if (recDatas.length != len) { + Log.w(TAG, + "received len is different from specific len, return null"); + return null; + } + return recDatas; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public void interrupt() { + Log.i(TAG, "USPSocketServer is interrupt"); + close(); + } + + public synchronized void close() { + if (!this.mIsClosed) { + Log.w(TAG, "mServerSocket is closed"); + mServerSocket.close(); + releaseLock(); + this.mIsClosed = true; + } + } + + @Override + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/ByteUtil.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/ByteUtil.java new file mode 100644 index 00000000..15c85db4 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/ByteUtil.java @@ -0,0 +1,323 @@ +package com.espressif.iot.esptouch.util; + +import java.io.UnsupportedEncodingException; +import java.util.Random; + +/** + * In Java, it don't support unsigned int, so we use char to replace uint8. + * The range of byte is [-128,127], and the range of char is [0,65535]. + * So the byte could used to store the uint8. + * (We assume that the String could be mapped to assic) + * + * @author afunx + */ +public class ByteUtil { + + public static final String ESPTOUCH_ENCODING_CHARSET = "UTF-8"; + + /** + * Put String to byte[] + * + * @param destbytes the byte[] of dest + * @param srcString the String of src + * @param destOffset the offset of byte[] + * @param srcOffset the offset of String + * @param count the count of dest, and the count of src as well + */ + public static void putString2bytes(byte[] destbytes, String srcString, + int destOffset, int srcOffset, int count) { + for (int i = 0; i < count; i++) { + destbytes[count + i] = srcString.getBytes()[i]; + } + } + + /** + * Convert uint8 into char( we treat char as uint8) + * + * @param uint8 the unit8 to be converted + * @return the byte of the unint8 + */ + public static byte convertUint8toByte(char uint8) { + if (uint8 > Byte.MAX_VALUE - Byte.MIN_VALUE) { + throw new RuntimeException("Out of Boundary"); + } + return (byte) uint8; + } + + /** + * Convert char into uint8( we treat char as uint8 ) + * + * @param b the byte to be converted + * @return the char(uint8) + */ + public static char convertByte2Uint8(byte b) { + // char will be promoted to int for char don't support & operator + // & 0xff could make negatvie value to positive + return (char) (b & 0xff); + } + + /** + * Convert byte[] into char[]( we treat char[] as uint8[]) + * + * @param bytes the byte[] to be converted + * @return the char[](uint8[]) + */ + public static char[] convertBytes2Uint8s(byte[] bytes) { + int len = bytes.length; + char[] uint8s = new char[len]; + for (int i = 0; i < len; i++) { + uint8s[i] = convertByte2Uint8(bytes[i]); + } + return uint8s; + } + + /** + * Put byte[] into char[]( we treat char[] as uint8[]) + * + * @param destUint8s the char[](uint8[]) array + * @param srcBytes the byte[] + * @param destOffset the offset of char[](uint8[]) + * @param srcOffset the offset of byte[] + * @param count the count of dest, and the count of src as well + */ + public static void putbytes2Uint8s(char[] destUint8s, byte[] srcBytes, + int destOffset, int srcOffset, int count) { + for (int i = 0; i < count; i++) { + destUint8s[destOffset + i] = convertByte2Uint8(srcBytes[srcOffset + + i]); + } + } + + /** + * Convert byte to Hex String + * + * @param b the byte to be converted + * @return the Hex String + */ + public static String convertByte2HexString(byte b) { + char u8 = convertByte2Uint8(b); + return Integer.toHexString(u8); + } + + /** + * Convert char(uint8) to Hex String + * + * @param u8 the char(uint8) to be converted + * @return the Hex String + */ + public static String convertU8ToHexString(char u8) { + return Integer.toHexString(u8); + } + + /** + * Split uint8 to 2 bytes of high byte and low byte. e.g. 20 = 0x14 should + * be split to [0x01,0x04] 0x01 is high byte and 0x04 is low byte + * + * @param uint8 the char(uint8) + * @return the high and low bytes be split, byte[0] is high and byte[1] is + * low + */ + public static byte[] splitUint8To2bytes(char uint8) { + if (uint8 < 0 || uint8 > 0xff) { + throw new RuntimeException("Out of Boundary"); + } + String hexString = Integer.toHexString(uint8); + byte low; + byte high; + if (hexString.length() > 1) { + high = (byte) Integer.parseInt(hexString.substring(0, 1), 16); + low = (byte) Integer.parseInt(hexString.substring(1, 2), 16); + } else { + high = 0; + low = (byte) Integer.parseInt(hexString.substring(0, 1), 16); + } + byte[] result = new byte[]{high, low}; + return result; + } + + /** + * Combine 2 bytes (high byte and low byte) to one whole byte + * + * @param high the high byte + * @param low the low byte + * @return the whole byte + */ + public static byte combine2bytesToOne(byte high, byte low) { + if (high < 0 || high > 0xf || low < 0 || low > 0xf) { + throw new RuntimeException("Out of Boundary"); + } + return (byte) (high << 4 | low); + } + + /** + * Combine 2 bytes (high byte and low byte) to + * + * @param high the high byte + * @param low the low byte + * @return the char(u8) + */ + public static char combine2bytesToU16(byte high, byte low) { + char highU8 = convertByte2Uint8(high); + char lowU8 = convertByte2Uint8(low); + return (char) (highU8 << 8 | lowU8); + } + + /** + * Generate the random byte to be sent + * + * @return the random byte + */ + private static byte randomByte() { + return (byte) (127 - new Random().nextInt(256)); + } + + /** + * Generate the random byte to be sent + * + * @param len the len presented by u8 + * @return the byte[] to be sent + */ + public static byte[] randomBytes(char len) { + byte[] data = new byte[len]; + for (int i = 0; i < len; i++) { + data[i] = randomByte(); + } + return data; + } + + public static byte[] genSpecBytes(char len) { + byte[] data = new byte[len]; + for (int i = 0; i < len; i++) { + data[i] = '1'; + } + return data; + } + + /** + * Generate the random byte to be sent + * + * @param len the len presented by byte + * @return the byte[] to be sent + */ + public static byte[] randomBytes(byte len) { + char u8 = convertByte2Uint8(len); + return randomBytes(u8); + } + + /** + * Generate the specific byte to be sent + * + * @param len the len presented by byte + * @return the byte[] + */ + public static byte[] genSpecBytes(byte len) { + char u8 = convertByte2Uint8(len); + return genSpecBytes(u8); + } + + public static String parseBssid(byte[] bssidBytes, int offset, int count) { + byte[] bytes = new byte[count]; + System.arraycopy(bssidBytes, offset, bytes, 0, count); + return parseBssid(bytes); + } + + /** + * parse "24,-2,52,-102,-93,-60" to "18,fe,34,9a,a3,c4" + * parse the bssid from hex to String + * + * @param bssidBytes the hex bytes bssid, e.g. {24,-2,52,-102,-93,-60} + * @return the String of bssid, e.g. 18fe349aa3c4 + */ + public static String parseBssid(byte[] bssidBytes) { + StringBuilder sb = new StringBuilder(); + int k; + String hexK; + String str; + for (byte bssidByte : bssidBytes) { + k = 0xff & bssidByte; + hexK = Integer.toHexString(k); + str = ((k < 16) ? ("0" + hexK) : (hexK)); + System.out.println(str); + sb.append(str); + } + return sb.toString(); + } + + /** + * @param string the string to be used + * @return the byte[] of String according to {@link #ESPTOUCH_ENCODING_CHARSET} + */ + public static byte[] getBytesByString(String string) { + try { + return string.getBytes(ESPTOUCH_ENCODING_CHARSET); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("the charset is invalid"); + } + } + + private static void test_splitUint8To2bytes() { + // 20 = 0x14 + byte[] result = splitUint8To2bytes((char) 20); + if (result[0] == 1 && result[1] == 4) { + System.out.println("test_splitUint8To2bytes(): pass"); + } else { + System.out.println("test_splitUint8To2bytes(): fail"); + } + } + + private static void test_combine2bytesToOne() { + byte high = 0x01; + byte low = 0x04; + if (combine2bytesToOne(high, low) == 20) { + System.out.println("test_combine2bytesToOne(): pass"); + } else { + System.out.println("test_combine2bytesToOne(): fail"); + } + } + + private static void test_convertChar2Uint8() { + byte b1 = 'a'; + // -128: 1000 0000 should be 128 in unsigned char + // -1: 1111 1111 should be 255 in unsigned char + byte b2 = (byte) -128; + byte b3 = (byte) -1; + if (convertByte2Uint8(b1) == 97 && convertByte2Uint8(b2) == 128 + && convertByte2Uint8(b3) == 255) { + System.out.println("test_convertChar2Uint8(): pass"); + } else { + System.out.println("test_convertChar2Uint8(): fail"); + } + } + + private static void test_convertUint8toByte() { + char c1 = 'a'; + // 128: 1000 0000 should be -128 in byte + // 255: 1111 1111 should be -1 in byte + char c2 = 128; + char c3 = 255; + if (convertUint8toByte(c1) == 97 && convertUint8toByte(c2) == -128 + && convertUint8toByte(c3) == -1) { + System.out.println("test_convertUint8toByte(): pass"); + } else { + System.out.println("test_convertUint8toByte(): fail"); + } + } + + private static void test_parseBssid() { + byte b[] = {15, -2, 52, -102, -93, -60}; + if (parseBssid(b).equals("0ffe349aa3c4")) { + System.out.println("test_parseBssid(): pass"); + } else { + System.out.println("test_parseBssid(): fail"); + } + } + + public static void main(String args[]) { + test_convertUint8toByte(); + test_convertChar2Uint8(); + test_splitUint8To2bytes(); + test_combine2bytesToOne(); + test_parseBssid(); + } + +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/CRC8.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/CRC8.java new file mode 100644 index 00000000..20b35dba --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/CRC8.java @@ -0,0 +1,63 @@ +package com.espressif.iot.esptouch.util; + +import java.util.zip.Checksum; + +public class CRC8 implements Checksum { + + private static final short[] crcTable = new short[256]; + private static final short CRC_POLYNOM = 0x8c; + private static final short CRC_INITIAL = 0x00; + + static { + for (int dividend = 0; dividend < 256; dividend++) { + int remainder = dividend;// << 8; + for (int bit = 0; bit < 8; ++bit) + if ((remainder & 0x01) != 0) + remainder = (remainder >>> 1) ^ CRC_POLYNOM; + else + remainder >>>= 1; + crcTable[dividend] = (short) remainder; + } + } + + private final short init; + private short value; + + public CRC8() { + this.value = this.init = CRC_INITIAL; + } + + @Override + public void update(byte[] buffer, int offset, int len) { + for (int i = 0; i < len; i++) { + int data = buffer[offset + i] ^ value; + value = (short) (crcTable[data & 0xff] ^ (value << 8)); + } + } + + /** + * Updates the current checksum with the specified array of bytes. + * Equivalent to calling update(buffer, 0, buffer.length). + * + * @param buffer the byte array to update the checksum with + */ + public void update(byte[] buffer) { + update(buffer, 0, buffer.length); + } + + @Override + public void update(int b) { + update(new byte[]{(byte) b}, 0, 1); + } + + @Override + public long getValue() { + return value & 0xff; + } + + @Override + public void reset() { + value = init; + } + +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/TouchNetUtil.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/TouchNetUtil.java new file mode 100644 index 00000000..d714600c --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/util/TouchNetUtil.java @@ -0,0 +1,118 @@ +package com.espressif.iot.esptouch.util; + +import android.content.Context; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class TouchNetUtil { + + /** + * get the local ip address by Android System + * + * @param context the context + * @return the local ip addr allocated by Ap + */ + public static InetAddress getLocalInetAddress(Context context) { + WifiManager wm = (WifiManager) context.getApplicationContext() + .getSystemService(Context.WIFI_SERVICE); + assert wm != null; + WifiInfo wifiInfo = wm.getConnectionInfo(); + int localAddrInt = wifiInfo.getIpAddress(); + String localAddrStr = __formatString(localAddrInt); + InetAddress localInetAddr = null; + try { + localInetAddr = InetAddress.getByName(localAddrStr); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return localInetAddr; + } + + private static String __formatString(int value) { + StringBuilder strValue = new StringBuilder(); + byte[] ary = __intToByteArray(value); + for (int i = ary.length - 1; i >= 0; i--) { + strValue.append(ary[i] & 0xFF); + if (i > 0) { + strValue.append("."); + } + } + return strValue.toString(); + } + + private static byte[] __intToByteArray(int value) { + byte[] b = new byte[4]; + for (int i = 0; i < 4; i++) { + int offset = (b.length - 1 - i) * 8; + b[i] = (byte) ((value >>> offset) & 0xFF); + } + return b; + } + + /** + * parse InetAddress + * + * @param inetAddrBytes + * @return + */ + public static InetAddress parseInetAddr(byte[] inetAddrBytes, int offset, + int count) { + InetAddress inetAddress = null; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < count; i++) { + sb.append((inetAddrBytes[offset + i] & 0xff)); + if (i != count - 1) { + sb.append('.'); + } + } + try { + inetAddress = InetAddress.getByName(sb.toString()); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return inetAddress; + } + + /** + * parse bssid + * + * @param bssid the bssid like aa:bb:cc:dd:ee:ff + * @return byte converted from bssid + */ + public static byte[] parseBssid2bytes(String bssid) { + String[] bssidSplits = bssid.split(":"); + byte[] result = new byte[bssidSplits.length]; + for (int i = 0; i < bssidSplits.length; i++) { + result[i] = (byte) Integer.parseInt(bssidSplits[i], 16); + } + return result; + } + + public static byte[] getOriginalSsidBytes(WifiInfo info) { + try { + Method method = info.getClass().getMethod("getWifiSsid"); + method.setAccessible(true); + Object wifiSsid = method.invoke(info); + if (wifiSsid == null) { + return null; + } + method = wifiSsid.getClass().getMethod("getOctets"); + method.setAccessible(true); + return (byte[]) method.invoke(wifiSsid); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NullPointerException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..5d43612f --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# 是否打包APK,打正式包时请设置为true,使用正式的签名 +isNeedPackage=false +# 是否使用booster优化APK,这里需要注意gradle的版本,对于最新的gradle版本可能存在兼容问题 +isUseBooster=false +android.precompileDependenciesResources=false + +android.useAndroidX=true +android.enableJetifier=true + +android.enableD8=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f6b961fd5a86aa5fbfe90f707c3138408be7c718 GIT binary patch literal 54329 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

<5G2M1WZP5 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 F{|7XC?P&l2 literal 0 HcmV?d00001 diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..ac44e589 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 28 16:23:16 CST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip diff --git a/android/gradlew b/android/gradlew new file mode 100644 index 00000000..cccdd3d5 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 00000000..f9553162 --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 00000000..002fcc6c --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +include ':app',':esptouch' diff --git a/android/versions.gradle b/android/versions.gradle new file mode 100644 index 00000000..534aad86 --- /dev/null +++ b/android/versions.gradle @@ -0,0 +1,173 @@ +import java.util.regex.Matcher +import java.util.regex.Pattern + +/** + * Shared file between builds so that they can all use the same dependencies and + * maven repositories. + **/ +ext.deps = [:] +def versions = [:] +versions.android_gradle_plugin = "3.6.1" +versions.android_maven_gradle_plugin = "2.0" +versions.gradle_bintray_plugin = "1.8.0" +versions.booster = "3.1.0" +versions.booster_all = "1.1.1" +versions.support = "28.0.0" +versions.androidx = "1.1.0" +versions.junit = "4.12" +versions.espresso = "3.2.0" +versions.constraint_layout = "1.1.3" +versions.glide = "4.11.0" +versions.rxjava2 = "2.2.20" +versions.rxandroid = "2.1.1" +versions.rxbinding = "2.2.0" +versions.butterknife = "10.1.0" +versions.runner = "1.2.0" +versions.gson = "2.8.5" + +def deps = [:] + +def support = [:] +support.annotations = "com.android.support:support-annotations:$versions.support" +support.app_compat = "com.android.support:appcompat-v7:$versions.support" +support.recyclerview = "com.android.support:recyclerview-v7:$versions.support" +support.cardview = "com.android.support:cardview-v7:$versions.support" +support.design = "com.android.support:design:$versions.support" +support.v4 = "com.android.support:support-v4:$versions.support" +support.core_utils = "com.android.support:support-core-utils:$versions.support" +deps.support = support + +def androidx = [:] +androidx.annotations = "androidx.annotation:annotation:$versions.androidx" +androidx.appcompat = "androidx.appcompat:appcompat:$versions.androidx" +androidx.recyclerview = "androidx.recyclerview:recyclerview:$versions.androidx" +androidx.design = "com.google.android.material:material:$versions.androidx" +androidx.multidex = 'androidx.multidex:multidex:2.0.1' +deps.androidx = androidx + +def booster = [:] +booster.gradle_plugin = "com.didiglobal.booster:booster-gradle-plugin:$versions.booster" +booster.task_all = "com.didiglobal.booster:booster-task-all:$versions.booster_all" +booster.transform_all = "com.didiglobal.booster:booster-transform-all:$versions.booster_all" +//采用 cwebp 对资源进行压缩 +booster.task_compression_cwebp = "com.didiglobal.booster:booster-task-compression-cwebp:$versions.booster" +//采用 pngquant 对资源进行压缩 +booster.task_compression_pngquant = "com.didiglobal.booster:booster-task-compression-pngquant:$versions.booster" +//ap_ 文件压缩 +booster.task_processed_res = "com.didiglobal.booster:booster-task-compression-processed-res:$versions.booster" +//去冗余资源 +booster.task_resource_deredundancy = "com.didiglobal.booster:booster-task-resource-deredundancy:$versions.booster" +//检查 SNAPSHOT 版本 +booster.task_check_snapshot = "com.didiglobal.booster:booster-task-check-snapshot:$versions.booster" +//性能瓶颈检测 +booster.transform_lint = "com.didiglobal.booster:booster-transform-lint:$versions.booster" +//多线程优化 +booster.transform_thread = "com.didiglobal.booster:booster-transform-thread:$versions.booster" +//资源索引内联 +booster.transform_r_inline = "com.didiglobal.booster:booster-transform-r-inline:$versions.booster" +//WebView 预加载 +booster.transform_webview = "com.didiglobal.booster:booster-transform-webview:$versions.booster" +//SharedPreferences 优化 +booster.transform_shared_preferences = "com.didiglobal.booster:booster-transform-shared-preferences:$versions.booster" +//检查覆盖安装导致的 Resources 和 Assets 未加载的 Bug +booster.transform_res_check = "com.didiglobal.booster:booster-transform-res-check:$versions.booster" +//修复 Toast 在 Android 7.1 上的 Bug +booster.transform_toast = "com.didiglobal.booster:booster-transform-toast:$versions.booster" +//处理系统 Crash +booster.transform_activity_thread = "com.didiglobal.booster:booster-transform-activity-thread:$versions.booster" +deps.booster = booster + +def butterknife = [:] +butterknife.runtime = "com.jakewharton:butterknife:$versions.butterknife" +butterknife.compiler = "com.jakewharton:butterknife-compiler:$versions.butterknife" + +deps.butterknife = butterknife + +def espresso = [:] +espresso.core = "androidx.test.espresso:espresso-core:$versions.espresso" +espresso.contrib = "androidx.test.espresso:espresso-contrib:$versions.espresso" +espresso.intents = "androidx.test.espresso:espresso-intents:$versions.espresso" +deps.espresso = espresso + +deps.android_gradle_plugin = "com.android.tools.build:gradle:$versions.android_gradle_plugin" +deps.android_maven_gradle_plugin = "com.github.dcendents:android-maven-gradle-plugin:$versions.android_maven_gradle_plugin" +deps.gradle_bintray_plugin = "com.jfrog.bintray.gradle:gradle-bintray-plugin:$versions.gradle_bintray_plugin" +deps.glide = "com.github.bumptech.glide:glide:$versions.glide" +deps.constraint_layout = "androidx.constraint:constraint-layout:$versions.constraint_layout" +deps.junit = "junit:junit:$versions.junit" +deps.runner = "androidx.test:runner:$versions.runner" +deps.rxjava2 = "io.reactivex.rxjava2:rxjava:$versions.rxjava2" +deps.rxandroid = "io.reactivex.rxjava2:rxandroid:$versions.rxandroid" +deps.rxbinding = "com.jakewharton.rxbinding2:rxbinding:$versions.rxbinding" +deps.gson = "com.google.code.gson:gson:$versions.gson" + +ext.deps = deps + +def build_versions = [:] +build_versions.min_sdk = 19 +build_versions.target_sdk = 28 +build_versions.build_tools = "28.0.3" +ext.build_versions = build_versions + +def app_release = [:] +app_release.storeFile = "../keystores/android.keystore" +app_release.storePassword = "xuexiang" +app_release.keyAlias = "android.keystore" +app_release.keyPassword = "xuexiang" + +ext.app_release = app_release + +/** + * @return 是否为release + */ +def isRelease() { + Gradle gradle = getGradle() + String tskReqStr = gradle.getStartParameter().getTaskRequests().toString() + + Pattern pattern + if (tskReqStr.contains("assemble")) { + println tskReqStr + pattern = Pattern.compile("assemble(\\w*)(Release|Debug)") + } else { + pattern = Pattern.compile("generate(\\w*)(Release|Debug)") + } + Matcher matcher = pattern.matcher(tskReqStr) + + if (matcher.find()) { + String task = matcher.group(0).toLowerCase() + println("[BuildType] Current task: " + task) + return task.contains("release") + } else { + println "[BuildType] NO MATCH FOUND" + return true + } +} + +ext.isRelease = this.&isRelease + +//默认添加代码仓库路径 +static def addRepos(RepositoryHandler handler) { + handler.mavenLocal() + handler.google { url 'https://maven.aliyun.com/repository/google' } + handler.jcenter { url 'https://maven.aliyun.com/repository/jcenter' } + handler.mavenCentral { url 'https://maven.aliyun.com/repository/central' } + handler.maven { url "https://jitpack.io" } + handler.maven { url 'https://maven.aliyun.com/repository/public' } + handler.maven { url "https://dl.bintray.com/umsdk/release" } + handler.maven { url 'https://oss.sonatype.org/content/repositories/public' } + //Add the Local repository + handler.maven { url 'LocalRepository' } +} + +ext.addRepos = this.&addRepos + + +//自动添加XAOP和XRouter插件 +project.buildscript.configurations.each { configuration -> + if (configuration.name == "classpath") { + //XAOP插件 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XAOP:xaop-plugin:1.1.0')) + //XRouter插件 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XRouter:xrouter-plugin:1.0.1')) + } +} \ No newline at end of file

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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..79c9e3d17d317228d97321849b95a960397d3bc9 GIT binary patch literal 11704 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..ef1d61e32f5055ae7f2b83e00d0ce43712255558 GIT binary patch literal 14152 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 S%HKQy0000 + + + + + + @string/menu_device + @string/menu_scene + @string/menu_news + @string/menu_profile + + + + ubmcmm.baidustatic.com + gss1.bdstatic.com/ + cpro2.baidustatic.com + cpro.baidustatic.com + lianmeng.360.cn + nsclick.baidu.com + caclick.baidu.com/ + jieaogd.com + publish-pic-cpu.baidu.com/ + cpro.baidustatic.com/ + hao61.net/ + cpu.baidu.com/ + pos.baidu.com + cbjs.baidu.com + cpro.baidu.com + images.sohu.com/cs/jsfile/js/c.js + union.sogou.com/ + sogou.com/ + 5txs.cn/ + liuzhi520.com/ + yhzm.cc/ + jieaogd.com + a.baidu.com + c.baidu.com + mlnbike.com + alipays://platformapi + alipay.com/ + jieaogd.com + vipshop.com + bayimob.com + + + + 教程 + 资讯 + 社区 + 产品 + + + + + @color/app_color_theme_1 + @color/app_color_theme_2 + @color/app_color_theme_3 + @color/app_color_theme_4 + @color/app_color_theme_5 + @color/app_color_theme_6 + @color/app_color_theme_7 + @color/app_color_theme_8 + + + \ No newline at end of file diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..a9a9a4ba --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,34 @@ + + + #006dfe + #006dfe + #006dfe + + #FFF1F1F1 + + #409eff + #f56c6c + #67c23a + #909399 + #e6a23c + + + @color/xui_config_color_white + @color/xui_config_color_red + @color/colorAccent + #388E3C + @color/xui_config_color_waring + #353A3E + + #EF5362 + #FE6D4B + #FFCF47 + #9FD661 + #3FD0AD + #2BBDF3 + #5A9AEF + #AC8FEF + #EE85C1 + + + diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml new file mode 100644 index 00000000..509606ca --- /dev/null +++ b/android/app/src/main/res/values/dimens.xml @@ -0,0 +1,16 @@ + + + 24dp + + 16dp + 14dp + 10dp + 20dp + 8dp + 5dp + 18dp + 30dp + 12dp + 24dp + + \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..fe495a1d --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,103 @@ + + 物美 + 通用浏览器 + + Open navigation drawer + Close navigation drawer + + 设备 + 动态 + 场景 + 添加 + 我的 + 添加设备 + 分享设备 + + 消息 + 意见反馈 + 问题 + 收藏 + 搜索 + 设置 + 关于 + + © %1$s wumei All rights reserved. + 访问官网 + 关于作者 + QQ联系 + http://wumei.live + https://gitee.com/kerwincui + http://wpa.qq.com/msgrd?v=3&uin=164770707&site=qq&menu=yes + + + + 是否允许页面打开第三方应用? + + + 退出应用 + 同意 + 不同意 + 再次查看 + 仍不同意 + 温馨提示 + 要不要再想想 + 我们非常重视对你个人信息的保护,承诺严格按照《%s隐私权政策》保护及处理你的信息。如果你不同意该政策,很遗憾我们将无法为你提供服务 + 《%s隐私权政策》 + + + 登录/注册 + 获取验证码 + 登录 + 验证码登录 + 注册 + 忘记密码? + 验证码登录 + 密码登录 + 请输入手机号码 + 手机号码 + 密码 + 旧密码 + 请输入验证码 + 验证码 + 密码必须是8~18位字母和数字的组合! + 新密码必须是8~18位字母和数字的组合! + 无效的手机号! + ^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(16[6])|(17[0,1,3,5-8])|(18[0-9])|(19[8,9]))\\d{8}$ + 请输入4位数验证码 + ^\\d{4}$ + ^(?:(?=.*[a-zA-Z])(?=.*[0-9])).{8,18}$ + 重置密码 + 点击注册即表示同意 + ]]> + 是否确认退出账号? + 跳过 + 上一条 + 下一条 + 以后不再提示此类信息 + 你知道吗? + + 需要位置权限来获取 Wi-Fi 信息。 \n点击申请权限 + 请打开 GPS 以获取 Wi-Fi 信息。 + 请先连上 Wi-Fi + 当前连接的是 5G Wi-Fi, 设备仅支持 2.4G Wi-Fi + + EspTouch + EspTouch 版本: %s + SSID: + BSSID: + 密码: + 设备数量: + 广播 + 组播 + 确认 + 设备不支持 5G Wi-Fi, 请确认当前连接的 Wi-Fi 为 2.4G, 或者您可以尝试选择组播 + ⚠️警告️ + 在 Android M 及以上版本,如果您禁止授权位置权限,APP将无法获取 Wi-Fi 信息。 + Wi-Fi 已断开或发生了变化 + Esptouch 正在执行配网, 请稍等片刻… + EspTouch 配网失败 + 建立 EspTouch 任务失败, 端口可能被其他程序占用 + EspTouch 完成 + BSSID: %1$s, 地址: %2$s + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..29400246 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/values/styles_widget.xml b/android/app/src/main/res/values/styles_widget.xml new file mode 100644 index 00000000..cba380d2 --- /dev/null +++ b/android/app/src/main/res/values/styles_widget.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 00000000..da03785b --- /dev/null +++ b/android/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/test/java/com/kerwin/templateproject/ExampleUnitTest.java b/android/app/src/test/java/com/kerwin/templateproject/ExampleUnitTest.java new file mode 100644 index 00000000..339be1e9 --- /dev/null +++ b/android/app/src/test/java/com/kerwin/templateproject/ExampleUnitTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) + * + * 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.kerwin.templateproject; + +import com.kerwin.wumei.core.http.entity.TipInfo; +import com.xuexiang.xhttp2.model.ApiResult; +import com.xuexiang.xutil.net.JsonUtil; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + + + TipInfo info = new TipInfo(); + info.setTitle("微信公众号"); + info.setContent("获取更多资讯,欢迎关注我的微信公众号:【我的Android开源之旅】"); + List list = new ArrayList<>(); + for (int i = 0; i <5 ; i++) { + list.add(info); + } + ApiResult> result = new ApiResult<>(); + result.setData(list); + System.out.println(JsonUtil.toJson(result)); + } +} \ No newline at end of file diff --git a/android/app/x-library.gradle b/android/app/x-library.gradle new file mode 100644 index 00000000..a1ffa01b --- /dev/null +++ b/android/app/x-library.gradle @@ -0,0 +1,46 @@ +apply plugin: 'com.xuexiang.xaop' //引用XAOP插件 +apply plugin: 'com.xuexiang.xrouter' //引用XRouter-plugin插件实现自动注册 + +//自动添加依赖 +project.configurations.each { configuration -> + if (configuration.name == "implementation") { + //为Project加入X-Library依赖 + //XUI框架 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys:XUI:1.1.6')) + configuration.dependencies.add(getProject().dependencies.create(deps.androidx.appcompat)) + configuration.dependencies.add(getProject().dependencies.create(deps.androidx.recyclerview)) + configuration.dependencies.add(getProject().dependencies.create(deps.androidx.design)) + configuration.dependencies.add(getProject().dependencies.create(deps.glide)) + //XUtil工具类 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XUtil:xutil-core:2.0.0')) + //XAOP切片,版本号前带x的是支持androidx的版本 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XAOP:xaop-runtime:1.1.0')) + //XUpdate版本更新 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys:XUpdate:2.0.7')) + //XHttp2 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys:XHttp2:2.0.2')) + configuration.dependencies.add(getProject().dependencies.create(deps.rxjava2)) + configuration.dependencies.add(getProject().dependencies.create(deps.rxandroid)) + configuration.dependencies.add(getProject().dependencies.create('com.squareup.okhttp3:okhttp:3.10.0')) + configuration.dependencies.add(getProject().dependencies.create(deps.gson)) + //XPage + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XPage:xpage-lib:3.1.1')) + configuration.dependencies.add(getProject().dependencies.create(deps.butterknife.runtime)) + //页面路由 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XRouter:xrouter-runtime:1.0.1')) + } + + if (configuration.name == "annotationProcessor") { + //XPage + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XPage:xpage-compiler:3.1.1')) + configuration.dependencies.add(getProject().dependencies.create(deps.butterknife.compiler)) + //页面路由 + configuration.dependencies.add(getProject().dependencies.create('com.github.xuexiangjys.XRouter:xrouter-compiler:1.0.1')) + } + + if (configuration.name == "debugImplementation") { + //内存泄漏监测leak + configuration.dependencies.add(getProject().dependencies.create('com.squareup.leakcanary:leakcanary-android:2.6')) + } +} + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 00000000..c4391db5 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,29 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + apply from: './versions.gradle' + addRepos(repositories) //增加代码仓库 + dependencies { + classpath deps.android_gradle_plugin + classpath deps.android_maven_gradle_plugin + + classpath 'com.chenenyu:img-optimizer:1.2.0' // 图片压缩 + //美团多渠道打包 + classpath 'com.meituan.android.walle:plugin:1.1.6' + //滴滴的质量优化框架 + if (isNeedPackage.toBoolean() && isUseBooster.toBoolean()) { + classpath deps.booster.gradle_plugin + classpath deps.booster.task_processed_res + classpath deps.booster.task_resource_deredundancy + } + } +} + +allprojects { + addRepos(repositories) +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + diff --git a/android/esptouch/.gitignore b/android/esptouch/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/android/esptouch/.gitignore @@ -0,0 +1 @@ +/build diff --git a/android/esptouch/README.md b/android/esptouch/README.md new file mode 100644 index 00000000..d0db4fed --- /dev/null +++ b/android/esptouch/README.md @@ -0,0 +1,42 @@ +# EspTouch +[example](../app/src/main/java/com/espressif/esptouch/android/v1) + +- Create task instance + ```java + Context context; // Set Applicatioin context + byte[] apSsid = {}; // Set AP's SSID + byte[] apBssid = {}; // Set AP's BSSID + byte[] apPassword = {}; // Set AP's password + + EsptouchTask task = new EsptouchTask(apSsid, apBssid, apPassword, context); + task.setPackageBroadcast(true); // if true send broadcast packets, else send multicast packets + ``` + +- Set result callback + ```java + task.setEsptouchListener(new IEsptouchListener() { + @Override + public void onEsptouchResultAdded(IEsptouchResult result) { + // Result callback + } + }); + ``` + +- Execute task + ```java + int expectResultCount = 1; + List results = task.executeForResults(expectResultCount); + IEsptouchResult first = results.get(0); + if (first.isCancelled()) { + // User cancel the task + return; + } + if (first.isSuc()) { + // EspTouch successfully + } + ``` + +- Cancel task + ```java + task.interrupt(); + ``` diff --git a/android/esptouch/build.gradle b/android/esptouch/build.gradle new file mode 100644 index 00000000..b26d7caf --- /dev/null +++ b/android/esptouch/build.gradle @@ -0,0 +1,31 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 29 + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 29 + versionCode 8 + versionName "v0.3.7.2" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/android/esptouch/proguard-rules.pro b/android/esptouch/proguard-rules.pro new file mode 100644 index 00000000..f1b42451 --- /dev/null +++ b/android/esptouch/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/android/esptouch/src/main/AndroidManifest.xml b/android/esptouch/src/main/AndroidManifest.xml new file mode 100644 index 00000000..90704c2c --- /dev/null +++ b/android/esptouch/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchResult.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchResult.java new file mode 100644 index 00000000..0d17c4db --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchResult.java @@ -0,0 +1,56 @@ +package com.espressif.iot.esptouch; + +import java.net.InetAddress; +import java.util.concurrent.atomic.AtomicBoolean; + +public class EsptouchResult implements IEsptouchResult { + + private final boolean mIsSuc; + private final String mBssid; + private final InetAddress mInetAddress; + private AtomicBoolean mIsCancelled; + + /** + * Constructor of EsptouchResult + * + * @param isSuc whether the esptouch task is executed suc + * @param bssid the device's bssid + * @param inetAddress the device's ip address + */ + public EsptouchResult(boolean isSuc, String bssid, InetAddress inetAddress) { + this.mIsSuc = isSuc; + this.mBssid = bssid; + this.mInetAddress = inetAddress; + this.mIsCancelled = new AtomicBoolean(false); + } + + @Override + public boolean isSuc() { + return this.mIsSuc; + } + + @Override + public String getBssid() { + return this.mBssid; + } + + @Override + public boolean isCancelled() { + return mIsCancelled.get(); + } + + public void setIsCancelled(boolean isCancelled) { + this.mIsCancelled.set(isCancelled); + } + + @Override + public InetAddress getInetAddress() { + return this.mInetAddress; + } + + @Override + public String toString() { + return String.format("bssid=%s, address=%s, suc=%b, cancel=%b", mBssid, + mInetAddress == null ? null : mInetAddress.getHostAddress(), mIsSuc, mIsCancelled.get()); + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchTask.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchTask.java new file mode 100644 index 00000000..eef9e885 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/EsptouchTask.java @@ -0,0 +1,115 @@ +package com.espressif.iot.esptouch; + +import android.content.Context; +import android.text.TextUtils; + +import com.espressif.iot.esptouch.protocol.TouchData; +import com.espressif.iot.esptouch.security.ITouchEncryptor; +import com.espressif.iot.esptouch.task.EsptouchTaskParameter; +import com.espressif.iot.esptouch.task.__EsptouchTask; +import com.espressif.iot.esptouch.util.TouchNetUtil; + +import java.util.List; + +public class EsptouchTask implements IEsptouchTask { + private __EsptouchTask _mEsptouchTask; + private EsptouchTaskParameter _mParameter; + + /** + * Constructor of EsptouchTask + * + * @param apSsid the Ap's ssid + * @param apBssid the Ap's bssid + * @param apPassword the Ap's password + * @param context the {@link Context} of the Application + */ + public EsptouchTask(String apSsid, String apBssid, String apPassword, Context context) { + this(apSsid, apBssid, apPassword, null, context); + } + + /** + * Constructor of EsptouchTask + * + * @param apSsid the Ap's ssid + * @param apBssid the Ap's bssid + * @param apPassword the Ap's password + * @param context the {@link Context} of the Application + */ + public EsptouchTask(byte[] apSsid, byte[] apBssid, byte[] apPassword, Context context) { + this(apSsid, apBssid, apPassword, null, context); + } + + private EsptouchTask(String apSsid, String apBssid, String apPassword, ITouchEncryptor encryptor, Context context) { + if (TextUtils.isEmpty(apSsid)) { + throw new NullPointerException("SSID can't be empty"); + } + if (TextUtils.isEmpty(apBssid)) { + throw new NullPointerException("BSSID can't be empty"); + } + if (apPassword == null) { + apPassword = ""; + } + TouchData ssid = new TouchData(apSsid); + TouchData bssid = new TouchData(TouchNetUtil.parseBssid2bytes(apBssid)); + if (bssid.getData().length != 6) { + throw new IllegalArgumentException("Bssid format must be aa:bb:cc:dd:ee:ff"); + } + TouchData password = new TouchData(apPassword); + init(context, ssid, bssid, password, encryptor); + } + + private EsptouchTask(byte[] apSsid, byte[] apBssid, byte[] apPassword, ITouchEncryptor encryptor, Context context) { + if (apSsid == null || apSsid.length == 0) { + throw new NullPointerException("SSID can't be empty"); + } + if (apBssid == null || apBssid.length != 6) { + throw new NullPointerException("BSSID is empty or length is not 6"); + } + if (apPassword == null) { + apPassword = new byte[0]; + } + TouchData ssid = new TouchData(apSsid); + TouchData bssid = new TouchData(apBssid); + TouchData password = new TouchData(apPassword); + init(context, ssid, bssid, password, encryptor); + } + + private void init(Context context, TouchData ssid, TouchData bssid, TouchData password, ITouchEncryptor encryptor) { + _mParameter = new EsptouchTaskParameter(); + _mEsptouchTask = new __EsptouchTask(context, ssid, bssid, password, encryptor, _mParameter); + } + + @Override + public void interrupt() { + _mEsptouchTask.interrupt(); + } + + @Override + public IEsptouchResult executeForResult() throws RuntimeException { + return _mEsptouchTask.executeForResult(); + } + + @Override + public boolean isCancelled() { + return _mEsptouchTask.isCancelled(); + } + + @Override + public List executeForResults(int expectTaskResultCount) + throws RuntimeException { + if (expectTaskResultCount <= 0) { + expectTaskResultCount = Integer.MAX_VALUE; + } + return _mEsptouchTask.executeForResults(expectTaskResultCount); + } + + @Override + public void setEsptouchListener(IEsptouchListener esptouchListener) { + _mEsptouchTask.setEsptouchListener(esptouchListener); + } + + @Override + public void setPackageBroadcast(boolean broadcast) { + _mParameter.setBroadcast(broadcast); + } +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchListener.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchListener.java new file mode 100644 index 00000000..4c9d992c --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchListener.java @@ -0,0 +1,11 @@ +package com.espressif.iot.esptouch; + +public interface IEsptouchListener { + /** + * when new esptouch result is added, the listener will call + * onEsptouchResultAdded callback + * + * @param result the Esptouch result + */ + void onEsptouchResultAdded(IEsptouchResult result); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchResult.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchResult.java new file mode 100644 index 00000000..0aad8788 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchResult.java @@ -0,0 +1,34 @@ +package com.espressif.iot.esptouch; + +import java.net.InetAddress; + +public interface IEsptouchResult { + + /** + * check whether the esptouch task is executed suc + * + * @return whether the esptouch task is executed suc + */ + boolean isSuc(); + + /** + * get the device's bssid + * + * @return the device's bssid + */ + String getBssid(); + + /** + * check whether the esptouch task is cancelled by user + * + * @return whether the esptouch task is cancelled by user + */ + boolean isCancelled(); + + /** + * get the ip address of the device + * + * @return the ip device of the device + */ + InetAddress getInetAddress(); +} diff --git a/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchTask.java b/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchTask.java new file mode 100644 index 00000000..821b9445 --- /dev/null +++ b/android/esptouch/src/main/java/com/espressif/iot/esptouch/IEsptouchTask.java @@ -0,0 +1,61 @@ +package com.espressif.iot.esptouch; + +import java.util.List; + +public interface IEsptouchTask { + String ESPTOUCH_VERSION = BuildConfig.VERSION_NAME; + + /** + * set the esptouch listener, when one device is connected to the Ap, it will be called back + * + * @param esptouchListener when one device is connected to the Ap, it will be called back + */ + void setEsptouchListener(IEsptouchListener esptouchListener); + + /** + * Interrupt the Esptouch Task when User tap back or close the Application. + */ + void interrupt(); + + /** + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will + * be thrown Execute the Esptouch Task and return the result + *