From f84afd11c168867900b32aa2a9bc9e3738ef26d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E9=92=A7=E6=B7=87?= <3054565072@qq.com> Date: Mon, 25 Sep 2023 11:18:51 +0800 Subject: [PATCH] demo --- src/java/.DS_Store | Bin 0 -> 10244 bytes src/java/com/.DS_Store | Bin 0 -> 8196 bytes src/java/com/gizwits/.DS_Store | Bin 0 -> 8196 bytes src/java/com/gizwits/opensource/.DS_Store | Bin 0 -> 8196 bytes .../com/gizwits/opensource/appkit/.DS_Store | Bin 0 -> 14340 bytes .../appkit/CommonModule/GosBaseActivity.java | 1077 ++++++++++ .../appkit/CommonModule/GosConstant.java | 34 + .../appkit/CommonModule/GosDeploy.java | 1910 +++++++++++++++++ .../CommonModule/NoScrollViewPager.java | 56 + .../appkit/CommonModule/SplashActivity.java | 115 + .../appkit/CommonModule/TipsDialog.java | 59 + .../opensource/appkit/ConfigModule/.DS_Store | Bin 0 -> 6148 bytes ...osAirlinkChooseDeviceWorkWiFiActivity.java | 505 +++++ .../GosAirlinkConfigCountdownActivity.java | 310 +++ .../ConfigModule/GosAirlinkReadyActivity.java | 132 ++ .../ConfigModule/GosChooseDeviceActivity.java | 279 +++ .../GosChooseDeviceWorkWiFiActivity.java | 465 ++++ .../GosChooseModuleHelpActivity.java | 41 + .../GosConfigCountdownActivity.java | 424 ++++ .../ConfigModule/GosConfigFailedActivity.java | 118 + .../GosConfigModuleBaseActivity.java | 238 ++ .../ConfigModule/GosDeviceReadyActivity.java | 139 ++ .../ConfigModule/GosDeviceResetActivity.java | 143 ++ .../ConfigModule/GosModeListActivity.java | 222 ++ .../ConfigModule/GosModeListActivity2.java | 219 ++ .../ConfigModule/GosWifiChangeReciver.java | 36 + .../ConfigModule/WifiAutoConnectManager.java | 231 ++ .../opensource/appkit/ControlModule/.DS_Store | Bin 0 -> 6148 bytes .../GosControlModuleBaseActivity.java | 429 ++++ .../GosDeviceControlActivity.java | 603 ++++++ .../appkit/DeviceModule/GosBaseFragment.java | 735 +++++++ .../DeviceModule/GosDeviceListAdapter.java | 311 +++ .../DeviceModule/GosDeviceListFragment.java | 847 ++++++++ .../GosDeviceModuleBaseActivity.java | 210 ++ .../GosDeviceModuleBaseFragment.java | 214 ++ .../appkit/DeviceModule/GosMainActivity.java | 403 ++++ .../DeviceModule/GosMessageHandler.java | 108 + .../DeviceModule/GosSettiingsFragment.java | 136 ++ .../DeviceModule/MessageCenterFragment.java | 136 ++ .../opensource/appkit/GosApplication.java | 13 + .../opensource/appkit/MessageCenter.java | 112 + .../opensource/appkit/PushModule/.DS_Store | Bin 0 -> 6148 bytes .../appkit/PushModule/BaiDuPushReceiver.java | 67 + .../appkit/PushModule/GosPushManager.java | 136 ++ .../appkit/PushModule/JPushReceiver.java | 125 ++ .../SettingsModule/GosAboutActivity.java | 135 ++ .../ThirdAccountModule/BaseUiListener.java | 28 + .../GosChangeUserPasswordActivity.java | 226 ++ .../UserModule/GosForgetPasswordActivity.java | 385 ++++ .../UserModule/GosRegisterUserActivity.java | 359 ++++ .../GosSendEmailPasswordActivity.java | 69 + .../UserModule/GosUserLoginActivity.java | 626 ++++++ .../appkit/UserModule/GosUserManager.java | 163 ++ .../UserModule/GosUserModuleBaseActivity.java | 132 ++ .../appkit/sharingdevice/InvitedFragment.java | 272 +++ .../sharingdevice/MsgNoticeActivity.java | 82 + .../SharedDeviceListAcitivity.java | 233 ++ .../SharedDeviceManagerActivity.java | 282 +++ .../appkit/sharingdevice/SharedFragment.java | 212 ++ .../sharingdevice/SharedStateFragment.java | 600 ++++++ .../sharingdevice/SharedUserFragment.java | 275 +++ .../sharingdevice/addSharedActivity.java | 88 + .../deviceSharedMessageActivity.java | 276 +++ .../gosZxingDeviceSharingActivity.java | 235 ++ .../sharingdevice/twoSharedActivity.java | 175 ++ .../sharingdevice/userSharedActivity.java | 145 ++ .../gizwits/opensource/appkit/utils/.DS_Store | Bin 0 -> 6148 bytes .../opensource/appkit/utils/AssetsUtils.java | 111 + .../opensource/appkit/utils/DateUtil.java | 1331 ++++++++++++ .../opensource/appkit/utils/HexStrUtils.java | 58 + .../opensource/appkit/utils/NetUtils.java | 226 ++ .../appkit/utils/ReflectionUtils.java | 138 ++ .../appkit/utils/SkxDrawableHelper.java | 66 + .../opensource/appkit/utils/ToolUtils.java | 146 ++ .../gizwits/opensource/appkit/view/.DS_Store | Bin 0 -> 6148 bytes .../opensource/appkit/view/BaseKeyboard.java | 210 ++ .../appkit/view/BaseKeyboardView.java | 202 ++ .../appkit/view/CircleProgress.java | 130 ++ .../opensource/appkit/view/DotView.java | 59 + .../opensource/appkit/view/GifView.java | 210 ++ .../opensource/appkit/view/HexWatcher.java | 63 + .../appkit/view/KeyboardWithSearchView.java | 123 ++ .../appkit/view/RoundProgressBar.java | 266 +++ .../appkit/view/SlideListView2.java | 309 +++ .../appkit/view/SuperSwipeRefreshLayout.java | 1466 +++++++++++++ .../opensource/appkit/view/SwitchView.java | 473 ++++ .../view/VerticalSwipeRefreshLayout.java | 42 + .../appkit/view/ViewPagerIndicator.java | 415 ++++ .../gizwits/opensource/appkit/wxapi/.DS_Store | Bin 0 -> 6148 bytes .../appkit/wxapi/WXEntryActivity.java | 148 ++ src/java/zxing/CaptureActivity.java | 443 ++++ src/java/zxing/camera/AutoFocusManager.java | 134 ++ .../camera/CameraConfigurationManager.java | 220 ++ src/java/zxing/camera/CameraManager.java | 209 ++ src/java/zxing/camera/PreviewCallback.java | 56 + .../camera/open/OpenCameraInterface.java | 86 + .../zxing/decoding/DecodeFormatManager.java | 51 + src/java/zxing/decoding/DecodeHandler.java | 161 ++ src/java/zxing/decoding/DecodeThread.java | 98 + .../zxing/utils/CaptureActivityHandler.java | 112 + src/java/zxing/utils/InactivityTimer.java | 124 ++ src/res/.DS_Store | Bin 0 -> 12292 bytes src/res/anim/in_from_left.xml | 9 + src/res/anim/in_from_right.xml | 9 + src/res/anim/out_to_left.xml | 9 + src/res/anim/out_to_right.xml | 7 + src/res/drawable-hdpi/launch.png | Bin 0 -> 35487 bytes src/res/drawable-xhdpi/.DS_Store | Bin 0 -> 6148 bytes src/res/drawable-xhdpi/about_logo.png | Bin 0 -> 5517 bytes src/res/drawable-xhdpi/button_blue_long.png | Bin 0 -> 1365 bytes src/res/drawable-xhdpi/checkmark.png | Bin 0 -> 1144 bytes src/res/drawable-xhdpi/common_add_button.png | Bin 0 -> 929 bytes src/res/drawable-xhdpi/common_arrow_right.png | Bin 0 -> 897 bytes .../common_device_lan_offline.png | Bin 0 -> 1377 bytes .../common_device_lan_online.png | Bin 0 -> 1702 bytes .../common_device_remote_offline.png | Bin 0 -> 4732 bytes .../common_device_remote_online.png | Bin 0 -> 6084 bytes .../drawable-xhdpi/common_password_hide.png | Bin 0 -> 9660 bytes .../drawable-xhdpi/common_password_show.png | Bin 0 -> 11598 bytes src/res/drawable-xhdpi/config_help_button.png | Bin 0 -> 2283 bytes src/res/drawable-xhdpi/device_none.png | Bin 0 -> 11149 bytes .../deviceonboarding_airlink_tips.png | Bin 0 -> 2352 bytes .../deviceonboarding_softap_tips.png | Bin 0 -> 2352 bytes .../devicesharing_user_icon.png | Bin 0 -> 1356 bytes .../feedbacksupport_selected.png | Bin 0 -> 2428 bytes .../feedbacksupport_unselected.png | Bin 0 -> 1207 bytes src/res/drawable-xhdpi/icon.png | Bin 0 -> 5517 bytes src/res/drawable-xhdpi/info_edit.png | Bin 0 -> 1026 bytes src/res/drawable-xhdpi/info_edit_cancel.png | Bin 0 -> 1297 bytes src/res/drawable-xhdpi/launch.png | Bin 0 -> 57394 bytes src/res/drawable-xhdpi/launch_logo.png | Bin 0 -> 1035 bytes src/res/drawable-xhdpi/page_back_button.png | Bin 0 -> 1587 bytes .../drawable-xhdpi/personal_sharing_icon.png | Bin 0 -> 3674 bytes .../personalcenter_usermanger_icon.png | Bin 0 -> 3112 bytes src/res/drawable-xhdpi/qrcode_scan_frame.png | Bin 0 -> 2879 bytes src/res/drawable-xhdpi/qrcode_scan_line.png | Bin 0 -> 481 bytes src/res/drawable-xhdpi/right_icon.png | Bin 0 -> 2674 bytes src/res/drawable-xhdpi/thumb.png | Bin 0 -> 1768 bytes src/res/drawable-xhdpi/txt_delete_btn.png | Bin 0 -> 823 bytes src/res/drawable-xhdpi/user_login_logo.png | Bin 0 -> 5433 bytes src/res/drawable-xhdpi/user_login_qq.png | Bin 0 -> 10849 bytes src/res/drawable-xhdpi/user_login_wechat.png | Bin 0 -> 8048 bytes src/res/drawable-xxhdpi/icon.png | Bin 0 -> 5517 bytes src/res/drawable-xxhdpi/launch.png | Bin 0 -> 93508 bytes src/res/drawable/alert_bottom_left_shape.xml | 10 + .../drawable/alert_bottom_left_shape_gray.xml | 10 + src/res/drawable/alert_bottom_right_shape.xml | 12 + .../alert_bottom_right_shape_gray.xml | 12 + src/res/drawable/alert_bottom_shape.xml | 12 + src/res/drawable/alert_shape.xml | 15 + src/res/drawable/alert_top_shape.xml | 10 + src/res/drawable/alert_top_shape_gray.xml | 11 + src/res/drawable/border_input_box.xml | 12 + src/res/drawable/border_layer_list.xml | 22 + src/res/drawable/btn_next_shape_gray.xml | 8 + src/res/drawable/checkbox_hook_selector.xml | 9 + src/res/drawable/checkbox_laws_selector.xml | 9 + src/res/drawable/common_page_back_button.xml | 4 + src/res/drawable/common_qrcode_button.xml | 9 + src/res/drawable/common_setting_more.xml | 4 + src/res/drawable/devicelist_item_selector.xml | 8 + src/res/drawable/deviceonboarding_add.xml | 4 + src/res/drawable/gray_thumb.xml | 22 + src/res/drawable/gray_track.xml | 15 + src/res/drawable/green_thumb.xml | 22 + src/res/drawable/green_track.xml | 14 + src/res/drawable/ic_list_divider.xml | 9 + src/res/drawable/img_bg_shape.xml | 8 + src/res/drawable/img_bg_shape_white.xml | 12 + src/res/drawable/key_number_bg.xml | 8 + src/res/drawable/keyboard_number.xml | 6 + src/res/drawable/keyboard_number_pressed.xml | 6 + src/res/drawable/redoval.xml | 9 + src/res/drawable/round_dot.xml | 5 + src/res/drawable/shape_button.xml | 11 + src/res/drawable/shape_button2.xml | 11 + src/res/drawable/tabbar_messages.xml | 12 + src/res/drawable/tabbar_mydevice.xml | 18 + src/res/drawable/tabbar_personal.xml | 9 + src/res/drawable/thumb.xml | 7 + src/res/drawable/track.xml | 6 + src/res/layout/.DS_Store | Bin 0 -> 14340 bytes src/res/layout/activity_device_item.xml | 85 + .../activity_device_shared_message_list.xml | 51 + src/res/layout/activity_gos_about.xml | 108 + src/res/layout/activity_gos_addshared.xml | 89 + ...ity_gos_airlink_choose_device_workwifi.xml | 143 ++ .../activity_gos_airlink_config_countdown.xml | 114 + src/res/layout/activity_gos_capture.xml | 121 ++ .../layout/activity_gos_change_password.xml | 110 + src/res/layout/activity_gos_choose_device.xml | 46 + .../activity_gos_choose_device_workwifi.xml | 141 ++ .../activity_gos_choose_module_help.xml | 20 + .../layout/activity_gos_config_countdown.xml | 67 + src/res/layout/activity_gos_config_failed.xml | 45 + .../layout/activity_gos_device_control.xml | 652 ++++++ src/res/layout/activity_gos_device_list.xml | 88 + src/res/layout/activity_gos_device_ready.xml | 64 + .../layout/activity_gos_forget_password.xml | 89 + src/res/layout/activity_gos_main.xml | 24 + src/res/layout/activity_gos_message.xml | 88 + src/res/layout/activity_gos_modelist.xml | 43 + src/res/layout/activity_gos_register_user.xml | 162 ++ .../activity_gos_send_email_password.xml | 82 + src/res/layout/activity_gos_settings.xml | 162 ++ .../activity_gos_shared_device_list.xml | 29 + src/res/layout/activity_gos_shared_list.xml | 69 + src/res/layout/activity_gos_shared_manage.xml | 161 ++ src/res/layout/activity_gos_splash.xml | 39 + src/res/layout/activity_gos_two_shared.xml | 36 + src/res/layout/activity_gos_user_login.xml | 259 +++ src/res/layout/activity_gos_user_shared.xml | 59 + src/res/layout/activity_gos_usermanager.xml | 81 + src/res/layout/activity_notice.xml | 40 + src/res/layout/actvity_gos_airlink_ready.xml | 63 + src/res/layout/actvity_gos_device_reset.xml | 39 + src/res/layout/alert_gos_edit_name.xml | 108 + src/res/layout/alert_gos_empty.xml | 95 + src/res/layout/alert_gos_no_id.xml | 51 + src/res/layout/alert_gos_overflow.xml | 50 + src/res/layout/alert_gos_quit.xml | 99 + src/res/layout/alert_gos_rename.xml | 106 + src/res/layout/alert_gos_set_device_info.xml | 134 ++ src/res/layout/alert_gos_tip.xml | 78 + src/res/layout/alert_gos_wifi.xml | 95 + src/res/layout/alert_gos_wifi_list.xml | 28 + src/res/layout/dialog_tips.xml | 34 + .../gos_devicesharing_zxing_activity.xml | 73 + src/res/layout/gos_shared_by_me_activity.xml | 124 ++ src/res/layout/gos_shared_to_me_activity.xml | 121 ++ src/res/layout/header_toolbar.xml | 17 + src/res/layout/item_gos_device_list.xml | 146 ++ .../layout/item_gos_device_shared_list.xml | 107 + src/res/layout/item_gos_mode_list.xml | 32 + src/res/layout/item_gos_wifi_device.xml | 32 + src/res/layout/item_gos_wifi_list.xml | 32 + .../layout/layout_recycler_keyboard_view.xml | 28 + src/res/layout/view_gos_title_listview.xml | 48 + src/res/menu/.DS_Store | Bin 0 -> 6148 bytes src/res/menu/device_more.xml | 25 + src/res/menu/gosdeviceconfig.xml | 13 + src/res/menu/gosnull.xml | 8 + src/res/menu/module_style.xml | 9 + src/res/menu/navigation.xml | 17 + src/res/values-en/.DS_Store | Bin 0 -> 6148 bytes src/res/values-en/appkitstrings.xml | 532 +++++ src/res/values-en/arrays_mode.xml | 21 + src/res/values-en/enum_strings.xml | 5 + src/res/values-en/ioestrings.xml | 28 + src/res/values-v11/styles.xml | 8 + src/res/values-v14/styles.xml | 9 + src/res/values-w820dp/dimens.xml | 9 + src/res/values/.DS_Store | Bin 0 -> 6148 bytes src/res/values/appkitstrings.xml | 538 +++++ src/res/values/arrays_mode.xml | 20 + src/res/values/attrs.xml | 77 + src/res/values/colors.xml | 36 + src/res/values/dimens.xml | 6 + src/res/values/enum_strings.xml | 5 + src/res/values/ids.xml | 26 + src/res/values/ioestrings.xml | 23 + src/res/values/jpush_style.xml | 2 + src/res/values/strings.xml | 2 + src/res/values/styles.xml | 166 ++ 264 files changed, 31339 insertions(+) create mode 100644 src/java/.DS_Store create mode 100644 src/java/com/.DS_Store create mode 100644 src/java/com/gizwits/.DS_Store create mode 100644 src/java/com/gizwits/opensource/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/CommonModule/GosBaseActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/CommonModule/GosConstant.java create mode 100644 src/java/com/gizwits/opensource/appkit/CommonModule/GosDeploy.java create mode 100644 src/java/com/gizwits/opensource/appkit/CommonModule/NoScrollViewPager.java create mode 100644 src/java/com/gizwits/opensource/appkit/CommonModule/SplashActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/CommonModule/TipsDialog.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkChooseDeviceWorkWiFiActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkConfigCountdownActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkReadyActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceWorkWiFiActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseModuleHelpActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigCountdownActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigFailedActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigModuleBaseActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceReadyActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceResetActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity2.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/GosWifiChangeReciver.java create mode 100644 src/java/com/gizwits/opensource/appkit/ConfigModule/WifiAutoConnectManager.java create mode 100644 src/java/com/gizwits/opensource/appkit/ControlModule/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/ControlModule/GosControlModuleBaseActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ControlModule/GosDeviceControlActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosBaseFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListAdapter.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosMainActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosMessageHandler.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/GosSettiingsFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/DeviceModule/MessageCenterFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/GosApplication.java create mode 100644 src/java/com/gizwits/opensource/appkit/MessageCenter.java create mode 100644 src/java/com/gizwits/opensource/appkit/PushModule/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/PushModule/BaiDuPushReceiver.java create mode 100644 src/java/com/gizwits/opensource/appkit/PushModule/GosPushManager.java create mode 100644 src/java/com/gizwits/opensource/appkit/PushModule/JPushReceiver.java create mode 100644 src/java/com/gizwits/opensource/appkit/SettingsModule/GosAboutActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/ThirdAccountModule/BaseUiListener.java create mode 100644 src/java/com/gizwits/opensource/appkit/UserModule/GosChangeUserPasswordActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/UserModule/GosForgetPasswordActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/UserModule/GosRegisterUserActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/UserModule/GosSendEmailPasswordActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/UserModule/GosUserLoginActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/UserModule/GosUserManager.java create mode 100644 src/java/com/gizwits/opensource/appkit/UserModule/GosUserModuleBaseActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/InvitedFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/MsgNoticeActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceListAcitivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceManagerActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/SharedFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/SharedStateFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/SharedUserFragment.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/addSharedActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/deviceSharedMessageActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/gosZxingDeviceSharingActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/twoSharedActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/sharingdevice/userSharedActivity.java create mode 100644 src/java/com/gizwits/opensource/appkit/utils/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/utils/AssetsUtils.java create mode 100644 src/java/com/gizwits/opensource/appkit/utils/DateUtil.java create mode 100644 src/java/com/gizwits/opensource/appkit/utils/HexStrUtils.java create mode 100644 src/java/com/gizwits/opensource/appkit/utils/NetUtils.java create mode 100644 src/java/com/gizwits/opensource/appkit/utils/ReflectionUtils.java create mode 100644 src/java/com/gizwits/opensource/appkit/utils/SkxDrawableHelper.java create mode 100644 src/java/com/gizwits/opensource/appkit/utils/ToolUtils.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/view/BaseKeyboard.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/BaseKeyboardView.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/CircleProgress.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/DotView.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/GifView.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/HexWatcher.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/KeyboardWithSearchView.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/RoundProgressBar.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/SlideListView2.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/SuperSwipeRefreshLayout.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/SwitchView.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/VerticalSwipeRefreshLayout.java create mode 100644 src/java/com/gizwits/opensource/appkit/view/ViewPagerIndicator.java create mode 100644 src/java/com/gizwits/opensource/appkit/wxapi/.DS_Store create mode 100644 src/java/com/gizwits/opensource/appkit/wxapi/WXEntryActivity.java create mode 100644 src/java/zxing/CaptureActivity.java create mode 100644 src/java/zxing/camera/AutoFocusManager.java create mode 100644 src/java/zxing/camera/CameraConfigurationManager.java create mode 100644 src/java/zxing/camera/CameraManager.java create mode 100644 src/java/zxing/camera/PreviewCallback.java create mode 100644 src/java/zxing/camera/open/OpenCameraInterface.java create mode 100644 src/java/zxing/decoding/DecodeFormatManager.java create mode 100644 src/java/zxing/decoding/DecodeHandler.java create mode 100644 src/java/zxing/decoding/DecodeThread.java create mode 100644 src/java/zxing/utils/CaptureActivityHandler.java create mode 100644 src/java/zxing/utils/InactivityTimer.java create mode 100644 src/res/.DS_Store create mode 100644 src/res/anim/in_from_left.xml create mode 100644 src/res/anim/in_from_right.xml create mode 100644 src/res/anim/out_to_left.xml create mode 100644 src/res/anim/out_to_right.xml create mode 100644 src/res/drawable-hdpi/launch.png create mode 100644 src/res/drawable-xhdpi/.DS_Store create mode 100644 src/res/drawable-xhdpi/about_logo.png create mode 100644 src/res/drawable-xhdpi/button_blue_long.png create mode 100644 src/res/drawable-xhdpi/checkmark.png create mode 100644 src/res/drawable-xhdpi/common_add_button.png create mode 100644 src/res/drawable-xhdpi/common_arrow_right.png create mode 100644 src/res/drawable-xhdpi/common_device_lan_offline.png create mode 100644 src/res/drawable-xhdpi/common_device_lan_online.png create mode 100644 src/res/drawable-xhdpi/common_device_remote_offline.png create mode 100644 src/res/drawable-xhdpi/common_device_remote_online.png create mode 100644 src/res/drawable-xhdpi/common_password_hide.png create mode 100644 src/res/drawable-xhdpi/common_password_show.png create mode 100644 src/res/drawable-xhdpi/config_help_button.png create mode 100644 src/res/drawable-xhdpi/device_none.png create mode 100644 src/res/drawable-xhdpi/deviceonboarding_airlink_tips.png create mode 100644 src/res/drawable-xhdpi/deviceonboarding_softap_tips.png create mode 100644 src/res/drawable-xhdpi/devicesharing_user_icon.png create mode 100644 src/res/drawable-xhdpi/feedbacksupport_selected.png create mode 100644 src/res/drawable-xhdpi/feedbacksupport_unselected.png create mode 100644 src/res/drawable-xhdpi/icon.png create mode 100644 src/res/drawable-xhdpi/info_edit.png create mode 100644 src/res/drawable-xhdpi/info_edit_cancel.png create mode 100644 src/res/drawable-xhdpi/launch.png create mode 100644 src/res/drawable-xhdpi/launch_logo.png create mode 100644 src/res/drawable-xhdpi/page_back_button.png create mode 100644 src/res/drawable-xhdpi/personal_sharing_icon.png create mode 100644 src/res/drawable-xhdpi/personalcenter_usermanger_icon.png create mode 100644 src/res/drawable-xhdpi/qrcode_scan_frame.png create mode 100644 src/res/drawable-xhdpi/qrcode_scan_line.png create mode 100644 src/res/drawable-xhdpi/right_icon.png create mode 100644 src/res/drawable-xhdpi/thumb.png create mode 100644 src/res/drawable-xhdpi/txt_delete_btn.png create mode 100644 src/res/drawable-xhdpi/user_login_logo.png create mode 100644 src/res/drawable-xhdpi/user_login_qq.png create mode 100644 src/res/drawable-xhdpi/user_login_wechat.png create mode 100644 src/res/drawable-xxhdpi/icon.png create mode 100644 src/res/drawable-xxhdpi/launch.png create mode 100644 src/res/drawable/alert_bottom_left_shape.xml create mode 100644 src/res/drawable/alert_bottom_left_shape_gray.xml create mode 100644 src/res/drawable/alert_bottom_right_shape.xml create mode 100644 src/res/drawable/alert_bottom_right_shape_gray.xml create mode 100644 src/res/drawable/alert_bottom_shape.xml create mode 100644 src/res/drawable/alert_shape.xml create mode 100644 src/res/drawable/alert_top_shape.xml create mode 100644 src/res/drawable/alert_top_shape_gray.xml create mode 100644 src/res/drawable/border_input_box.xml create mode 100644 src/res/drawable/border_layer_list.xml create mode 100644 src/res/drawable/btn_next_shape_gray.xml create mode 100644 src/res/drawable/checkbox_hook_selector.xml create mode 100644 src/res/drawable/checkbox_laws_selector.xml create mode 100644 src/res/drawable/common_page_back_button.xml create mode 100644 src/res/drawable/common_qrcode_button.xml create mode 100644 src/res/drawable/common_setting_more.xml create mode 100644 src/res/drawable/devicelist_item_selector.xml create mode 100644 src/res/drawable/deviceonboarding_add.xml create mode 100644 src/res/drawable/gray_thumb.xml create mode 100644 src/res/drawable/gray_track.xml create mode 100644 src/res/drawable/green_thumb.xml create mode 100644 src/res/drawable/green_track.xml create mode 100644 src/res/drawable/ic_list_divider.xml create mode 100644 src/res/drawable/img_bg_shape.xml create mode 100644 src/res/drawable/img_bg_shape_white.xml create mode 100644 src/res/drawable/key_number_bg.xml create mode 100644 src/res/drawable/keyboard_number.xml create mode 100644 src/res/drawable/keyboard_number_pressed.xml create mode 100644 src/res/drawable/redoval.xml create mode 100644 src/res/drawable/round_dot.xml create mode 100644 src/res/drawable/shape_button.xml create mode 100644 src/res/drawable/shape_button2.xml create mode 100644 src/res/drawable/tabbar_messages.xml create mode 100644 src/res/drawable/tabbar_mydevice.xml create mode 100644 src/res/drawable/tabbar_personal.xml create mode 100644 src/res/drawable/thumb.xml create mode 100644 src/res/drawable/track.xml create mode 100644 src/res/layout/.DS_Store create mode 100644 src/res/layout/activity_device_item.xml create mode 100644 src/res/layout/activity_device_shared_message_list.xml create mode 100644 src/res/layout/activity_gos_about.xml create mode 100644 src/res/layout/activity_gos_addshared.xml create mode 100644 src/res/layout/activity_gos_airlink_choose_device_workwifi.xml create mode 100644 src/res/layout/activity_gos_airlink_config_countdown.xml create mode 100644 src/res/layout/activity_gos_capture.xml create mode 100644 src/res/layout/activity_gos_change_password.xml create mode 100644 src/res/layout/activity_gos_choose_device.xml create mode 100644 src/res/layout/activity_gos_choose_device_workwifi.xml create mode 100644 src/res/layout/activity_gos_choose_module_help.xml create mode 100644 src/res/layout/activity_gos_config_countdown.xml create mode 100644 src/res/layout/activity_gos_config_failed.xml create mode 100644 src/res/layout/activity_gos_device_control.xml create mode 100644 src/res/layout/activity_gos_device_list.xml create mode 100644 src/res/layout/activity_gos_device_ready.xml create mode 100644 src/res/layout/activity_gos_forget_password.xml create mode 100644 src/res/layout/activity_gos_main.xml create mode 100644 src/res/layout/activity_gos_message.xml create mode 100644 src/res/layout/activity_gos_modelist.xml create mode 100644 src/res/layout/activity_gos_register_user.xml create mode 100644 src/res/layout/activity_gos_send_email_password.xml create mode 100644 src/res/layout/activity_gos_settings.xml create mode 100644 src/res/layout/activity_gos_shared_device_list.xml create mode 100644 src/res/layout/activity_gos_shared_list.xml create mode 100644 src/res/layout/activity_gos_shared_manage.xml create mode 100644 src/res/layout/activity_gos_splash.xml create mode 100644 src/res/layout/activity_gos_two_shared.xml create mode 100644 src/res/layout/activity_gos_user_login.xml create mode 100644 src/res/layout/activity_gos_user_shared.xml create mode 100644 src/res/layout/activity_gos_usermanager.xml create mode 100644 src/res/layout/activity_notice.xml create mode 100644 src/res/layout/actvity_gos_airlink_ready.xml create mode 100644 src/res/layout/actvity_gos_device_reset.xml create mode 100644 src/res/layout/alert_gos_edit_name.xml create mode 100644 src/res/layout/alert_gos_empty.xml create mode 100644 src/res/layout/alert_gos_no_id.xml create mode 100644 src/res/layout/alert_gos_overflow.xml create mode 100644 src/res/layout/alert_gos_quit.xml create mode 100644 src/res/layout/alert_gos_rename.xml create mode 100644 src/res/layout/alert_gos_set_device_info.xml create mode 100644 src/res/layout/alert_gos_tip.xml create mode 100644 src/res/layout/alert_gos_wifi.xml create mode 100644 src/res/layout/alert_gos_wifi_list.xml create mode 100644 src/res/layout/dialog_tips.xml create mode 100644 src/res/layout/gos_devicesharing_zxing_activity.xml create mode 100644 src/res/layout/gos_shared_by_me_activity.xml create mode 100644 src/res/layout/gos_shared_to_me_activity.xml create mode 100644 src/res/layout/header_toolbar.xml create mode 100644 src/res/layout/item_gos_device_list.xml create mode 100644 src/res/layout/item_gos_device_shared_list.xml create mode 100644 src/res/layout/item_gos_mode_list.xml create mode 100644 src/res/layout/item_gos_wifi_device.xml create mode 100644 src/res/layout/item_gos_wifi_list.xml create mode 100644 src/res/layout/layout_recycler_keyboard_view.xml create mode 100644 src/res/layout/view_gos_title_listview.xml create mode 100644 src/res/menu/.DS_Store create mode 100644 src/res/menu/device_more.xml create mode 100644 src/res/menu/gosdeviceconfig.xml create mode 100644 src/res/menu/gosnull.xml create mode 100644 src/res/menu/module_style.xml create mode 100644 src/res/menu/navigation.xml create mode 100644 src/res/values-en/.DS_Store create mode 100644 src/res/values-en/appkitstrings.xml create mode 100644 src/res/values-en/arrays_mode.xml create mode 100644 src/res/values-en/enum_strings.xml create mode 100644 src/res/values-en/ioestrings.xml create mode 100644 src/res/values-v11/styles.xml create mode 100644 src/res/values-v14/styles.xml create mode 100644 src/res/values-w820dp/dimens.xml create mode 100644 src/res/values/.DS_Store create mode 100644 src/res/values/appkitstrings.xml create mode 100644 src/res/values/arrays_mode.xml create mode 100644 src/res/values/attrs.xml create mode 100644 src/res/values/colors.xml create mode 100644 src/res/values/dimens.xml create mode 100644 src/res/values/enum_strings.xml create mode 100644 src/res/values/ids.xml create mode 100644 src/res/values/ioestrings.xml create mode 100644 src/res/values/jpush_style.xml create mode 100644 src/res/values/strings.xml create mode 100644 src/res/values/styles.xml diff --git a/src/java/.DS_Store b/src/java/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..88674d36707987b05e106849abe71805bd45276b GIT binary patch literal 10244 zcmeHMOK=oL82vIz+fU1oPi7@VD1c4jw$ z7%Gb1D9|b|LV2;MQpA&wi=}6=^kPYssHGPV9=vGj#gqQsJsUO&Ip{$tolbTC-T$Mf z`|EF})4c$IeFb9^KokHZ%1o-&RNN;qJInJ@MWCr6i4+fRCT+WEYN_*lLq&){h(L%y zh(L%yh`@t^0PWcN}0(-Ag6`opAIVc5rAYBsd=J0|L31% zlqpCi0y!-tX(*uxB`HENIAUOMc0dtM_C(-6Eu;tscCgzR7w*zWLd#1cbwP1RNm$B0{K;{~#Y_HfaW?Ydi&G>F<#n&pcw1pH(ym$lDvUs5|DSqI|1*S!88v+lJ1b?TI@zOKVl7 zUTGLDTAr1*&5?1-@Xs96y^QG?mUH?zVdwbPGnSc`>#$uOcJ!>tqqIh?SyEf2u|nE9 zSFrr^qOTThg{*!coiymN2VH|j8p6LtdrXo}FnxdCq|&&fF0HLuwOUh#JvK63lDTH> zIz<_NmKIUTizX0tS8k92Hu+D>hk zq~4aEW)D7~d;Z~^=>*U2ZPB!2Oy6r5rXfjEYobl8uiTpG2v%BxX4ps@%3e4LCgk7} zT!t%f6|Tb#cn98vkKhxy4WGg1@CAGW-@ha<7{~AwrZIyCX0eFlIDyaO3-}_wgsaKo|{t!vhIbZ^@=vu<-1 zY8H{o*~3XASi#v+VuN6)*4We>S*|>?5U)pwU*?3wD6KBO)7;pkt&Bz@Dr1VooARoN zLOhmvqiq%0D#*gRRW?LoGO<;y?&4&J5>Zh09!W>!jKzbCBp>~!u7TIHPmTE=Hv00-$6pS)>KknIz$-HB`&S}!H z_i7P6Z-V!9dd~KCldR?2Tbbtrw#9XKcG4Et6))T3Hvg?Hu55}A_(IPfX=$;`w6m9X z&Z3hsOd$dx0wDq+0wDq+0t+BeDfCfx|G#_T-~Shg4%Hz7Ap-ve1h8r#InYNlDcwZO zofNxkk5WEGnI+~oEhG=2f?vmzlYT6AU%`QLQ;*=KmKDtc>d?O S3-H79Kf|HyaQVMD|NjZ#%G{;^ literal 0 HcmV?d00001 diff --git a/src/java/com/.DS_Store b/src/java/com/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0adfb8d81d1b37ae7d891505e9cae0f05cfa3990 GIT binary patch literal 8196 zcmeHMOKjXk82?B0W2Qa_|XUw#d39~3VFa!()3-V5nY~7Hssp^7 zh>tNJ^8&q8I;W@}&`(9b#6Xcw{s<2zjQN-sDAEB%I-q}L^eYtfu1{ z0tSj1;I(@hEKudX47nTYcRN8I{xJ1YZ~fbAG%Jcu_De>}cu=i;vFW}E>vJf3(G4{tzLZ1+X$flE`e%sygpto-lpax%>*r!r)=QMbh3kjfl#Wzz;^`(7^_f* z>qbWBWI5yLr*uX7lWTeYi6z&tEoV|sJA{l~*|mG$fu`2O9X-9VwaTh$ znboqosjT4`2~(fQ8JfFzT6L1Tr5V=33{h#h##uv8vl@)DaZ63pI9H>xpUEFfXEa*nBeupfHP53oDtAcIEVmD)bsB}4wJ3KnS(U~eTCq6A zAr@t_!^WSa`zliJW$luzu?bU6=%z3oVcnAa5Sz-1Z3$y7J0`K|q@7C9q8(xDQy!G$ zFQg~g^GdPP$G%77WF$p1 z&wH?iydmFr_#X0=ka&f!qmzZ@9i&r{*>jXJxs-$~y!ZE!cPB|!c>5d33yf`|xh)m< zCVT*&klMb5Yw$fO?H5wnpYRu!VioQ|1skvt!+0mQ;vu{nqolDOybq6gIveqH_87)- z0w+mr^O!&lbv%nUo{wV+KmZ+7w>@4{!bZ|2E!1u(W`IfPsI@0G1BLhX&{@TfM`1tsS90Pn|a& umlx=z(BPHhgkCvLxc-MB%_9`bb7DT`1(Jo@fBr*2@cj?I|DN)0?cpCsC*hX> literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/.DS_Store b/src/java/com/gizwits/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..05f86efe3c3ea8dfd030c9e402b4a930e268f691 GIT binary patch literal 8196 zcmeHMOHdp|82*1Ap=W?FAQ@o6WEEma0tw+EBqU~eg-|hqSzbxdWp`%`Q_jwio!Ny1 zNnxV5RH9X0Ov;OuDj)IW<6`OASbDLf%BZCm4<5W|>BW=&Jv~qfum`Iwr7F`^-GBH0 z=;{9Yo9X&@0RVe5+5v!S0AN(PREnwDpl~~{>q?%lDI|#$58!|e8AwAC^mX2WB0wNO zAV45MAV45MU^5^7d3-0Z0~*+AGwj zJiv4x* z+tTt4=H(X@ZYg3+W^$?gOmxPci@I?)EtpsVOW|y*K21i&GF`m3Ik&jlVVEs!a`d|TT{5Tt!uFsVZrSk=x0M~0?T7cMTmuz2ZpZ##hgcLmDCc(uKeYqO@4?Gu~LORa47?#gB*xmX>j zlm}x)bw(w9QP)a$-t(GHxa_X57_#Ofza+ z)SXFJpLcohjAN(WKF=|xC>cjTrIVkL)%(fYnKWoR?xvu0yJTBvM}1>+YiD<4xpZrp zB3H9~{BEzPjbogvsP*Lcp*(^5G$NuyRgrF&6om0H7;dN!F! z80RyFdqK=qr*4;&kJyw(k3DH?JW><>b?T#xo#pzzv`($ItZXeSZP=;GqYhtLoJpQ$ z_a0dueV)!waU`MHw_jGr%y>dK6-{EEQ(L>NPGkjQ$_ZcDRUxaBNjsIIB|D_!n^TXd zN11YmJcBU*MfU8S1Z;kNrP{{I-N2RC&cimD{%0@7mkaap>sk zDXuxT`)GA9mplpyj(FTz;fCO=T2);Ws+Awk#qu#?n?BDt!Ih%rnyPAbM>rHxIB%FY zlo~=Zv0Cy5jSXbWBMYBaZVv62h`UO@Hw?AP?TlEe6bfsnd{81DD+R)OSbl;LU6n1~ zM3GuqRzQ;e5%1oF+wd`Q?rXS9O#2CbA+G&NJS)O-tRkM(VjXVBUBtA#*o4jaII-;@ z@vV>8b_@q`1fRwzj^a4Re9q};p^fJ;jV>A%xQ2DN za4i|kUAW#$$4RdKVMzV3Z;SYHNl3C#`Okj{2=4#j{`Z*oU^jmQ DHM`%c literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/opensource/.DS_Store b/src/java/com/gizwits/opensource/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..151aec8ef90f7c8e87fa0224b4f63729157572c1 GIT binary patch literal 8196 zcmeI0T}&KR6oAj6l+L9;3@r?>P~CLJ(iST%rC<@e{Pc(Z2(nP1w578<157$Qv(C&e zrAS5NqxJX6`jZ%aQ0t2t6HViz|1ZXn)EbS64?Y+ZeKI~6>$!7hY599qW9M$}J$LRo zXYSl{zrC|(0RTI)+Ae@f0FbD1DX*nwnZotFE-3}UND)aSe*go#ZqrUBO*^^7IvfZi z5Jn)3Kp25A0$~LH3lX4qHZRf&?|q>S+b{xQ1a8X+@be)`mCJY_XNB~S4r=@qfMg*J z`-S?H2lzhGK*j?(E2QsA_Y~O!2Cf*S7%1FHALZsGnj9i`Ga|u~fXi_;g~zo=kYEmvuW-XM|t%s@_C0==a;UIp0^4Ck%aZR4(hZEl)Kp z-SM3bO(&C6gNCKqlO1-}(p>*O389cACb3bua(cS4sj)t~yRl`aK04jp+)y9g)7UgK z!=#GZU2WZG(^D6wADOxMg1-#F;2ePxaXsH&rrv@@8mU~cNPI89$RA`mzf4xVcHR07 zC35M;O{Ha}<>lo{MR{daRrRR6DXFH;jXV5-J8jc;I?Sv-WTb2>VO-FMJpH`KJEQW( zMRt927PxrWtb-=bj8Vb5H1wOLB?-(6H(_sx_{6Or18>q;B?D9k%D$X>Q5yMhoe6 zbbcp)rbI?f8P<4g|8F9cv3PI3Qztqy#6*XFa?03m*_O^&EPgZ?lwb$6!x2cp1WdwH za2ei)58z|?7Jh->u@Dv9f;(^zw&8v}jNNz?d+{Oc6W#^+?X1a9Ata8FT(F&{o9h(J z7Nqmr`3(llGPYJZPi zsyn~ECtcg|Xv@fOe(#sv0LHGYE05e6tGj1+b8CE#BgHndvca6;8c9FM_q~(~rAm@x(oi;OJe)PWsX2K=$@=OVg`Lvq36I+v z_tNC|CFX0QHHtFAHJy%5ttLtS@LjbE>vw4_vKkm}+s;`3Ir4~MKV z;nui^DT6t|lzcQ8Y}v?^p_H9Y(<8gV*!^vaa)wWPOm)4UjBe2*eMWQhg)22mrz8z? zZM&w?BgNtYL$P>+*jSnWV5ow6cmNKj-rZ5OreQc z%;6-?;?wvnK8MfaOZYOrf^XoP_%2=*&ovL?VR4;r@gwRj1~E8S3i_41LN7!fQN z3T+$PFA=D6(OgwUrP5x_m<)_9L)?nIy$Wx^hs4^~aE%E25q>7d{vf`JQ1#?Y;v(7({|8q7|6f>zZ5V+t0{_bhU}0CH ztAmy{e=;muCeO8_RL@f7h1<;v>AO(lr{g63bev?6j{CMzGUYz;K+XzDBUJwRKLWz{ Se?AFW;fHAW{=W_0|9=Cp7|lZf literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/opensource/appkit/.DS_Store b/src/java/com/gizwits/opensource/appkit/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2cec6f4eb4cf45f52a08987ca7819f21d0206e1b GIT binary patch literal 14340 zcmeHNeQX@n5ub5vvg@pqwc{jf$4RbnLqg()bIx`g+B9c7X)qy*8{4s+7|hqcR+Z=%QdLVWRJ3aQS4E{(Y5}$VgU)-q zckJzb6dk6zqJ5{`dHdd*x4ZLxGxKKl000LwscwKM00?w2Dob?wG(dz=Ut#_1C@Sly z1?kvN2i0YOEa;E~4NikqG`hHaqj6?10{#(Th-!-<|j( zd^lj-rQtc0Kq!G?3A9twW;jXlx(x%cNI!$e@G3Y&EimCA+zu*5=IXFvB@>2~AP!P8 z{5w&9G~Pl{zecmzGBE5k@HLw_%=V5WEaP;eFwwbl)%h zH=e|jz34sbPZEoUZadNFud!}jeZw{D1)))BY-+q^blzGTbyO!~531=4>}o`H<`Z6h z%(9GpT}_` zP#{IJ5k^Vq4qrf%mcp(e%%^Eizc4HE)|gPcySuw0v1reG7HY+p4hXl2qf;eJ>xAw( zNRg<$tW_aSaa%yN6*y~5u(2ckB-p-QpJ02dLTiOr4v4h{#z^UP5^IXgP?CNY83JZL zSSqokAwV)71=wwbaatT^Zp!m8qvgkYNuC;8j-Eq(WITGiealg;@hBmnz(O>T*qP-w zz%Ilyv%3Yh+BdSs1QzQffyMgzeFCcvzrI)0lUdK9;CFHk<@d6jb17ou2B~S|Cb_v~ zb8~C+mMvShZrh@?wQZk~Hz(BO#kn+d4nvkpm`m%aGqba{=1ltPQ#0}=JDIi&W5lv`N4LzWX`6i9 zu%j&uo3j?(F-tz}%p&Wu&uM9!Xc5okl$uVf=A1To`4&S>XvP_H&~hAWfsJId(Tj|v zH8vB!_voUU)XllhV}Bz>qtY24$yN5b6&X6+3MC$795XFb6UEN>DX&q017rYhA{RCf zOYi_Z3Qxgz;m7bQ`~}{`dfbY;@c{PVQ9On>;xL}V5&R^cb-C+uuCpU|3zy;rqQ1op zV7{JPa1E9Mh$rV*fcX5l4=UdCFIWxQTiVN@y%;KM4f`V4PWcsKEn%P6+>&S~99KZO zPZtW&J_^%t2du#7;YoN7UWAw7Pw)o3jZGffyRa7zV;l!?h-3cUpgq5o0jxKWR$ZbU z`XcCsXlMJC0<`-^)*9Ypy=32e{Pw*%hv<97fS3yHM|c%V-~%cF7Gz2kt6Q)@KNjzo z-8}Qi+aK|l<*PM&u~zX+*%z+HUzXh+`d!OfdrH4wEcTjf=_yNi{oJnCw>$J4VMV`5 zUe((~QjVDI4o|~5xCmF^A$S~~hVQ{k@EZIT{)y|ct?J!j*`*CQ26vnZvlJuERnQfd zSSi+(5`49$D?Qw|`eXm1?WAU=DB3+w>0Z;(XLT(tHe;7KW~vJs=Th2~ z?SkAXOlA`L9U0xZyxJl+Z`!d_k)~7h6sN5e<4VcT2_o;=y;D&xu%4l`M(30u@aAjx zD$Ah34)v5>)aXNqFNN=`wzzYj}GRs5CA{{K>e8HKy;DD5tu`mi+ZK4eS60aX;(R287ItYmjtFJ z^7>UidUwZ%1%jI_@JnfL$8{npgp6+Q-j0t5f?VhJMLQ0OqyzFgx35<^ED+k|2DkSH z>0=`4gIw?S9+L(Hg1vmr>h`vFWoU;a$smdq@mmqSzoaD8pD77dM;nbMY{7Qih5HDt zeH5BAwBAI?sMC0k5IcqEaT+z8#d$(4!)yk#cnR;ud+<|uFCq6cgxrVm5&RrJfnUNe z zA0oPe=!x?G|F4Bd4WA*DKq!ItNdj1ZeDwGrO`iLF7Q7GpuU&+W+vs3pUZ8^&s&f`P zu_5e&{~eDmSVYjz+H!^Z;;c?|#idlE@<0D0;Jf>hS{!PI@jqKF_9eAapcKac|0nVP Fe*oRNF?av~ literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/opensource/appkit/CommonModule/GosBaseActivity.java b/src/java/com/gizwits/opensource/appkit/CommonModule/GosBaseActivity.java new file mode 100644 index 0000000..1ddc9ff --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/CommonModule/GosBaseActivity.java @@ -0,0 +1,1077 @@ +package com.gizwits.opensource.appkit.CommonModule; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ActivityInfo; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.os.Handler; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.opensource.appkit.utils.ToolUtils; +import java.util.ArrayList; +import java.util.List; + +public class GosBaseActivity extends AppCompatActivity { + + /** + * 设备热点默认密码 + */ + public static String SoftAP_PSW = "123456789"; + + /** + * 设备热点默认前缀 + */ + public static String SoftAP_Start = "XPG-GAgent"; + + /** + * 存储器默认名称 + */ + public static final String SPF_Name = "set"; + + /** + * Toast time + */ + public int toastTime = 2000; + + /** + * 存储器 + */ + public SharedPreferences spf; + + /** + * 等待框 + */ + public ProgressDialog progressDialog; + + /** + * 标题栏 + */ +// public ActionBar actionBar; + + public Toolbar mToolbar; + + /** + * 实现WXEntryActivity与GosUserLoginActivity共用 + */ + public static Handler baseHandler; + + public static boolean isclean = false; + public TextView tvTitle; + + public void setBaseHandler(Handler basehandler) { + if (null != basehandler) { + baseHandler = basehandler; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + /** + * 设置为竖屏 + */ + if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + spf = getSharedPreferences(SPF_Name, Context.MODE_PRIVATE); + // 初始化 + setProgressDialog(); + } + + /** + * 添加ProductKeys + * + * @param productkeys + * @return + */ + public List addProductKey(String[] productkeys) { + List productkeysList = new ArrayList(); + for (String productkey : productkeys) { + productkeysList.add(productkey); + } + + return productkeysList; + } + + /** + * 设置setToolBar(工具方法*开发用*) + * + * @param Title + */ + public void setToolBar(boolean isIcon, int Title) { + mToolbar = (Toolbar) findViewById(R.id.toolbar); + mToolbar.setTitle(""); + setSupportActionBar(mToolbar); + tvTitle = (TextView) findViewById(R.id.tvTitle); + // 工具栏的背景颜色 + mToolbar.setBackgroundColor(GosDeploy.appConfig_Background()); + SpannableString ssTitle = new SpannableString(this.getString(Title)); + ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvTitle.setText(ssTitle); + if (isIcon) { + mToolbar.setNavigationIcon(ToolUtils.editIcon(getResources(), R.drawable.common_page_back_button)); + } else { + mToolbar.setNavigationIcon(null); + } + } + + /** + * 设置setToolBar(工具方法*开发用*) + * + * @param isLeft + * @param Title + */ + public void setToolBar(boolean isLeft, String Title) { + mToolbar = (Toolbar) findViewById(R.id.toolbar); + mToolbar.setTitle(""); + setSupportActionBar(mToolbar); + tvTitle = (TextView) findViewById(R.id.tvTitle); + // 工具栏的背景颜色 + mToolbar.setBackgroundColor(GosDeploy.appConfig_Background()); + SpannableString ssTitle = new SpannableString(Title); + ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvTitle.setText(ssTitle); + if (isLeft) { + mToolbar.setNavigationIcon(ToolUtils.editIcon(getResources(), R.drawable.common_page_back_button)); + } else { + mToolbar.setNavigationIcon(null); + } + } + + +// /** +// * 设置ActionBar(工具方法*开发用*) +// * +// * @param HBE +// * @param DSHE +// * @param Title +// */ +// public void setActionBar(Boolean HBE, Boolean DSHE, int Title) { +// SpannableString ssTitle = new SpannableString(this.getString(Title)); +// ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), +// Spannable.SPAN_INCLUSIVE_EXCLUSIVE); +// actionBar = getSupportActionBar();// 初始化ActionBar +// Log.e("TAG", "setActionBar=========: " + actionBar); +// if (actionBar != null) { +// actionBar.setBackgroundDrawable(new ColorDrawable(GosDeploy.appConfig_Background())); +// actionBar.setHomeButtonEnabled(HBE); +//// actionBar.setIcon(R.drawable.back_bt_); +// // 设置返回按钮的颜色 +// actionBar.setIcon(ToolUtils.editIcon(getResources(), R.drawable.back_bt_)); +// actionBar.setTitle(ssTitle); +// actionBar.setDisplayShowHomeEnabled(DSHE); +// } +// +// } +// +// +// /** +// * 设置ActionBar(工具方法*GosAirlinkChooseDeviceWorkWiFiActivity.java中使用*) +// * +// * @param HBE +// * @param DSHE 使左上角图标是否显示 +// * @param Title +// */ +// public void setActionBar(Boolean HBE, Boolean DSHE, CharSequence Title) { +// SpannableString ssTitle = new SpannableString(Title); +// ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), +// Spannable.SPAN_INCLUSIVE_EXCLUSIVE); +// actionBar = getSupportActionBar();// 初始化ActionBar +// if (actionBar != null) { +// actionBar.setBackgroundDrawable(new ColorDrawable(GosDeploy.appConfig_Background())); +// actionBar.setHomeButtonEnabled(HBE); +// // 从资源文件中获取图片 +// actionBar.setIcon(ToolUtils.editIcon(getResources(), R.drawable.back_bt_)); +// actionBar.setTitle(ssTitle); +// actionBar.setDisplayShowHomeEnabled(DSHE); +// } +// } + + /** + * 设置ProgressDialog + */ + public void setProgressDialog() { + progressDialog = new ProgressDialog(this); + String loadingText = getString(R.string.loadingtext); + progressDialog.setMessage(loadingText); + progressDialog.setCanceledOnTouchOutside(false); + } + + /** + * 设置ProgressDialog + * + * @param Message + * @param Cancelable + * @param CanceledOnTouchOutside + */ + public void setProgressDialog(String Message, boolean Cancelable, boolean CanceledOnTouchOutside) { + progressDialog = new ProgressDialog(this); + progressDialog.setMessage(Message); + progressDialog.setCancelable(Cancelable); + progressDialog.setCanceledOnTouchOutside(CanceledOnTouchOutside); + } + + /** + * 检查网络连通性(工具方法) + * + * @param context + * @return + */ + public boolean checkNetwork(Context context) { + ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo net = conn.getActiveNetworkInfo(); + if (net != null && net.isConnected()) { + return true; + } + return false; + } + + /** + * 验证手机格式.(工具方法) + */ + // public boolean isMobileNO(String mobiles) { + // /* + // * 移动:134、135、136、137、138、139、150、151、157(TD)、158、159、187、188 + // * 联通:130、131、132、152、155、156、185、186 电信:133、153、180、189、(1349卫通) + // * 总结起来就是第一位必定为1,第二位必定为3或5或8,其他位置的可以为0-9 + // */ + // String telRegex = "[1][3578]\\d{9}";// + // "[1]"代表第1位为数字1,"[358]"代表第二位可以为3、5、8中的一个,"\\d{9}"代表后面是可以是0~9的数字,有9位。 + // if (TextUtils.isEmpty(mobiles)) + // return false; + // else + // return !mobiles.matches(telRegex); + // } + public String toastError(GizWifiErrorCode errorCode) { + String errorString = (String) getText(R.string.UNKNOWN_ERROR); + switch (errorCode) { + case GIZ_SDK_SUCCESS: + errorString = (String) getText(R.string.GIZ_SDK_SUCCESS); + break; + case GIZ_SDK_PARAM_FORM_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PARAM_FORM_INVALID); + break; + case GIZ_SDK_CLIENT_NOT_AUTHEN: + errorString = (String) getText(R.string.GIZ_SDK_CLIENT_NOT_AUTHEN); + break; + case GIZ_SDK_CLIENT_VERSION_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_CLIENT_VERSION_INVALID); + break; + case GIZ_SDK_UDP_PORT_BIND_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_UDP_PORT_BIND_FAILED); + break; + case GIZ_SDK_DAEMON_EXCEPTION: + errorString = (String) getText(R.string.GIZ_SDK_DAEMON_EXCEPTION); + break; + case GIZ_SDK_PARAM_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PARAM_INVALID); + break; + case GIZ_SDK_APPID_LENGTH_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_APPID_LENGTH_ERROR); + break; + case GIZ_SDK_LOG_PATH_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_LOG_PATH_INVALID); + break; + case GIZ_SDK_LOG_LEVEL_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_LOG_LEVEL_INVALID); + break; + case GIZ_SDK_UID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_UID_INVALID); + break; + case GIZ_SDK_TOKEN_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_TOKEN_INVALID); + break; + case GIZ_SDK_USER_NOT_LOGIN: + errorString = (String) getText(R.string.GIZ_SDK_USER_NOT_LOGIN); + break; + case GIZ_SDK_APPID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_APPID_INVALID); + break; + case GIZ_SDK_APP_SECRET_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_APP_SECRET_INVALID); + break; + case GIZ_SDK_PRODUCT_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCT_KEY_INVALID); + break; + case GIZ_SDK_PRODUCT_SECRET_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCT_SECRET_INVALID); + break; + case GIZ_SDK_DEVICE_NOT_IN_LAN: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_IN_LAN); + break; + case GIZ_SDK_PRODUCTKEY_NOT_IN_SPECIAL_LIST: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCTKEY_NOT_IN_SPECIAL_LIST); + break; + case GIZ_SDK_PRODUCTKEY_NOT_RELATED_WITH_APPID: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCTKEY_NOT_RELATED_WITH_APPID); + break; + case GIZ_SDK_NO_AVAILABLE_DEVICE: + errorString = (String) getText(R.string.GIZ_SDK_NO_AVAILABLE_DEVICE); + break; + case GIZ_SDK_DEVICE_CONFIG_SEND_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_SEND_FAILED); + break; + case GIZ_SDK_DEVICE_CONFIG_IS_RUNNING: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_IS_RUNNING); + break; + case GIZ_SDK_DEVICE_CONFIG_TIMEOUT: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_TIMEOUT); + break; + case GIZ_SDK_DEVICE_DID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_DID_INVALID); + break; + case GIZ_SDK_DEVICE_MAC_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_MAC_INVALID); + break; + case GIZ_SDK_SUBDEVICE_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_SUBDEVICE_INVALID); + break; + case GIZ_SDK_DEVICE_PASSCODE_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_PASSCODE_INVALID); + break; + case GIZ_SDK_DEVICE_NOT_CENTERCONTROL: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_CENTERCONTROL); + break; + case GIZ_SDK_DEVICE_NOT_SUBSCRIBED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_SUBSCRIBED); + break; + case GIZ_SDK_DEVICE_NO_RESPONSE: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NO_RESPONSE); + break; + case GIZ_SDK_DEVICE_NOT_READY: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_READY); + break; + case GIZ_SDK_DEVICE_NOT_BINDED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_BINDED); + break; + case GIZ_SDK_DEVICE_CONTROL_WITH_INVALID_COMMAND: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_WITH_INVALID_COMMAND); + break; +// case GIZ_SDK_DEVICE_CONTROL_FAILED: +// errorString= (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_FAILED); +// break; + case GIZ_SDK_DEVICE_GET_STATUS_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_GET_STATUS_FAILED); + break; + case GIZ_SDK_DEVICE_CONTROL_VALUE_TYPE_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_VALUE_TYPE_ERROR); + break; + case GIZ_SDK_DEVICE_CONTROL_VALUE_OUT_OF_RANGE: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_VALUE_OUT_OF_RANGE); + break; + case GIZ_SDK_DEVICE_CONTROL_NOT_WRITABLE_COMMAND: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_NOT_WRITABLE_COMMAND); + break; + case GIZ_SDK_BIND_DEVICE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_BIND_DEVICE_FAILED); + break; + case GIZ_SDK_UNBIND_DEVICE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_UNBIND_DEVICE_FAILED); + break; + case GIZ_SDK_DNS_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DNS_FAILED); + break; + case GIZ_SDK_M2M_CONNECTION_SUCCESS: + errorString = (String) getText(R.string.GIZ_SDK_M2M_CONNECTION_SUCCESS); + break; + case GIZ_SDK_SET_SOCKET_NON_BLOCK_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SET_SOCKET_NON_BLOCK_FAILED); + break; + case GIZ_SDK_CONNECTION_TIMEOUT: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_TIMEOUT); + break; + case GIZ_SDK_CONNECTION_REFUSED: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_REFUSED); + break; + case GIZ_SDK_CONNECTION_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_ERROR); + break; + case GIZ_SDK_CONNECTION_CLOSED: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_CLOSED); + break; + case GIZ_SDK_SSL_HANDSHAKE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SSL_HANDSHAKE_FAILED); + break; + case GIZ_SDK_DEVICE_LOGIN_VERIFY_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_LOGIN_VERIFY_FAILED); + break; + case GIZ_SDK_INTERNET_NOT_REACHABLE: + errorString = (String) getText(R.string.GIZ_SDK_INTERNET_NOT_REACHABLE); + break; + case GIZ_SDK_M2M_CONNECTION_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_M2M_CONNECTION_FAILED); + break; + case GIZ_SDK_HTTP_SERVER_NOT_SUPPORT_API: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_SERVER_NOT_SUPPORT_API); + break; + case GIZ_SDK_HTTP_ANSWER_FORMAT_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_ANSWER_FORMAT_ERROR); + break; + case GIZ_SDK_HTTP_ANSWER_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_ANSWER_PARAM_ERROR); + break; + case GIZ_SDK_HTTP_SERVER_NO_ANSWER: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_SERVER_NO_ANSWER); + break; + case GIZ_SDK_HTTP_REQUEST_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_REQUEST_FAILED); + break; + case GIZ_SDK_OTHERWISE: + errorString = (String) getText(R.string.GIZ_SDK_OTHERWISE); + break; + case GIZ_SDK_MEMORY_MALLOC_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_MEMORY_MALLOC_FAILED); + break; + case GIZ_SDK_THREAD_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_THREAD_CREATE_FAILED); + break; + case GIZ_SDK_JSON_OBJECT_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_JSON_OBJECT_CREATE_FAILED); + break; + case GIZ_SDK_JSON_PARSE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_JSON_PARSE_FAILED); + break; + case GIZ_SDK_SCHEDULER_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_CREATE_FAILED); + break; + case GIZ_SDK_SCHEDULER_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_DELETE_FAILED); + break; + case GIZ_SDK_SCHEDULER_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_EDIT_FAILED); + break; + case GIZ_SDK_SCHEDULER_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCHEDULER_TASK_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_TASK_EDIT_FAILED); + break; + case GIZ_SDK_SCHEDULER_TASK_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_TASK_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCHEDULER_ID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_ID_INVALID); + break; + case GIZ_SDK_SCHEDULER_ENABLE_DISABLE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_ENABLE_DISABLE_FAILED); + break; + case GIZ_SDK_SCHEDULER_STATUS_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_STATUS_UPDATE_FAILED); + break; + case GIZ_SDK_GROUP_ID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_ID_INVALID); + break; + case GIZ_SDK_GROUP_FAILED_DELETE_DEVICE: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_FAILED_DELETE_DEVICE); + break; + case GIZ_SDK_GROUP_FAILED_ADD_DEVICE: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_FAILED_ADD_DEVICE); + break; + case GIZ_SDK_GROUP_PRODUCTKEY_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_PRODUCTKEY_INVALID); + break; + case GIZ_SDK_GROUP_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_CREATE_FAILED); + break; + case GIZ_SDK_GROUP_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_FAILED_DELETE_DEVICE); + break; + case GIZ_SDK_GROUP_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_EDIT_FAILED); + break; + case GIZ_SDK_GROUP_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_GET_DEVICE_FAILED); + break; + case GIZ_SDK_SCENE_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_CREATE_FAILED); + break; + case GIZ_SDK_SCENE_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_DELETE_FAILED); + break; + case GIZ_SDK_SCENE_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_EDIT_FAILED); + break; + case GIZ_SDK_SCENE_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCENE_ITEM_LIST_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_ITEM_LIST_EDIT_FAILED); + break; + case GIZ_SDK_SCENE_ITEM_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_ITEM_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCENE_ID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_ID_INVALID); + break; + case GIZ_SDK_SCENE_RUN_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_RUN_FAILED); + break; + case GIZ_SDK_SCENE_STATUS_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_STATUS_UPDATE_FAILED); + break; + case GIZ_SDK_JOINT_ACTION_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_JOINT_ACTION_CREATE_FAILED); + break; + case GIZ_SDK_JOINT_ACTION_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_JOINT_ACTION_DELETE_FAILED); + break; + case GIZ_SDK_JOINT_ACTION_VER_UNSUPPORTED: + errorString = (String) getText(R.string.GIZ_SDK_JOINT_ACTION_VER_UNSUPPORTED); + break; +// case GIZ_SDK_JOINT_ACTION_INVALID_CONDITION_TYPE: +// errorString = (String) getText(R.string.GIZ_SDK_JOINT_ACTION_INVALID_CONDITION_TYPE); +// break; +// case GIZ_SDK_JOINT_ACTION_INVALID_RESULT_EVENT_TYPE: +// errorString = (String) getText(R.string.GIZ_SDK_JOINT_ACTION_INVALID_RESULT_EVENT_TYPE); +// break; + case GIZ_SDK_DATAPOINT_NOT_DOWNLOAD: + errorString = (String) getText(R.string.GIZ_SDK_DATAPOINT_NOT_DOWNLOAD); + break; + case GIZ_SDK_DATAPOINT_SERVICE_UNAVAILABLE: + errorString = (String) getText(R.string.GIZ_SDK_DATAPOINT_SERVICE_UNAVAILABLE); + break; + case GIZ_SDK_DATAPOINT_PARSE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DATAPOINT_PARSE_FAILED); + break; + // case GIZ_SDK_NOT_INITIALIZED: + // errorString= (String) getText(R.string.GIZ_SDK_SDK_NOT_INITIALIZED); + // break; + case GIZ_SDK_APK_CONTEXT_IS_NULL: + errorString = (String) getText(R.string.GIZ_SDK_APK_CONTEXT_IS_NULL); + break; + case GIZ_SDK_APK_PERMISSION_NOT_SET: + errorString = (String) getText(R.string.GIZ_SDK_APK_PERMISSION_NOT_SET); + break; + case GIZ_SDK_CHMOD_DAEMON_REFUSED: + errorString = (String) getText(R.string.GIZ_SDK_CHMOD_DAEMON_REFUSED); + break; + case GIZ_SDK_EXEC_DAEMON_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_EXEC_DAEMON_FAILED); + break; + case GIZ_SDK_EXEC_CATCH_EXCEPTION: + errorString = (String) getText(R.string.GIZ_SDK_EXEC_CATCH_EXCEPTION); + break; + case GIZ_SDK_APPID_IS_EMPTY: + errorString = (String) getText(R.string.GIZ_SDK_APPID_IS_EMPTY); + break; + case GIZ_SDK_UNSUPPORTED_API: + errorString = (String) getText(R.string.GIZ_SDK_UNSUPPORTED_API); + break; + case GIZ_SDK_REQUEST_TIMEOUT: + errorString = (String) getText(R.string.GIZ_SDK_REQUEST_TIMEOUT); + break; + case GIZ_SDK_DAEMON_VERSION_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DAEMON_VERSION_INVALID); + break; + case GIZ_SDK_PHONE_NOT_CONNECT_TO_SOFTAP_SSID: + errorString = (String) getText(R.string.GIZ_SDK_PHONE_NOT_CONNECT_TO_SOFTAP_SSID); + break; + case GIZ_SDK_DEVICE_CONFIG_SSID_NOT_MATCHED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_SSID_NOT_MATCHED); + break; + case GIZ_SDK_NOT_IN_SOFTAPMODE: + errorString = (String) getText(R.string.GIZ_SDK_NOT_IN_SOFTAPMODE); + break; +// case GIZ_SDK_PHONE_WIFI_IS_UNAVAILABLE: +// errorString= (String)getText(R.string.GIZ_SDK_PHONE_WIFI_IS_UNAVAILABLE); +// break; + case GIZ_SDK_RAW_DATA_TRANSMIT: + errorString = (String) getText(R.string.GIZ_SDK_RAW_DATA_TRANSMIT); + break; + case GIZ_SDK_PRODUCT_IS_DOWNLOADING: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCT_IS_DOWNLOADING); + break; + case GIZ_SDK_START_SUCCESS: + errorString = (String) getText(R.string.GIZ_SDK_START_SUCCESS); + break; + case GIZ_SDK_NEED_UPDATE_TO_LATEST: + errorString = (String) getText(R.string.GIZ_SDK_NEED_UPDATE_TO_LATEST); + break; + case GIZ_SDK_ONBOARDING_STOPPED: + errorString = (String) getText(R.string.GIZ_SDK_ONBOARDING_STOPPED); + break; + case GIZ_SDK_ONBOARDING_WIFI_IS_5G: + errorString = (String) getText(R.string.GIZ_SDK_ONBOARDING_WIFI_IS_5G); + break; + case GIZ_SDK_OTA_FIRMWARE_IS_LATEST: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_IS_LATEST); + break; + case GIZ_SDK_OTA_FIRMWARE_CHECK_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_CHECK_UPDATE_FAILED); + break; + case GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_OK: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_OK); + break; + case GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_FAILED); + break; + case GIZ_SDK_OTA_DEVICE_BUSY_IN_UPGRADE: + errorString = (String) getText(R.string.GIZ_SDK_OTA_DEVICE_BUSY_IN_UPGRADE); + break; + case GIZ_SDK_OTA_PUSH_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_PUSH_FAILED); + break; + case GIZ_SDK_OTA_FIRMWARE_VERSION_TOO_LOW: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_VERSION_TOO_LOW); + break; + case GIZ_SDK_OTA_FIRMWARE_CHECK_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_CHECK_FAILED); + break; + case GIZ_SDK_OTA_UPGRADE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_UPGRADE_FAILED); + break; + case GIZ_SDK_OTA_FIRMWARE_VERIFY_SUCCESS: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_VERIFY_SUCCESS); + break; + case GIZ_SDK_OTA_DEVICE_NOT_SUPPORT: + errorString = (String) getText(R.string.GIZ_SDK_OTA_DEVICE_NOT_SUPPORT); + break; + case GIZ_SDK_WS_HANDSHAKE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_WS_HANDSHAKE_FAILED); + break; + case GIZ_SDK_WS_LOGIN_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_WS_LOGIN_FAILED); + break; +// case GIZ_SDK_WS_DEVICE_SUBSCRIBE_FAILED: +// errorString = (String) getText(R.string.GIZ_SDK_WS_DEVICE_SUBSCRIBE_FAILED); +// break; +// case GIZ_SDK_WS_DEVICE_UNSUBSCRIBE_FAILED: +// errorString = (String) getText(R.string.GIZ_SDK_WS_DEVICE_UNSUBSCRIBE_FAILED); +// break; + case GIZ_SITE_PRODUCTKEY_INVALID: + errorString = (String) getText(R.string.GIZ_SITE_PRODUCTKEY_INVALID); + break; + case GIZ_SITE_DATAPOINTS_NOT_DEFINED: + errorString = (String) getText(R.string.GIZ_SITE_DATAPOINTS_NOT_DEFINED); + break; + case GIZ_SITE_DATAPOINTS_NOT_MALFORME: + errorString = (String) getText(R.string.GIZ_SITE_DATAPOINTS_NOT_MALFORME); + break; + case GIZ_OPENAPI_MAC_ALREADY_REGISTERED: + errorString = (String) getText(R.string.GIZ_OPENAPI_MAC_ALREADY_REGISTERED); + break; + case GIZ_OPENAPI_PRODUCT_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCT_KEY_INVALID); + break; + case GIZ_OPENAPI_APPID_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_APPID_INVALID); + break; + case GIZ_OPENAPI_TOKEN_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_TOKEN_INVALID); + break; + case GIZ_OPENAPI_USER_NOT_EXIST: + errorString = (String) getText(R.string.GIZ_OPENAPI_USER_NOT_EXIST); + break; + case GIZ_OPENAPI_TOKEN_EXPIRED: + errorString = (String) getText(R.string.GIZ_OPENAPI_TOKEN_EXPIRED); + break; + case GIZ_OPENAPI_M2M_ID_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_M2M_ID_INVALID); + break; + case GIZ_OPENAPI_SERVER_ERROR: + errorString = (String) getText(R.string.GIZ_OPENAPI_SERVER_ERROR); + break; + case GIZ_OPENAPI_CODE_EXPIRED: + errorString = (String) getText(R.string.GIZ_OPENAPI_CODE_EXPIRED); + break; + case GIZ_OPENAPI_CODE_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_CODE_INVALID); + break; + case GIZ_OPENAPI_SANDBOX_SCALE_QUOTA_EXHAUSTED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SANDBOX_SCALE_QUOTA_EXHAUSTED); + break; + case GIZ_OPENAPI_PRODUCTION_SCALE_QUOTA_EXHAUSTED: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCTION_SCALE_QUOTA_EXHAUSTED); + break; + case GIZ_OPENAPI_PRODUCT_HAS_NO_REQUEST_SCALE: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCT_HAS_NO_REQUEST_SCALE); + break; + case GIZ_OPENAPI_DEVICE_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_NOT_FOUND); + break; + case GIZ_OPENAPI_FORM_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_FORM_INVALID); + break; + case GIZ_OPENAPI_DID_PASSCODE_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_DID_PASSCODE_INVALID); + break; + case GIZ_OPENAPI_DEVICE_NOT_BOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_NOT_BOUND); + break; + case GIZ_OPENAPI_PHONE_UNAVALIABLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_PHONE_UNAVALIABLE); + break; + case GIZ_OPENAPI_USERNAME_UNAVALIABLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_USERNAME_UNAVALIABLE); + break; + case GIZ_OPENAPI_USERNAME_PASSWORD_ERROR: + errorString = (String) getText(R.string.GIZ_OPENAPI_USERNAME_PASSWORD_ERROR); + break; + case GIZ_OPENAPI_SEND_COMMAND_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SEND_COMMAND_FAILED); + break; + case GIZ_OPENAPI_EMAIL_UNAVALIABLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_EMAIL_UNAVALIABLE); + break; + case GIZ_OPENAPI_DEVICE_DISABLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_DISABLED); + break; + case GIZ_OPENAPI_FAILED_NOTIFY_M2M: + errorString = (String) getText(R.string.GIZ_OPENAPI_FAILED_NOTIFY_M2M); + break; + case GIZ_OPENAPI_ATTR_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_ATTR_INVALID); + break; + case GIZ_OPENAPI_USER_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_USER_INVALID); + break; + case GIZ_OPENAPI_FIRMWARE_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_FIRMWARE_NOT_FOUND); + break; + case GIZ_OPENAPI_JD_PRODUCT_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_JD_PRODUCT_NOT_FOUND); + break; + case GIZ_OPENAPI_DATAPOINT_DATA_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_DATAPOINT_DATA_NOT_FOUND); + break; + case GIZ_OPENAPI_SCHEDULER_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_SCHEDULER_NOT_FOUND); + break; + case GIZ_OPENAPI_QQ_OAUTH_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_QQ_OAUTH_KEY_INVALID); + break; + case GIZ_OPENAPI_OTA_SERVICE_OK_BUT_IN_IDLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_OTA_SERVICE_OK_BUT_IN_IDLE); + break; + case GIZ_OPENAPI_BT_FIRMWARE_UNVERIFIED: + errorString = (String) getText(R.string.GIZ_OPENAPI_BT_FIRMWARE_UNVERIFIED); + break; + case GIZ_OPENAPI_BT_FIRMWARE_NOTHING_TO_UPGRADE: + errorString = (String) getText(R.string.GIZ_OPENAPI_SAVE_KAIROSDB_ERROR); + break; + case GIZ_OPENAPI_SAVE_KAIROSDB_ERROR: + errorString = (String) getText(R.string.GIZ_OPENAPI_SAVE_KAIROSDB_ERROR); + break; + case GIZ_OPENAPI_EVENT_NOT_DEFINED: + errorString = (String) getText(R.string.GIZ_OPENAPI_EVENT_NOT_DEFINED); + break; + case GIZ_OPENAPI_SEND_SMS_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SEND_SMS_FAILED); + break; +// case GIZ_OPENAPI_APPLICATION_AUTH_INVALID: +// errorString= (String) +// getText(R.string.GIZ_OPENAPI_APPLICATION_AUTH_INVALID); +// break; + case GIZ_OPENAPI_NOT_ALLOWED_CALL_API: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_ALLOWED_CALL_API); + break; + case GIZ_OPENAPI_BAD_QRCODE_CONTENT: + errorString = (String) getText(R.string.GIZ_OPENAPI_BAD_QRCODE_CONTENT); + break; + case GIZ_OPENAPI_REQUEST_THROTTLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_REQUEST_THROTTLED); + break; + case GIZ_OPENAPI_DEVICE_OFFLINE: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_OFFLINE); + break; + case GIZ_OPENAPI_TIMESTAMP_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_TIMESTAMP_INVALID); + break; + case GIZ_OPENAPI_SIGNATURE_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_SIGNATURE_INVALID); + break; + case GIZ_OPENAPI_DEPRECATED_API: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEPRECATED_API); + break; + case GIZ_OPENAPI_REGISTER_IS_BUSY: + errorString = (String) getText(R.string.GIZ_OPENAPI_REGISTER_IS_BUSY); + break; + case GIZ_OPENAPI_ALTER_PASSWORD_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_ALTER_PASSWORD_FAILED); + break; + case GIZ_OPENAPI_APPID_PK_NOT_RELATION: + errorString = (String) getText(R.string.GIZ_OPENAPI_APPID_PK_NOT_RELATION); + break; + case GIZ_OPENAPI_CALL_INNER_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_CALL_INNER_FAILED); + break; + case GIZ_OPENAPI_DEVICE_SHARING_NOT_ENABLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_SHARING_NOT_ENABLED); + break; + case GIZ_OPENAPI_NOT_FIRST_USER_OF_DEVICE: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FIRST_USER_OF_DEVICE); + break; + case GIZ_OPENAPI_PRODUCT_KEY_AUTHEN_FAULT: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCT_KEY_AUTHEN_FAULT); + break; + case GIZ_OPENAPI_BUSY_NOW: + errorString = (String) getText(R.string.GIZ_OPENAPI_BUSY_NOW); + break; + case GIZ_OPENAPI_TWITTER_CONSUMER_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_TWITTER_CONSUMER_KEY_INVALID); + break; + case GIZ_OPENAPI_NOT_ALLOW_WEEK_PASSWORD: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_ALLOW_WEEK_PASSWORD); + break; +// case GIZ_OPENAPI_CODE_NOT_EXIST: +// errorString = (String) getText(R.string.GIZ_OPENAPI_CODE_NOT_EXIST); +// break; +// case GIZ_OPENAPI_EMAIL_NOT_ACTIVE: +// errorString = (String) getText(R.string.GIZ_OPENAPI_EMAIL_NOT_ACTIVE); +// break; +// case GIZ_OPENAPI_EMAIL_NOT_ENABLE: +// errorString = (String) getText(R.string.GIZ_OPENAPI_EMAIL_NOT_ENABLE); +// break; +// case GIZ_OPENAPI_DEVICE_REGISTER_NOT_FOUND: +// errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_REGISTER_NOT_FOUND); +// break; + case GIZ_OPENAPI_CANNOT_SHARE_TO_SELF: + errorString = (String) getText(R.string.GIZ_OPENAPI_CANNOT_SHARE_TO_SELF); + break; + case GIZ_OPENAPI_ONLY_OWNER_CAN_SHARE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_OWNER_CAN_SHARE); + break; + case GIZ_OPENAPI_NOT_FOUND_GUEST: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FOUND_GUEST); + break; + case GIZ_OPENAPI_GUEST_ALREADY_BOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_GUEST_ALREADY_BOUND); + break; + case GIZ_OPENAPI_NOT_FOUND_SHARING_INFO: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FOUND_SHARING_INFO); + break; + case GIZ_OPENAPI_NOT_FOUND_THE_MESSAGE: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FOUND_THE_MESSAGE); + break; + case GIZ_OPENAPI_SHARING_IS_WAITING_FOR_ACCEPT: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_IS_WAITING_FOR_ACCEPT); + break; + case GIZ_OPENAPI_SHARING_IS_EXPIRED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_IS_EXPIRED); + break; + case GIZ_OPENAPI_SHARING_IS_COMPLETED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_IS_COMPLETED); + break; + case GIZ_OPENAPI_INVALID_SHARING_BECAUSE_UNBINDING: + errorString = (String) getText(R.string.GIZ_OPENAPI_INVALID_SHARING_BECAUSE_UNBINDING); + break; + case GIZ_OPENAPI_ONLY_OWNER_CAN_BIND: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_OWNER_CAN_BIND); + break; + case GIZ_OPENAPI_ONLY_OWNER_CAN_OPERATE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_OWNER_CAN_OPERATE); + break; + case GIZ_OPENAPI_SHARING_ALREADY_CANCELLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_ALREADY_CANCELLED); + break; + case GIZ_OPENAPI_OWNER_CANNOT_UNBIND_SELF: + errorString = (String) getText(R.string.GIZ_OPENAPI_OWNER_CANNOT_UNBIND_SELF); + break; + case GIZ_OPENAPI_ONLY_GUEST_CAN_CHECK_QRCODE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_GUEST_CAN_CHECK_QRCODE); + break; + case GIZ_OPENAPI_MESSAGE_ALREADY_DELETED: + errorString = (String) getText(R.string.GIZ_OPENAPI_MESSAGE_ALREADY_DELETED); + break; + case GIZ_OPENAPI_BINDING_NOTIFY_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_BINDING_NOTIFY_FAILED); + break; + case GIZ_OPENAPI_ONLY_SELF_CAN_MODIFY_ALIAS: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_SELF_CAN_MODIFY_ALIAS); + break; + case GIZ_OPENAPI_ONLY_RECEIVER_CAN_MARK_MESSAGE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_RECEIVER_CAN_MARK_MESSAGE); + break; + case GIZ_OPENAPI_GUEST_NOT_BIND: + errorString = (String) getText(R.string.GIZ_OPENAPI_GUEST_NOT_BIND); + break; + case GIZ_OPENAPI_CANNOT_TRANSFER_OWNER_TO_SELF: + errorString = (String) getText(R.string.GIZ_OPENAPI_CANNOT_TRANSFER_OWNER_TO_SELF); + break; + case GIZ_OPENAPI_TRANSFER_OWNER_TO_LIMIT_GUEST: + errorString = (String) getText(R.string.GIZ_OPENAPI_TRANSFER_OWNER_TO_LIMIT_GUEST); + break; + case GIZ_OPENAPI_RESERVED: + errorString = (String) getText(R.string.GIZ_OPENAPI_RESERVED); + break; + case GIZ_PUSHAPI_BODY_JSON_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_BODY_JSON_INVALID); + break; + case GIZ_PUSHAPI_DATA_NOT_EXIST: + errorString = (String) getText(R.string.GIZ_PUSHAPI_DATA_NOT_EXIST); + break; + case GIZ_PUSHAPI_NO_CLIENT_CONFIG: + errorString = (String) getText(R.string.GIZ_PUSHAPI_NO_CLIENT_CONFIG); + break; + case GIZ_PUSHAPI_NO_SERVER_DATA: + errorString = (String) getText(R.string.GIZ_PUSHAPI_NO_SERVER_DATA); + break; + case GIZ_PUSHAPI_GIZWITS_APPID_EXIST: + errorString = (String) getText(R.string.GIZ_PUSHAPI_GIZWITS_APPID_EXIST); + break; + case GIZ_PUSHAPI_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_PARAM_ERROR); + break; + case GIZ_PUSHAPI_AUTH_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_AUTH_KEY_INVALID); + break; + case GIZ_PUSHAPI_APPID_OR_TOKEN_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_APPID_OR_TOKEN_ERROR); + break; + case GIZ_PUSHAPI_TYPE_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_TYPE_PARAM_ERROR); + break; + case GIZ_PUSHAPI_ID_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_ID_PARAM_ERROR); + break; + case GIZ_PUSHAPI_APPKEY_SECRETKEY_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_APPKEY_SECRETKEY_INVALID); + break; + case GIZ_PUSHAPI_CHANNELID_ERROR_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_CHANNELID_ERROR_INVALID); + break; + case GIZ_PUSHAPI_PUSH_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_PUSH_ERROR); + break; + case GIZ_SDK_SUBDEVICE_ADD_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_ADD_SUBDEVICE_FAILED); + break; + + case GIZ_SDK_SUBDEVICE_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DELETE_SUBDEVICE_FAILED); + break; + + case GIZ_SDK_SUBDEVICE_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GET_SUBDEVICES_FAILED); + break; + default: + errorString = (String) getText(R.string.UNKNOWN_ERROR); + break; + } + return errorString; + } + + /** + * NoID 提示 + * + * @param context 当前上下文 + * @param alertTextID 提示内容 + */ + public static void noIDAlert(Context context, int alertTextID) { + final Dialog dialog = new AlertDialog.Builder(context, R.style.alert_dialog_style) + .setView(new EditText(context)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_no_id); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llSure; + TextView tvAlert; + llSure = (LinearLayout) window.findViewById(R.id.llSure); + tvAlert = (TextView) window.findViewById(R.id.tvAlert); + tvAlert.setText(alertTextID); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + } + + + public void startAlert(final Intent intent, String content) { + final Dialog dialog = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + TextView tvContent; + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + tvContent = (TextView) window.findViewById(R.id.tv_prompt); + + tvContent.setText(content); + + llNo.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + startActivity(intent); + + } + }); + } + + /** + * 推出提示 AppId 无效 + * + * @param context 当前上下文 + */ + public void tipAlert(Context context, String content) { + final Dialog dialog = new AlertDialog.Builder(context, R.style.alert_dialog_style) + .setView(new EditText(context)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_tip); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + TextView tvContent; + LinearLayout llSure; + llSure = (LinearLayout) window.findViewById(R.id.llSure); + tvContent = (TextView) window.findViewById(R.id.tvContent); + tvContent.setText(content); + + llSure.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + dialog.dismiss(); + } + }); + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/CommonModule/GosConstant.java b/src/java/com/gizwits/opensource/appkit/CommonModule/GosConstant.java new file mode 100644 index 0000000..2fee94c --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/CommonModule/GosConstant.java @@ -0,0 +1,34 @@ +package com.gizwits.opensource.appkit.CommonModule; + +import android.net.wifi.ScanResult; + +import com.gizwits.gizwifisdk.api.GizDeviceSharingInfo; +import com.gizwits.gizwifisdk.api.GizUserInfo; + +import java.util.ArrayList; +import java.util.List; + +public class GosConstant { + + // 设备热点默认前缀 + public static final String SoftAP_Start = "XPG-GAgent"; + + public static final String SSIDPsw = "#10v3#"; + public static boolean isOpenHot = false; + /** + * 0 使用旧接口 setDeviceOnboarding + * 1 配网绑定接口 setDeviceOnboardingByBind + * 2 域名配网接口 setDeviceOnboardingDeploy false + * 3 域名配网接口 setDeviceOnboardingDeploy true + */ + public static int mNew = 0; + public static List ssidList = new ArrayList(); + public static int nowPager = -1; + public static List mybindUsers = new ArrayList(); + public static boolean isEdit = false; + + public static List mydeviceSharingInfos = new ArrayList(); + public static List newmydeviceSharingInfos = new ArrayList(); + + +} diff --git a/src/java/com/gizwits/opensource/appkit/CommonModule/GosDeploy.java b/src/java/com/gizwits/opensource/appkit/CommonModule/GosDeploy.java new file mode 100644 index 0000000..b5e3141 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/CommonModule/GosDeploy.java @@ -0,0 +1,1910 @@ +package com.gizwits.opensource.appkit.CommonModule; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.text.TextUtils; +import android.util.Log; + +import com.gizwits.opensource.appkit.utils.AssetsUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +public class GosDeploy { + + public static HashMap allMap; + public static HashMap infoMap; + public static HashMap moduleMap; + public static HashMap uiMap; + public static HashMap templateMap; + public static HashMap functionMap; + public static HashMap viewMap; + public static List> deviceList; + private static final String TAG = "GosDeploy"; + + static Context context; + + // 配置文件名称 + private static final String fileName = "appConfig.json"; + + // 输出json的路径 + public static String fileOutName = null; + + public GosDeploy(Context context) { + super(); + GosDeploy.context = context; + + fileOutName = (context.getFilesDir().getAbsolutePath() + fileName); + copyJson(); + readJSON(); + } + /* + * ====================================================================== + * 以下Key值用来对应JSON文件中的个配置信息的名称,用于配置App主要参数 + * ====================================================================== + */ + /** + * The App_Info Key 应用信息 + */ + private static final String AppInfo_Key = "appInfo"; + + /** + * The TemplateSelect Key 模版选择 + */ + private static final String TemplateSelect_Key = "templateSelect"; + + /** + * The FunctionConfig Key 功能选择 + */ + private static final String FunctionConfig_Key = "functionConfig"; + + /** + * The ViewConfig Key 视图配置 + */ + private static final String ViewConfig_Key = "viewConfig"; + + /** + * The DeviceInfo Key 设备定制信息 + */ + private static final String DeviceInfo_Key = "deviceInfo"; + + /** + * The CloudService Key 云服务域名信息 + */ + private static final String CloudService_Key = "cloudService"; + + /** + * The API Key openapi域名信息,形如:myapi.mygizwits.com 或 myapi.mycompany.com:8081&8443。 + */ + private static final String API_Key = "api"; + + /** + * The Site Key site域名信息,形如:mysite.mygizwits.com或mysite.mycompany.com:8081&8443。 + */ + private static final String SITE_Key = "site"; + + /** + * The PUSH Key push域名信息,形如:mypush.mygizwits.com或mypush.mycompany.com:8081&8443 + */ + private static final String PUSH_Key = "push"; + + /** + * The Gizwits_Info Key 机智云应用标识 + */ + private static final String GizwitsInfo_Key = "gizwitsInfo"; + + /** + * The AppID Key 应用标识 + */ + private static final String AppID_Key = "appId"; + + /** + * The AppSecret Key 应用密钥 + */ + private static final String AppSecret_Key = "appSecret"; + + /** + * The ProductInfo Key 机智云产品标识 + */ + private static final String ProductInfo_Key = "productInfo"; + + /** + * The ProductKey Key 产品标识 + */ + private static final String ProductKey_Key = "productKey"; + + /** + * The ProductSecret Key 产品密钥 + */ + private static final String ProductSecret_Key = "productSecret"; + + /** + * The UmengInfo Key 友盟应用标识 + */ + private static final String UmengInfo_Key = "umengInfo"; + + /** + * The AppKey Key 友盟ID + */ + private static final String AppKey_Key = "appKey"; + + /** + * The MessageKey Key 友盟密钥 + */ + private static final String MessageKey_Key = "messageKey"; + + /** + * The TencentInfo Key QQ应用标识 + */ + private static final String TencentInfo_Key = "tencentInfo"; + + /** + * The WechatInfo Key 微信应用标识 + */ + private static final String WechatInfo_Key = "weChatInfo"; + + /** + * The FacebookInfo Key facebook应用标识 + */ + private static final String FacebookInfo_Key = "facebookInfo"; + + /** + * The TwitterInfo Key 推特应用标识 + */ + private static final String TwitterInfo_Key = "twitterInfo"; + + /** + * The PushInfo Key 推送应用标识 + */ + private static final String PushInfo_Key = "pushInfo"; + + /** + * The JpushAppKey Key 极光推送应用ID + */ + private static final String JpushAppKey_Key = "jpushAppKey"; + + /** + * The BpushAppKey Key 百度推送应用ID + */ + private static final String BpushAppKey_Key = "bpushAppKey"; + + /** + * The DeviceList Key 设备列表模版:提供两种显示方式,一种显示新设备和常用设备,一种显示在线设备和离线设备。 + */ + private static final String DeviceList_Key = "deviceList"; + + /** + * The AutoSubscribe Key 自动订阅设备 + */ + private static final String AutoSubscribe_Key = "autoSubscribe"; + + /** + * The UnbindDevice Key 解绑设备的按钮 + */ + private static final String UnbindDevice_Key = "unbindDevice"; + + /** + * The DisplayMac Key 设备Mac地址 + */ + private static final String DisplayMac_Key = "displayMac"; + + /** + * The ShortCutButton Key 快捷操作按钮的数据点标识 + */ + private static final String ShortCutButton_Key = "shortCutButton"; + + /** + * The DataPointID Key 快捷操作的数据点标识 + */ + private static final String DataPointID_Key = "dataPointID"; + + /** + * The Product_Light Key 灯模版_圆环样式 + */ + private static final String Product_Light_Key = "product_light"; + + /** + * The Color Key 配置彩光效果 + */ + private static final String Color_Key = "color"; + + /** + * The HueConvert Key RGB与Hue值的转换 + */ + private static final String HueConvert_Key = "hueConvert"; + + /** + * The RGBButton Key R、G、B按钮 + */ + private static final String RGBButton_Key = "rgbButton"; + + /** + * The ColorTemprature Key 配置色温效果 + */ + private static final String ColorTemprature_Key = "colorTemprature"; + + /** + * The CttLevelValue Key 色温档位值 + */ + private static final String CttLevelValue_Key = "cttLevelValue"; + + /** + * The DisplayName Key 档位值对应的显示名称 + */ + private static final String DisplayName_Key = "displayName"; + + /** + * The BindDevice_Qrcode Key 扫码绑定设备 + */ + private static final String BindDevice_Qrcode_Key = "bindDevice_qrcode"; + + /** + * The DeviceOnboarding Key 设备配网 + */ + private static final String DeviceOnboarding_Key = "deviceOnboarding"; + + /** + * The Config_softap Key 设备softap配网 + */ + private static final String Config_softap_Key = "config_softap"; + + /** + * The Config_Airlink_Key Key 设备airlink配网 + */ + private static final String Config_Airlink_Key = "config_airlink"; + + /** + * The WifiModuleType Key 模组类型 + */ + private static final String WifiModuleType_Key = "wifiModuleType"; + + /** + * The DeviceOnboarding Key 使用新的配网部署接口 + */ + private static final String UseOnboardingDeploy_Key = "useOnboardingDeploy"; + + /** + * The OnboardingBind Key 配网时是否自动绑定 + */ + private static final String OnboardingBind_Key = "onboardingBind"; + + /** + * The Login_Anonymou Key 匿名登录 + */ + private static final String Login_Anonymous_Key = "login_anonymous"; + + /** + * The Login_QQ Key qq登录 + */ + private static final String Login_QQ_Key = "login_qq"; + + /** + * The Login_WeChat Key 微信登录 + */ + private static final String Login_WeChat_Key = "login_weChat"; + + /** + * The Register_PhoneUser Key 手机用户注册 + */ + private static final String Register_PhoneUser_Key = "register_phoneUser"; + + + /** + * The ResetPassword_PhoneUser Key 手机用户找回密码 + */ + private static final String ResetPassword_PhoneUser_Key = "resetPassword_phoneUser"; + + /** + * The PersonalCenter_ChangePassword Key + */ + private static final String PersonalCenter_ChangePassword_Key = "personalCenter_changePassword"; + + /** + * The Push_BaiDu Key + */ + private static final String Push_BaiDu_Key = "push_baidu"; + + /** + * The Push_JiGuang_Key Key + */ + private static final String Push_JiGuang_Key = "push_jiguang"; + + /** + * The DisableLan Key + */ + private static final String DisableLan_Key = "disableLan"; + + /** + * The UmengSupport Key + */ + private static final String UmengSupport_Key = "umengSupport"; + + /** + * The UsingTabSet_Switch Key + */ + private static final String UsingTabSet = "usingTabSet"; + + /** + * The Device_OnBoarding Key + */ + private static final String Device_OnBoarding_Key = "deviceOnboarding"; + + + /** + * The ViewColor Key + */ + private static final String ViewColor_Key = "viewColor"; + + /** + * The Background Key + */ + private static final String Background_Key = "background"; + + /** + * The Contrast Key + */ + private static final String Contrast_Key = "contrast"; + + /** + * The TextContent Key + */ + private static final String TextContent_Key = "textContent"; + + /** + * The AboutInfo Key + */ + private static final String AboutInfo_Key = "aboutInfo"; + + /** + * The AboutInfo Key + */ + private static final String LaunchPageInfo_Key = "launchPageInfo"; + + /** + * The CH Key + */ + private static final String CH_Key = "ch"; + + /** + * The EN Key + */ + private static final String EN_Key = "en"; + + /** + * The StatusBarStyle Key + */ + private static final String StatusBarStyle_Key = "statusBarStyle"; + + /** + * The ProductName Key + */ + private static final String ProductName_Key = "productName"; + + /** + * The DataPoint Key + */ + private static final String DataPoint_Key = "dataPoint"; + + /** + * The ID Key + */ + private static final String ID_Key = "id"; + + /** + * The Name Key + */ + private static final String Name_Key = "name"; + + /** + * The GatewaySupport Key + */ + private static final String GatewaySupport_Key = "gatewaySupport"; + + /** + * The ShowGatewayDataPoint Key + */ + private static final String ShowGatewayDataPoint_Key = "showGatewayDataPoint"; + + /** + * The UsingDevicePageTemplate Key + */ + private static final String UsingDevicePageTemplate_Key = "usingDevicePageTemplate"; + + /** + * The UsingUnbindButton Key + */ + private static final String UsingPowerOnShortcutButton_Key = "usingPowerOnShortcutButton"; + + /** + * The UsingUnbindButton Key + */ + private static final String DataPointName_Key = "dataPointName"; + + /** + * The Text Key + */ + private static final String Text_Key = "text"; + + /** + * The LaunchPage_Text Key + */ + private static final String LaunchPage_Text_Key = "launchPageText"; + + /** + * The AboutPage Key + */ + private static final String AboutPage_Key = "aboutPage"; + + + /** + * The ShowSDKVersion Key + */ + private static final String ShowSDKVersion_Key = "showSDKVersion"; + + + /** + * The ShowAppVersion Key + */ + private static final String ShowAppVersion_Key = "showAppVersion"; + + + /** + * The PowerOn Key + */ + private static final String PowerOn_Key = "powerOn"; + + /** + * The PowerOff Key + */ + private static final String PowerOff_Key = "powerOff"; + + + /** The StatusBarStyle Key */ + // private static final String StatusBarStyle_Key = "statusBarStyle"; + + /* + * =================================================================== + * 以下是解析配置文件后,对各配置信息赋值的方法。 + * =================================================================== + */ + + /** + * 设置CloudService参数--ApiUrl + * + * @return + */ + public static String appConfig_CloudServiceApi() { + String api = null; + if (infoMap != null) { + if (infoMap.containsKey(CloudService_Key)) { + try { + if (infoMap.get(CloudService_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(CloudService_Key).toString()); + if (jo.has(API_Key)) { + api = (String) jo.get(API_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return api; + } + + /** + * 设置CloudService参数--SiteUrl + * + * @return + */ + public static String appConfig_CloudServiceSite() { + String site = null; + if (infoMap != null) { + try { + if (infoMap.get(CloudService_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(CloudService_Key).toString()); + if (jo.has(SITE_Key)) { + site = (String) jo.get(SITE_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return site; + } + + /** + * 设置CloudService参数--PushUrl + * + * @return + */ + public static String appConfig_CloudServicePush() { + String push = null; + if (infoMap != null) { + try { + if (infoMap.get(CloudService_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(CloudService_Key).toString()); + if (jo.has(PUSH_Key)) { + push = (String) jo.get(PUSH_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return push; + } + + /** + * 设置SDK参数--AppID(必填) + * + * @return + */ + public static String appConfig_GizwitsInfoAppID() { + String id = null; + if (infoMap != null) { + if (infoMap.containsKey(GizwitsInfo_Key)) { + try { + if (infoMap.get(GizwitsInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(GizwitsInfo_Key).toString()); + if (jo.has(AppID_Key)) { + id = (String) jo.get(AppID_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return id; + } + + /** + * 设置SDK参数--AppSecret(必填且必须与上述AppKey匹配) + * + * @return + */ + public static String appConfig_GizwitsInfoAppSecret() { + String secret = null; + if (infoMap != null) { + if (infoMap.containsKey(GizwitsInfo_Key)) { + try { + if (infoMap.get(GizwitsInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(GizwitsInfo_Key).toString()); + if (jo.has(AppSecret_Key)) { + secret = (String) jo.get(AppSecret_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return secret; + } + + /** + * 设置ProductInfo + * + * @return + */ + public static List> appConfig_ProductList() { + List> list = new ArrayList>(); + if (infoMap != null) { + if (infoMap.containsKey(ProductInfo_Key)) { + JSONArray array = (JSONArray) infoMap.get(ProductInfo_Key); + if (array != null) { + for (int i = 0; i < array.length(); i++) { + HashMap product = new HashMap(); + JSONObject jo = null; + try { + jo = new JSONObject(array.get(i).toString()); + String productkey = null, productsecret = null; + if (jo.has(ProductKey_Key)) { + productkey = (String) jo.get(ProductKey_Key); + } + if (jo.has(ProductSecret_Key)) { + productsecret = (String) jo.get(ProductSecret_Key); + } + product.put(productkey, productsecret); + list.add(product); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + } + return list; + } + + /** + * 设置ProductKeyInfo + * + * @return + */ + public static List> appConfig_ProductInfoList() { + List> productInfoList = new ArrayList>(); + if (infoMap != null) { + if (infoMap.containsKey(ProductInfo_Key)) { + JSONArray array = (JSONArray) infoMap.get(ProductInfo_Key); + if (array != null) { + for (int i = 0; i < array.length(); i++) { + JSONObject jo = null; + try { + ConcurrentHashMap map = new ConcurrentHashMap(); + jo = new JSONObject(array.get(i).toString()); + if (jo.has(ProductKey_Key)) { + String productkey = (String) jo.get(ProductKey_Key); + if (productkey != null) { + map.put("productKey", productkey); + } + } + if (jo.has(ProductSecret_Key)) { + String productsecret = (String) jo.get(ProductSecret_Key); + if (productsecret != null) { + map.put("productSecret", productsecret); + } + } + productInfoList.add(map); + } catch (JSONException e) { + e.printStackTrace(); + } + + } + } + } + } + return productInfoList; + } + + + /** + * 设置TencentID + * + * @return + */ + public static String appConfig_TencentAppID() { + String id = null; + if (infoMap != null) { + try { + if (infoMap.get(TencentInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(TencentInfo_Key).toString()); + if (jo.has(AppID_Key)) { + id = (String) jo.get(AppID_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return id; + } + + /** + * 设置WechatAppID + * + * @return + */ + public static String appConfig_WechatAppID() { + String id = null; + if (infoMap != null) { + try { + if (infoMap.get(WechatInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(WechatInfo_Key).toString()); + if (jo.has(AppID_Key)) { + id = (String) jo.get(AppID_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return id; + } + + /** + * 设置WeChatAppSecret + * + * @return + */ + public static String appConfig_WechatAppSecret() { + String id = null; + if (infoMap != null) { + try { + if (infoMap.get(WechatInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(WechatInfo_Key).toString()); + if (jo.has(AppSecret_Key)) { + id = (String) jo.get(AppSecret_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return id; + } + + /** + * 设置FacebookAppID + * + * @return + */ + public static String appConfig_FacebookAppID() { + String id = null; + if (infoMap != null) { + try { + if (infoMap.get(FacebookInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(FacebookInfo_Key).toString()); + if (jo.has(AppID_Key)) { + id = (String) jo.get(AppID_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return id; + } + + /** + * 设置TwitterAppID + * + * @return + */ + public static String appConfig_TwitterAppID() { + String id = null; + if (infoMap != null) { + try { + if (infoMap.get(TwitterInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(TwitterInfo_Key).toString()); + if (jo.has(AppID_Key)) { + id = (String) jo.get(AppID_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return id; + } + + /** + * 设置TwitterAppSecret + * + * @return + */ + public static String appConfig_TwitterAppSecret() { + String id = null; + if (infoMap != null) { + try { + if (infoMap.get(TwitterInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(TwitterInfo_Key).toString()); + if (jo.has(AppSecret_Key)) { + id = (String) jo.get(AppSecret_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return id; + } + + /** + * 设置JiGuangPushAppKey + * + * @return + */ + public static String appConfig_JpushAppKey() { + String key = null; + if (infoMap != null) { + try { + if (infoMap.get(PushInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(PushInfo_Key).toString()); + if (jo.has(JpushAppKey_Key)) { + key = (String) jo.get(JpushAppKey_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return key; + } + + /** + * 设置BaiDuPushAppKey + * + * @return + */ + public static String appConfig_BpushAppKey() { + String key = null; + if (infoMap != null) { + try { + if (infoMap.get(PushInfo_Key) != null) { + JSONObject jo = new JSONObject(infoMap.get(PushInfo_Key).toString()); + if (jo.has(BpushAppKey_Key)) { + key = (String) jo.get(BpushAppKey_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return key; + } + + /** + * 是否自动订阅设备 + * + * @return boolean + */ + public static boolean appConfig_AutoSubscribe() { + boolean isOn = false; + if (templateMap != null) { + if (templateMap.get(DeviceList_Key) != null) { + try { + JSONObject jo = new JSONObject(templateMap.get(DeviceList_Key).toString()); + if (jo.has(AutoSubscribe_Key)) { + if (jo.get(AutoSubscribe_Key) != null) { + isOn = (Boolean) jo.get(AutoSubscribe_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return isOn; + } + + /** + * 是否显示解绑设备的按钮 + * + * @return boolean + */ + public static boolean appConfig_UnbindDevice() { + boolean isOn = false; + if (templateMap != null) { + if (templateMap.get(DeviceList_Key) != null) { + try { + JSONObject jo = new JSONObject(templateMap.get(DeviceList_Key).toString()); + if (jo.has(UnbindDevice_Key)) { + if (jo.get(UnbindDevice_Key) != null) { + isOn = (Boolean) jo.get(UnbindDevice_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return isOn; + } + + /** + * 是否显示设备Mac地址 + * + * @return boolean + */ + public static boolean appConfig_DisplayMac() { + boolean isOn = false; + if (templateMap != null) { + if (templateMap.get(DeviceList_Key) != null) { + try { + JSONObject jo = new JSONObject(templateMap.get(DeviceList_Key).toString()); + if (jo.has(DisplayMac_Key)) { + if (jo.get(DisplayMac_Key) != null) { + isOn = (Boolean) jo.get(DisplayMac_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return isOn; + } + + /** + * 快捷操作按钮的数据点标识 + * + * @return List> + */ + public static List> appConfig_ShortCutButton() { + List> colorTemprature = new ArrayList>(); + if (templateMap != null) { + if (templateMap.get(deviceList) != null) { + try { + JSONObject jo = new JSONObject(templateMap.get(deviceList).toString()); + if (jo.has(ShortCutButton_Key)) { + if (jo.get(ShortCutButton_Key) != null) { + JSONArray array = (JSONArray) jo.get(ShortCutButton_Key); + for (int i = 0; i < array.length(); i++) { + Map map = new HashMap(); + JSONObject object = (JSONObject) array.get(i); + if (object.has(ProductKey_Key)) { + if (object.get(ProductKey_Key) != null) { + String value = (String) object.get(ProductKey_Key); + map.put("productKey", value); + } + } + if (object.has(DataPointID_Key)) { + if (object.get(DataPointID_Key) != null) { + String dataPoint = (String) object.get(DataPoint_Key); + map.put("dataPointID", dataPoint); + } + } + if (!colorTemprature.contains(map)) { + colorTemprature.add(map); + } + Log.e(TAG, "appConfig_ColorTemprature------: " + map); + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return colorTemprature; + } + + /** + * 是否做RGB与Hue值的转换 + * + * @return boolean + */ + public static boolean appConfig_HueConvert() { + boolean isOn = false; + if (templateMap != null) { + if (templateMap.get(Product_Light_Key) != null) { + try { + JSONObject jo = new JSONObject(templateMap.get(Product_Light_Key).toString()); + if (jo.has(Color_Key)) { + if (jo.get(Color_Key) != null) { + JSONObject jo1 = (JSONObject) jo.get(Color_Key); + if (jo1.has(HueConvert_Key)) { + if (jo1.get(HueConvert_Key) != null) { + isOn = (Boolean) jo1.get(HueConvert_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return isOn; + } + + /** + * 是否需要R、G、B按钮 + * + * @return boolean + */ + public static boolean appConfig_RGBButton() { + boolean isOn = false; + if (templateMap != null) { + if (templateMap.get(Product_Light_Key) != null) { + try { + JSONObject jo = new JSONObject(templateMap.get(Product_Light_Key).toString()); + if (jo.has(Color_Key)) { + if (jo.get(Color_Key) != null) { + JSONObject jo1 = (JSONObject) jo.get(Color_Key); + if (jo1.has(RGBButton_Key)) { + if (jo1.get(RGBButton_Key) != null) { + isOn = (Boolean) jo1.get(RGBButton_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return isOn; + } + + /** + * 色温档位值 + * + * @return boolean + */ + public static List> appConfig_ColorTemprature() { + List> colorTemprature = new ArrayList>(); + if (templateMap != null) { + if (templateMap.get(Product_Light_Key) != null) { + try { + JSONObject jo = new JSONObject(templateMap.get(Product_Light_Key).toString()); + if (jo.has(ColorTemprature_Key)) { + if (jo.get(ColorTemprature_Key) != null) { + JSONArray array = (JSONArray) jo.get(ColorTemprature_Key); + for (int i = 0; i < array.length(); i++) { + Map map = new HashMap(); + JSONObject object = (JSONObject) array.get(i); + if (object.has(CttLevelValue_Key)) { + if (object.get(CttLevelValue_Key) != null) { + String value = object.get(CttLevelValue_Key) + ""; + map.put("cttLevelValue", value); + } + } + if (object.has(DisplayName_Key)) { + if (object.get(DisplayName_Key) != null) { + String name = (String) object.get(DisplayName_Key); + map.put("displayName", name); + } + } + colorTemprature.add(map); + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + return colorTemprature; + } + + /** + * 是否需要扫码绑定设备 + * + * @return boolean + */ + public static boolean appConfig_BindDevice_Qrcode() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(BindDevice_Qrcode_Key)) { + if (functionMap.get(BindDevice_Qrcode_Key) != null) { + isOn = (Boolean) functionMap.get(BindDevice_Qrcode_Key); + } + } + } + return isOn; + } + + /** + * 设备softap配网 + * + * @return boolean + */ + public static boolean appConfig_Config_Softap() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(DeviceOnboarding_Key)) { + if (functionMap.get(DeviceOnboarding_Key) != null) { + JSONObject ob = (JSONObject) functionMap.get(DeviceOnboarding_Key); + try { + if (ob.has(Config_softap_Key)) { + if (ob.get(Config_softap_Key) != null) { + isOn = (Boolean) ob.get(Config_softap_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + return isOn; + } + + /** + * 设备airlink配网 + * + * @return boolean + */ + public static boolean appConfig_Config_Airlink() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(DeviceOnboarding_Key)) { + if (functionMap.get(DeviceOnboarding_Key) != null) { + JSONObject ob = (JSONObject) functionMap.get(DeviceOnboarding_Key); + try { + if (ob.has(Config_Airlink_Key)) { + if (ob.get(Config_Airlink_Key) != null) { + isOn = (Boolean) ob.get(Config_Airlink_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + return isOn; + } + + /** + * 设置模组类型 + * + * @return + */ + public static List appConfig_WifiModuleType() { + List types = new ArrayList(); + if (functionMap != null) { + if (functionMap.get(Device_OnBoarding_Key) != null) { + JSONObject jo = null; + try { + jo = new JSONObject(functionMap.get(Device_OnBoarding_Key).toString()); + if (jo.has(WifiModuleType_Key)) { + if (jo.get(WifiModuleType_Key) != null) { + JSONArray array = (JSONArray) jo.get(WifiModuleType_Key); + for (int i = 0; i < array.length(); i++) { + types.add((Integer) array.get(i)); + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + Log.e(TAG, "toAirlinkReady----------: " + types); + return types; + } + + /** + * 使用新的配网部署接口 + * + * @return boolean + */ + public static boolean appConfig_UseOnboardingDeploy() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(DeviceOnboarding_Key)) { + if (functionMap.get(DeviceOnboarding_Key) != null) { + JSONObject ob = (JSONObject) functionMap.get(DeviceOnboarding_Key); + try { + if (ob.has(UseOnboardingDeploy_Key)) { + if (ob.get(UseOnboardingDeploy_Key) != null) { + isOn = (Boolean) ob.get(UseOnboardingDeploy_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + return isOn; + } + + /** + * 配网时是否自动绑定 + * + * @return boolean + */ + public static boolean appConfig_OnboardingBind() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(DeviceOnboarding_Key)) { + if (functionMap.get(DeviceOnboarding_Key) != null) { + JSONObject ob = (JSONObject) functionMap.get(DeviceOnboarding_Key); + try { + if (ob.has(OnboardingBind_Key)) { + if (ob.get(OnboardingBind_Key) != null) { + isOn = (Boolean) ob.get(OnboardingBind_Key); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + return isOn; + } + + /** + * 用来判断是否需要打开匿名登录 + * + * @return boolean + */ + public static boolean appConfig_Login_Anonymous() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(Login_Anonymous_Key)) { + if (functionMap.get(Login_Anonymous_Key) != null) { + isOn = (Boolean) functionMap.get(Login_Anonymous_Key); + } + } + } + return isOn; + } + + + /** + * 用来判断是否需要qq登录 + * + * @return boolean + */ + public static boolean appConfig_Login_QQ() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(Login_QQ_Key)) { + if (functionMap.get(Login_QQ_Key) != null) { + isOn = (Boolean) functionMap.get(Login_QQ_Key); + } + } + } + return isOn; + } + + + /** + * 用来判断是否需要weChat登录 + * + * @return boolean + */ + public static boolean appConfig_Login_Wechat() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(Login_WeChat_Key)) { + if (functionMap.get(Login_WeChat_Key) != null) { + isOn = (Boolean) functionMap.get(Login_WeChat_Key); + } + } + } + return isOn; + } + + /** + * 是否需要手机用户注册 + * + * @return boolean + */ + public static boolean appConfig_Register_PhoneUser() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(Register_PhoneUser_Key)) { + if (functionMap.get(Register_PhoneUser_Key) != null) { + isOn = (Boolean) functionMap.get(Register_PhoneUser_Key); + } + } + } + return isOn; + } + + /** + * 是否需要手机用户找回密码 + * + * @return boolean + */ + public static boolean appConfig_ResetPassword_PhoneUser() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(ResetPassword_PhoneUser_Key)) { + if (functionMap.get(ResetPassword_PhoneUser_Key) != null) { + isOn = (Boolean) functionMap.get(ResetPassword_PhoneUser_Key); + } + } + } + return isOn; + } + + + /** + * 是否需要修改密码 + * + * @return boolean + */ + public static boolean appConfig_PersonalCenter_ChangePassword() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(PersonalCenter_ChangePassword_Key)) { + if (functionMap.get(PersonalCenter_ChangePassword_Key) != null) { + isOn = (Boolean) functionMap.get(PersonalCenter_ChangePassword_Key); + } + } + } + return isOn; + } + + /** + * 是否需要百度推送功能 + * + * @return boolean + */ + public static boolean appConfig_Push_BaiDu() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(Push_BaiDu_Key)) { + if (functionMap.get(Push_BaiDu_Key) != null) { + isOn = (Boolean) functionMap.get(Push_BaiDu_Key); + } + } + } + return isOn; + } + + /** + * 是否需要极光推送功能 + * + * @return boolean + */ + public static boolean appConfig_Push_JiGuang() { + boolean isOn = false; + if (functionMap != null) { + if (functionMap.containsKey(Push_JiGuang_Key)) { + if (functionMap.get(Push_JiGuang_Key) != null) { + isOn = (Boolean) functionMap.get(Push_JiGuang_Key); + } + } + } + return isOn; + } + + + /** + * 设置背景颜色(返回int 型) + * + * @return + */ + public static int appConfig_Background() { + int color = Color.parseColor("#FBDA51"); + if (viewMap != null) { + String ButtonTextColor_FromMap = null; + if (viewMap.get(ViewColor_Key) != null) { + JSONObject jo = null; + try { + jo = new JSONObject(viewMap.get(ViewColor_Key).toString()); + if (jo.get(Background_Key) != null) { + ButtonTextColor_FromMap = (String) jo.get(Background_Key); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + if (!TextUtils.isEmpty(ButtonTextColor_FromMap)) { + color = Color.parseColor("#" + ButtonTextColor_FromMap); + } + } + return color; + } + + /** + * 设置背景颜色(返回 Drawable 型) + * + * @return + */ + public static Drawable appConfig_BackgroundColor() { + GradientDrawable drawable = new GradientDrawable(); + drawable.setShape(GradientDrawable.RECTANGLE); + drawable.setCornerRadius(100); + if (viewMap != null) { + String ButtonColor_FromMap = null; + if (viewMap.get(ViewColor_Key) != null) { + JSONObject jo = null; + try { + jo = new JSONObject(viewMap.get(ViewColor_Key).toString()); + if (jo.get(Background_Key) != null) { + ButtonColor_FromMap = (String) jo.get(Background_Key); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + if (!TextUtils.isEmpty(ButtonColor_FromMap)) { + drawable.setColor(Color.parseColor("#" + ButtonColor_FromMap)); + } else { + drawable.setColor(Color.argb(255, 248, 220, 38)); + } + } + return drawable; + } + + /** + * 设置背景对应颜色 + * + * @return + */ + public static int appConfig_Contrast() { + int color = Color.parseColor("#333333"); + if (viewMap != null) { + String ButtonTextColor_FromMap = null; + if (viewMap.get(ViewColor_Key) != null) { + JSONObject jo = null; + try { + jo = new JSONObject(viewMap.get(ViewColor_Key).toString()); + if (jo.get(Contrast_Key) != null) { + ButtonTextColor_FromMap = (String) jo.get(Contrast_Key); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + if (!TextUtils.isEmpty(ButtonTextColor_FromMap)) { + color = Color.parseColor("#" + ButtonTextColor_FromMap); + } + } + return color; + } + + /** + * 设置关于页面文本中文文字 + * + * @return + */ + public static String appConfig_AboutInfoCH() { + String text = null; + JSONObject jo = null; + JSONObject jo1 = null; + if (viewMap != null) { + try { + if (viewMap.containsKey(TextContent_Key)) { + if (viewMap.get(TextContent_Key) != null) { + jo = new JSONObject(viewMap.get(TextContent_Key).toString()); + if (jo.get(AboutInfo_Key) != null) { + jo1 = new JSONObject(jo.get(AboutInfo_Key).toString()); + if (jo1.get(CH_Key) != null) { + text = (String) jo1.get(CH_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return text; + } + + /** + * 设置关于页面文本英文文字 + * + * @return + */ + public static String appConfig_AboutInfoEN() { + String text = null; + JSONObject jo = null; + JSONObject jo1 = null; + if (viewMap != null) { + try { + if (viewMap.containsKey(TextContent_Key)) { + if (viewMap.get(TextContent_Key) != null) { + jo = new JSONObject(viewMap.get(TextContent_Key).toString()); + if (jo.get(LaunchPageInfo_Key) != null) { + jo1 = new JSONObject(jo.get(LaunchPageInfo_Key).toString()); + if (jo1.get(EN_Key) != null) { + text = (String) jo1.get(EN_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return text; + } + + /** + * 设置启动页中文文字 + * + * @return + */ + public static String appConfig_LaunchInfoCH() { + String text = null; + JSONObject jo = null; + JSONObject jo1 = null; + if (viewMap != null) { + try { + if (viewMap.containsKey(TextContent_Key)) { + if (viewMap.get(TextContent_Key) != null) { + jo = new JSONObject(viewMap.get(TextContent_Key).toString()); + if (jo.get(LaunchPageInfo_Key) != null) { + jo1 = new JSONObject(jo.get(LaunchPageInfo_Key).toString()); + if (jo1.get(CH_Key) != null) { + text = (String) jo1.get(CH_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return text; + } + + /** + * 设置启动页英文文字 + * + * @return + */ + public static String appConfig_LaunchInfoEN() { + String text = null; + JSONObject jo = null; + JSONObject jo1 = null; + if (viewMap != null) { + try { + if (viewMap.containsKey(TextContent_Key)) { + if (viewMap.get(TextContent_Key) != null) { + jo = new JSONObject(viewMap.get(TextContent_Key).toString()); + if (jo.get(LaunchPageInfo_Key) != null) { + jo1 = new JSONObject(jo.get(LaunchPageInfo_Key).toString()); + if (jo1.get(EN_Key) != null) { + text = (String) jo1.get(EN_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return text; + } + + /** + * 状态栏样式 + * + * @return boolean + */ + public static String appConfig_StatusBarStyle() { + String style = "default"; + if (viewMap != null) { + if (viewMap.containsKey(StatusBarStyle_Key)) { + if (viewMap.get(StatusBarStyle_Key) != null) { + style = (String) functionMap.get(StatusBarStyle_Key); + } + } + } + return style; + } + + /** + * 可在此填写设备需要显示的产品名称或者操作名称 + * + * @return boolean + */ + public static List> appConfig_DeviceInfo() { + List> mapList = new ArrayList>(); + if (deviceList != null) { + for (Map device : deviceList) { + Map map = new HashMap(); + if (device.containsKey(ProductKey_Key)) { + if (device.get(ProductKey_Key) != null) { + String productKey = (String) device.get(ProductKey_Key); + map.put(ProductKey_Key, productKey); + } + } + if (device.containsKey(ProductName_Key)) { + if (device.get(ProductName_Key) != null) { + JSONObject productName = (JSONObject) device.get(ProductName_Key); + try { + if (productName.get(CH_Key) != null) { + String text = (String) productName.get(CH_Key); + map.put("productNameCH", text); + } + if (productName.get(EN_Key) != null) { + String text = (String) productName.get(EN_Key); + map.put("productNameEN", text); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + mapList.add(map); + } + } + return mapList; + } + +// /** +// * 设置UsingTab 开关 +// * +// * @return +// */ +// public static int appConfig_UsingTabSetOn() { +// int modeOnOff = View.GONE; +// boolean isOn = false; +// if (uiMap != null) { +// if (uiMap.get(UsingTabSet) == null) { +// isOn = false; +// } else { +// isOn = (Boolean) uiMap.get(UsingTabSet); +// } +// if (isOn) { +// modeOnOff = View.VISIBLE; +// } +// } +// return modeOnOff; +// } + +// /** +// * 用来判断是否需要打开设备控制界面 +// * +// * @return +// */ +// public static boolean setUsingDevicePageTemplate() { +// boolean isOn = false; +// if (uiMap != null) { +// if (uiMap.get(UsingDevicePageTemplate_Key) == null) { +// isOn = false; +// } else { +// isOn = (Boolean) uiMap.get(UsingDevicePageTemplate_Key); +// } +// } +// return isOn; +// } + + /** + * 用来判断是否要在设备(子设备)列表中显示指定品类的快捷开关机按钮 + * + * @return + */ + public static List> appConfig_UsingPowerOnShortcutButton() { + List> list = new ArrayList>(); + List list1 = new ArrayList(); + if (uiMap != null) { + JSONArray jsonArray = (JSONArray) uiMap.get(UsingPowerOnShortcutButton_Key); + if (jsonArray != null) { + for (int i = 0; i < jsonArray.length(); i++) { + HashMap product = new HashMap(); + JSONObject jo = null; + try { + jo = new JSONObject(jsonArray.get(i).toString()); + String productkey = (String) jo.get(ProductKey_Key); + String datapointname = (String) jo.get(DataPointName_Key); + product.put(productkey, datapointname); + if (!list1.contains(productkey)) { + list1.add(productkey); + list.add(product); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + return list; + } + + /** + * 设置ProductKey + * + * @return + */ + public static List appConfig_ProductKeyList() { + //entity.getAppInfo().getProductInfo(); + List productKeyList = new ArrayList(); + if (uiMap != null) { + JSONArray array = (JSONArray) infoMap.get(ProductInfo_Key); + if (array != null) { + for (int i = 0; i < array.length(); i++) { + JSONObject jo = null; + try { + jo = new JSONObject(array.get(i).toString()); + if (jo.has(ProductKey_Key)) { + String productkey = (String) jo.get(ProductKey_Key); + productKeyList.add(productkey); + } + } catch (JSONException e) { + e.printStackTrace(); + } + + } + } + } + return productKeyList; + } + + /** + * 是否显示SDK版本号 + * + * @return + */ + public static boolean appConfig_ShowSDKVersion() { + boolean isOn = false; + JSONObject jo = null; + JSONObject jo1 = null; + if (uiMap != null) { + try { + if (uiMap.containsKey(Text_Key)) { + if (uiMap.get(Text_Key) != null) { + jo = new JSONObject(uiMap.get(Text_Key).toString()); + if (jo.get(AboutPage_Key) != null) { + jo1 = new JSONObject(jo.get(AboutPage_Key).toString()); + if (jo1.get(ShowSDKVersion_Key) != null) { + isOn = (Boolean) jo1.get(ShowSDKVersion_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return isOn; + } + + + /** + * 是否显示APP版本号 + * + * @return + */ + public static boolean appConfig_ShowAPPVersion() { + boolean isOn = false; + JSONObject jo = null; + JSONObject jo1 = null; + if (uiMap != null) { + try { + if (uiMap.containsKey(Text_Key)) { + if (uiMap.get(Text_Key) != null) { + jo = new JSONObject(uiMap.get(Text_Key).toString()); + if (jo.get(AboutPage_Key) != null) { + jo1 = new JSONObject(jo.get(AboutPage_Key).toString()); + if (jo1.get(ShowAppVersion_Key) != null) { + isOn = (Boolean) jo1.get(ShowAppVersion_Key); + } + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + return isOn; + } + +// /** +// * 设置添加设备标题 +// * +// * @return +// */ +// public static String setAddDeviceTitle() { +// +// String addDeviceTitle = context.getResources().getString( +// R.string.addDeviceTitle); +// String AddDeviceTitle_FromMap = infoMap.get(AddDeviceTitle_Key) +// .toString(); +// if (!TextUtils.isEmpty(AddDeviceTitle_FromMap)) { +// addDeviceTitle = AddDeviceTitle_FromMap; +// } +// +// return addDeviceTitle; +// +// } + + /** + * 读取本地的JSON文件 + */ + public static void readJSON() { + try { + FileInputStream input = new FileInputStream(fileOutName); + InputStreamReader inputStreamReader = new InputStreamReader(input, "UTF-8"); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String line; + StringBuilder stringBuilder = new StringBuilder(); + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line); + } + bufferedReader.close(); + inputStreamReader.close(); + // 加载JSON数据到Entity + //setEntity(stringBuilder); + setMap(stringBuilder); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + +// public static void setEntity(StringBuilder stringBuilder) { +// // 加载JSON数据到Map +// Gson gson = new Gson(); +// +// entity = gson.fromJson(stringBuilder.toString(), Entity.class); +// } + + + //拷贝json文件 + private void copyJson() { + try { + AssetsUtils.assetsDataToSD(fileOutName, fileName, context); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + + public static void setMap(StringBuilder stringBuilder) { + infoMap = new HashMap(); + moduleMap = new HashMap(); + uiMap = new HashMap(); + templateMap = new HashMap(); + functionMap = new HashMap(); + viewMap = new HashMap(); + deviceList = new ArrayList>(); + + try { + JSONObject root = new JSONObject(stringBuilder.toString()); + Iterator actions = root.keys(); + while (actions.hasNext()) { + String param = actions.next().toString(); + Object valus = root.get(param); + String info = valus.toString(); + if (param.matches(DeviceInfo_Key)) { + JSONArray array = new JSONArray(info); + for (int i = 0; i < array.length(); i++) { + JSONObject data = (JSONObject) array.get(i); + Iterator action = data.keys(); + HashMap map = new HashMap(); + while (action.hasNext()) { + String param1 = action.next().toString(); + Object valus1 = data.get(param1); + map.put(param1, valus1); + } + deviceList.add(map); + } + Log.e(TAG, "setMap----: " + deviceList); + } else { + JSONObject data = new JSONObject(info); + Iterator action = data.keys(); + Log.e(TAG, "param-----: " + param); + Log.e(TAG, "info------: " + info); + if (param.matches(AppInfo_Key)) { + while (action.hasNext()) { + String param1 = action.next().toString(); + Object valus1 = data.get(param1); + infoMap.put(param1, valus1); + } + } + if (param.matches(TemplateSelect_Key)) { + while (action.hasNext()) { + String param1 = action.next().toString(); + Object valus1 = data.get(param1); + templateMap.put(param1, valus1); + } + } + if (param.matches(FunctionConfig_Key)) { + while (action.hasNext()) { + String param1 = action.next().toString(); + Object valus1 = data.get(param1); + functionMap.put(param1, valus1); + } + } + if (param.matches(ViewConfig_Key)) { + while (action.hasNext()) { + String param1 = action.next().toString(); + Object valus1 = data.get(param1); + viewMap.put(param1, valus1); + } + } + } + + } + } catch (JSONException e) { + e.printStackTrace(); + } + + } +} diff --git a/src/java/com/gizwits/opensource/appkit/CommonModule/NoScrollViewPager.java b/src/java/com/gizwits/opensource/appkit/CommonModule/NoScrollViewPager.java new file mode 100644 index 0000000..a439094 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/CommonModule/NoScrollViewPager.java @@ -0,0 +1,56 @@ +package com.gizwits.opensource.appkit.CommonModule; + +import android.content.Context; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; + +public class NoScrollViewPager extends ViewPager { + private boolean noScroll = false; + + public NoScrollViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + // TODO Auto-generated constructor stub + } + + public NoScrollViewPager(Context context) { + super(context); + } + + public void setNoScroll(boolean noScroll) { + this.noScroll = noScroll; + } + + @Override + public void scrollTo(int x, int y) { + super.scrollTo(x, y); + } + + @Override + public boolean onTouchEvent(MotionEvent arg0) { + /* return false;//super.onTouchEvent(arg0); */ + if (noScroll) + return false; + else + return super.onTouchEvent(arg0); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent arg0) { + if (noScroll) + return false; + else + return super.onInterceptTouchEvent(arg0); + } + + @Override + public void setCurrentItem(int item, boolean smoothScroll) { + super.setCurrentItem(item, smoothScroll); + } + + @Override + public void setCurrentItem(int item) { + super.setCurrentItem(item); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/CommonModule/SplashActivity.java b/src/java/com/gizwits/opensource/appkit/CommonModule/SplashActivity.java new file mode 100644 index 0000000..96107ab --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/CommonModule/SplashActivity.java @@ -0,0 +1,115 @@ +package com.gizwits.opensource.appkit.CommonModule; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.app.ActivityCompat; +import android.util.Log; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.MessageCenter; +import com.gizwits.opensource.appkit.PushModule.GosPushManager; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.UserModule.GosUserLoginActivity; +import com.gizwits.opensource.appkit.utils.AssetsUtils; + +/** + * Created by admin on 2017/6/8. + */ + +public class SplashActivity extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback { + private final int SPLASH_DISPLAY_LENGHT = 2000; + private Handler handler; + + private static final int REQUEST_EXTERNAL_STORAGE = 1; + private static String[] PERMISSIONS_STORAGE = { + "android.permission.READ_EXTERNAL_STORAGE", + "android.permission.WRITE_EXTERNAL_STORAGE"}; + + //push-all-start + private GosPushManager gosPushManager; + //push-all-end + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (!this.isTaskRoot()) {// 判断此activity是不是任务控件的源Activity,“非”也就是说是被系统重新实例化出来的 + Intent mainIntent = getIntent(); + String action = mainIntent.getAction(); + if (mainIntent.hasCategory(Intent.CATEGORY_LAUNCHER) + && action.equals(Intent.ACTION_MAIN)) { + finish(); + return; + } + } +// getWindow().requestFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.activity_gos_splash); + + handler = new Handler(); + getWindow().getDecorView().post(new Runnable() { + @Override + public void run() { + //检测是否有写的权限 + int permission = ActivityCompat.checkSelfPermission(SplashActivity.this, + "android.permission.WRITE_EXTERNAL_STORAGE"); + if (permission != PackageManager.PERMISSION_GRANTED) { + try { + // 没有写的权限,去申请写的权限,会弹出对话框 + ActivityCompat.requestPermissions(SplashActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + initEvent(); + } + } + }); + + } + + private void initEvent() { + + // 延迟SPLASH_DISPLAY_LENGHT时间然后跳转到MainActivity + handler.postDelayed(new Runnable() { + @Override + public void run() { + Intent intent = new Intent(SplashActivity.this, + GosUserLoginActivity.class); + startActivity(intent); + SplashActivity.this.finish(); + } + }, SPLASH_DISPLAY_LENGHT); + + MessageCenter.getInstance(SplashActivity.this); + // 在配置文件中选择推送类型((2:百度,1:极光推送 )) + if (GosDeploy.appConfig_Push_BaiDu()) { + Log.e("TAG", "initEvent----: 百度推送"); + gosPushManager = new GosPushManager(2, this); + } + if (GosDeploy.appConfig_Push_JiGuang()) { + gosPushManager = new GosPushManager(1, this); + } + + TextView tvName = (TextView) findViewById(R.id.tvName); + if (AssetsUtils.isZh(SplashActivity.this)) { + if (GosDeploy.appConfig_LaunchInfoCH() != null) { + tvName.setText(GosDeploy.appConfig_LaunchInfoCH()); + } + } else { + if (GosDeploy.appConfig_LaunchInfoEN() != null) { + tvName.setText(GosDeploy.appConfig_LaunchInfoEN()); + } + } + + } + + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + initEvent(); + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/CommonModule/TipsDialog.java b/src/java/com/gizwits/opensource/appkit/CommonModule/TipsDialog.java new file mode 100644 index 0000000..30e0247 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/CommonModule/TipsDialog.java @@ -0,0 +1,59 @@ +package com.gizwits.opensource.appkit.CommonModule; + +import android.app.Dialog; +import android.content.Context; +import android.view.View; +import android.view.Window; +import android.widget.Button; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; + + +public class TipsDialog extends Dialog implements + View.OnClickListener { + + private Button btnSure; + private TextView tvTips; + + public TipsDialog(Context context) { + super(context); + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setBackgroundDrawableResource(R.drawable.shape_button2); + setContentView(R.layout.dialog_tips); + initView(); + setCancelable(false); + + } + + public TipsDialog(Context context, String txt) { + this(context); + + tvTips.setText(txt); + } + + public TipsDialog(Context context, int res) { + this(context); + + tvTips.setText(res); + } + + + + + private void initView() { + btnSure = (Button) findViewById(R.id.btnSure); + tvTips = (TextView) findViewById(R.id.tvTips); + + btnSure.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btnSure: + cancel(); + break; + } + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/.DS_Store b/src/java/com/gizwits/opensource/appkit/ConfigModule/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b28d391cc2569d745d867e7f15fd69eac69743ed GIT binary patch literal 6148 zcmeHKO;5ux41F0p3~||k12^&unD_@_6mdaZ5O)RxG`>2mEr?rxI?u5+F%?b>G$C8E zU+mgR`y#~+fG}>RhrkfPfGXJArujnTxoAgv77+}2juJ1p!wmO0?qqvl6B&@b+s7$N zRNS-A`&XjjZq}GG`o_@_Zs^VMO0DsZ13X|tZ!)j1&zh=UaHd^ca-Lf(Xh+m%=04FM zp`fks$jTCP`s-Nr+*bYJ`)}g5_&YfR&VV!Us|>Jbiwt%Y-8uu#fHSaUK+cCq6--(@)dyCXE+PTa+i>rXqXIJMLwYfEhTDcuq#H;a>k?OCBs%x%MtR*oX1uUc0&ny zb;e^(M@WipodIWHm4PjFhtmH~zQ6yk7P;pPI0OHRfzU55iZMUQdTZz7q}N936;(v? mTE%4v2e}n9S6cBNH4EcW2E=68Dl$UxAAwAR8)x888TbG%0zirY literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkChooseDeviceWorkWiFiActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkChooseDeviceWorkWiFiActivity.java new file mode 100644 index 0000000..70f2c49 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkChooseDeviceWorkWiFiActivity.java @@ -0,0 +1,505 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosMainActivity; +import com.gizwits.opensource.appkit.utils.NetUtils; +import com.gizwits.opensource.appkit.utils.ToolUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +@SuppressLint("InflateParams") +public class GosAirlinkChooseDeviceWorkWiFiActivity extends GosConfigModuleBaseActivity implements OnClickListener { + + private AlertDialog create; + private ArrayList wifiList; + + private static final int REQUEST_EXTERNAL_STORAGE = 1; + private static String[] PERMISSIONS_STORAGE = { + "android.permission.ACCESS_FINE_LOCATION", + "android.permission.ACCESS_COARSE_LOCATION"}; + /** + * wifi信息 + */ + public WifiInfo wifiInfo; + + /** + * The et SSID + */ + private EditText etSSID; + + /** + * The et Psw + */ + private EditText etPsw; + + /** + * The btn Next + */ + private Button btnNext; + + /** The ll ChooseMode */ + //private LinearLayout llChooseMode; + + /** + * The cb Laws + */ + private CheckBox cbLaws; + + /** The tv Mode */ + //private TextView tvMode; + + /** + * The rl WiFiList + */ + private RelativeLayout rlWiFiList; + + /** + * 配置用参数 + */ + private String workSSID, workSSIDPsw; + + /** + * The data + */ + List modeList; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_airlink_choose_device_workwifi); + // 设置ActionBar + setToolBar(true, getString(R.string.choose_wifi)); + + initData(); + initView(); + ininEvent(); + } + + @Override + protected void onResume() { + super.onResume(); + try { + // 预设workSSID && workSSIDPsw + workSSID = NetUtils.getCurentWifiSSID(this); + String mypass = spf.getString("mypass", ""); + + if (!TextUtils.isEmpty(workSSID)) { + etSSID.setText(workSSID); + etSSID.setSelection(workSSID.length()); + if (!TextUtils.isEmpty(mypass)) { + JSONObject obj = new JSONObject(mypass); + + if (obj.has(workSSID)) { + String pass = obj.getString(workSSID); + etPsw.setText(pass); + } else { + etPsw.setText(""); + } + } + } else { + etSSID.setText(NetUtils.getCurentWifiSSID(this)); + } + + // 当没有任何文字的时候设置为明文显示 +// if (TextUtils.isEmpty(etPsw.getText().toString())) { +// cbLaws.setChecked(true); +// etPsw.setInputType(0x90); +// } else { +// etPsw.setInputType(0x81); +// cbLaws.setChecked(false); +// } + } catch(JSONException e) { + e.printStackTrace(); + } + } + + private void initView() { + //tvMode = (TextView) findViewById(R.id.tvMode); + etSSID = (EditText) findViewById(R.id.etSSID); + + etPsw = (EditText) findViewById(R.id.etPsw); + cbLaws = (CheckBox) findViewById(R.id.cbLaws); + btnNext = (Button) findViewById(R.id.btnNext); + //llChooseMode = (LinearLayout) findViewById(R.id.llChooseMode); + rlWiFiList = (RelativeLayout) findViewById(R.id.rlWiFiList); + + // 配置文件部署 + btnNext.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnNext.setTextColor(GosDeploy.appConfig_Contrast()); + // llChooseMode.setVisibility(GosDeploy.setModuleSelectOn()); + + //llChooseMode.setVisibility(View.GONE); + } + + + private void ininEvent() { + btnNext.setOnClickListener(this); + rlWiFiList.setOnClickListener(this); + //llChooseMode.setOnClickListener(this); + + cbLaws.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + String psw = etPsw.getText().toString(); + + if (isChecked) { + etPsw.setInputType(0x90); + } else { + etPsw.setInputType(0x81); + } + etPsw.setSelection(psw.length()); + } + }); + + //检测是否有位置定位的权限 + int permission = ActivityCompat.checkSelfPermission(GosAirlinkChooseDeviceWorkWiFiActivity.this, + "android.permission.ACCESS_FINE_LOCATION"); + if (permission != PackageManager.PERMISSION_GRANTED) { + try { + // 没有写的权限,去申请写的权限,会弹出对话框 + ActivityCompat.requestPermissions(GosAirlinkChooseDeviceWorkWiFiActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); + } catch(Exception e) { + e.printStackTrace(); + } + } + } + + private void initData() { + modeList = new ArrayList(); + String[] modes = this.getResources().getStringArray(R.array.mode); + for (String string : modes) { + modeList.add(string); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btnNext: + if (ToolUtils.noDoubleClick()) { + workSSID = etSSID.getText().toString(); + workSSIDPsw = etPsw.getText().toString(); + + if (TextUtils.isEmpty(workSSID)) { + Toast.makeText(GosAirlinkChooseDeviceWorkWiFiActivity.this, R.string.choose_wifi_list_title, toastTime) + .show(); + return; + } + + if (!workSSID.equals(NetUtils.getCurentWifiSSID(this))) { + final Dialog dialog1 = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog1.setCanceledOnTouchOutside(false); + dialog1.show(); + + Window window = dialog1.getWindow(); + window.setContentView(R.layout.alert_gos_wifi); + + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog1.cancel(); + return; + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (dialog1.isShowing()) { + dialog1.cancel(); + } + isEmptyAlert(); + } + }); + } else { + isEmptyAlert(); + } + } + break; + + case R.id.rlWiFiList: + AlertDialog.Builder dia = new AlertDialog.Builder(GosAirlinkChooseDeviceWorkWiFiActivity.this); + View view = View.inflate(GosAirlinkChooseDeviceWorkWiFiActivity.this, R.layout.alert_gos_wifi_list, null); + ListView listview = (ListView) view.findViewById(R.id.wifi_list); + List rsList = NetUtils.getCurrentWifiScanResult(this); + List localList = new ArrayList(); + localList.clear(); + wifiList = new ArrayList(); + wifiList.clear(); + for (ScanResult sss : rsList) { + if (sss.SSID.contains(SoftAP_Start)) { + } else { + if (localList.toString().contains(sss.SSID)) { + } else { + localList.add(sss.SSID); + wifiList.add(sss); + } + } + } + if (wifiList.size() == 0) { + LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + // 未打开位置开关,可能导致定位失败或定位不准,提示用户或做相应处理 + Toast.makeText(this, getString(R.string.open), Toast.LENGTH_LONG).show(); + return; + } + } + WifiListAdapter adapter = new WifiListAdapter(wifiList); + listview.setAdapter(adapter); + listview.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { + ScanResult sResult = wifiList.get(arg2); + String sSID = sResult.SSID; + etSSID.setText(sSID); + etSSID.setSelection(sSID.length()); + etPsw.setText(""); + create.dismiss(); + } + }); + dia.setView(view); + create = dia.create(); + create.show(); + break; + + default: + break; + } + } + + private static final String TAG = "GosAirlinkChooseDevice"; + + private void toAirlinkReady() { + // 需要记录所有配置过的wifi和密码 + + try { + String mypass = spf.getString("mypass", ""); + if (TextUtils.isEmpty(mypass)) { + JSONObject mUserAndPass = new JSONObject(); + mUserAndPass.put(workSSID, workSSIDPsw); + spf.edit().putString("mypass", mUserAndPass.toString()).commit(); + } else { + JSONObject obj = new JSONObject(mypass); + obj.put(workSSID, workSSIDPsw); + spf.edit().putString("mypass", obj.toString()).commit(); + } + } catch(JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + spf.edit().putString("workSSID", workSSID).commit(); + spf.edit().putString("workSSIDPsw", workSSIDPsw).commit(); + //wifiModuleType-false-start wifiModuleType-true-start + if (GosDeploy.appConfig_WifiModuleType().size() == 0) { + //wifiModuleType-false-end + Intent intent = new Intent(this, GosModeListActivity2.class); + startActivity(intent); + //wifiModuleType-false-start + } else { + //wifiModuleType-true-end + List moduleTypes = GosDeploy.appConfig_WifiModuleType(); + JSONArray array = new JSONArray(); + for (int type : moduleTypes) { + if (type == 4) { + type = 0; + } else if (type < 4) { + type = type + 1; + } else if (type == 12) { + type = 6; + } else if (type >= 6 && type < 12) { + type = type + 1; + } + array.put(type); + } + spf.edit().putString("modulestyles", array.toString()).commit(); + Intent intent = new Intent(this, GosAirlinkReadyActivity.class); + startActivity(intent); + //wifiModuleType-true-start + } + //wifiModuleType-false-end wifiModuleType-true-end + + } + + /* + * // 检查当前使用的WiFi是否曾经用过 protected boolean checkworkSSIDUsed(String workSSID) + * { if (spf.contains("workSSID")) { if (spf.getString("workSSID", + * "").equals(workSSID)) { return true; } } return false; } + */ + + // 屏蔽掉返回键 + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + Intent intent = new Intent(this, GosMainActivity.class); + startActivity(intent); + //quitAlert(this, intent); + return true; + } + return false; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + Intent intent = new Intent(this, GosMainActivity.class); + startActivity(intent); + //quitAlert(this, intent); + break; + } + + return true; + } + + + private void isEmptyAlert() { + if (TextUtils.isEmpty(workSSIDPsw)) { + final Dialog dialog = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_empty); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + if (dialog.isShowing()) { + dialog.cancel(); + } + toAirlinkReady(); + } + }); + } else { + toAirlinkReady(); + } + } + + class WifiListAdapter extends BaseAdapter { + + ArrayList xpgList; + + public WifiListAdapter(ArrayList list) { + this.xpgList = list; + } + + @Override + public int getCount() { + return xpgList.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + Holder holder; + if (view == null) { + view = LayoutInflater.from(GosAirlinkChooseDeviceWorkWiFiActivity.this) + .inflate(R.layout.item_gos_wifi_list, null); + holder = new Holder(view); + view.setTag(holder); + } else { + holder = (Holder) view.getTag(); + } + + String ssid = xpgList.get(position).SSID; + holder.getTextView().setText(ssid); + + return view; + } + + } + + class Holder { + View view; + + public Holder(View view) { + this.view = view; + } + + TextView textView; + + public TextView getTextView() { + if (textView == null) { + textView = (TextView) view.findViewById(R.id.SSID_text); + } + return textView; + } + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkConfigCountdownActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkConfigCountdownActivity.java new file mode 100644 index 0000000..754177b --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkConfigCountdownActivity.java @@ -0,0 +1,310 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.WindowManager; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizWifiConfigureMode; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.enumration.GizWifiGAgentType; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosMainActivity; +import com.gizwits.opensource.appkit.view.RoundProgressBar; + +import org.json.JSONArray; +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import static com.gizwits.gizwifisdk.enumration.GizWifiErrorCode.GIZ_SDK_ONBOARDING_STOPPED; + +@SuppressLint("HandlerLeak") +public class GosAirlinkConfigCountdownActivity extends + GosConfigModuleBaseActivity { + + /** The tv Time */ + //private TextView tvTimer; + + /** + * The rpb Config + */ + private RoundProgressBar rpbConfig; + + /** + * 倒计时 + */ + int secondleft = 60; + + /** + * The timer + */ + Timer timer; + + /** + * 配置用参数 + */ + String workSSID, workSSIDPsw; + + + List modeList, modeDataList; + private TextView tvLeft; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_airlink_config_countdown); + // 设置ActionBar + setToolBar(false, R.string.search_join); + initView(); + initData(); + startAirlink(); + tvLeft = (TextView) findViewById(R.id.tvLeft); + tvLeft.setVisibility(View.VISIBLE); + SpannableString ssTitle = new SpannableString(this.getString(R.string.cancel)); + ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvLeft.setText(ssTitle); + tvLeft.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(GosAirlinkConfigCountdownActivity.this, GosMainActivity.class); + quitAlert(GosAirlinkConfigCountdownActivity.this, intent, getString(R.string.cancel_configuration)); + } + }); + } + + private void initView() { + WindowManager wm = this.getWindowManager(); + int width = wm.getDefaultDisplay().getWidth(); + + RelativeLayout cel_layout = (RelativeLayout) findViewById(R.id.params); + LayoutParams params = cel_layout.getLayoutParams(); + params.height = width; + params.width = width; + cel_layout.setLayoutParams(params); + //tvTimer = (TextView) findViewById(R.id.tvTimer); + + rpbConfig = (RoundProgressBar) findViewById(R.id.rpbConfig); + + } + + private static final String TAG = "GosAirlinkConfigCountdo"; + + private void initData() { + workSSID = spf.getString("workSSID", ""); + workSSIDPsw = spf.getString("workSSIDPsw", ""); + modeDataList = new ArrayList(); + modeDataList.add(GizWifiGAgentType.GizGAgentESP); + modeDataList.add(GizWifiGAgentType.GizGAgentMXCHIP); + modeDataList.add(GizWifiGAgentType.GizGAgentHF); + modeDataList.add(GizWifiGAgentType.GizGAgentRTK); + modeDataList.add(GizWifiGAgentType.GizGAgentWM); + modeDataList.add(GizWifiGAgentType.GizGAgentQCA); + modeDataList.add(GizWifiGAgentType.GizGAgentFlyLink); + modeDataList.add(GizWifiGAgentType.GizGAgentTI); + modeDataList.add(GizWifiGAgentType.GizGAgentFSK); + modeDataList.add(GizWifiGAgentType.GizGAgentMXCHIP3); + modeDataList.add(GizWifiGAgentType.GizGAgentBL); + modeDataList.add(GizWifiGAgentType.GizGAgentAtmelEE); + modeDataList.add(GizWifiGAgentType.GizGAgentOther); + modeList = new ArrayList(); + + String types = spf.getString("modulestyles", null); + if (types != null) { + try { + JSONArray array = new JSONArray(types); + for (int i = 0; i < array.length(); i++) { + int type = (Integer) array.get(i); + modeList.add(modeDataList.get(type)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + private void startAirlink() { + String nullStr = null; + switch (GosConstant.mNew) { + case 0: + GizWifiSDK.sharedInstance().setDeviceOnboarding(workSSID, workSSIDPsw, + GizWifiConfigureMode.GizWifiAirLink, null, 60, modeList); + break; + case 1: + GizWifiSDK.sharedInstance().setDeviceOnboardingByBind(workSSID, workSSIDPsw, + GizWifiConfigureMode.GizWifiAirLink, null, 60, modeList); + break; + case 2: + GizWifiSDK.sharedInstance().setDeviceOnboardingDeploy( + workSSID, + workSSIDPsw, + GizWifiConfigureMode.GizWifiAirLink, + nullStr, + 60, + modeList, + false + ); + break; + case 3: + GizWifiSDK.sharedInstance().setDeviceOnboardingDeploy( + workSSID, + workSSIDPsw, + GizWifiConfigureMode.GizWifiAirLink, + nullStr, + 60, + modeList, + true + ); + break; + } + handler.sendEmptyMessage(handler_key.START_TIMER.ordinal()); + } + + private enum handler_key { + + /** + * 倒计时提示 + */ + TIMER_TEXT, + + /** + * 倒计时开始 + */ + START_TIMER, + + /** + * 配置成功 + */ + SUCCESSFUL, + + /** + * 配置失败 + */ + FAILED, + + } + + /** + * The handler. + */ + Handler handler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + + case START_TIMER: + isStartTimer(); + break; + + case SUCCESSFUL: + Toast.makeText(GosAirlinkConfigCountdownActivity.this, + R.string.configuration_successful, toastTime).show(); + Intent intent1 = new Intent(GosAirlinkConfigCountdownActivity.this, GosMainActivity.class); + startActivity(intent1); + break; + + case FAILED: + if (GosDeploy.appConfig_Config_Softap()) { + Toast.makeText(GosAirlinkConfigCountdownActivity.this, + getString(R.string.configuration_timeout), toastTime).show(); + Intent intent = new Intent( + GosAirlinkConfigCountdownActivity.this, + GosDeviceReadyActivity.class); + /** 判断是否是从一键配置界面传过去的 */ + intent.putExtra("isAirLink", true); + startActivity(intent); + } else { + Intent intent = new Intent( + GosAirlinkConfigCountdownActivity.this, + GosConfigFailedActivity.class); + /** 判断是否是从一键配置界面传过去的 */ + intent.putExtra("isAirLink", true); + startActivity(intent); + } + break; + + default: + break; + + } + } + + }; + + // 屏蔽掉返回键 + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + Intent intent = new Intent(GosAirlinkConfigCountdownActivity.this, GosMainActivity.class); + //quitAlert(this, intent); + quitAlert(this, intent, getString(R.string.cancel_configuration)); + overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); + return true; + } + return false; + } + + // 倒计时 + public void isStartTimer() { + + secondleft = 60; + timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + secondleft--; + rpbConfig.setProgress((60 - secondleft) * (100 / 60.0)); + } + }, 1000, 1000); + } + + /** + * 设备配置回调 + * + * @param result 错误码 + * @param mac MAC + * @param did DID + * @param productKey PK + */ + protected void didSetDeviceOnboarding(GizWifiErrorCode result, String mac, + String did, String productKey) { + if (GizWifiErrorCode.GIZ_SDK_DEVICE_CONFIG_IS_RUNNING == result) { + return; + } + + if (timer != null) { + timer.cancel(); + } + Message message = new Message(); + if (result == GizWifiErrorCode.GIZ_SDK_SUCCESS) { + message.what = handler_key.SUCCESSFUL.ordinal(); + } else if (result == GIZ_SDK_ONBOARDING_STOPPED) { + + } else { + message.what = handler_key.FAILED.ordinal(); + message.obj = toastError(result); + } + Log.i("Apptest", result.toString()); + handler.sendMessage(message); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkReadyActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkReadyActivity.java new file mode 100644 index 0000000..41cfb61 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosAirlinkReadyActivity.java @@ -0,0 +1,132 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.utils.AssetsUtils; +import com.gizwits.opensource.appkit.utils.ToolUtils; + +import java.util.ArrayList; +import java.util.List; + +public class GosAirlinkReadyActivity extends GosConfigModuleBaseActivity implements OnClickListener { + + + /** + * The tv Ready + */ + TextView tvReady; + + + /** + * The btn Next + */ + Button btnNext; + + TextView tvDeviceTip; + + private int sum = 0; + + //private TextView moudlechoose; + + private List modeList; + private ImageView ivReady; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.actvity_gos_airlink_ready); + // 设置ActionBar + setToolBar(true, R.string.airlink_ready_title); + + initData(); + initView(); + initEvent(); + } + + private void initData() { + // workSSID = spf.getString("workSSID", ""); + + modeList = new ArrayList(); + String[] modes = this.getResources().getStringArray(R.array.mode); + for (String string : modes) { + modeList.add(string); + } + } + + private void initView() { + tvReady = (TextView) findViewById(R.id.tvReady); + btnNext = (Button) findViewById(R.id.btnNext); + tvDeviceTip = (TextView) findViewById(R.id.tvDeviceTip); + ivReady = (ImageView) findViewById(R.id.ivReady); + SpannableString spannableString = new SpannableString(getString(R.string.common_ready_message)); + if (AssetsUtils.isZh(this)) { + spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#007AFF")), 9, 14, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else { + spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#007AFF")), 28, 45, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + tvReady.setText(spannableString); + + // 配置文件部署 + btnNext.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnNext.setTextColor(GosDeploy.appConfig_Contrast()); + } + + private void initEvent() { + btnNext.setOnClickListener(this); + tvDeviceTip.setOnClickListener(this); + ivReady.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btnNext: + if (ToolUtils.noDoubleClick()) { + sum = 0; + Intent intent = new Intent(this, GosAirlinkConfigCountdownActivity.class); + startActivity(intent); + } + break; + + default: + break; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + sum = 0; + this.finish(); + //overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); + break; + } + return true; + } + +// @Override +// public boolean onKeyDown(int keyCode, KeyEvent event) { +// Intent intent = new Intent(this, GosAirlinkChooseDeviceWorkWiFiActivity.class); +// startActivity(intent); +// overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); +// this.finish(); +// return true; +// } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceActivity.java new file mode 100644 index 0000000..3ba9e57 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceActivity.java @@ -0,0 +1,279 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.location.LocationManager; +import android.net.wifi.ScanResult; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.log.SDKLog; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.utils.AssetsUtils; + +import java.util.ArrayList; +import java.util.Timer; +import java.util.TimerTask; + +@SuppressLint({"InflateParams", "HandlerLeak"}) +public class GosChooseDeviceActivity extends GosConfigModuleBaseActivity implements OnClickListener { + + /** + * The tv Nodevice + */ + TextView tvNodevice; + + /** + * The list View + */ + ListView listView; + + /** + * 系统WiFi集合 + */ + ArrayList list; + + /** + * 设备热点集合 + */ + ArrayList softList; + + /** + * 适配器 + */ + Myadapter myadapter; + + /** + * 计时器 + */ + Timer timer; + + int flag = 0; + + private enum handler_key { + + /** + * 刷新列表 + */ + UPDATALIST, + + } + + Handler handler = new Handler() { + public void handleMessage(android.os.Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + // 更新列表 + case UPDATALIST: + initData(); + break; + } + } + + ; + + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_choose_device); + // 设置ActionBar + setToolBar(true, R.string.choosedevice); + + initView(); + initEvent(); + } + + @Override + protected void onResume() { + super.onResume(); + startTimer(); + } + + @Override + public void onPause() { + super.onPause(); + timer.cancel(); + } + + private void initData() { +// list = new ArrayList(); + list = (ArrayList) GosConstant.ssidList; + //list = (ArrayList) NetUtils.getCurrentWifiScanResult(GosChooseDeviceActivity.this); + softList = new ArrayList(); + ScanResult scanResult; + for (int i = 0; i < list.size(); i++) { + scanResult = list.get(i); + if (scanResult.SSID.length() > SoftAP_Start.length()) { + if (scanResult.SSID.contains(SoftAP_Start)) { + softList.add(scanResult); + } + } + } + myadapter = new Myadapter(softList); + listView.setAdapter(myadapter); + } + + private void initView() { + tvNodevice = (TextView) findViewById(R.id.nodevice); + listView = (ListView) findViewById(R.id.list_view); + } + + private void initEvent() { + tvNodevice.setOnClickListener(this); + + listView.setOnItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Intent intent = new Intent(GosChooseDeviceActivity.this, GosConfigCountdownActivity.class); + intent.putExtra("softSSID", softList.get(position).SSID); + startActivity(intent); + finish(); + } + }); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.nodevice: + if (list == null) { + LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + // 未打开位置开关,可能导致定位失败或定位不准,提示用户或做相应处理 + Toast.makeText(this, getString(R.string.open), Toast.LENGTH_LONG).show(); + return; + } + } else if (list.size() == 0) { + LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + // 未打开位置开关,可能导致定位失败或定位不准,提示用户或做相应处理 + Toast.makeText(this, getString(R.string.open), Toast.LENGTH_LONG).show(); + return; + } + } + finish(); + break; + + default: + break; + } + } + + private void startTimer() { + timer = new Timer(); + timer.schedule(new TimerTask() { + + @Override + public void run() { + handler.sendEmptyMessage(handler_key.UPDATALIST.ordinal()); + } + }, 0, 3000); + } + + class Myadapter extends BaseAdapter { + + ArrayList softList; + + public Myadapter(ArrayList list) { + this.softList = list; + } + + @Override + public int getCount() { + return softList.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + Holder holder; + if (view == null) { + view = LayoutInflater.from(GosChooseDeviceActivity.this).inflate(R.layout.item_gos_wifi_device, null); + holder = new Holder(view); + view.setTag(holder); + } else { + + holder = (Holder) view.getTag(); + } + String ssid = softList.get(position).SSID; + +// String itemStart = (String) getText(R.string.itemtext_start); +// String itemEnd = (String) getText(R.string.itemtext_end); + String s = ""; + if (AssetsUtils.isZh(GosChooseDeviceActivity.this)) { + s = getString(R.string.device) + ssid.substring(ssid.length() - 4); + } else { + s = getString(R.string.device) + " " + ssid.substring(ssid.length() - 4); + } + holder.getTextView().setText(s); + + return view; + } + } + + class Holder { + View view; + + public Holder(View view) { + this.view = view; + } + + TextView textView; + + public TextView getTextView() { + if (textView == null) { + textView = (TextView) view.findViewById(R.id.SSID_text); + } + return textView; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + } + return true; + } + + // 屏蔽掉返回键 + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + finish(); + return true; + } + return false; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceWorkWiFiActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceWorkWiFiActivity.java new file mode 100644 index 0000000..0041362 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseDeviceWorkWiFiActivity.java @@ -0,0 +1,465 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; +import android.os.Bundle; +import android.support.v4.app.ActivityCompat; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosMainActivity; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.NetUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class GosChooseDeviceWorkWiFiActivity extends GosConfigModuleBaseActivity + implements OnClickListener, OnItemClickListener { + + private AlertDialog create; + private ArrayList wifiList; + + private static final int REQUEST_EXTERNAL_STORAGE = 1; + private static String[] PERMISSIONS_STORAGE = { + "android.permission.ACCESS_FINE_LOCATION", + "android.permission.ACCESS_COARSE_LOCATION"}; + + /** + * wifi信息 + */ + public WifiInfo wifiInfo; + + /** + * The et SSID + */ + private EditText etSSID; + + /** + * The et Psw + */ + private EditText etPsw; + + /** + * The btn Next + */ + private Button btnNext; + + /** + * The cb Laws + */ + private CheckBox cbLaws; + + /** + * The img WiFiList + */ + private RelativeLayout rlWiFiList; + + /** + * 配置用参数 + */ + private String softSSID, workSSID, workSSIDPsw; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_choose_device_workwifi); + // 设置ActionBar + setToolBar(true, R.string.choose_wifi); + + initData(); + initView(); + ininEvent(); + } + + private void initView() { + etSSID = (EditText) findViewById(R.id.etSSID); + etPsw = (EditText) findViewById(R.id.etPsw); + btnNext = (Button) findViewById(R.id.btnNext); + cbLaws = (CheckBox) findViewById(R.id.cbLaws); + rlWiFiList = (RelativeLayout) findViewById(R.id.rlWiFiList); + // 配置文件部署 + btnNext.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnNext.setTextColor(GosDeploy.appConfig_Contrast()); + if (!TextUtils.isEmpty(workSSID)) { + etSSID.setText(workSSID); + etSSID.setSelection(workSSID.length()); + if (checkworkSSIDUsed(workSSID)) { + if (!TextUtils.isEmpty(spf.getString("workSSIDPsw", ""))) { + etPsw.setText(spf.getString("workSSIDPsw", "")); + } + } + } + } + + + private void ininEvent() { + + btnNext.setOnClickListener(this); + rlWiFiList.setOnClickListener(this); + + cbLaws.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + String psw = etPsw.getText().toString(); + + if (isChecked) { + etPsw.setInputType(0x90); + } else { + etPsw.setInputType(0x81); + } + etPsw.setSelection(psw.length()); + } + }); + + //检测是否有位置定位的权限 + int permission = ActivityCompat.checkSelfPermission(GosChooseDeviceWorkWiFiActivity.this, + "android.permission.ACCESS_FINE_LOCATION"); + if (permission != PackageManager.PERMISSION_GRANTED) { + try { + // 没有写的权限,去申请写的权限,会弹出对话框 + ActivityCompat.requestPermissions(GosChooseDeviceWorkWiFiActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void initData() { + //softSSID = getIntent().getStringExtra("softssid"); + workSSID = spf.getString("workSSID", ""); + } + + + @Override + protected void onResume() { + super.onResume(); + + try { + // 预设workSSID && workSSIDPsw + workSSID = NetUtils.getCurentWifiSSID(this); + String mypass = spf.getString("mypass", ""); + + if (!TextUtils.isEmpty(workSSID)) { + etSSID.setText(workSSID); + etSSID.setSelection(workSSID.length()); + if (!TextUtils.isEmpty(mypass)) { + JSONObject obj = new JSONObject(mypass); + + if (obj.has(workSSID)) { + String pass = obj.getString(workSSID); + etPsw.setText(pass); + } else { + etPsw.setText(""); + } + } + + } else { + etSSID.setText(NetUtils.getCurentWifiSSID(this)); + } + + } catch (JSONException e) { + e.printStackTrace(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + Intent intent = new Intent(this, GosMainActivity.class); + startActivity(intent); + //quitAlert(this, intent); + break; + } + return true; + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btnNext: + workSSID = etSSID.getText().toString(); + workSSIDPsw = etPsw.getText().toString(); + + if (TextUtils.isEmpty(workSSID)) { + Toast.makeText(GosChooseDeviceWorkWiFiActivity.this, R.string.choose_wifi_list_title, + Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(workSSIDPsw)) { + final Dialog dialog = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_empty); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + if (dialog.isShowing()) { + dialog.cancel(); + } + Intent intent = null; + //wifiModuleType-false-start wifiModuleType-true-start + if (GosDeploy.appConfig_WifiModuleType().size() == 0) { + //wifiModuleType-false-end + intent = new Intent(GosChooseDeviceWorkWiFiActivity.this, + GosModeListActivity2.class); + //wifiModuleType-false-start + } else { + //wifiModuleType-true-end + List moduleTypes = GosDeploy.appConfig_WifiModuleType(); + JSONArray array = new JSONArray(); + for (int type : moduleTypes) { + if (type == 4) { + type = 0; + } else if (type < 4) { + type = type + 1; + } else if (type == 12) { + type = 6; + } else if (type >= 6 && type < 12) { + type = type + 1; + } + array.put(type); + } + spf.edit().putString("modulestyles", array.toString()).commit(); + intent = new Intent(GosChooseDeviceWorkWiFiActivity.this, + GosDeviceReadyActivity.class); + //wifiModuleType-true-start + } + //wifiModuleType-false-end wifiModuleType-true-end + spf.edit().putString("workSSID", workSSID).commit(); + spf.edit().putString("workSSIDPsw", workSSIDPsw).commit(); + intent.putExtra("isAirlink", false); + startActivity(intent); + } + }); + } else { + Intent intent = null; + //wifiModuleType-false-start wifiModuleType-true-start + if (GosDeploy.appConfig_WifiModuleType().size() == 0) { + //wifiModuleType-false-end + intent = new Intent(GosChooseDeviceWorkWiFiActivity.this, + GosModeListActivity2.class); + //wifiModuleType-false-start + } else { + //wifiModuleType-true-end + List moduleTypes = GosDeploy.appConfig_WifiModuleType(); + JSONArray array = new JSONArray(); + for (int type : moduleTypes) { + if (type == 4) { + type = 0; + } else if (type < 4) { + type = type + 1; + } else if (type == 12) { + type = 6; + } else if (type >= 6 && type < 12) { + type = type + 1; + } + array.put(type); + } + spf.edit().putString("modulestyles", array.toString()).commit(); + intent = new Intent(GosChooseDeviceWorkWiFiActivity.this, + GosDeviceReadyActivity.class); + //wifiModuleType-true-start + } + //wifiModuleType-false-end wifiModuleType-true-end + spf.edit().putString("workSSID", workSSID).commit(); + spf.edit().putString("workSSIDPsw", workSSIDPsw).commit(); + /** 判断是否是从一键配置界面传过去的 */ + intent.putExtra("isAirlink", false); + startActivity(intent); + } + break; + + case R.id.rlWiFiList: + AlertDialog.Builder dia = new AlertDialog.Builder(GosChooseDeviceWorkWiFiActivity.this); + View view = View.inflate(GosChooseDeviceWorkWiFiActivity.this, R.layout.alert_gos_wifi_list, null); + ListView listview = (ListView) view.findViewById(R.id.wifi_list); + List rsList = NetUtils.getCurrentWifiScanResult(this); + List localList = new ArrayList(); + localList.clear(); + wifiList = new ArrayList(); + wifiList.clear(); + + for (ScanResult sss : rsList) { + if (sss.SSID.contains(GosConstant.SoftAP_Start)) { + + } else { + if (localList.toString().contains(sss.SSID)) { + } else { + localList.add(sss.SSID); + wifiList.add(sss); + } + } + } + if (wifiList.size() == 0) { + LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + // 未打开位置开关,可能导致定位失败或定位不准,提示用户或做相应处理 + Toast.makeText(this, getString(R.string.open), Toast.LENGTH_LONG).show(); + return; + } + } + + WifiListAdapter adapter = new WifiListAdapter(wifiList); + listview.setAdapter(adapter); + listview.setOnItemClickListener(this); + dia.setView(view); + create = dia.create(); + create.show(); + + break; + + default: + break; + } + } + + @Override + public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { + + ScanResult sResult = wifiList.get(arg2); + String sSID = sResult.SSID; + etSSID.setText(sSID); + etSSID.setSelection(sSID.length()); + etPsw.setText(""); + create.dismiss(); + } + + // 检查当前使用的WiFi是否曾经用过 + protected boolean checkworkSSIDUsed(String workSSID) { + if (spf.contains("workSSID")) { + if (spf.getString("workSSID", "").equals(workSSID)) { + return true; + } + } + return false; + } + + // 屏蔽掉返回键 + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + Intent intent = new Intent(this, GosMainActivity.class); + startActivity(intent); + //quitAlert(this, intent); + return true; + } + return false; + } + + class WifiListAdapter extends BaseAdapter { + + ArrayList xpgList; + + public WifiListAdapter(ArrayList list) { + this.xpgList = list; + } + + @Override + public int getCount() { + return xpgList.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @SuppressLint("InflateParams") + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + Holder holder; + if (view == null) { + view = LayoutInflater.from(GosChooseDeviceWorkWiFiActivity.this).inflate(R.layout.item_gos_wifi_list, + null); + holder = new Holder(view); + view.setTag(holder); + } else { + holder = (Holder) view.getTag(); + } + String ssid = xpgList.get(position).SSID; + holder.getTextView().setText(ssid); + + return view; + } + + } + + class Holder { + View view; + + public Holder(View view) { + this.view = view; + } + + TextView textView; + + public TextView getTextView() { + if (textView == null) { + textView = (TextView) view.findViewById(R.id.SSID_text); + } + return textView; + } + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseModuleHelpActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseModuleHelpActivity.java new file mode 100644 index 0000000..96efd82 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosChooseModuleHelpActivity.java @@ -0,0 +1,41 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.os.Bundle; +import android.webkit.WebSettings; +import android.webkit.WebView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.AssetsUtils; + + +/** + * Created by admin on 2017/6/15. + */ + +public class GosChooseModuleHelpActivity extends com.gizwits.opensource.appkit.ConfigModule.GosConfigModuleBaseActivity { + private WebView webHelp; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_choose_module_help); + initView(); + initEvent(); + } + + private void initEvent() { + setToolBar(true, getString(R.string.module_help)); + WebSettings wSet = webHelp.getSettings(); + wSet.setJavaScriptEnabled(true); + if (AssetsUtils.isZh(this)) { + webHelp.loadUrl("file:///android_asset/moduleTypeInfo.html"); + } else { + webHelp.loadUrl("file:///android_asset/moduleTypeInfoEnglish.html"); + } + + } + + private void initView() { + webHelp = (WebView) findViewById(R.id.webHelp); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigCountdownActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigCountdownActivity.java new file mode 100644 index 0000000..c51b93a --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigCountdownActivity.java @@ -0,0 +1,424 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizWifiConfigureMode; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.enumration.GizWifiGAgentType; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosMainActivity; +import com.gizwits.opensource.appkit.utils.NetUtils; +import com.gizwits.opensource.appkit.view.RoundProgressBar; +import com.gizwits.opensource.appkit.R; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.view.KeyEvent; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONArray; +import org.json.JSONException; + +import static com.gizwits.gizwifisdk.enumration.GizWifiErrorCode.GIZ_SDK_ONBOARDING_STOPPED; + +@SuppressLint("HandlerLeak") +public class GosConfigCountdownActivity extends GosConfigModuleBaseActivity { + + private GosWifiChangeReciver broadcase; + + /** + * The rpb Config + */ + private RoundProgressBar rpbConfig; + + /** + * 倒计时 + */ + int secondleft = 60; + + /** + * The timer + */ + Timer timer; + + /** + * The Frist + */ + boolean isFrist = true; + + /** + * The isChecked + */ + boolean isChecked = false; + + String softSSID, presentSSID, workSSID, workSSIDPsw; + + private boolean isShowing = false; + private String SSID = null, SSIDPsw = null; + List modeList, modeDataList; + private TextView tvLeft; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_config_countdown); + // 设置ActionBar + setToolBar(false, R.string.search_join); + initView(); + initData(); + tvLeft = (TextView) findViewById(R.id.tvLeft); + tvLeft.setVisibility(View.VISIBLE); + SpannableString ssTitle = new SpannableString(this.getString(R.string.cancel)); + ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvLeft.setText(ssTitle); + tvLeft.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(GosConfigCountdownActivity.this, GosMainActivity.class); + quitAlert(GosConfigCountdownActivity.this, intent, getString(R.string.cancel_configuration)); + } + }); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus && isFrist) { + isShowing = true; + new Thread() { + public void run() { + try { + Thread.sleep(1 * 1000); + readyToSoftAP(); + } catch(InterruptedException e) { + e.printStackTrace(); + } + + } + + ; + }.start(); + + isFrist = false; + } + } + + private void initView() { + rpbConfig = (RoundProgressBar) findViewById(R.id.rpbConfig); + } + + private void initData() { + softSSID = getIntent().getStringExtra("softSSID"); + workSSIDPsw = spf.getString("workSSIDPsw", ""); + modeDataList = new ArrayList(); + modeDataList.add(GizWifiGAgentType.GizGAgentESP); + modeDataList.add(GizWifiGAgentType.GizGAgentMXCHIP); + modeDataList.add(GizWifiGAgentType.GizGAgentHF); + modeDataList.add(GizWifiGAgentType.GizGAgentRTK); + modeDataList.add(GizWifiGAgentType.GizGAgentWM); + modeDataList.add(GizWifiGAgentType.GizGAgentQCA); + modeDataList.add(GizWifiGAgentType.GizGAgentFlyLink); + modeDataList.add(GizWifiGAgentType.GizGAgentTI); + modeDataList.add(GizWifiGAgentType.GizGAgentFSK); + modeDataList.add(GizWifiGAgentType.GizGAgentMXCHIP3); + modeDataList.add(GizWifiGAgentType.GizGAgentBL); + modeDataList.add(GizWifiGAgentType.GizGAgentAtmelEE); + modeDataList.add(GizWifiGAgentType.GizGAgentOther); + modeList = new ArrayList(); + + String types = spf.getString("modulestyles", null); + if (types != null) { + try { + JSONArray array = new JSONArray(types); + for (int i = 0; i < array.length(); i++) { + int type = (Integer) array.get(i); + modeList.add(modeDataList.get(type)); + } + } catch(JSONException e) { + e.printStackTrace(); + } + } + } + + private enum handler_key { + + /** + * 倒计时结束 + */ + TICK_TIME, + + /** + * 设置手机开启热点 + */ + OPEN_HOT, + + /** + * 倒计时开始 + */ + START_TIMER, + + /** + * 配置成功 + */ + SUCCESSFUL, + + /** + * 配置失败 + */ + FAILED, + + } + + private static final String TAG = "GosConfigCountdownActiv"; + /** + * The handler. + */ + Handler handler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + + case TICK_TIME: + + break; + case OPEN_HOT: + if (GosConstant.isOpenHot) { + boolean b = setWifiApEnabled(true); + // boolean b = setWifiAp(true); + } + break; + + case START_TIMER: + isStartTimer(); + break; + // 配置成功 + case SUCCESSFUL: + Toast.makeText(GosConfigCountdownActivity.this, R.string.configuration_successful, toastTime) + .show(); + Intent intent1 = new Intent(GosConfigCountdownActivity.this, GosMainActivity.class); + startActivity(intent1); + break; + // 配置失败 + case FAILED: + isChecked = false; + if (msg.obj != null) { + Toast.makeText(GosConfigCountdownActivity.this, msg.obj.toString(), toastTime) + .show(); + } + Intent intent = new Intent(GosConfigCountdownActivity.this, GosConfigFailedActivity.class); + startActivity(intent); + finish(); + break; + + + default: + break; + + } + } + }; + + // 屏蔽掉返回键 + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + quitAlert(this, timer); + return true; + } + return false; + } + + // 倒计时 + public void isStartTimer() { + secondleft = 60; + timer = new Timer(); + // 切换至设备热点 + wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); + final WifiAutoConnectManager.WifiCipherType cipherType = WifiAutoConnectManager.getCipherType(GosConfigCountdownActivity.this, softSSID); + final WifiAutoConnectManager manager = new WifiAutoConnectManager(wifiManager); + timer.schedule(new TimerTask() { + @Override + public void run() { + if (isShowing) { + manager.connect(softSSID, SoftAP_PSW, cipherType); + } + secondleft--; + rpbConfig.setProgress((60 - secondleft) * (100 / 60.0)); + if (secondleft == 1) { + handler.sendEmptyMessage(handler_key.FAILED.ordinal()); + timer.cancel(); + } + + } + }, 1000, 1000); + } + + private void readyToSoftAP() { + + IntentFilter filter = new IntentFilter(); + filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); + + workSSID = spf.getString("workSSID", ""); + workSSIDPsw = spf.getString("workSSIDPsw", ""); + if (!workSSIDPsw.isEmpty() && workSSIDPsw.equals(GosConstant.SSIDPsw)) { + GosConstant.isOpenHot = true; + } + //新加 + handler.sendEmptyMessage(handler_key.START_TIMER.ordinal()); + isChecked = true; + while (isChecked) { + String presentSSID = NetUtils.getCurentWifiSSID(GosConfigCountdownActivity.this); + if (!TextUtils.isEmpty(presentSSID) && presentSSID.contains(SoftAP_Start)) { + if (checkNetwork(GosConfigCountdownActivity.this)) { + String connectWifiSsid = NetUtils.getConnectWifiSsid(GosConfigCountdownActivity.this); + isShowing = false; + isChecked = false; + //handler.sendEmptyMessage(handler_key.START_TIMER.ordinal()); + switch (GosConstant.mNew) { + case 0: + GizWifiSDK.sharedInstance().setDeviceOnboarding(workSSID, workSSIDPsw, + GizWifiConfigureMode.GizWifiSoftAP, presentSSID, 60, modeList); + break; + case 1: + GizWifiSDK.sharedInstance().setDeviceOnboardingByBind(workSSID, workSSIDPsw, + GizWifiConfigureMode.GizWifiSoftAP, presentSSID, 60, modeList); + break; + case 2: + GizWifiSDK.sharedInstance().setDeviceOnboardingDeploy(workSSID, workSSIDPsw, + GizWifiConfigureMode.GizWifiSoftAP, presentSSID, 60, modeList, false); + break; + case 3: + GizWifiSDK.sharedInstance().setDeviceOnboardingDeploy(workSSID, workSSIDPsw, + GizWifiConfigureMode.GizWifiSoftAP, presentSSID, 60, modeList, true); + break; + } + if (GosConstant.isOpenHot) { + final Timer mtimer1 = new Timer(); + mtimer1.schedule(new TimerTask() { + @Override + public void run() { + handler.sendEmptyMessage(handler_key.OPEN_HOT.ordinal()); + } + }, 5 * 1000); + } + // handler.sendEmptyMessageDelayed(handler_key.OFFTIME.ordinal(), 2000); + } + if (broadcase == null && !GosConstant.isOpenHot) { + broadcase = new GosWifiChangeReciver(); + registerReceiver(broadcase, filter); + } + + } + } + } + + + private WifiManager wifiManager = null; + + + // wifi热点开关 + public boolean setWifiApEnabled(boolean enabled) { + //获取wifi管理服务 + if (enabled) { // disable WiFi in any case + //wifi和热点不能同时打开,所以打开热点的时候需要关闭wifi + wifiManager.setWifiEnabled(false); + } + try { + //热点的配置类 + WifiConfiguration apConfig = new WifiConfiguration(); + //配置热点的名称(可以在名字后面加点随机数什么的) + if (SSID == null && SSID.equals("")) { + SSID = android.os.Build.MODEL; + apConfig.SSID = SSID; + apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + } else if (SSIDPsw == null && SSIDPsw.equals("")) { + apConfig.SSID = SSID; + apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + } else { + apConfig.SSID = SSID; + //配置热点的密码 + apConfig.preSharedKey = SSIDPsw; + //返回热点打开状态 +// for (int i = 0; i < WifiConfiguration.KeyMgmt.strings.length; i++) { +// if ("WPA2_PSK".equals(WifiConfiguration.KeyMgmt.strings[i])) { +// apConfig.allowedKeyManagement.set(i);//直接给它赋索引的值 +// Log.e("wpa2索引", String.valueOf(i));//结果是4 +// } +// } + apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);//直接给它赋索引的值 + } + //通过反射调用设置热点 + Method method = wifiManager.getClass().getMethod( + "setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE); + //返回热点打开状态 + return (Boolean) method.invoke(wifiManager, apConfig, enabled); + } catch(Exception e) { + return false; + } + + } + + + /** + * 设备配置回调 + * + * @param result 错误码 + * @param mac MAC + * @param did DID + * @param productKey PK + */ + protected void didSetDeviceOnboarding(GizWifiErrorCode result, String mac, String did, String productKey) { + if (GizWifiErrorCode.GIZ_SDK_DEVICE_CONFIG_IS_RUNNING == result) { + return; + } + if (timer != null) { + timer.cancel(); + } + Message message = new Message(); + if (result == GizWifiErrorCode.GIZ_SDK_SUCCESS) { + message.what = handler_key.SUCCESSFUL.ordinal(); + } else if (result == GIZ_SDK_ONBOARDING_STOPPED) { + + } else { + message.what = handler_key.FAILED.ordinal(); + message.obj = toastError(result); + } + handler.sendMessage(message); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + isChecked = false; + if (timer != null) { + timer.cancel(); + } + if (broadcase != null) { + unregisterReceiver(broadcase); + broadcase = null; + } + + + } +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigFailedActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigFailedActivity.java new file mode 100644 index 0000000..b2a00e9 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigFailedActivity.java @@ -0,0 +1,118 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.content.Intent; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosMainActivity; +import com.gizwits.opensource.appkit.utils.ToolUtils; + +public class GosConfigFailedActivity extends GosConfigModuleBaseActivity implements OnClickListener { + + /** + * The btn Again + */ + Button btnAgain; + + /** + * The soft SSID + */ + String softSSID; + + /** + * The data + */ + String promptText, cancelBesureText, beSureText, cancelText; + private boolean isAirLink; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_config_failed); + // 设置ActionBar + setToolBar(false, R.string.join_failed_title); + TextView tvLeft = (TextView) findViewById(R.id.tvLeft); + tvLeft.setVisibility(View.VISIBLE); + SpannableString ssTitle = new SpannableString(this.getString(R.string.cancel)); + ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvLeft.setText(ssTitle); + tvLeft.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(GosConfigFailedActivity.this, GosMainActivity.class); + quitAlert(GosConfigFailedActivity.this, intent); + } + }); + initView(); + initEvent(); + initData(); + } + + private void initView() { + btnAgain = (Button) findViewById(R.id.btnAgain); + + // 配置文件部署 + btnAgain.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnAgain.setTextColor(GosDeploy.appConfig_Contrast()); + } + + private void initEvent() { + btnAgain.setOnClickListener(this); + } + + private void initData() { + /** 判断是否是从一键配置界面传过去的 */ + isAirLink = getIntent().getBooleanExtra("isAirLink", false); + promptText = (String) getText(R.string.prompt); + cancelBesureText = (String) getText(R.string.cancel_besure); + beSureText = (String) getText(R.string.besure); + cancelText = (String) getText(R.string.cancel); + } + + // 屏蔽掉返回键 + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + Intent intent = new Intent(GosConfigFailedActivity.this, GosMainActivity.class); + quitAlert(this, intent); + return true; + } + return false; + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btnAgain: + if (ToolUtils.noDoubleClick()) { + if (isAirLink) { + //config_airlink-false-start + Intent intent = new Intent(this, GosAirlinkChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + //config_airlink-false-end + } else { + // config_softap-false-start + Intent intent = new Intent(this, GosChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + // config_softap-false-end + } + + } + + break; + + default: + break; + } + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigModuleBaseActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigModuleBaseActivity.java new file mode 100644 index 0000000..4597b29 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosConfigModuleBaseActivity.java @@ -0,0 +1,238 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiDevice; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizWifiSDKListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; + +import java.util.List; +import java.util.Timer; + +public class GosConfigModuleBaseActivity extends GosBaseActivity { + + private GizWifiSDKListener gizWifiSDKListener = new GizWifiSDKListener() { + + /** 用于设备配置 */ + public void didSetDeviceOnboarding(GizWifiErrorCode result, String mac, String did, String productKey) { + GosConfigModuleBaseActivity.this.didSetDeviceOnboarding(result, mac, did, productKey); + } + + }; + + /** + * 设备配置回调 + * + * @param result 错误码 + * @param mac MAC + * @param did DID + * @param productKey PK + */ + protected void didSetDeviceOnboarding(GizWifiErrorCode result, String mac, String did, String productKey) { + } + + @Override + protected void onResume() { + super.onResume(); + // 每次返回activity都要注册一次sdk监听器,保证sdk状态能正确回调 + GizWifiSDK.sharedInstance().setListener(gizWifiSDKListener); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + break; + } + return super.onOptionsItemSelected(item); + } + + /** + * 推出提示 + * + * @param context 当前上下文 + */ + protected void quitAlert(Context context, final Intent intent) { + final Dialog dialog = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + if (dialog.isShowing()) { + dialog.cancel(); + } + startActivity(intent); + + } + }); + } + + /** + * 推出提示 + * + * @param context 当前上下文 + */ + protected void quitAlert(Context context) { + final Dialog dialog = new AlertDialog.Builder(context, R.style.alert_dialog_style).setView(new EditText(context)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + if (dialog.isShowing()) { + dialog.cancel(); + } + finish(); + + } + }); + } + + /** + * 推出提示 + * + * @param context 当前上下文 + */ + protected void quitAlert(Context context, final Intent intent, String content) { + final Dialog dialog = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + TextView tvContent; + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + tvContent = (TextView) window.findViewById(R.id.tv_prompt); + + tvContent.setText(content); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + GizWifiSDK.sharedInstance().stopDeviceOnboarding(); + startActivity(intent); + } + }); + } + + + /** + * 退出提示 + * + * @param context 当前上下文 + * @param timer 已开启定时器 + */ + protected void quitAlert(Context context, final Timer timer) { + final Dialog dialog = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + GizWifiSDK.sharedInstance().stopDeviceOnboarding(); + if (timer != null) { + timer.cancel(); + } + if (dialog.isShowing()) { + dialog.cancel(); + } + finish(); + } + }); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceReadyActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceReadyActivity.java new file mode 100644 index 0000000..e8851a8 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceReadyActivity.java @@ -0,0 +1,139 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosMainActivity; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.AssetsUtils; +import com.gizwits.opensource.appkit.utils.ToolUtils; + +public class GosDeviceReadyActivity extends GosConfigModuleBaseActivity implements OnClickListener { + + /** + * The tv Ready + */ + TextView tvReady; + + /** + * The tv DeviceTip + */ + TextView tvDeviceTips; + + /** + * The btn Next + */ + Button btnNext; + + private int sum = 0; + /** + * The flag + */ + boolean flag = false; + + boolean isAirLink = false; + private ImageView ivReady; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_device_ready); + // 设置ActionBar + setToolBar(true, R.string.model_confirmation); + /** 判断是否是从一键配置界面传过去的 */ + isAirLink = getIntent().getBooleanExtra("isAirLink", false); + + initView(); + initEvent(); + } + + private void initView() { + tvReady = (TextView) findViewById(R.id.tvReady); + tvDeviceTips = (TextView) findViewById(R.id.tvDeviceTip); + btnNext = (Button) findViewById(R.id.btnNext); + ivReady = (ImageView) findViewById(R.id.ivReady); + SpannableString spannableString = new SpannableString(getString(R.string.common_ready_message)); + if (AssetsUtils.isZh(this)) { + spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#FF9500")), 9, 14, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else { + spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#FF9500")), 28, 45, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + tvReady.setText(spannableString); + + // 配置文件部署 + btnNext.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnNext.setTextColor(GosDeploy.appConfig_Contrast()); + + } + + private void initEvent() { + btnNext.setOnClickListener(this); + tvDeviceTips.setOnClickListener(this); + ivReady.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + + case R.id.btnNext: + if (ToolUtils.noDoubleClick()) { + sum = 0; + Intent intent2 = new Intent(GosDeviceReadyActivity.this, GosChooseDeviceActivity.class); + startActivity(intent2); + } + + break; + + default: + break; + } + } + + // 屏蔽掉返回键 + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + sum = 0; + if (isAirLink) { + Intent intent = new Intent(GosDeviceReadyActivity.this, GosMainActivity.class); + startActivity(intent); + } else { + finish(); + } + return true; + } + return false; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + sum = 0; + if (isAirLink) { + Intent intent = new Intent(GosDeviceReadyActivity.this, GosMainActivity.class); + startActivity(intent); + } else { + finish(); + } + break; + } + return true; + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceResetActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceResetActivity.java new file mode 100644 index 0000000..f2aec95 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosDeviceResetActivity.java @@ -0,0 +1,143 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; + +public class GosDeviceResetActivity extends GosConfigModuleBaseActivity implements OnClickListener { + + /** + * The cb Select + */ + CheckBox cbSelect; + + /** + * The tv Select + */ + TextView tvSelect; + + /** + * The btn Next + */ + Button btnNext; + + /** + * The flag + */ + String flag; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.actvity_gos_device_reset); + // 设置ActionBar + setToolBar(true, R.string.reset_device); + + initView(); + initEvent(); + } + + private void initView() { + cbSelect = (CheckBox) findViewById(R.id.cbSelect); + tvSelect = (TextView) findViewById(R.id.tvSelect); + btnNext = (Button) findViewById(R.id.btnNext); + + + /** 加载标志位 */ + flag = getIntent().getStringExtra("flag").toString(); + + // 配置文件部署 + btnNext.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnNext.setTextColor(GosDeploy.appConfig_Contrast()); + + } + + private void initEvent() { + btnNext.setOnClickListener(this); + tvSelect.setOnClickListener(this); + btnNext.setClickable(false); + btnNext.setBackgroundResource(R.drawable.btn_next_shape_gray); + + cbSelect.setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + btnNext.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnNext.setClickable(true); + } else { + btnNext.setBackgroundResource(R.drawable.btn_next_shape_gray); + btnNext.setClickable(false); + } + + } + }); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btnNext: + if (TextUtils.isEmpty(flag)) { + Intent intent = new Intent(GosDeviceResetActivity.this, GosChooseDeviceActivity.class); + startActivity(intent); + } + finish(); + + break; + + case R.id.tvSelect: + if (cbSelect.isChecked()) { + cbSelect.setChecked(false); + } else { + cbSelect.setChecked(true); + } + break; + + default: + break; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + if (TextUtils.isEmpty(flag)) { + Intent intent = new Intent(GosDeviceResetActivity.this, GosDeviceReadyActivity.class); + startActivity(intent); + overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); + } + this.finish(); + + break; + } + return true; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + if (TextUtils.isEmpty(flag)) { + Intent intent = new Intent(GosDeviceResetActivity.this, GosDeviceReadyActivity.class); + startActivity(intent); + overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); + } + this.finish(); + + } + return true; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity.java new file mode 100644 index 0000000..68266e1 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity.java @@ -0,0 +1,222 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.content.Context; +import android.content.Intent; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.utils.ToolUtils; + +import org.json.JSONArray; +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.List; + +public class GosModeListActivity extends GosConfigModuleBaseActivity { + + /** + * The lv Mode + */ + ListView lvMode; + + /** + * The data + */ + List modeList; + + /** + * The Adapter + */ + ModeListAdapter modeListAdapter; + + List list = new ArrayList(); + + private Button btnOk; + + private boolean isAirlink = true; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_modelist); + // 设置ActionBar + setToolBar(true, R.string.choose_mode_start); + final Drawable add = getResources().getDrawable(R.drawable.config_help_button); + int color = GosDeploy.appConfig_Contrast(); + add.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + mToolbar.setOverflowIcon(add); + initData(); + initView(); + initEvent(); + } + + private void initView() { + lvMode = (ListView) findViewById(R.id.lvMode); + + lvMode.setAdapter(modeListAdapter);// 初始化 + + btnOk = (Button) findViewById(R.id.btnOk); + btnOk.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnOk.setTextColor(GosDeploy.appConfig_Contrast()); + + } + + private void initEvent() { + + lvMode.setOnItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { + modeListAdapter.selectIndex = arg2; + modeListAdapter.notifyDataSetChanged(); + } + }); + + btnOk.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (ToolUtils.noDoubleClick()) { + if (modeListAdapter.selectIndex == 100) { + Toast.makeText(GosModeListActivity.this, getString(R.string.selece_module_type), toastTime).show(); + } else { + JSONArray array = new JSONArray(); + array.put(modeListAdapter.selectIndex); + spf.edit().putString("modulestyles", array.toString()).commit(); + if (isAirlink) { + // config_airlink-false-start + Intent intent = new Intent(GosModeListActivity.this, GosAirlinkReadyActivity.class); + startActivity(intent); + // config_airlink-false-end + } else { + //config_softap-false-start + Intent intent = new Intent(GosModeListActivity.this, GosDeviceReadyActivity.class); + startActivity(intent); + //config_softap-false-end + } + } + } + + } + }); + } + + private void initData() { + isAirlink = getIntent().getBooleanExtra("isAirlink", true); + modeList = new ArrayList(); + String[] modes = this.getResources().getStringArray(R.array.mode); + for (String string : modes) { + modeList.add(string); + } + modeListAdapter = new ModeListAdapter(this, modeList); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.module_style, menu); + return super.onCreateOptionsMenu(menu); + } + + class ModeListAdapter extends BaseAdapter { + + Context context; + List modeList; + int selectIndex = 100; + + public ModeListAdapter(Context context, List modeList) { + super(); + this.context = context; + this.modeList = modeList; + if (spf.getString("modulestyles", null) != null) { + try { + JSONArray array = new JSONArray(spf.getString("modulestyles", null)); + for (int i = 0; i < array.length(); i++) { + selectIndex = Integer.parseInt(array.get(i).toString()); + } + } catch(JSONException e) { + e.printStackTrace(); + } + } + } + + @Override + public int getCount() { + return modeList.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (null == convertView) { + convertView = View.inflate(context, R.layout.item_gos_mode_list, null); + } + + TextView tvModeText = (TextView) convertView.findViewById(R.id.tvModeText); + + String modeText = modeList.get(position); + tvModeText.setText(modeText); + + ImageView ivChoosed = (ImageView) convertView.findViewById(R.id.ivChoosed); + if (selectIndex == position) { + ivChoosed.setVisibility(View.VISIBLE); + } else { + ivChoosed.setVisibility(View.GONE); + } + + + return convertView; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); + break; + case R.id.module_help: + if (ToolUtils.noDoubleClick()) { + startActivity(new Intent(GosModeListActivity.this, GosChooseModuleHelpActivity.class)); + } + break; + } + return true; + } + +// @Override +// public boolean onKeyDown(int keyCode, KeyEvent event) { +// Intent intent = new Intent(this, GosAirlinkChooseDeviceWorkWiFiActivity.class); +// startActivity(intent); +// overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); +// this.finish(); +// return true; +// } + +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity2.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity2.java new file mode 100644 index 0000000..c2391e9 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosModeListActivity2.java @@ -0,0 +1,219 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.utils.ToolUtils; + +import org.json.JSONArray; +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.List; + +public class GosModeListActivity2 extends GosConfigModuleBaseActivity { + + /** + * The lv Mode + */ + ListView lvMode; + + /** + * The data + */ + List modeList; + + /** + * The Adapter + */ + ModeListAdapter modeListAdapter; + + List list = new ArrayList(); + + private Button btnOk; + private boolean isAirlink = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_modelist); + // 设置ActionBar + setToolBar(true, R.string.choose_mode_start); + initData(); + initView(); + initEvent(); + } + + private void initView() { + lvMode = (ListView) findViewById(R.id.lvMode); + + lvMode.setAdapter(modeListAdapter);// 初始化 + + btnOk = (Button) findViewById(R.id.btnOk); + btnOk.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnOk.setTextColor(GosDeploy.appConfig_Contrast()); + } + + private void initEvent() { + + lvMode.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { + boolean isRemove = false; + for (int i = 0; i < list.size(); i++) { + if (list.get(i) == arg2) { + list.remove(i); + isRemove = true; + } + } + if (!isRemove) { + list.add(arg2); + } + modeListAdapter.notifyDataSetChanged(); + } + }); + + + btnOk.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (ToolUtils.noDoubleClick()) { + if (list.size() == 0) { + Toast.makeText(GosModeListActivity2.this, getString(R.string.selece_module_type), toastTime).show(); + } else { + JSONArray array = new JSONArray(); + for (int i = 0; i < list.size(); i++) { + array.put(list.get(i)); + } + Log.e("TAG", "onClick: " + array.toString()); + spf.edit().putString("modulestyles", array.toString()).commit(); + if (isAirlink) { + // config_airlink-false-start + Intent intent = new Intent(GosModeListActivity2.this, GosAirlinkReadyActivity.class); + startActivity(intent); + // config_airlink-false-end + } else { + //config_softap-false-start + Intent intent = new Intent(GosModeListActivity2.this, GosDeviceReadyActivity.class); + startActivity(intent); + //config_softap-false-end + } + } + } + + } + }); + } + + private void initData() { + isAirlink = getIntent().getBooleanExtra("isAirlink", true); + String modules = spf.getString("modulestyles", null); + if (modules != null) { + try { + JSONArray array = new JSONArray(modules); + for (int i = 0; i < array.length(); i++) { + int type = (Integer) array.get(i); + list.add(type); + } + } catch(JSONException e) { + e.printStackTrace(); + } + } + modeList = new ArrayList(); + String[] modes = this.getResources().getStringArray(R.array.mode); + for (String string : modes) { + modeList.add(string); + } + modeListAdapter = new ModeListAdapter(this, modeList); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.module_style, menu); + MenuItem menuItem = menu.findItem(R.id.module_help); + menuItem.setIcon(ToolUtils.editIcon(getResources(), R.drawable.config_help_button)); + return super.onCreateOptionsMenu(menu); + } + + class ModeListAdapter extends BaseAdapter { + + Context context; + List modeList; + + public ModeListAdapter(Context context, List modeList) { + super(); + this.context = context; + this.modeList = modeList; + } + + @Override + public int getCount() { + return modeList.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (null == convertView) { + convertView = View.inflate(context, R.layout.item_gos_mode_list, null); + } + + TextView tvModeText = (TextView) convertView.findViewById(R.id.tvModeText); + + String modeText = modeList.get(position); + tvModeText.setText(modeText); + + ImageView ivChoosed = (ImageView) convertView.findViewById(R.id.ivChoosed); + if (list.contains(position)) { + ivChoosed.setVisibility(View.VISIBLE); + } else { + ivChoosed.setVisibility(View.GONE); + } + + return convertView; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right); + break; + case R.id.module_help: + if (ToolUtils.noDoubleClick()) { + startActivity(new Intent(GosModeListActivity2.this, GosChooseModuleHelpActivity.class)); + } + break; + } + return true; + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/GosWifiChangeReciver.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosWifiChangeReciver.java new file mode 100644 index 0000000..f78f158 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/GosWifiChangeReciver.java @@ -0,0 +1,36 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.utils.NetUtils; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.wifi.WifiManager; + + +public class GosWifiChangeReciver extends BroadcastReceiver { + + SharedPreferences spf; + + @Override + public void onReceive(Context context, Intent intent) { + + spf = context.getSharedPreferences(GosBaseActivity.SPF_Name, Context.MODE_PRIVATE); + + String wifiname = spf.getString("workSSID", ""); + String wifipass = spf.getString("workSSIDPsw", ""); + String connectWifiSsid = NetUtils.getConnectWifiSsid(context); + if (connectWifiSsid != null && connectWifiSsid.contains(GosBaseActivity.SoftAP_Start)) { + } else { + if (connectWifiSsid.contains(wifiname)) { + return; + } + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + WifiAutoConnectManager manager = new WifiAutoConnectManager(wifiManager); + manager.connect(wifiname, wifipass, WifiAutoConnectManager.getCipherType(context, wifiname)); + + } + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ConfigModule/WifiAutoConnectManager.java b/src/java/com/gizwits/opensource/appkit/ConfigModule/WifiAutoConnectManager.java new file mode 100644 index 0000000..9ba59e7 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ConfigModule/WifiAutoConnectManager.java @@ -0,0 +1,231 @@ +package com.gizwits.opensource.appkit.ConfigModule; + +import android.content.Context; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.AuthAlgorithm; +import android.net.wifi.WifiConfiguration.KeyMgmt; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.Log; + +import java.util.List; + +public class WifiAutoConnectManager { + + private static final String TAG = WifiAutoConnectManager.class + .getSimpleName(); + + WifiManager wifiManager; + + // 定义几种加密方式,一种是WEP,一种是WPA,还有没有密码的情况 + public enum WifiCipherType { + WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID + } + + // 构造函数 + public WifiAutoConnectManager(WifiManager wifiManager) { + this.wifiManager = wifiManager; + } + + // 提供一个外部接口,传入要连接的无线网 + public void connect(String ssid, String password, WifiCipherType type) { + Thread thread = new Thread(new ConnectRunnable(ssid, password, type)); + thread.start(); + } + + // 查看以前是否也配置过这个网络 + private WifiConfiguration isExsits(String SSID) { + List existingConfigs = wifiManager + .getConfiguredNetworks(); + if (existingConfigs != null) { + for (WifiConfiguration existingConfig : existingConfigs) { + if (existingConfig.SSID != null) { + if (existingConfig.SSID.equals("\"" + SSID + "\"")) { + return existingConfig; + } + } + } + } + return null; + } + + private WifiConfiguration createWifiInfo(String SSID, String Password, + WifiCipherType Type) { + WifiConfiguration config = new WifiConfiguration(); + config.allowedAuthAlgorithms.clear(); + config.allowedGroupCiphers.clear(); + config.allowedKeyManagement.clear(); + config.allowedPairwiseCiphers.clear(); + config.allowedProtocols.clear(); + config.SSID = "\"" + SSID + "\""; + // config.SSID = SSID; + // nopass + if (Type == WifiCipherType.WIFICIPHER_NOPASS) { + // config.wepKeys[0] = ""; + config.allowedKeyManagement.set(KeyMgmt.NONE); + // config.wepTxKeyIndex = 0; + } + // wep + if (Type == WifiCipherType.WIFICIPHER_WEP) { + if (!TextUtils.isEmpty(Password)) { + if (isHexWepKey(Password)) { + config.wepKeys[0] = Password; + } else { + config.wepKeys[0] = "\"" + Password + "\""; + } + } + config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); + config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); + config.allowedKeyManagement.set(KeyMgmt.NONE); + config.wepTxKeyIndex = 0; + } + // wpa + if (Type == WifiCipherType.WIFICIPHER_WPA) { + config.preSharedKey = "\"" + Password + "\""; + config.hiddenSSID = true; + config.allowedAuthAlgorithms + .set(AuthAlgorithm.OPEN); + config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); + config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); + config.allowedPairwiseCiphers + .set(WifiConfiguration.PairwiseCipher.TKIP); + // 此处需要修改否则不能自动重联 + // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA); + config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); + config.allowedPairwiseCiphers + .set(WifiConfiguration.PairwiseCipher.CCMP); + config.status = WifiConfiguration.Status.ENABLED; + + } + return config; + } + + // 打开wifi功能 + private boolean openWifi() { + boolean bRet = true; + if (!wifiManager.isWifiEnabled()) { + bRet = wifiManager.setWifiEnabled(true); + } + return bRet; + } + + // 关闭WIFI + private void closeWifi() { + if (wifiManager.isWifiEnabled()) { + wifiManager.setWifiEnabled(false); + } + } + + class ConnectRunnable implements Runnable { + private String ssid; + + private String password; + + private WifiCipherType type; + + public ConnectRunnable(String ssid, String password, WifiCipherType type) { + this.ssid = ssid; + this.password = password; + this.type = type; + } + + @Override + public void run() { + // 打开wifi + openWifi(); + // 开启wifi功能需要一段时间(我在手机上测试一般需要1-3秒左右),所以要等到wifi + // 状态变成WIFI_STATE_ENABLED的时候才能执行下面的语句 + while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) { + try { + // 为了避免程序一直while循环,让它睡个100毫秒检测…… + Thread.sleep(100); + + } catch (InterruptedException ie) { + Log.i(TAG, ie.toString()); + } + } + + WifiConfiguration tempConfig = isExsits(ssid); + + if (tempConfig != null) { + // wifiManager.removeNetwork(tempConfig.networkId); + + boolean b = wifiManager.enableNetwork(tempConfig.networkId, + true); + } else { + WifiConfiguration wifiConfig = createWifiInfo(ssid, password, + type); + // + if (wifiConfig == null) { + Log.d(TAG, "wifiConfig is null!"); + return; + } + + int netID = wifiManager.addNetwork(wifiConfig); + boolean enabled = wifiManager.enableNetwork(netID, true); + Log.d(TAG, "enableNetwork status enable=" + enabled); + boolean connected = wifiManager.reconnect(); + Log.d(TAG, "enableNetwork connected=" + connected); + } + + } + } + + private static boolean isHexWepKey(String wepKey) { + final int len = wepKey.length(); + + // WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?) + if (len != 10 && len != 26 && len != 58) { + return false; + } + + return isHex(wepKey); + } + + private static boolean isHex(String key) { + for (int i = key.length() - 1; i >= 0; i--) { + final char c = key.charAt(i); + if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' + && c <= 'f')) { + return false; + } + } + + return true; + } + + // 获取ssid的加密方式 + + public static WifiCipherType getCipherType(Context context, String ssid) { + WifiManager wifiManager = (WifiManager) context + .getSystemService(Context.WIFI_SERVICE); + + List list = wifiManager.getScanResults(); + + for (ScanResult scResult : list) { + + if (!TextUtils.isEmpty(scResult.SSID) && scResult.SSID.equals(ssid)) { + String capabilities = scResult.capabilities; + // Log.i("hefeng","capabilities=" + capabilities); + + if (!TextUtils.isEmpty(capabilities)) { + + if (capabilities.contains("WPA") + || capabilities.contains("wpa")) { + Log.i("hefeng", "wpa"); + return WifiCipherType.WIFICIPHER_WPA; + } else if (capabilities.contains("WEP") + || capabilities.contains("wep")) { + Log.i("hefeng", "wep"); + return WifiCipherType.WIFICIPHER_WEP; + } else { + Log.i("hefeng", "no"); + return WifiCipherType.WIFICIPHER_NOPASS; + } + } + } + } + return WifiCipherType.WIFICIPHER_INVALID; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/ControlModule/.DS_Store b/src/java/com/gizwits/opensource/appkit/ControlModule/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 dataMap) { + // 已定义的设备数据点,有布尔、数值和枚举型数据 + + if (dataMap.get("data") != null) { + ConcurrentHashMap map = (ConcurrentHashMap) dataMap.get("data"); + for (String dataKey : map.keySet()) { + if (dataKey.equals(KEY_HREAT)) { + + data_hreat = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_HEARTUP)) { + + data_heartup = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_HEARTDW)) { + + data_heartdw = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_SPO2)) { + + data_spo2 = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_SPO2UP)) { + + data_spo2up = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_SPO2DW)) { + + data_spo2dw = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_TEMPUP)) { + + data_tempup = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_TEMPDW)) { + + data_tempdw = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_BUS)) { + + data_bus = (Integer) map.get(dataKey); + } + if (dataKey.equals(KEY_GPS_N)) { + + if (map.get(dataKey) instanceof Integer) { + data_GPS_N = (Integer) map.get(dataKey); + } else { + data_GPS_N = (Double) map.get(dataKey); + } + } + if (dataKey.equals(KEY_TEMP)) { + + if (map.get(dataKey) instanceof Integer) { + data_temp = (Integer) map.get(dataKey); + } else { + data_temp = (Double) map.get(dataKey); + } + } + if (dataKey.equals(KEY_GPS_E)) { + + if (map.get(dataKey) instanceof Integer) { + data_GPS_E = (Integer) map.get(dataKey); + } else { + data_GPS_E = (Double) map.get(dataKey); + } + } + } + } + + StringBuilder sBuilder = new StringBuilder(); + + // 已定义的设备报警数据点,设备发生报警后该字段有内容,没有发生报警则没内容 + if (dataMap.get("alerts") != null) { + ConcurrentHashMap map = (ConcurrentHashMap) dataMap.get("alerts"); + for (String alertsKey : map.keySet()) { + if ((Boolean) map.get(alertsKey)) { + sBuilder.append("报警:" + alertsKey + "=true" + "\n"); + } + } + } + + // 已定义的设备故障数据点,设备发生故障后该字段有内容,没有发生故障则没内容 + if (dataMap.get("faults") != null) { + ConcurrentHashMap map = (ConcurrentHashMap) dataMap.get("faults"); + for (String faultsKey : map.keySet()) { + if ((Boolean) map.get(faultsKey)) { + sBuilder.append("故障:" + faultsKey + "=true" + "\n"); + } + } + } + + if (sBuilder.length() > 0) { + sBuilder.insert(0, "[设备故障或报警]\n"); + myToast(sBuilder.toString().trim()); + } + + // 透传数据,无数据点定义,适合开发者自行定义协议自行解析 + if (dataMap.get("binary") != null) { + byte[] binary = (byte[]) dataMap.get("binary"); + Log.i("", "Binary data:" + HexStrUtils.bytesToHexString(binary)); + } + } + + GizWifiDeviceListener gizWifiDeviceListener = new GizWifiDeviceListener() { + + /** 用于设备订阅 */ + public void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + GosControlModuleBaseActivity.this.didSetSubscribe(result, device, isSubscribed); + }; + + /** 用于获取设备状态 */ + public void didReceiveData(GizWifiErrorCode result, GizWifiDevice device, + java.util.concurrent.ConcurrentHashMap dataMap, int sn) { + GosControlModuleBaseActivity.this.didReceiveData(result, device, dataMap, sn); + }; + + /** 用于设备硬件信息 */ + public void didGetHardwareInfo(GizWifiErrorCode result, GizWifiDevice device, + java.util.concurrent.ConcurrentHashMap hardwareInfo) { + GosControlModuleBaseActivity.this.didGetHardwareInfo(result, device, hardwareInfo); + }; + + /** 用于修改设备信息 */ + public void didSetCustomInfo(GizWifiErrorCode result, GizWifiDevice device) { + GosControlModuleBaseActivity.this.didSetCustomInfo(result, device); + }; + + /** 用于设备状态变化 */ + public void didUpdateNetStatus(GizWifiDevice device, GizWifiDeviceNetStatus netStatus) { + GosControlModuleBaseActivity.this.didUpdateNetStatus(device, netStatus); + }; + + }; + + /** + * 设备订阅回调 + * + * @param result + * 错误码 + * @param device + * 被订阅设备 + * @param isSubscribed + * 订阅状态 + */ + protected void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + } + + /** + * 设备状态回调 + * + * @param result + * 错误码 + * @param device + * 当前设备 + * @param dataMap + * 当前设备状态 + * @param sn + * 命令序号 + */ + protected void didReceiveData(GizWifiErrorCode result, GizWifiDevice device, + java.util.concurrent.ConcurrentHashMap dataMap, int sn) { + } + + /** + * 设备硬件信息回调 + * + * @param result + * 错误码 + * @param device + * 当前设备 + * @param hardwareInfo + * 当前设备硬件信息 + */ + protected void didGetHardwareInfo(GizWifiErrorCode result, GizWifiDevice device, + java.util.concurrent.ConcurrentHashMap hardwareInfo) { + } + + /** + * 修改设备信息回调 + * + * @param result + * 错误码 + * @param device + * 当前设备 + */ + protected void didSetCustomInfo(GizWifiErrorCode result, GizWifiDevice device) { + } + + /** + * 设备状态变化回调 + */ + protected void didUpdateNetStatus(GizWifiDevice device, GizWifiDeviceNetStatus netStatus) { + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + break; + } + return super.onOptionsItemSelected(item); + } + + public void myToast(String string) { + if (mToast != null) { + mToast.setText(string); + } else { + mToast = Toast.makeText(getApplicationContext(), string, Toast.LENGTH_LONG); + } + mToast.show(); + } + + protected void hideKeyBoard() { + // 隐藏键盘 + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0); + } + } + + + /** + *Description:显示格式化数值,保留对应分辨率的小数个数,比如传入参数(20.3656,0.01),将返回20.37 + *@param date 传入的数值 + *@param scale 保留多少位小数 + *@return + */ + protected String formatValue(double date, Object scale) { + if (scale instanceof Double) { + DecimalFormat df = new DecimalFormat(scale.toString()); + return df.format(date); + } + return Math.round(date) + ""; + } + +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/ControlModule/GosDeviceControlActivity.java b/src/java/com/gizwits/opensource/appkit/ControlModule/GosDeviceControlActivity.java new file mode 100644 index 0000000..eab6491 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ControlModule/GosDeviceControlActivity.java @@ -0,0 +1,603 @@ +package com.gizwits.opensource.appkit.ControlModule; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnDismissListener; +import android.content.Intent; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.Log; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.View.OnClickListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.Spinner; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; +import android.widget.Toast; + +import java.util.concurrent.ConcurrentHashMap; + +import com.gizwits.gizwifisdk.api.GizWifiDevice; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceNetStatus; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.HexStrUtils; +import com.gizwits.opensource.appkit.view.HexWatcher; + +public class GosDeviceControlActivity extends GosControlModuleBaseActivity + implements OnClickListener, OnEditorActionListener, OnSeekBarChangeListener { + + /** 设备列表传入的设备变量 */ + private GizWifiDevice mDevice; + + private TextView tv_data_hreat; + private SeekBar sb_data_hreat; + private TextView tv_data_heartup; + private SeekBar sb_data_heartup; + private TextView tv_data_heartdw; + private SeekBar sb_data_heartdw; + private TextView tv_data_spo2; + private SeekBar sb_data_spo2; + private TextView tv_data_spo2up; + private SeekBar sb_data_spo2up; + private TextView tv_data_spo2dw; + private SeekBar sb_data_spo2dw; + private TextView tv_data_tempup; + private SeekBar sb_data_tempup; + private TextView tv_data_tempdw; + private SeekBar sb_data_tempdw; + private TextView tv_data_bus; + private SeekBar sb_data_bus; + private TextView tv_data_GPS_N; + private SeekBar sb_data_GPS_N; + private TextView tv_data_temp; + private SeekBar sb_data_temp; + private TextView tv_data_GPS_E; + private SeekBar sb_data_GPS_E; + + private enum handler_key { + + /** 更新界面 */ + UPDATE_UI, + + DISCONNECT, + } + + private Runnable mRunnable = new Runnable() { + public void run() { + if (isDeviceCanBeControlled()) { + progressDialog.cancel(); + } else { + toastDeviceNoReadyAndExit(); + } + } + + }; + + /** The handler. */ + Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + case UPDATE_UI: + updateUI(); + break; + case DISCONNECT: + toastDeviceDisconnectAndExit(); + break; + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_device_control); + initDevice(); + setToolBar(true, getDeviceName()); + final Drawable add = getResources().getDrawable(R.drawable.common_setting_more); + int color = GosDeploy.appConfig_Contrast(); + add.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + mToolbar.setOverflowIcon(add); + initView(); + initEvent(); + } + + private void initView() { + + tv_data_hreat = (TextView) findViewById(R.id.tv_data_hreat); + sb_data_hreat = (SeekBar) findViewById(R.id.sb_data_hreat); + tv_data_heartup = (TextView) findViewById(R.id.tv_data_heartup); + sb_data_heartup = (SeekBar) findViewById(R.id.sb_data_heartup); + tv_data_heartdw = (TextView) findViewById(R.id.tv_data_heartdw); + sb_data_heartdw = (SeekBar) findViewById(R.id.sb_data_heartdw); + tv_data_spo2 = (TextView) findViewById(R.id.tv_data_spo2); + sb_data_spo2 = (SeekBar) findViewById(R.id.sb_data_spo2); + tv_data_spo2up = (TextView) findViewById(R.id.tv_data_spo2up); + sb_data_spo2up = (SeekBar) findViewById(R.id.sb_data_spo2up); + tv_data_spo2dw = (TextView) findViewById(R.id.tv_data_spo2dw); + sb_data_spo2dw = (SeekBar) findViewById(R.id.sb_data_spo2dw); + tv_data_tempup = (TextView) findViewById(R.id.tv_data_tempup); + sb_data_tempup = (SeekBar) findViewById(R.id.sb_data_tempup); + tv_data_tempdw = (TextView) findViewById(R.id.tv_data_tempdw); + sb_data_tempdw = (SeekBar) findViewById(R.id.sb_data_tempdw); + tv_data_bus = (TextView) findViewById(R.id.tv_data_bus); + sb_data_bus = (SeekBar) findViewById(R.id.sb_data_bus); + tv_data_GPS_N = (TextView) findViewById(R.id.tv_data_GPS_N); + sb_data_GPS_N = (SeekBar) findViewById(R.id.sb_data_GPS_N); + tv_data_temp = (TextView) findViewById(R.id.tv_data_temp); + sb_data_temp = (SeekBar) findViewById(R.id.sb_data_temp); + tv_data_GPS_E = (TextView) findViewById(R.id.tv_data_GPS_E); + sb_data_GPS_E = (SeekBar) findViewById(R.id.sb_data_GPS_E); + } + + private void initEvent() { + + sb_data_hreat.setOnSeekBarChangeListener(this); + sb_data_heartup.setOnSeekBarChangeListener(this); + sb_data_heartdw.setOnSeekBarChangeListener(this); + sb_data_spo2.setOnSeekBarChangeListener(this); + sb_data_spo2up.setOnSeekBarChangeListener(this); + sb_data_spo2dw.setOnSeekBarChangeListener(this); + sb_data_tempup.setOnSeekBarChangeListener(this); + sb_data_tempdw.setOnSeekBarChangeListener(this); + sb_data_bus.setOnSeekBarChangeListener(this); + sb_data_GPS_N.setOnSeekBarChangeListener(this); + sb_data_temp.setOnSeekBarChangeListener(this); + sb_data_GPS_E.setOnSeekBarChangeListener(this); + + } + + private void initDevice() { + Intent intent = getIntent(); + mDevice = (GizWifiDevice) intent.getParcelableExtra("GizWifiDevice"); + mDevice.setListener(gizWifiDeviceListener); + Log.i("Apptest", mDevice.getDid()); + } + + private String getDeviceName() { + if (TextUtils.isEmpty(mDevice.getAlias())) { + return mDevice.getProductName(); + } + return mDevice.getAlias(); + } + + @Override + protected void onResume() { + super.onResume(); + getStatusOfDevice(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mHandler.removeCallbacks(mRunnable); + // 退出页面,取消设备订阅 + mDevice.setSubscribe(false); + mDevice.setListener(null); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + default: + break; + } + } + + /* + * ======================================================================== + * EditText 点击键盘“完成”按钮方法 + * ======================================================================== + */ + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + + switch (v.getId()) { + default: + break; + } + hideKeyBoard(); + return false; + + } + + /* + * ======================================================================== + * seekbar 回调方法重写 + * ======================================================================== + */ + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + + switch (seekBar.getId()) { + case R.id.sb_data_hreat: + tv_data_hreat.setText(formatValue((progress + HREAT_OFFSET) * HREAT_RATIO + HREAT_ADDITION, 1)); + break; + case R.id.sb_data_heartup: + tv_data_heartup.setText(formatValue((progress + HEARTUP_OFFSET) * HEARTUP_RATIO + HEARTUP_ADDITION, 1)); + break; + case R.id.sb_data_heartdw: + tv_data_heartdw.setText(formatValue((progress + HEARTDW_OFFSET) * HEARTDW_RATIO + HEARTDW_ADDITION, 1)); + break; + case R.id.sb_data_spo2: + tv_data_spo2.setText(formatValue((progress + SPO2_OFFSET) * SPO2_RATIO + SPO2_ADDITION, 1)); + break; + case R.id.sb_data_spo2up: + tv_data_spo2up.setText(formatValue((progress + SPO2UP_OFFSET) * SPO2UP_RATIO + SPO2UP_ADDITION, 1)); + break; + case R.id.sb_data_spo2dw: + tv_data_spo2dw.setText(formatValue((progress + SPO2DW_OFFSET) * SPO2DW_RATIO + SPO2DW_ADDITION, 1)); + break; + case R.id.sb_data_tempup: + tv_data_tempup.setText(formatValue((progress + TEMPUP_OFFSET) * TEMPUP_RATIO + TEMPUP_ADDITION, 1)); + break; + case R.id.sb_data_tempdw: + tv_data_tempdw.setText(formatValue((progress + TEMPDW_OFFSET) * TEMPDW_RATIO + TEMPDW_ADDITION, 1)); + break; + case R.id.sb_data_bus: + tv_data_bus.setText(formatValue((progress + BUS_OFFSET) * BUS_RATIO + BUS_ADDITION, 1)); + break; + case R.id.sb_data_GPS_N: + tv_data_GPS_N.setText(formatValue((progress + GPS_N_OFFSET) * GPS_N_RATIO + GPS_N_ADDITION, 0.001)); + break; + case R.id.sb_data_temp: + tv_data_temp.setText(formatValue((progress + TEMP_OFFSET) * TEMP_RATIO + TEMP_ADDITION, 0.1)); + break; + case R.id.sb_data_GPS_E: + tv_data_GPS_E.setText(formatValue((progress + GPS_E_OFFSET) * GPS_E_RATIO + GPS_E_ADDITION, 0.001)); + break; + default: + break; + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + switch (seekBar.getId()) { + case R.id.sb_data_hreat: + sendCommand(KEY_HREAT, (seekBar.getProgress() + HREAT_OFFSET ) * HREAT_RATIO + HREAT_ADDITION); + break; + case R.id.sb_data_heartup: + sendCommand(KEY_HEARTUP, (seekBar.getProgress() + HEARTUP_OFFSET ) * HEARTUP_RATIO + HEARTUP_ADDITION); + break; + case R.id.sb_data_heartdw: + sendCommand(KEY_HEARTDW, (seekBar.getProgress() + HEARTDW_OFFSET ) * HEARTDW_RATIO + HEARTDW_ADDITION); + break; + case R.id.sb_data_spo2: + sendCommand(KEY_SPO2, (seekBar.getProgress() + SPO2_OFFSET ) * SPO2_RATIO + SPO2_ADDITION); + break; + case R.id.sb_data_spo2up: + sendCommand(KEY_SPO2UP, (seekBar.getProgress() + SPO2UP_OFFSET ) * SPO2UP_RATIO + SPO2UP_ADDITION); + break; + case R.id.sb_data_spo2dw: + sendCommand(KEY_SPO2DW, (seekBar.getProgress() + SPO2DW_OFFSET ) * SPO2DW_RATIO + SPO2DW_ADDITION); + break; + case R.id.sb_data_tempup: + sendCommand(KEY_TEMPUP, (seekBar.getProgress() + TEMPUP_OFFSET ) * TEMPUP_RATIO + TEMPUP_ADDITION); + break; + case R.id.sb_data_tempdw: + sendCommand(KEY_TEMPDW, (seekBar.getProgress() + TEMPDW_OFFSET ) * TEMPDW_RATIO + TEMPDW_ADDITION); + break; + case R.id.sb_data_bus: + sendCommand(KEY_BUS, (seekBar.getProgress() + BUS_OFFSET ) * BUS_RATIO + BUS_ADDITION); + break; + case R.id.sb_data_GPS_N: + sendCommand(KEY_GPS_N, (seekBar.getProgress() + GPS_N_OFFSET ) * GPS_N_RATIO + GPS_N_ADDITION); + break; + case R.id.sb_data_temp: + sendCommand(KEY_TEMP, (seekBar.getProgress() + TEMP_OFFSET ) * TEMP_RATIO + TEMP_ADDITION); + break; + case R.id.sb_data_GPS_E: + sendCommand(KEY_GPS_E, (seekBar.getProgress() + GPS_E_OFFSET ) * GPS_E_RATIO + GPS_E_ADDITION); + break; + default: + break; + } + } + + /* + * ======================================================================== + * 菜单栏 + * ======================================================================== + */ + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.device_more, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + + case R.id.action_setDeviceInfo: + setDeviceInfo(); + break; + + case R.id.action_getHardwareInfo: + if (mDevice.isLAN()) { + mDevice.getHardwareInfo(); + } else { + myToast("只允许在局域网下获取设备硬件信息!"); + } + break; + + case R.id.action_getStatu: + mDevice.getDeviceStatus(); + break; + + default: + break; + } + + return super.onOptionsItemSelected(item); + } + + /** + * Description:根据保存的的数据点的值来更新UI + */ + protected void updateUI() { + + tv_data_hreat.setText(data_hreat+""); + sb_data_hreat.setProgress((int)((data_hreat - HREAT_ADDITION) / HREAT_RATIO - HREAT_OFFSET)); + tv_data_heartup.setText(data_heartup+""); + sb_data_heartup.setProgress((int)((data_heartup - HEARTUP_ADDITION) / HEARTUP_RATIO - HEARTUP_OFFSET)); + tv_data_heartdw.setText(data_heartdw+""); + sb_data_heartdw.setProgress((int)((data_heartdw - HEARTDW_ADDITION) / HEARTDW_RATIO - HEARTDW_OFFSET)); + tv_data_spo2.setText(data_spo2+""); + sb_data_spo2.setProgress((int)((data_spo2 - SPO2_ADDITION) / SPO2_RATIO - SPO2_OFFSET)); + tv_data_spo2up.setText(data_spo2up+""); + sb_data_spo2up.setProgress((int)((data_spo2up - SPO2UP_ADDITION) / SPO2UP_RATIO - SPO2UP_OFFSET)); + tv_data_spo2dw.setText(data_spo2dw+""); + sb_data_spo2dw.setProgress((int)((data_spo2dw - SPO2DW_ADDITION) / SPO2DW_RATIO - SPO2DW_OFFSET)); + tv_data_tempup.setText(data_tempup+""); + sb_data_tempup.setProgress((int)((data_tempup - TEMPUP_ADDITION) / TEMPUP_RATIO - TEMPUP_OFFSET)); + tv_data_tempdw.setText(data_tempdw+""); + sb_data_tempdw.setProgress((int)((data_tempdw - TEMPDW_ADDITION) / TEMPDW_RATIO - TEMPDW_OFFSET)); + tv_data_bus.setText(data_bus+""); + sb_data_bus.setProgress((int)((data_bus - BUS_ADDITION) / BUS_RATIO - BUS_OFFSET)); + tv_data_GPS_N.setText(data_GPS_N+""); + sb_data_GPS_N.setProgress((int)((data_GPS_N - GPS_N_ADDITION) / GPS_N_RATIO - GPS_N_OFFSET)); + tv_data_temp.setText(data_temp+""); + sb_data_temp.setProgress((int)((data_temp - TEMP_ADDITION) / TEMP_RATIO - TEMP_OFFSET)); + tv_data_GPS_E.setText(data_GPS_E+""); + sb_data_GPS_E.setProgress((int)((data_GPS_E - GPS_E_ADDITION) / GPS_E_RATIO - GPS_E_OFFSET)); + + } + + private void setEditText(EditText et, Object value) { + et.setText(value.toString()); + et.setSelection(value.toString().length()); + et.clearFocus(); + } + + /** + * Description:页面加载后弹出等待框,等待设备可被控制状态回调,如果一直不可被控,等待一段时间后自动退出界面 + */ + private void getStatusOfDevice() { + // 设备是否可控 + if (isDeviceCanBeControlled()) { + // 可控则查询当前设备状态 + mDevice.getDeviceStatus(); + } else { + // 显示等待栏 + progressDialog.show(); + if (mDevice.isLAN()) { + // 小循环10s未连接上设备自动退出 + mHandler.postDelayed(mRunnable, 10000); + } else { + // 大循环20s未连接上设备自动退出 + mHandler.postDelayed(mRunnable, 20000); + } + } + } + + /** + * 发送指令,下发单个数据点的命令可以用这个方法 + * + *

注意

+ *

+ * 下发多个数据点命令不能用这个方法多次调用,一次性多次调用这个方法会导致模组无法正确接收消息,参考方法内注释。 + *

+ * + * @param key + * 数据点对应的标识名 + * @param value + * 需要改变的值 + */ + private void sendCommand(String key, Object value) { + if (value == null) { + return; + } + int sn = 5; + ConcurrentHashMap hashMap = new ConcurrentHashMap(); + hashMap.put(key, value); + // 同时下发多个数据点需要一次性在map中放置全部需要控制的key,value值 + // hashMap.put(key2, value2); + // hashMap.put(key3, value3); + mDevice.write(hashMap, sn); + Log.i("liang", "下发命令:" + hashMap.toString()); + } + + private boolean isDeviceCanBeControlled() { + return mDevice.getNetStatus() == GizWifiDeviceNetStatus.GizDeviceControlled; + } + + private void toastDeviceNoReadyAndExit() { + Toast.makeText(this, "设备无响应,请检查设备是否正常工作", Toast.LENGTH_SHORT).show(); + finish(); + } + + private void toastDeviceDisconnectAndExit() { + Toast.makeText(GosDeviceControlActivity.this, "连接已断开", Toast.LENGTH_SHORT).show(); + finish(); + } + + /** + * 展示设备硬件信息 + * + * @param hardwareInfo + */ + private void showHardwareInfo(String hardwareInfo) { + String hardwareInfoTitle = "设备硬件信息"; + new AlertDialog.Builder(this).setTitle(hardwareInfoTitle).setMessage(hardwareInfo) + .setPositiveButton(R.string.besure, null).show(); + } + + /** + * Description:设置设备别名与备注 + */ + private void setDeviceInfo() { + + final Dialog mDialog = new AlertDialog.Builder(this,R.style.edit_dialog_style).setView(new EditText(this)).create(); + mDialog.show(); + + Window window = mDialog.getWindow(); + window.setContentView(R.layout.alert_gos_set_device_info); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + final EditText etAlias; + final EditText etRemark; + etAlias = (EditText) window.findViewById(R.id.etAlias); + etRemark = (EditText) window.findViewById(R.id.etRemark); + + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + if (!TextUtils.isEmpty(mDevice.getAlias())) { + setEditText(etAlias, mDevice.getAlias()); + } + if (!TextUtils.isEmpty(mDevice.getRemark())) { + setEditText(etRemark, mDevice.getRemark()); + } + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + mDialog.dismiss(); + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (TextUtils.isEmpty(etRemark.getText().toString()) + && TextUtils.isEmpty(etAlias.getText().toString())) { + myToast("请输入设备别名或备注!"); + return; + } + mDevice.setCustomInfo(etRemark.getText().toString(), etAlias.getText().toString()); + mDialog.dismiss(); + String loadingText = (String) getText(R.string.loadingtext); + progressDialog.setMessage(loadingText); + progressDialog.show(); + } + }); + + mDialog.setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + hideKeyBoard(); + } + }); + } + + /* + * 获取设备硬件信息回调 + */ + @Override + protected void didGetHardwareInfo(GizWifiErrorCode result, GizWifiDevice device, + ConcurrentHashMap hardwareInfo) { + super.didGetHardwareInfo(result, device, hardwareInfo); + StringBuffer sb = new StringBuffer(); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + myToast("获取设备硬件信息失败:" + result.name()); + } else { + sb.append("Wifi Hardware Version:" + hardwareInfo.get(WIFI_HARDVER_KEY) + "\r\n"); + sb.append("Wifi Software Version:" + hardwareInfo.get(WIFI_SOFTVER_KEY) + "\r\n"); + sb.append("MCU Hardware Version:" + hardwareInfo.get(MCU_HARDVER_KEY) + "\r\n"); + sb.append("MCU Software Version:" + hardwareInfo.get(MCU_SOFTVER_KEY) + "\r\n"); + sb.append("Wifi Firmware Id:" + hardwareInfo.get(WIFI_FIRMWAREID_KEY) + "\r\n"); + sb.append("Wifi Firmware Version:" + hardwareInfo.get(WIFI_FIRMWAREVER_KEY) + "\r\n"); + sb.append("Product Key:" + "\r\n" + hardwareInfo.get(PRODUCT_KEY) + "\r\n"); + + // 设备属性 + sb.append("Device ID:" + "\r\n" + mDevice.getDid() + "\r\n"); + sb.append("Device IP:" + mDevice.getIPAddress() + "\r\n"); + sb.append("Device MAC:" + mDevice.getMacAddress() + "\r\n"); + } + showHardwareInfo(sb.toString()); + } + + /* + * 设置设备别名和备注回调 + */ + @Override + protected void didSetCustomInfo(GizWifiErrorCode result, GizWifiDevice device) { + super.didSetCustomInfo(result, device); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS == result) { + myToast("设置成功"); + progressDialog.cancel(); + finish(); + } else { + myToast("设置失败:" + result.name()); + } + } + + /* + * 设备状态改变回调,只有设备状态为可控才可以下发控制命令 + */ + @Override + protected void didUpdateNetStatus(GizWifiDevice device, GizWifiDeviceNetStatus netStatus) { + super.didUpdateNetStatus(device, netStatus); + if (netStatus == GizWifiDeviceNetStatus.GizDeviceControlled) { + mHandler.removeCallbacks(mRunnable); + progressDialog.cancel(); + } else { + mHandler.sendEmptyMessage(handler_key.DISCONNECT.ordinal()); + } + } + + /* + * 设备上报数据回调,此回调包括设备主动上报数据、下发控制命令成功后设备返回ACK + */ + @Override + protected void didReceiveData(GizWifiErrorCode result, GizWifiDevice device, + ConcurrentHashMap dataMap, int sn) { + super.didReceiveData(result, device, dataMap, sn); + Log.i("liang", "接收到数据"); + if (result == GizWifiErrorCode.GIZ_SDK_SUCCESS && dataMap.get("data") != null) { + getDataFromReceiveDataMap(dataMap); + mHandler.sendEmptyMessage(handler_key.UPDATE_UI.ordinal()); + } + } + +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosBaseFragment.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosBaseFragment.java new file mode 100644 index 0000000..3cd8df7 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosBaseFragment.java @@ -0,0 +1,735 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v4.app.Fragment; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; + +/** + * author: smile . + * date: On 2018/6/7 + */ +public class GosBaseFragment extends Fragment { + /** + * 存储器 + */ + public SharedPreferences spf; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + spf = getActivity().getSharedPreferences("set", Context.MODE_PRIVATE); + } + public String toastError(GizWifiErrorCode errorCode) { + String errorString = (String) getText(R.string.UNKNOWN_ERROR); + switch (errorCode) { + case GIZ_SDK_SUCCESS: + errorString=(String)getText(R.string.GIZ_SDK_SUCCESS); + break; + case GIZ_SDK_PARAM_FORM_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PARAM_FORM_INVALID); + break; + case GIZ_SDK_CLIENT_NOT_AUTHEN: + errorString = (String) getText(R.string.GIZ_SDK_CLIENT_NOT_AUTHEN); + break; + case GIZ_SDK_CLIENT_VERSION_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_CLIENT_VERSION_INVALID); + break; + case GIZ_SDK_UDP_PORT_BIND_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_UDP_PORT_BIND_FAILED); + break; + case GIZ_SDK_DAEMON_EXCEPTION: + errorString = (String) getText(R.string.GIZ_SDK_DAEMON_EXCEPTION); + break; + case GIZ_SDK_PARAM_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PARAM_INVALID); + break; + case GIZ_SDK_APPID_LENGTH_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_APPID_LENGTH_ERROR); + break; + case GIZ_SDK_LOG_PATH_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_LOG_PATH_INVALID); + break; + case GIZ_SDK_LOG_LEVEL_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_LOG_LEVEL_INVALID); + break; + case GIZ_SDK_UID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_UID_INVALID); + break; + case GIZ_SDK_TOKEN_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_TOKEN_INVALID); + break; + case GIZ_SDK_USER_NOT_LOGIN: + errorString = (String) getText(R.string.GIZ_SDK_USER_NOT_LOGIN); + break; + case GIZ_SDK_APPID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_APPID_INVALID); + break; + case GIZ_SDK_APP_SECRET_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_APP_SECRET_INVALID); + break; + case GIZ_SDK_PRODUCT_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCT_KEY_INVALID); + break; + case GIZ_SDK_PRODUCT_SECRET_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCT_SECRET_INVALID); + break; + case GIZ_SDK_DEVICE_NOT_IN_LAN: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_IN_LAN); + break; + case GIZ_SDK_PRODUCTKEY_NOT_IN_SPECIAL_LIST: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCTKEY_NOT_IN_SPECIAL_LIST); + break; + case GIZ_SDK_PRODUCTKEY_NOT_RELATED_WITH_APPID: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCTKEY_NOT_RELATED_WITH_APPID); + break; + case GIZ_SDK_NO_AVAILABLE_DEVICE: + errorString = (String) getText(R.string.GIZ_SDK_NO_AVAILABLE_DEVICE); + break; + case GIZ_SDK_DEVICE_CONFIG_SEND_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_SEND_FAILED); + break; + case GIZ_SDK_DEVICE_CONFIG_IS_RUNNING: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_IS_RUNNING); + break; + case GIZ_SDK_DEVICE_CONFIG_TIMEOUT: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_TIMEOUT); + break; + case GIZ_SDK_DEVICE_DID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_DID_INVALID); + break; + case GIZ_SDK_DEVICE_MAC_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_MAC_INVALID); + break; + case GIZ_SDK_SUBDEVICE_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_SUBDEVICE_INVALID); + break; + case GIZ_SDK_DEVICE_PASSCODE_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_PASSCODE_INVALID); + break; + case GIZ_SDK_DEVICE_NOT_CENTERCONTROL: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_CENTERCONTROL); + break; + case GIZ_SDK_DEVICE_NOT_SUBSCRIBED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_SUBSCRIBED); + break; + case GIZ_SDK_DEVICE_NO_RESPONSE: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NO_RESPONSE); + break; + case GIZ_SDK_DEVICE_NOT_READY: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_READY); + break; + case GIZ_SDK_DEVICE_NOT_BINDED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_NOT_BINDED); + break; + case GIZ_SDK_DEVICE_CONTROL_WITH_INVALID_COMMAND: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_WITH_INVALID_COMMAND); + break; +// case GIZ_SDK_DEVICE_CONTROL_FAILED: +// errorString= (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_FAILED); +// break; + case GIZ_SDK_DEVICE_GET_STATUS_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_GET_STATUS_FAILED); + break; + case GIZ_SDK_DEVICE_CONTROL_VALUE_TYPE_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_VALUE_TYPE_ERROR); + break; + case GIZ_SDK_DEVICE_CONTROL_VALUE_OUT_OF_RANGE: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_VALUE_OUT_OF_RANGE); + break; + case GIZ_SDK_DEVICE_CONTROL_NOT_WRITABLE_COMMAND: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONTROL_NOT_WRITABLE_COMMAND); + break; + case GIZ_SDK_BIND_DEVICE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_BIND_DEVICE_FAILED); + break; + case GIZ_SDK_UNBIND_DEVICE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_UNBIND_DEVICE_FAILED); + break; + case GIZ_SDK_DNS_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DNS_FAILED); + break; + case GIZ_SDK_M2M_CONNECTION_SUCCESS: + errorString = (String) getText(R.string.GIZ_SDK_M2M_CONNECTION_SUCCESS); + break; + case GIZ_SDK_SET_SOCKET_NON_BLOCK_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SET_SOCKET_NON_BLOCK_FAILED); + break; + case GIZ_SDK_CONNECTION_TIMEOUT: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_TIMEOUT); + break; + case GIZ_SDK_CONNECTION_REFUSED: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_REFUSED); + break; + case GIZ_SDK_CONNECTION_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_ERROR); + break; + case GIZ_SDK_CONNECTION_CLOSED: + errorString = (String) getText(R.string.GIZ_SDK_CONNECTION_CLOSED); + break; + case GIZ_SDK_SSL_HANDSHAKE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SSL_HANDSHAKE_FAILED); + break; + case GIZ_SDK_DEVICE_LOGIN_VERIFY_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_LOGIN_VERIFY_FAILED); + break; + case GIZ_SDK_INTERNET_NOT_REACHABLE: + errorString = (String) getText(R.string.GIZ_SDK_INTERNET_NOT_REACHABLE); + break; + case GIZ_SDK_M2M_CONNECTION_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_M2M_CONNECTION_FAILED); + break; + case GIZ_SDK_HTTP_SERVER_NOT_SUPPORT_API: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_SERVER_NOT_SUPPORT_API); + break; + case GIZ_SDK_HTTP_ANSWER_FORMAT_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_ANSWER_FORMAT_ERROR); + break; + case GIZ_SDK_HTTP_ANSWER_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_ANSWER_PARAM_ERROR); + break; + case GIZ_SDK_HTTP_SERVER_NO_ANSWER: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_SERVER_NO_ANSWER); + break; + case GIZ_SDK_HTTP_REQUEST_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_HTTP_REQUEST_FAILED); + break; + case GIZ_SDK_OTHERWISE: + errorString = (String) getText(R.string.GIZ_SDK_OTHERWISE); + break; + case GIZ_SDK_MEMORY_MALLOC_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_MEMORY_MALLOC_FAILED); + break; + case GIZ_SDK_THREAD_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_THREAD_CREATE_FAILED); + break; + case GIZ_SDK_JSON_OBJECT_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_JSON_OBJECT_CREATE_FAILED); + break; + case GIZ_SDK_JSON_PARSE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_JSON_PARSE_FAILED); + break; + case GIZ_SDK_SCHEDULER_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_CREATE_FAILED); + break; + case GIZ_SDK_SCHEDULER_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_DELETE_FAILED); + break; + case GIZ_SDK_SCHEDULER_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_EDIT_FAILED); + break; + case GIZ_SDK_SCHEDULER_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCHEDULER_TASK_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_TASK_EDIT_FAILED); + break; + case GIZ_SDK_SCHEDULER_TASK_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_TASK_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCHEDULER_ID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_ID_INVALID); + break; + case GIZ_SDK_SCHEDULER_ENABLE_DISABLE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_ENABLE_DISABLE_FAILED); + break; + case GIZ_SDK_SCHEDULER_STATUS_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCHEDULER_STATUS_UPDATE_FAILED); + break; + case GIZ_SDK_GROUP_ID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_ID_INVALID); + break; + case GIZ_SDK_GROUP_FAILED_DELETE_DEVICE: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_FAILED_DELETE_DEVICE); + break; + case GIZ_SDK_GROUP_FAILED_ADD_DEVICE: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_FAILED_ADD_DEVICE); + break; + case GIZ_SDK_GROUP_PRODUCTKEY_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_PRODUCTKEY_INVALID); + break; + case GIZ_SDK_GROUP_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_CREATE_FAILED); + break; + case GIZ_SDK_GROUP_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_FAILED_DELETE_DEVICE); + break; + case GIZ_SDK_GROUP_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_EDIT_FAILED); + break; + case GIZ_SDK_GROUP_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GROUP_GET_DEVICE_FAILED); + break; + case GIZ_SDK_SCENE_CREATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_CREATE_FAILED); + break; + case GIZ_SDK_SCENE_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_DELETE_FAILED); + break; + case GIZ_SDK_SCENE_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_EDIT_FAILED); + break; + case GIZ_SDK_SCENE_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCENE_ITEM_LIST_EDIT_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_ITEM_LIST_EDIT_FAILED); + break; + case GIZ_SDK_SCENE_ITEM_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_ITEM_LIST_UPDATE_FAILED); + break; + case GIZ_SDK_SCENE_ID_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_ID_INVALID); + break; + case GIZ_SDK_SCENE_RUN_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_RUN_FAILED); + break; + case GIZ_SDK_SCENE_STATUS_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_SCENE_STATUS_UPDATE_FAILED); + break; + case GIZ_SDK_JOINT_ACTION_CREATE_FAILED: + errorString= (String) getText(R.string.GIZ_SDK_JOINT_ACTION_CREATE_FAILED); + break; + case GIZ_SDK_JOINT_ACTION_DELETE_FAILED: + errorString= (String) getText(R.string.GIZ_SDK_JOINT_ACTION_DELETE_FAILED); + break; + case GIZ_SDK_JOINT_ACTION_VER_UNSUPPORTED: + errorString= (String) getText(R.string.GIZ_SDK_JOINT_ACTION_VER_UNSUPPORTED); + break; +// case GIZ_SDK_JOINT_ACTION_INVALID_CONDITION_TYPE: +// errorString= (String) getText(R.string.GIZ_SDK_JOINT_ACTION_INVALID_CONDITION_TYPE); +// break; +// case GIZ_SDK_JOINT_ACTION_INVALID_RESULT_EVENT_TYPE: +// errorString= (String) getText(R.string.GIZ_SDK_JOINT_ACTION_INVALID_RESULT_EVENT_TYPE); +// break; + case GIZ_SDK_DATAPOINT_NOT_DOWNLOAD: + errorString = (String) getText(R.string.GIZ_SDK_DATAPOINT_NOT_DOWNLOAD); + break; + case GIZ_SDK_DATAPOINT_SERVICE_UNAVAILABLE: + errorString = (String) getText(R.string.GIZ_SDK_DATAPOINT_SERVICE_UNAVAILABLE); + break; + case GIZ_SDK_DATAPOINT_PARSE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DATAPOINT_PARSE_FAILED); + break; + // case GIZ_SDK_NOT_INITIALIZED: + // errorString= (String) getText(R.string.GIZ_SDK_SDK_NOT_INITIALIZED); + // break; + case GIZ_SDK_APK_CONTEXT_IS_NULL: + errorString = (String) getText(R.string.GIZ_SDK_APK_CONTEXT_IS_NULL); + break; + case GIZ_SDK_APK_PERMISSION_NOT_SET: + errorString = (String) getText(R.string.GIZ_SDK_APK_PERMISSION_NOT_SET); + break; + case GIZ_SDK_CHMOD_DAEMON_REFUSED: + errorString = (String) getText(R.string.GIZ_SDK_CHMOD_DAEMON_REFUSED); + break; + case GIZ_SDK_EXEC_DAEMON_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_EXEC_DAEMON_FAILED); + break; + case GIZ_SDK_EXEC_CATCH_EXCEPTION: + errorString = (String) getText(R.string.GIZ_SDK_EXEC_CATCH_EXCEPTION); + break; + case GIZ_SDK_APPID_IS_EMPTY: + errorString = (String) getText(R.string.GIZ_SDK_APPID_IS_EMPTY); + break; + case GIZ_SDK_UNSUPPORTED_API: + errorString = (String) getText(R.string.GIZ_SDK_UNSUPPORTED_API); + break; + case GIZ_SDK_REQUEST_TIMEOUT: + errorString = (String) getText(R.string.GIZ_SDK_REQUEST_TIMEOUT); + break; + case GIZ_SDK_DAEMON_VERSION_INVALID: + errorString = (String) getText(R.string.GIZ_SDK_DAEMON_VERSION_INVALID); + break; + case GIZ_SDK_PHONE_NOT_CONNECT_TO_SOFTAP_SSID: + errorString = (String) getText(R.string.GIZ_SDK_PHONE_NOT_CONNECT_TO_SOFTAP_SSID); + break; + case GIZ_SDK_DEVICE_CONFIG_SSID_NOT_MATCHED: + errorString = (String) getText(R.string.GIZ_SDK_DEVICE_CONFIG_SSID_NOT_MATCHED); + break; + case GIZ_SDK_NOT_IN_SOFTAPMODE: + errorString = (String) getText(R.string.GIZ_SDK_NOT_IN_SOFTAPMODE); + break; +// case GIZ_SDK_PHONE_WIFI_IS_UNAVAILABLE: +// errorString= (String)getText(R.string.GIZ_SDK_PHONE_WIFI_IS_UNAVAILABLE); +// break; + case GIZ_SDK_RAW_DATA_TRANSMIT: + errorString = (String) getText(R.string.GIZ_SDK_RAW_DATA_TRANSMIT); + break; + case GIZ_SDK_PRODUCT_IS_DOWNLOADING: + errorString = (String) getText(R.string.GIZ_SDK_PRODUCT_IS_DOWNLOADING); + break; + case GIZ_SDK_START_SUCCESS: + errorString = (String) getText(R.string.GIZ_SDK_START_SUCCESS); + break; + case GIZ_SDK_NEED_UPDATE_TO_LATEST: + errorString = (String) getText(R.string.GIZ_SDK_NEED_UPDATE_TO_LATEST); + break; + case GIZ_SDK_ONBOARDING_STOPPED: + errorString = (String) getText(R.string.GIZ_SDK_ONBOARDING_STOPPED); + break; + case GIZ_SDK_ONBOARDING_WIFI_IS_5G: + errorString = (String) getText(R.string.GIZ_SDK_ONBOARDING_WIFI_IS_5G); + break; + case GIZ_SDK_OTA_FIRMWARE_IS_LATEST: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_IS_LATEST); + break; + case GIZ_SDK_OTA_FIRMWARE_CHECK_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_CHECK_UPDATE_FAILED); + break; + case GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_OK: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_OK); + break; + case GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_DOWNLOAD_FAILED); + break; + case GIZ_SDK_OTA_DEVICE_BUSY_IN_UPGRADE: + errorString = (String) getText(R.string.GIZ_SDK_OTA_DEVICE_BUSY_IN_UPGRADE); + break; + case GIZ_SDK_OTA_PUSH_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_PUSH_FAILED); + break; + case GIZ_SDK_OTA_FIRMWARE_VERSION_TOO_LOW: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_VERSION_TOO_LOW); + break; + case GIZ_SDK_OTA_FIRMWARE_CHECK_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_CHECK_FAILED); + break; + case GIZ_SDK_OTA_UPGRADE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_OTA_UPGRADE_FAILED); + break; + case GIZ_SDK_OTA_FIRMWARE_VERIFY_SUCCESS: + errorString = (String) getText(R.string.GIZ_SDK_OTA_FIRMWARE_VERIFY_SUCCESS); + break; + case GIZ_SDK_OTA_DEVICE_NOT_SUPPORT: + errorString = (String) getText(R.string.GIZ_SDK_OTA_DEVICE_NOT_SUPPORT); + break; + case GIZ_SDK_WS_HANDSHAKE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_WS_HANDSHAKE_FAILED); + break; + case GIZ_SDK_WS_LOGIN_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_WS_LOGIN_FAILED); + break; +// case GIZ_SDK_WS_DEVICE_SUBSCRIBE_FAILED: +// errorString = (String) getText(R.string.GIZ_SDK_WS_DEVICE_SUBSCRIBE_FAILED); +// break; +// case GIZ_SDK_WS_DEVICE_UNSUBSCRIBE_FAILED: +// errorString = (String) getText(R.string.GIZ_SDK_WS_DEVICE_UNSUBSCRIBE_FAILED); +// break; + case GIZ_SITE_PRODUCTKEY_INVALID: + errorString = (String) getText(R.string.GIZ_SITE_PRODUCTKEY_INVALID); + break; + case GIZ_SITE_DATAPOINTS_NOT_DEFINED: + errorString = (String) getText(R.string.GIZ_SITE_DATAPOINTS_NOT_DEFINED); + break; + case GIZ_SITE_DATAPOINTS_NOT_MALFORME: + errorString = (String) getText(R.string.GIZ_SITE_DATAPOINTS_NOT_MALFORME); + break; + case GIZ_OPENAPI_MAC_ALREADY_REGISTERED: + errorString = (String) getText(R.string.GIZ_OPENAPI_MAC_ALREADY_REGISTERED); + break; + case GIZ_OPENAPI_PRODUCT_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCT_KEY_INVALID); + break; + case GIZ_OPENAPI_APPID_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_APPID_INVALID); + break; + case GIZ_OPENAPI_TOKEN_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_TOKEN_INVALID); + break; + case GIZ_OPENAPI_USER_NOT_EXIST: + errorString = (String) getText(R.string.GIZ_OPENAPI_USER_NOT_EXIST); + break; + case GIZ_OPENAPI_TOKEN_EXPIRED: + errorString = (String) getText(R.string.GIZ_OPENAPI_TOKEN_EXPIRED); + break; + case GIZ_OPENAPI_M2M_ID_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_M2M_ID_INVALID); + break; + case GIZ_OPENAPI_SERVER_ERROR: + errorString = (String) getText(R.string.GIZ_OPENAPI_SERVER_ERROR); + break; + case GIZ_OPENAPI_CODE_EXPIRED: + errorString = (String) getText(R.string.GIZ_OPENAPI_CODE_EXPIRED); + break; + case GIZ_OPENAPI_CODE_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_CODE_INVALID); + break; + case GIZ_OPENAPI_SANDBOX_SCALE_QUOTA_EXHAUSTED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SANDBOX_SCALE_QUOTA_EXHAUSTED); + break; + case GIZ_OPENAPI_PRODUCTION_SCALE_QUOTA_EXHAUSTED: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCTION_SCALE_QUOTA_EXHAUSTED); + break; + case GIZ_OPENAPI_PRODUCT_HAS_NO_REQUEST_SCALE: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCT_HAS_NO_REQUEST_SCALE); + break; + case GIZ_OPENAPI_DEVICE_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_NOT_FOUND); + break; + case GIZ_OPENAPI_FORM_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_FORM_INVALID); + break; + case GIZ_OPENAPI_DID_PASSCODE_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_DID_PASSCODE_INVALID); + break; + case GIZ_OPENAPI_DEVICE_NOT_BOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_NOT_BOUND); + break; + case GIZ_OPENAPI_PHONE_UNAVALIABLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_PHONE_UNAVALIABLE); + break; + case GIZ_OPENAPI_USERNAME_UNAVALIABLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_USERNAME_UNAVALIABLE); + break; + case GIZ_OPENAPI_USERNAME_PASSWORD_ERROR: + errorString = (String) getText(R.string.GIZ_OPENAPI_USERNAME_PASSWORD_ERROR); + break; + case GIZ_OPENAPI_SEND_COMMAND_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SEND_COMMAND_FAILED); + break; + case GIZ_OPENAPI_EMAIL_UNAVALIABLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_EMAIL_UNAVALIABLE); + break; + case GIZ_OPENAPI_DEVICE_DISABLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_DISABLED); + break; + case GIZ_OPENAPI_FAILED_NOTIFY_M2M: + errorString = (String) getText(R.string.GIZ_OPENAPI_FAILED_NOTIFY_M2M); + break; + case GIZ_OPENAPI_ATTR_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_ATTR_INVALID); + break; + case GIZ_OPENAPI_USER_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_USER_INVALID); + break; + case GIZ_OPENAPI_FIRMWARE_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_FIRMWARE_NOT_FOUND); + break; + case GIZ_OPENAPI_JD_PRODUCT_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_JD_PRODUCT_NOT_FOUND); + break; + case GIZ_OPENAPI_DATAPOINT_DATA_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_DATAPOINT_DATA_NOT_FOUND); + break; + case GIZ_OPENAPI_SCHEDULER_NOT_FOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_SCHEDULER_NOT_FOUND); + break; + case GIZ_OPENAPI_QQ_OAUTH_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_QQ_OAUTH_KEY_INVALID); + break; + case GIZ_OPENAPI_OTA_SERVICE_OK_BUT_IN_IDLE: + errorString = (String) getText(R.string.GIZ_OPENAPI_OTA_SERVICE_OK_BUT_IN_IDLE); + break; + case GIZ_OPENAPI_BT_FIRMWARE_UNVERIFIED: + errorString = (String) getText(R.string.GIZ_OPENAPI_BT_FIRMWARE_UNVERIFIED); + break; + case GIZ_OPENAPI_BT_FIRMWARE_NOTHING_TO_UPGRADE: + errorString = (String) getText(R.string.GIZ_OPENAPI_SAVE_KAIROSDB_ERROR); + break; + case GIZ_OPENAPI_SAVE_KAIROSDB_ERROR: + errorString = (String) getText(R.string.GIZ_OPENAPI_SAVE_KAIROSDB_ERROR); + break; + case GIZ_OPENAPI_EVENT_NOT_DEFINED: + errorString = (String) getText(R.string.GIZ_OPENAPI_EVENT_NOT_DEFINED); + break; + case GIZ_OPENAPI_SEND_SMS_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SEND_SMS_FAILED); + break; +// case GIZ_OPENAPI_APPLICATION_AUTH_INVALID: +// errorString= (String) +// getText(R.string.GIZ_OPENAPI_APPLICATION_AUTH_INVALID); +// break; + case GIZ_OPENAPI_NOT_ALLOWED_CALL_API: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_ALLOWED_CALL_API); + break; + case GIZ_OPENAPI_BAD_QRCODE_CONTENT: + errorString = (String) getText(R.string.GIZ_OPENAPI_BAD_QRCODE_CONTENT); + break; + case GIZ_OPENAPI_REQUEST_THROTTLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_REQUEST_THROTTLED); + break; + case GIZ_OPENAPI_DEVICE_OFFLINE: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_OFFLINE); + break; + case GIZ_OPENAPI_TIMESTAMP_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_TIMESTAMP_INVALID); + break; + case GIZ_OPENAPI_SIGNATURE_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_SIGNATURE_INVALID); + break; + case GIZ_OPENAPI_DEPRECATED_API: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEPRECATED_API); + break; + case GIZ_OPENAPI_REGISTER_IS_BUSY: + errorString = (String) getText(R.string.GIZ_OPENAPI_REGISTER_IS_BUSY); + break; + case GIZ_OPENAPI_ALTER_PASSWORD_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_ALTER_PASSWORD_FAILED); + break; + case GIZ_OPENAPI_APPID_PK_NOT_RELATION: + errorString = (String) getText(R.string.GIZ_OPENAPI_APPID_PK_NOT_RELATION); + break; + case GIZ_OPENAPI_CALL_INNER_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_CALL_INNER_FAILED); + break; + case GIZ_OPENAPI_DEVICE_SHARING_NOT_ENABLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_SHARING_NOT_ENABLED); + break; + case GIZ_OPENAPI_NOT_FIRST_USER_OF_DEVICE: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FIRST_USER_OF_DEVICE); + break; + case GIZ_OPENAPI_PRODUCT_KEY_AUTHEN_FAULT: + errorString = (String) getText(R.string.GIZ_OPENAPI_PRODUCT_KEY_AUTHEN_FAULT); + break; + case GIZ_OPENAPI_BUSY_NOW: + errorString = (String) getText(R.string.GIZ_OPENAPI_BUSY_NOW); + break; + case GIZ_OPENAPI_TWITTER_CONSUMER_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_OPENAPI_TWITTER_CONSUMER_KEY_INVALID); + break; + case GIZ_OPENAPI_NOT_ALLOW_WEEK_PASSWORD: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_ALLOW_WEEK_PASSWORD); + break; +// case GIZ_OPENAPI_CODE_NOT_EXIST: +// errorString = (String) getText(R.string.GIZ_OPENAPI_CODE_NOT_EXIST); +// break; +// case GIZ_OPENAPI_EMAIL_NOT_ACTIVE: +// errorString = (String) getText(R.string.GIZ_OPENAPI_EMAIL_NOT_ACTIVE); +// break; +// case GIZ_OPENAPI_EMAIL_NOT_ENABLE: +// errorString = (String) getText(R.string.GIZ_OPENAPI_EMAIL_NOT_ENABLE); +// break; +// case GIZ_OPENAPI_DEVICE_REGISTER_NOT_FOUND: +// errorString = (String) getText(R.string.GIZ_OPENAPI_DEVICE_REGISTER_NOT_FOUND); +// break; + case GIZ_OPENAPI_CANNOT_SHARE_TO_SELF: + errorString = (String) getText(R.string.GIZ_OPENAPI_CANNOT_SHARE_TO_SELF); + break; + case GIZ_OPENAPI_ONLY_OWNER_CAN_SHARE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_OWNER_CAN_SHARE); + break; + case GIZ_OPENAPI_NOT_FOUND_GUEST: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FOUND_GUEST); + break; + case GIZ_OPENAPI_GUEST_ALREADY_BOUND: + errorString = (String) getText(R.string.GIZ_OPENAPI_GUEST_ALREADY_BOUND); + break; + case GIZ_OPENAPI_NOT_FOUND_SHARING_INFO: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FOUND_SHARING_INFO); + break; + case GIZ_OPENAPI_NOT_FOUND_THE_MESSAGE: + errorString = (String) getText(R.string.GIZ_OPENAPI_NOT_FOUND_THE_MESSAGE); + break; + case GIZ_OPENAPI_SHARING_IS_WAITING_FOR_ACCEPT: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_IS_WAITING_FOR_ACCEPT); + break; + case GIZ_OPENAPI_SHARING_IS_EXPIRED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_IS_EXPIRED); + break; + case GIZ_OPENAPI_SHARING_IS_COMPLETED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_IS_COMPLETED); + break; + case GIZ_OPENAPI_INVALID_SHARING_BECAUSE_UNBINDING: + errorString = (String) getText(R.string.GIZ_OPENAPI_INVALID_SHARING_BECAUSE_UNBINDING); + break; + case GIZ_OPENAPI_ONLY_OWNER_CAN_BIND: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_OWNER_CAN_BIND); + break; + case GIZ_OPENAPI_ONLY_OWNER_CAN_OPERATE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_OWNER_CAN_OPERATE); + break; + case GIZ_OPENAPI_SHARING_ALREADY_CANCELLED: + errorString = (String) getText(R.string.GIZ_OPENAPI_SHARING_ALREADY_CANCELLED); + break; + case GIZ_OPENAPI_OWNER_CANNOT_UNBIND_SELF: + errorString = (String) getText(R.string.GIZ_OPENAPI_OWNER_CANNOT_UNBIND_SELF); + break; + case GIZ_OPENAPI_ONLY_GUEST_CAN_CHECK_QRCODE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_GUEST_CAN_CHECK_QRCODE); + break; + case GIZ_OPENAPI_MESSAGE_ALREADY_DELETED: + errorString = (String) getText(R.string.GIZ_OPENAPI_MESSAGE_ALREADY_DELETED); + break; + case GIZ_OPENAPI_BINDING_NOTIFY_FAILED: + errorString = (String) getText(R.string.GIZ_OPENAPI_BINDING_NOTIFY_FAILED); + break; + case GIZ_OPENAPI_ONLY_SELF_CAN_MODIFY_ALIAS: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_SELF_CAN_MODIFY_ALIAS); + break; + case GIZ_OPENAPI_ONLY_RECEIVER_CAN_MARK_MESSAGE: + errorString = (String) getText(R.string.GIZ_OPENAPI_ONLY_RECEIVER_CAN_MARK_MESSAGE); + break; + case GIZ_OPENAPI_GUEST_NOT_BIND: + errorString = (String) getText(R.string.GIZ_OPENAPI_GUEST_NOT_BIND); + break; + case GIZ_OPENAPI_CANNOT_TRANSFER_OWNER_TO_SELF: + errorString = (String) getText(R.string.GIZ_OPENAPI_CANNOT_TRANSFER_OWNER_TO_SELF); + break; + case GIZ_OPENAPI_TRANSFER_OWNER_TO_LIMIT_GUEST: + errorString = (String) getText(R.string.GIZ_OPENAPI_TRANSFER_OWNER_TO_LIMIT_GUEST); + break; + case GIZ_OPENAPI_RESERVED: + errorString = (String) getText(R.string.GIZ_OPENAPI_RESERVED); + break; + case GIZ_PUSHAPI_BODY_JSON_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_BODY_JSON_INVALID); + break; + case GIZ_PUSHAPI_DATA_NOT_EXIST: + errorString = (String) getText(R.string.GIZ_PUSHAPI_DATA_NOT_EXIST); + break; + case GIZ_PUSHAPI_NO_CLIENT_CONFIG: + errorString = (String) getText(R.string.GIZ_PUSHAPI_NO_CLIENT_CONFIG); + break; + case GIZ_PUSHAPI_NO_SERVER_DATA: + errorString = (String) getText(R.string.GIZ_PUSHAPI_NO_SERVER_DATA); + break; + case GIZ_PUSHAPI_GIZWITS_APPID_EXIST: + errorString = (String) getText(R.string.GIZ_PUSHAPI_GIZWITS_APPID_EXIST); + break; + case GIZ_PUSHAPI_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_PARAM_ERROR); + break; + case GIZ_PUSHAPI_AUTH_KEY_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_AUTH_KEY_INVALID); + break; + case GIZ_PUSHAPI_APPID_OR_TOKEN_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_APPID_OR_TOKEN_ERROR); + break; + case GIZ_PUSHAPI_TYPE_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_TYPE_PARAM_ERROR); + break; + case GIZ_PUSHAPI_ID_PARAM_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_ID_PARAM_ERROR); + break; + case GIZ_PUSHAPI_APPKEY_SECRETKEY_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_APPKEY_SECRETKEY_INVALID); + break; + case GIZ_PUSHAPI_CHANNELID_ERROR_INVALID: + errorString = (String) getText(R.string.GIZ_PUSHAPI_CHANNELID_ERROR_INVALID); + break; + case GIZ_PUSHAPI_PUSH_ERROR: + errorString = (String) getText(R.string.GIZ_PUSHAPI_PUSH_ERROR); + break; + case GIZ_SDK_SUBDEVICE_ADD_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_ADD_SUBDEVICE_FAILED); + break; + + case GIZ_SDK_SUBDEVICE_DELETE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_DELETE_SUBDEVICE_FAILED); + break; + + case GIZ_SDK_SUBDEVICE_LIST_UPDATE_FAILED: + errorString = (String) getText(R.string.GIZ_SDK_GET_SUBDEVICES_FAILED); + break; + default: + errorString = (String) getText(R.string.UNKNOWN_ERROR); + break; + } + return errorString; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListAdapter.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListAdapter.java new file mode 100644 index 0000000..c79b5cf --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListAdapter.java @@ -0,0 +1,311 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizWifiCentralControlDevice; +import com.gizwits.gizwifisdk.api.GizWifiDevice; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingUserRole; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceNetStatus; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.sharingdevice.addSharedActivity; +import com.gizwits.opensource.appkit.utils.AssetsUtils; + +import java.util.List; +import java.util.Map; + +import static com.gizwits.gizwifisdk.enumration.GizWifiDeviceType.GizDeviceCenterControl; + + +@SuppressLint("InflateParams") +public class GosDeviceListAdapter extends BaseAdapter { + + private static final String TAG = "GosDeviceListAdapter"; + Handler handler = new Handler(); + SharedPreferences spf; + protected static final int UNBOUND = 99; + protected static final int SHARE = 100; + + public void setHandler(Handler handler) { + this.handler = handler; + } + + Context context; + List deviceList; + + public GosDeviceListAdapter(Context context, List deviceList) { + super(); + this.context = context; + this.deviceList = deviceList; + } + + public void setSpf(SharedPreferences spf) { + this.spf = spf; + } + + @Override + public int getCount() { + return deviceList.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + Holder holder; + + if (view == null) { + view = LayoutInflater.from(context).inflate( + R.layout.item_gos_device_list, null); + holder = new Holder(view); + view.setTag(holder); + } else { + holder = (Holder) view.getTag(); + } + final GizWifiDevice device = deviceList.get(position); + + String deviceAlias = device.getAlias(); + String devicePN = device.getProductName(); + + GizDeviceSharingUserRole role = device.getSharingRole(); + + if (role != null) { + if (role.name().equals("GizDeviceSharingSpecial") || role.name().equals("GizDeviceSharingOwner")) { + holder.getDelete2().setVisibility(View.VISIBLE); + holder.getDelete1().setVisibility(View.VISIBLE); + holder.getDevice().setPadding(0, 0, AssetsUtils.diptopx(context, -181), 0); + } else { + holder.getDelete1().setVisibility(View.GONE); + holder.getDelete2().setVisibility(View.VISIBLE); + holder.getDevice().setPadding(0, 0, AssetsUtils.diptopx(context, -91), 0); + } + } + GizWifiCentralControlDevice centralControlDevice = null; + holder.getTvDeviceMac().setVisibility(View.GONE); + holder.getTvDeviceMac().setVisibility(View.VISIBLE); + holder.getTvDeviceMac().setText(device.getMacAddress()); + + if (device.getNetStatus() == GizWifiDeviceNetStatus.GizDeviceOnline + || device.getNetStatus() == GizWifiDeviceNetStatus.GizDeviceControlled) { + + if (device.isLAN()) { + holder.getLlLeft().setImageResource(R.drawable.common_device_lan_online); + } else { + holder.getLlLeft().setImageResource(R.drawable.common_device_remote_online); + } + holder.getImgRight().setVisibility(View.VISIBLE); + + if (device.isBind()) {// 已绑定设备 + if (device.getProductType() == GizDeviceCenterControl) { + if (device instanceof GizWifiCentralControlDevice) { + centralControlDevice = (GizWifiCentralControlDevice) device; + } + } + if (centralControlDevice != null) { + if (centralControlDevice.getSubDeviceList().size() != 0) { + holder.getTvDeviceMac().setVisibility(View.VISIBLE); + if (AssetsUtils.isZh(context)) { + StringBuffer sb = new StringBuffer(); + sb.append("已连接"); + sb.append(centralControlDevice.getSubDeviceList().size()); + sb.append("个设备"); + holder.getTvDeviceMac().setText(sb.toString()); + } else { + StringBuffer sb = new StringBuffer(); + sb.append(centralControlDevice.getSubDeviceList().size()); + sb.append(" devices connected"); + holder.getTvDeviceMac().setText(sb.toString()); + } + if (AssetsUtils.isZh(context)) { + StringBuffer sb = new StringBuffer(); + sb.append(centralControlDevice.getMacAddress()); + sb.append(" 已连接"); + sb.append(centralControlDevice.getSubDeviceList().size()); + sb.append("个设备"); + holder.getTvDeviceMac().setText(sb.toString()); + } else { + StringBuffer sb = new StringBuffer(); + sb.append(centralControlDevice.getMacAddress()); + sb.append(" "); + sb.append(centralControlDevice.getSubDeviceList().size()); + sb.append(" devices connected"); + holder.getTvDeviceMac().setText(sb.toString()); + } + } + } + //这里会出现箭头不显示的状态 +// holder.getImgRight().setVisibility(View.VISIBLE); + + } else {// 未绑定设备 + holder.getDelete2().setVisibility(View.GONE); + holder.getDevice().setPadding(0, 0, AssetsUtils.diptopx(context, 0), 0); + } + } else {// 设备不在线 + holder.getSbDeviceStatus().setClickable(false); + holder.getImgRight().setVisibility(View.GONE); + if (device.isLAN()) { + holder.getLlLeft().setImageResource(R.drawable.common_device_lan_offline); + } else { + holder.getLlLeft().setImageResource(R.drawable.common_device_remote_offline); + } + } + if (TextUtils.isEmpty(deviceAlias)) { + List> list = GosDeploy.appConfig_DeviceInfo(); + boolean isName = true; + for (Map map : list) { + if (map.containsKey("productKey")) { + if (device.getProductKey().equals(map.get("productKey"))) { + if (AssetsUtils.isZh(context)) { + if (map.containsKey("productNameCH")) { + isName = false; + holder.getTvDeviceName().setText(map.get("productNameCH").toString()); + } + } else { + if (map.containsKey("productNameEN")) { + isName = false; + holder.getTvDeviceName().setText(map.get("productNameEN").toString()); + } + } + } + } + } + if (isName) { + holder.getTvDeviceName().setText(devicePN); + } + } else { + holder.getTvDeviceName().setText(deviceAlias); + } + holder.getDelete2().setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + Message message = new Message(); + message.what = UNBOUND; + message.obj = device.getDid().toString(); + handler.sendMessage(message); + + } + }); + holder.getDelete1().setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Message message = new Message(); + message.what = SHARE; + message.obj = device.getDid().toString(); + handler.sendMessage(message); + + if (!TextUtils.isEmpty(spf.getString("UserName", "")) && !TextUtils.isEmpty(spf.getString("PassWord", ""))) { + Intent intent = new Intent(context, addSharedActivity.class); + intent.putExtra("productname", device.getProductName()); + intent.putExtra("did", device.getDid()); + context.startActivity(intent); + } else { + Toast.makeText(context, context.getString(R.string.please_login), 2000).show(); + } + } + }); + return view; + } + +} + +class Holder { + View view; + + public Holder(View view) { + this.view = view; + } + + private TextView tvDeviceMac, tvDeviceStatus, tvDeviceName; + + private RelativeLayout delete1, delete2, device; + + private ImageView imgRight; + + private ImageView lvLeft; + + private Switch sbDeviceStatus; + + public ImageView getLlLeft() { + if (null == lvLeft) { + lvLeft = (ImageView) view.findViewById(R.id.imgLeft); + } + return lvLeft; + } + + public ImageView getImgRight() { + if (null == imgRight) { + imgRight = (ImageView) view.findViewById(R.id.imgRight); + } + return imgRight; + } + + public RelativeLayout getDevice() { + if (null == device) { + device = (RelativeLayout) view.findViewById(R.id.rl_device); + } + return device; + } + + public RelativeLayout getDelete2() { + if (null == delete2) { + delete2 = (RelativeLayout) view.findViewById(R.id.delete2); + } + return delete2; + } + + public RelativeLayout getDelete1() { + if (null == delete1) { + delete1 = (RelativeLayout) view.findViewById(R.id.delete1); + } + return delete1; + } + + public TextView getTvDeviceMac() { + if (null == tvDeviceMac) { + tvDeviceMac = (TextView) view.findViewById(R.id.tvDeviceMac); + } + return tvDeviceMac; + } + + + public TextView getTvDeviceName() { + if (null == tvDeviceName) { + tvDeviceName = (TextView) view.findViewById(R.id.tvDeviceName); + } + return tvDeviceName; + } + + public Switch getSbDeviceStatus() { + if (null == sbDeviceStatus) { + sbDeviceStatus = (Switch) view.findViewById(R.id.sbDeviceStatus); + } + return sbDeviceStatus; + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListFragment.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListFragment.java new file mode 100644 index 0000000..f515224 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceListFragment.java @@ -0,0 +1,847 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizWifiDevice; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceNetStatus; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.ConfigModule.GosAirlinkChooseDeviceWorkWiFiActivity; +import com.gizwits.opensource.appkit.ConfigModule.GosChooseDeviceWorkWiFiActivity; +import com.gizwits.opensource.appkit.ControlModule.GosDeviceControlActivity; +import com.gizwits.opensource.appkit.PushModule.GosPushManager; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.view.SlideListView2; +import com.gizwits.opensource.appkit.view.VerticalSwipeRefreshLayout; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +// config-all-start +// config_airlink-false-start +// config_airlink-false-end +//config_softap-false-start +//config_softap-false-end +// config-all-end + + +@SuppressLint("HandlerLeak") +public class GosDeviceListFragment extends GosDeviceModuleBaseFragment implements OnRefreshListener { + + /** + * The ll NoDevice + */ + private ScrollView llNoDevice; + + SwipeRefreshLayout mSwipeLayout; + + /** + * The img NoDevice + */ + private ImageView imgNoDevice; + + /** + * The btn NoDevice + */ + private Button btnNoDevice; + + /** + * The ic BoundDevices + */ + private View icBoundDevices; + + /** + * The ic FoundDevices + */ + private View icFoundDevices; + + + /** + * The tv BoundDevicesListTitle + */ + private TextView tvBoundDevicesListTitle; + + /** + * The tv FoundDevicesListTitle + */ + private TextView tvFoundDevicesListTitle; + + + /** + * The ll NoBoundDevices + */ + private LinearLayout llNoBoundDevices; + + /** + * The ll NoFoundDevices + */ + private LinearLayout llNoFoundDevices; + + + /** + * The slv BoundDevices + */ + private SlideListView2 slvBoundDevices; + + /** + * The slv FoundDevices + */ + private SlideListView2 slvFoundDevices; + + + /** + * The sv ListGroup + */ + private ScrollView svListGroup; + + /** + * 适配器 + */ + private GosDeviceListAdapter myadapter; + + private GosDeviceListAdapter myadapter1; + + /** + * 设备列表分类 + */ + List boundDevicesList = new ArrayList(); + List foundDevicesList = new ArrayList(); + List offlineDevicesList = new ArrayList(); + + /** + * 设备热点名称列表 + */ + ArrayList softNameList; + + /** + * 与APP绑定的设备的ProductKey + */ + private List ProductKeyList; + + Intent intent; + + String softssid, uid, token; + + public static List boundMessage; + + /** + * 判断用户登录状态 0:未登录 1:实名用户登录 2:匿名用户登录 3:匿名用户登录中 4:匿名用户登录中断 + */ + public static int loginStatus; + + int threeSeconds = 3; + + /** + * 获取设备列表 + */ + protected static final int GETLIST = 0; + + /** + * 刷新设备列表 + */ + protected static final int UPDATALIST = 1; + + /** + * 订阅成功前往控制页面 + */ + protected static final int TOCONTROL = 2; + + /** + * 通知 + */ + protected static final int TOAST = 3; + + /** + * 设备绑定 + */ + protected static final int BOUND = 9; + + /** + * 设备解绑 + */ + protected static final int UNBOUND = 99; + + + private static final int PULL_TO_REFRESH = 888; + + private VerticalSwipeRefreshLayout mSwipeLayout1; + + /** + * 等待框 + */ + public ProgressDialog progressDialog; + + Handler handler = new Handler() { + private AlertDialog myDialog; + private TextView dialog_name; + + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case GETLIST: + Log.e(TAG, "handleMessage:GETLIST -----------------" + uid); + if (!uid.isEmpty() && !token.isEmpty()) { + // GizWifiSDK.sharedInstance().getBoundDevices(uid, token, ProductKeyList); + GizWifiSDK.sharedInstance().getBoundDevices(uid, token); + } + + //login_anonymous-false-start + if (loginStatus == 0 && GosDeploy.appConfig_Login_Anonymous()) { + loginStatus = 3; + GizWifiSDK.sharedInstance().userLoginAnonymous(); + } + //login_anonymous-false-end + break; + + case UPDATALIST: + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.cancel(); + } + UpdateUI(); + break; + + case BOUND: + + break; + + case UNBOUND: + if (progressDialog != null) { + progressDialog.show(); + } + GizWifiSDK.sharedInstance().unbindDevice(uid, token, msg.obj.toString()); + break; + + case TOCONTROL: + intent = null; + Bundle bundle = new Bundle(); + GizWifiDevice device = (GizWifiDevice) msg.obj; + if (intent == null) { + intent = new Intent(getContext(), GosDeviceControlActivity.class); + } + bundle.putParcelable("GizWifiDevice", device); + intent.putExtras(bundle); + startActivityForResult(intent, 1); + break; + + case TOAST: + Toast.makeText(getContext(), msg.obj.toString(), 2000).show(); + break; + + case PULL_TO_REFRESH: + handler.sendEmptyMessage(GETLIST); + mSwipeLayout.setRefreshing(false); + mSwipeLayout1.setRefreshing(false); + + break; + } + } + }; + private View allView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + allView = inflater.inflate(R.layout.activity_gos_device_list, container, false); + //handler.sendEmptyMessage(GETLIST); + + GosMessageHandler.getSingleInstance().StartLooperWifi(getContext()); + setProgressDialog(); + softNameList = new ArrayList(); + initData(); + initView(); + initEvent(); + return allView; + } + + /* + * @Override public void onWindowFocusChanged(boolean hasFocus) { + * super.onWindowFocusChanged(hasFocus); if (hasFocus && isFrist) { + * progressDialog.show(); + * + * isFrist = false; } } + */ + @Override + public void onResume() { + super.onResume(); + Log.e(TAG, "onResume: -------------"); + handler.sendEmptyMessage(GETLIST); + GosDeviceModuleBaseFragment.deviceslist = GizWifiSDK.sharedInstance().getDeviceList(); + UpdateUI(); + // TODO GosMessageHandler.getSingleInstance().SetHandler(handler); + if (boundMessage.size() != 0) { + progressDialog.show(); + if (boundMessage.size() == 2) { + GizWifiSDK.sharedInstance().bindDevice(uid, token, boundMessage.get(0), boundMessage.get(1), null); + } else if (boundMessage.size() == 1) { + GizWifiSDK.sharedInstance().bindDeviceByQRCode(uid, token, boundMessage.get(0), false); + } else if (boundMessage.size() == 3) { + GizDeviceSharing.checkDeviceSharingInfoByQRCode(spf.getString("Token", ""), boundMessage.get(2)); + } else { + Log.i("Apptest", "ListSize:" + boundMessage.size()); + } + } + + } + + @Override + public void onPause() { + super.onPause(); + boundMessage.clear(); + // TODO GosMessageHandler.getSingleInstance().SetHandler(null); + + } + + private void initView() { + svListGroup = (ScrollView) allView.findViewById(R.id.svListGroup); + llNoDevice = (ScrollView) allView.findViewById(R.id.llNoDevice); + imgNoDevice = (ImageView) allView.findViewById(R.id.imgNoDevice); + btnNoDevice = (Button) allView.findViewById(R.id.btnNoDevice); + + icBoundDevices = allView.findViewById(R.id.icBoundDevices); + icFoundDevices = allView.findViewById(R.id.icFoundDevices); + + slvBoundDevices = (SlideListView2) icBoundDevices.findViewById(R.id.slideListView1); + slvFoundDevices = (SlideListView2) icFoundDevices.findViewById(R.id.slideListView1); + + llNoBoundDevices = (LinearLayout) icBoundDevices.findViewById(R.id.llHaveNotDevice); + llNoFoundDevices = (LinearLayout) icFoundDevices.findViewById(R.id.llHaveNotDevice); + + tvBoundDevicesListTitle = (TextView) icBoundDevices.findViewById(R.id.tvListViewTitle); + tvFoundDevicesListTitle = (TextView) icFoundDevices.findViewById(R.id.tvListViewTitle); + String boundDevicesListTitle = null; + String foundDevicesListTitle = null; + boundDevicesListTitle = (String) getText(R.string.my_device); + foundDevicesListTitle = (String) getText(R.string.found_devices); + + tvBoundDevicesListTitle.setText(boundDevicesListTitle); + + tvFoundDevicesListTitle.setText(foundDevicesListTitle); + + // 下拉刷新 + + mSwipeLayout = (VerticalSwipeRefreshLayout) allView.findViewById(R.id.id_swipe_ly); + + mSwipeLayout.setOnRefreshListener(this); + mSwipeLayout.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, + android.R.color.holo_orange_light, android.R.color.holo_red_light); + + mSwipeLayout1 = (VerticalSwipeRefreshLayout) allView.findViewById(R.id.id_swipe_ly1); + mSwipeLayout1.setOnRefreshListener(this); + mSwipeLayout1.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, + android.R.color.holo_orange_light, android.R.color.holo_red_light); +// setActionBar(true, true, ""); +// actionBar.setIcon(getResources().getDrawable(R.drawable.qr_code)); + } + + private void initEvent() { + myadapter = new GosDeviceListAdapter(getContext(), foundDevicesList); + myadapter.setHandler(handler); + myadapter.setSpf(spf); + slvFoundDevices.setAdapter(myadapter); + myadapter1 = new GosDeviceListAdapter(getContext(), boundDevicesList); + myadapter1.setHandler(handler); + myadapter1.setSpf(spf); + slvBoundDevices.setAdapter(myadapter1); + // config-all-start + imgNoDevice.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + addDevice(); + } + }); + btnNoDevice.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + addDevice(); + } + }); + // config-all-end + slvFoundDevices.initSlideMode(SlideListView2.MOD_FORBID); + slvFoundDevices.setFocusable(false); + slvBoundDevices.initSlideMode(SlideListView2.MOD_RIGHT); + slvBoundDevices.setFocusable(false); + slvFoundDevices.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, final View view, int position, long id) { + + slvFoundDevices.setEnabled(false); + slvFoundDevices.postDelayed(new Runnable() { + @Override + public void run() { + slvFoundDevices.setEnabled(true); + } + }, 1000); + final GizWifiDevice device = foundDevicesList.get(position); + device.setListener(getGizWifiDeviceListener(device)); + if (device.getNetStatus() != GizWifiDeviceNetStatus.GizDeviceOffline) { + boolean isAuto = false; + + List> list2 = GosDeploy.appConfig_ProductList(); + for (Map map2 : list2) { + String productkey = device.getProductKey(); + Iterator it1 = map2.entrySet().iterator(); + while (it1.hasNext()) { + Map.Entry entry1 = (Map.Entry) it1.next(); + if (productkey.equals(entry1.getKey())) { + isAuto = true; + device.setSubscribe(entry1.getValue().toString(), true); + progressDialog.show(); + break; + } + } + } + + if (device.getNetStatus() == GizWifiDeviceNetStatus.GizDeviceOnline + && !TextUtils.isEmpty(device.getDid()) && !device.isBind() + && device.getProductType() == GizWifiDeviceType.GizDeviceSub) { + + if (!isAuto) { + final Dialog dialog = new AlertDialog.Builder(getContext(), R.style.alert_dialog_style) + .setView(new EditText(getContext())).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_edit_name); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + TextView title = (TextView) window.findViewById(R.id.tvTitle); + final EditText remarkname = (EditText) window.findViewById(R.id.remarkname); + title.setText(getString(R.string.pleaseenterps)); + LinearLayout llyes = (LinearLayout) window.findViewById(R.id.llSure); + LinearLayout llno = (LinearLayout) window.findViewById(R.id.llNo); + remarkname.setHint(getResources().getString(R.string.pleaseenter32ps)); + llno.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + dialog.dismiss(); + } + }); + llyes.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + String ps = remarkname.getText().toString(); + if (TextUtils.isEmpty(ps) || ps.length() != 32) { + Toast.makeText(getContext(), + getResources().getString(R.string.psiserror), 0).show(); + } else { + device.setSubscribe(remarkname.getText().toString(), true); + //device.setSubscribe(true); + progressDialog.show(); + /**隐藏软键盘**/ + View view = getActivity().getWindow().peekDecorView(); + if (view != null) { + InputMethodManager inputmanger = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + dialog.dismiss(); + } + } + }); + } + } else { +// device.setSubscribe(null, true); + if (!isAuto) { + device.setSubscribe(null, true); + progressDialog.show(); + } + } + } + + } + }); + + slvBoundDevices.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, final View view, int position, long id) { + if (position < boundDevicesList.size()) { + + slvBoundDevices.setEnabled(false); + slvBoundDevices.postDelayed(new Runnable() { + @Override + public void run() { + slvBoundDevices.setEnabled(true); + } + }, 1000); + + final GizWifiDevice device = boundDevicesList.get(position); + device.setListener(getGizWifiDeviceListener(device)); + if (device.getNetStatus() != GizWifiDeviceNetStatus.GizDeviceOffline) { + String productKey = device.getProductKey(); + List> list2 = GosDeploy.appConfig_ProductList(); + boolean isSubscribe = false; + for (Map map2 : list2) { + Iterator it1 = map2.entrySet().iterator(); + while (it1.hasNext()) { + Map.Entry entry1 = (Map.Entry) it1.next(); + if (productKey.equals(entry1.getKey())) { + isSubscribe = true; + device.setSubscribe(entry1.getValue().toString(), true); + } + } + } + if (!isSubscribe) { + device.setSubscribe(null, true); + progressDialog.show(); + } + } + } + + } + }); + } + + + private void initData() { + boundMessage = new ArrayList(); + // ProductKeyList = GosDeploy.setProductKeyList(); + ProductKeyList = null; + uid = spf.getString("Uid", ""); + token = spf.getString("Token", ""); + if (uid.isEmpty() && token.isEmpty()) { + loginStatus = 0; + } + } + + protected void didDiscovered(GizWifiErrorCode result, List deviceList) { + Log.e(TAG, "didDiscovered: 更新数据---------------"); + GosDeviceModuleBaseFragment.deviceslist.clear(); + for (GizWifiDevice gizWifiDevice : deviceList) { + GosDeviceModuleBaseFragment.deviceslist.add(gizWifiDevice); + } + handler.sendEmptyMessage(UPDATALIST); + } + + protected void didUserLogin(GizWifiErrorCode result, String uid, String token) { + Log.e(TAG, "didUserLogin: -----------"); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS == result) { + loginStatus = 2; + this.uid = uid; + this.token = token; + spf.edit().putString("Uid", this.uid).commit(); + spf.edit().putString("Token", this.token).commit(); + handler.sendEmptyMessage(GETLIST); + // TODO 绑定推送 + //GosPushManager.pushBindService(token); + if (GosDeploy.appConfig_Push_BaiDu()) { + GosPushManager.pushBindService(uid, token); + } + if (GosDeploy.appConfig_Push_JiGuang()) { + GosPushManager.pushBindService(uid, token); + } + } else { + loginStatus = 0; + if (GosDeploy.appConfig_Login_Anonymous()) { + tryUserLoginAnonymous(); + } + } + } + + protected void didUnbindDevice(GizWifiErrorCode result, String did) { + if (progressDialog != null) { + progressDialog.cancel(); + } + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + // String unBoundFailed = (String) getText(R.string.unbound_failed); + Toast.makeText(getContext(), toastError(result), 2000).show(); + } + } + + @Override + protected void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + // TODO 控制页面跳转 + if (progressDialog != null) { + progressDialog.cancel(); + } + Message msg = new Message(); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS == result) { + msg.what = TOCONTROL; + msg.obj = device; + } else { + if (device.isBind()) { + msg.what = TOAST; + // String setSubscribeFail = (String) + // getText(R.string.setsubscribe_failed); + msg.obj = toastError(result);// setSubscribeFail + "\n" + arg0; + } + } + handler.sendMessage(msg); + } + + /** + * 推送绑定回调 + * + * @param result + */ + @Override + protected void didChannelIDBind(GizWifiErrorCode result) { + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + Toast.makeText(getContext(), toastError(result), 2000).show(); + } + } + + /** + * 设备绑定回调(旧) + * + * @param error + * @param errorMessage + * @param did + */ + protected void didBindDevice(int error, String errorMessage, String did) { + if (progressDialog != null) { + progressDialog.cancel(); + } + if (error != 0) { + + String toast = getResources().getString(R.string.bound_failed) + "\n" + errorMessage; + Toast.makeText(getContext(), toast, 2000).show(); + // Toast.makeText(this, R.string.bound_failed + "\n" + errorMessage, + // 2000).show(); + } else { + + Toast.makeText(getContext(), R.string.bound_successful, 2000).show(); + } + + } + + private static final String TAG = "GosDeviceListFragment"; + + /** + * 设备绑定回调 + * + * @param result + * @param did + */ + protected void didBindDevice(GizWifiErrorCode result, String did) { + if (progressDialog != null) { + progressDialog.cancel(); + + } + if (result != GizWifiErrorCode.GIZ_SDK_SUCCESS) { + Toast.makeText(getContext(), toastError(result), 2000).show(); + } else { + + Toast.makeText(getContext(), R.string.add_successful, 2000).show(); + } + } + + + private void UpdateUI() { + + if (GosDeviceModuleBaseFragment.deviceslist.isEmpty()) { + svListGroup.setVisibility(View.GONE); + llNoDevice.setVisibility(View.VISIBLE); + mSwipeLayout1.setVisibility(View.VISIBLE); + return; + } else { + llNoDevice.setVisibility(View.GONE); + mSwipeLayout1.setVisibility(View.GONE); + svListGroup.setVisibility(View.VISIBLE); + } + + if (boundDevicesList == null) { + boundDevicesList = new ArrayList(); + } else { + boundDevicesList.clear(); + } + if (foundDevicesList == null) { + foundDevicesList = new ArrayList(); + } else { + foundDevicesList.clear(); + } + if (offlineDevicesList == null) { + offlineDevicesList = new ArrayList(); + } else { + offlineDevicesList.clear(); + } + + for (GizWifiDevice gizWifiDevice : GosDeviceModuleBaseFragment.deviceslist) { + if (gizWifiDevice.isBind()) { + boundDevicesList.add(gizWifiDevice); + } else { + foundDevicesList.add(gizWifiDevice); + } + } + if (foundDevicesList.isEmpty()) { + slvFoundDevices.setVisibility(View.GONE); + llNoFoundDevices.setVisibility(View.VISIBLE); + } else { + if (myadapter == null) { + myadapter = new GosDeviceListAdapter(getContext(), foundDevicesList); + myadapter.setHandler(handler); + myadapter.setSpf(spf); + slvFoundDevices.setAdapter(myadapter); + } else { + myadapter.notifyDataSetChanged(); + } + llNoFoundDevices.setVisibility(View.GONE); + slvFoundDevices.setVisibility(View.VISIBLE); + } + if (boundDevicesList.isEmpty()) { + slvBoundDevices.setVisibility(View.GONE); + llNoBoundDevices.setVisibility(View.VISIBLE); + } else { + if (myadapter1 == null) { + myadapter1 = new GosDeviceListAdapter(getContext(), boundDevicesList); + myadapter1.setHandler(handler); + myadapter1.setSpf(spf); + slvBoundDevices.setAdapter(myadapter1); + } else { + if (slvBoundDevices.isSlided()) { + slvBoundDevices.slideBack(); + } + myadapter1.notifyDataSetChanged(); + } + llNoBoundDevices.setVisibility(View.GONE); + slvBoundDevices.setVisibility(View.VISIBLE); + } + } + + private void addDevice() { + if (GosDeploy.appConfig_Config_Softap()) { + if (!checkNetwork(getContext())) { + Toast.makeText(getContext(), R.string.network_error, 2000).show(); + return; + } + if (GosDeploy.appConfig_Config_Airlink()) { + final Dialog dialog = new AlertDialog.Builder(getContext(), R.style.alert_dialog_style) + .setView(new EditText(getContext())).create(); + dialog.setCanceledOnTouchOutside(true); + dialog.show(); + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_overflow); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llAirlink; + LinearLayout llSoftap; + llAirlink = (LinearLayout) window.findViewById(R.id.llAirlink); + llSoftap = (LinearLayout) window.findViewById(R.id.llSoftap); + llAirlink.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + intent = new Intent(getContext(), GosAirlinkChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + dialog.dismiss(); + } + }); + llSoftap.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + intent = new Intent(getContext(), GosChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + dialog.dismiss(); + } + }); + } else { + Intent intent = new Intent(getContext(), GosChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + } + } else { + if (GosDeploy.appConfig_Config_Airlink()) { + if (!checkNetwork(getContext())) { + Toast.makeText(getContext(), R.string.network_error, 2000).show(); + return; + } + Intent intent = new Intent(getContext(), GosAirlinkChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + } + } + } + + private void tryUserLoginAnonymous() { + threeSeconds = 3; + final Timer tsTimer = new Timer(); + tsTimer.schedule(new TimerTask() { + + @Override + public void run() { + threeSeconds--; + if (threeSeconds <= 0) { + tsTimer.cancel(); + handler.sendEmptyMessage(GETLIST); + } else { + if (loginStatus == 4) { + tsTimer.cancel(); + } + } + } + }, 1000, 1000); + } + + @Override + public void onRefresh() { + handler.sendEmptyMessageDelayed(PULL_TO_REFRESH, 2000); + } + + @Override + public void onDestroy() { + super.onDestroy(); + progressDialog = null; + } + + /** + * 设置ProgressDialog + */ + public void setProgressDialog() { + progressDialog = new ProgressDialog(getContext()); + String loadingText = getString(R.string.loadingtext); + progressDialog.setMessage(loadingText); + progressDialog.setCanceledOnTouchOutside(false); + } + + /** + * 检查网络连通性(工具方法) + * + * @param context + * @return + */ + public boolean checkNetwork(Context context) { + ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo net = conn.getActiveNetworkInfo(); + if (net != null && net.isConnected()) { + return true; + } + return false; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseActivity.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseActivity.java new file mode 100644 index 0000000..e84e3d5 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseActivity.java @@ -0,0 +1,210 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import com.gizwits.gizwifisdk.api.GizWifiCentralControlDevice; +import com.gizwits.gizwifisdk.api.GizWifiDevice; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceNetStatus; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizWifiCentralControlDeviceListener; +import com.gizwits.gizwifisdk.listener.GizWifiDeviceListener; +import com.gizwits.gizwifisdk.listener.GizWifiSDKListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class GosDeviceModuleBaseActivity extends GosBaseActivity { + + /** + * 设备列表 + */ + protected static List deviceslist = new ArrayList(); + + private GizWifiSDKListener gizWifiSDKListener = new GizWifiSDKListener() { + + /** 用于设备列表 */ + public void didDiscovered(GizWifiErrorCode result, List deviceList) { + GosDeviceModuleBaseActivity.this.didDiscovered(result, deviceList); + } + + /** 用于用户匿名登录 */ + public void didUserLogin(GizWifiErrorCode result, String uid, String token) { + GosDeviceModuleBaseActivity.this.didUserLogin(result, uid, token); + } + + /** 用于设备解绑 */ + public void didUnbindDevice(GizWifiErrorCode result, String did) { + GosDeviceModuleBaseActivity.this.didUnbindDevice(result, did); + } + + /** 用于设备绑定 */ + public void didBindDevice(GizWifiErrorCode result, String did) { + GosDeviceModuleBaseActivity.this.didBindDevice(result, did); + } + + /** 用于设备绑定(旧) */ + public void didBindDevice(int error, String errorMessage, String did) { + GosDeviceModuleBaseActivity.this.didBindDevice(error, errorMessage, did); + } + + ; + + /** 用于绑定推送 */ + public void didChannelIDBind(GizWifiErrorCode result) { + GosDeviceModuleBaseActivity.this.didChannelIDBind(result); + } + + }; + + /** + * 设备列表回调 + * + * @param result + * @param deviceList + */ + protected void didDiscovered(GizWifiErrorCode result, List deviceList) { + } + + /** + * 用户匿名登录回调 + * + * @param result + * @param uid + * @param token + */ + protected void didUserLogin(GizWifiErrorCode result, String uid, String token) { + } + + /** + * 设备解绑回调 + * + * @param result + * @param did + */ + protected void didUnbindDevice(GizWifiErrorCode result, String did) { + } + + /** + * 设备绑定回调(旧) + * + * @param error + * @param errorMessage + * @param did + */ + protected void didBindDevice(int error, String errorMessage, String did) { + } + + ; + + /** + * 设备绑定回调 + * + * @param result + * @param did + */ + protected void didBindDevice(GizWifiErrorCode result, String did) { + } + + /** + * 绑定推送回调 + * + * @param result + */ + protected void didChannelIDBind(GizWifiErrorCode result) { + } + + /** + * 设备监听 + */ + protected GizWifiDeviceListener gizWifiDeviceListener = new GizWifiDeviceListener() { + + // 用于设备订阅 + public void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + GosDeviceModuleBaseActivity.this.didSetSubscribe(result, device, isSubscribed); + } + + ; + + }; + + protected GizWifiCentralControlDeviceListener gizWifisubDeviceListener = new GizWifiCentralControlDeviceListener() { + + // 用于设备订阅 + public void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + GosDeviceModuleBaseActivity.this.didSetSubscribe(result, device, isSubscribed); + } + + //同步更新子设备列表 + @Override + public void didUpdateSubDevices(GizWifiCentralControlDevice device, GizWifiErrorCode result, List subDeviceList) { + GosDeviceModuleBaseActivity.this.didUpdateSubDevices(device, result, subDeviceList); + } + + //设备网络状态变化通知 + @Override + public void didUpdateNetStatus(GizWifiDevice device, GizWifiDeviceNetStatus netStatus) { + GosDeviceModuleBaseActivity.this.didUpdateNetStatus(device, netStatus); + } + + ; + + }; + + public GizWifiDeviceListener getGizWifiDeviceListener(GizWifiDevice device) { + + if (device.getProductType() == GizWifiDeviceType.GizDeviceNormal) { + return gizWifiDeviceListener; + } else { + return gizWifisubDeviceListener; + } + + } + + /** + * 设备网络状态变化通知 + * + * @param device + * @param netStatus + */ + protected void didUpdateNetStatus(GizWifiDevice device, GizWifiDeviceNetStatus netStatus) { + } + + /** + * 同步更新子设备列表 + * + * @param device + * @param result + * @param subDeviceList + */ + protected void didUpdateSubDevices(GizWifiCentralControlDevice device, GizWifiErrorCode result, List subDeviceList) { + } + + + /** + * 设备订阅回调 + * + * @param result + * @param device + * @param isSubscribed + */ + protected void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + } + + @Override + protected void onResume() { + super.onResume(); + // 每次返回activity都要注册一次sdk监听器,保证sdk状态能正确回调 + GizWifiSDK.sharedInstance().setListener(gizWifiSDKListener); + } + + /** + * @param result + * @param cloudServiceInfo + */ + protected void didGetCurrentCloudService(GizWifiErrorCode result, + ConcurrentHashMap cloudServiceInfo) { + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseFragment.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseFragment.java new file mode 100644 index 0000000..335d0c9 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosDeviceModuleBaseFragment.java @@ -0,0 +1,214 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.util.Log; + +import com.gizwits.gizwifisdk.api.GizWifiCentralControlDevice; +import com.gizwits.gizwifisdk.api.GizWifiDevice; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceNetStatus; +import com.gizwits.gizwifisdk.enumration.GizWifiDeviceType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizWifiCentralControlDeviceListener; +import com.gizwits.gizwifisdk.listener.GizWifiDeviceListener; +import com.gizwits.gizwifisdk.listener.GizWifiSDKListener; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class GosDeviceModuleBaseFragment extends GosBaseFragment { + + /** + * 设备列表 + */ + protected static List deviceslist = new ArrayList(); + + private GizWifiSDKListener gizWifiSDKListener = new GizWifiSDKListener() { + + /** 用于设备列表 */ + public void didDiscovered(GizWifiErrorCode result, List deviceList) { + GosDeviceModuleBaseFragment.this.didDiscovered(result, deviceList); + Log.e("GosDeviceModuleBaseFragment", "didDiscovered=====----: 更新数据"); + } + + /** 用于用户匿名登录 */ + public void didUserLogin(GizWifiErrorCode result, String uid, String token) { + GosDeviceModuleBaseFragment.this.didUserLogin(result, uid, token); + } + + /** 用于设备解绑 */ + public void didUnbindDevice(GizWifiErrorCode result, String did) { + GosDeviceModuleBaseFragment.this.didUnbindDevice(result, did); + } + + /** 用于设备绑定 */ + public void didBindDevice(GizWifiErrorCode result, String did) { + GosDeviceModuleBaseFragment.this.didBindDevice(result, did); + } + + /** 用于设备绑定(旧) */ + public void didBindDevice(int error, String errorMessage, String did) { + GosDeviceModuleBaseFragment.this.didBindDevice(error, errorMessage, did); + } + + ; + + /** 用于绑定推送 */ + public void didChannelIDBind(GizWifiErrorCode result) { + GosDeviceModuleBaseFragment.this.didChannelIDBind(result); + } + + }; + + /** + * 设备列表回调 + * + * @param result + * @param deviceList + */ + protected void didDiscovered(GizWifiErrorCode result, List deviceList) { + } + + /** + * 用户匿名登录回调 + * + * @param result + * @param uid + * @param token + */ + protected void didUserLogin(GizWifiErrorCode result, String uid, String token) { + } + + /** + * 设备解绑回调 + * + * @param result + * @param did + */ + protected void didUnbindDevice(GizWifiErrorCode result, String did) { + } + + /** + * 设备绑定回调(旧) + * + * @param error + * @param errorMessage + * @param did + */ + protected void didBindDevice(int error, String errorMessage, String did) { + } + + ; + + /** + * 设备绑定回调 + * + * @param result + * @param did + */ + protected void didBindDevice(GizWifiErrorCode result, String did) { + } + + /** + * 绑定推送回调 + * + * @param result + */ + protected void didChannelIDBind(GizWifiErrorCode result) { + } + + /** + * 设备监听 + */ + protected GizWifiDeviceListener gizWifiDeviceListener = new GizWifiDeviceListener() { + + // 用于设备订阅 + public void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + GosDeviceModuleBaseFragment.this.didSetSubscribe(result, device, isSubscribed); + } + + ; + + }; + + protected GizWifiCentralControlDeviceListener gizWifisubDeviceListener = new GizWifiCentralControlDeviceListener() { + + // 用于设备订阅 + public void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + GosDeviceModuleBaseFragment.this.didSetSubscribe(result, device, isSubscribed); + } + + //同步更新子设备列表 + @Override + public void didUpdateSubDevices(GizWifiCentralControlDevice device, GizWifiErrorCode result, List subDeviceList) { + GosDeviceModuleBaseFragment.this.didUpdateSubDevices(device, result, subDeviceList); + } + + //设备网络状态变化通知 + @Override + public void didUpdateNetStatus(GizWifiDevice device, GizWifiDeviceNetStatus netStatus) { + GosDeviceModuleBaseFragment.this.didUpdateNetStatus(device, netStatus); + } + + ; + + }; + + public GizWifiDeviceListener getGizWifiDeviceListener(GizWifiDevice device) { + + if (device.getProductType() == GizWifiDeviceType.GizDeviceNormal) { + return gizWifiDeviceListener; + } else { + return gizWifisubDeviceListener; + } + + } + + /** + * 设备网络状态变化通知 + * + * @param device + * @param netStatus + */ + protected void didUpdateNetStatus(GizWifiDevice device, GizWifiDeviceNetStatus netStatus) { + } + + /** + * 同步更新子设备列表 + * + * @param device + * @param result + * @param subDeviceList + */ + protected void didUpdateSubDevices(GizWifiCentralControlDevice device, GizWifiErrorCode result, List subDeviceList) { + } + + + /** + * 设备订阅回调 + * + * @param result + * @param device + * @param isSubscribed + */ + protected void didSetSubscribe(GizWifiErrorCode result, GizWifiDevice device, boolean isSubscribed) { + } + + @Override + public void onResume() { + super.onResume(); + // 每次返回activity都要注册一次sdk监听器,保证sdk状态能正确回调 + GizWifiSDK.sharedInstance().setListener(gizWifiSDKListener); + Log.e("TAG", "GosDeviceModuleBaseFragment ----onResume: ---"); + } + + + /** + * @param result + * @param cloudServiceInfo + */ + protected void didGetCurrentCloudService(GizWifiErrorCode result, + ConcurrentHashMap cloudServiceInfo) { + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosMainActivity.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosMainActivity.java new file mode 100644 index 0000000..a6ce368 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosMainActivity.java @@ -0,0 +1,403 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.ColorStateList; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.design.widget.BottomNavigationView; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.CommonModule.NoScrollViewPager; +import com.gizwits.opensource.appkit.CommonModule.TipsDialog; +//config-all-start +// config_airlink-false-start +import com.gizwits.opensource.appkit.ConfigModule.GosAirlinkChooseDeviceWorkWiFiActivity; +// config_airlink-false-end +//config_softap-false-start +import com.gizwits.opensource.appkit.ConfigModule.GosChooseDeviceWorkWiFiActivity; +//config_softap-false-end +//config-all-end +//push-all-start +import com.gizwits.opensource.appkit.PushModule.GosPushManager; +//push-all-end + +import com.gizwits.opensource.appkit.utils.ToolUtils; + +import java.util.Timer; +import java.util.TimerTask; + +import zxing.CaptureActivity; + + +public class GosMainActivity extends GosDeviceModuleBaseActivity implements BottomNavigationView.OnNavigationItemSelectedListener { + + Context context = null; + @SuppressWarnings("deprecation") + + private int viewPagerSelected = 0; + private Intent intent; + + public static Activity instance = null; + private BottomNavigationView navigation; + private NoScrollViewPager viewPager; + + private static final int REQUEST_EXTERNAL_STORAGE = 22; + private static String[] PERMISSIONS_STORAGE = {"android.permission.CAMERA"}; + + @Override + public boolean onNavigationItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.navigation_device: + if (GosDeploy.appConfig_BindDevice_Qrcode()) { + int color = GosDeploy.appConfig_Contrast(); + final Drawable upArrow = getResources().getDrawable(R.drawable.common_qrcode_button); + upArrow.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + mToolbar.setNavigationIcon(upArrow); + SpannableString ssTitle = new SpannableString(this.getString(R.string.devicelist_title)); + ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvTitle.setText(ssTitle); + } else { + mToolbar.setNavigationIcon(null); + SpannableString ssTitle = new SpannableString(this.getString(R.string.devicelist_title)); + ssTitle.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvTitle.setText(ssTitle); + } + break; + case R.id.navigation_message: + mToolbar.setNavigationIcon(null); + SpannableString ssTitle1 = new SpannableString(this.getString(R.string.messagecenter)); + ssTitle1.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle1.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvTitle.setText(ssTitle1); + break; + case R.id.navigation_user: + mToolbar.setNavigationIcon(null); + SpannableString ssTitle2 = new SpannableString(this.getString(R.string.personal_center)); + ssTitle2.setSpan(new ForegroundColorSpan(GosDeploy.appConfig_Contrast()), 0, ssTitle2.length(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + tvTitle.setText(ssTitle2); + break; + } + viewPager.setCurrentItem(TabFragment.form(item.getItemId()).ordinal()); + return true; + } + + private enum TabFragment { + + device(R.id.navigation_device, GosDeviceListFragment.class), + message(R.id.navigation_message, MessageCenterFragment.class), + user(R.id.navigation_user, GosSettiingsFragment.class); + + private int menuId; + private Class mClass; + private Fragment fragment; + + TabFragment(int menuId, Class mClass) { + this.menuId = menuId; + this.mClass = mClass; + } + + private Fragment fragment() { + if (fragment == null) { + try { + fragment = mClass.newInstance(); + } catch (Exception e) { + e.printStackTrace(); + fragment = new Fragment(); + } + } + return fragment; + } + + public static TabFragment form(int menuId) { + for (TabFragment fragment : values()) { + if (fragment.menuId == menuId) { + return fragment; + } + } + return user; + } + + public static void onDestroy() { + for (TabFragment fragment : values()) { + fragment.fragment = null; + } + } + } + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_main); + context = GosMainActivity.this; + if (GosDeploy.appConfig_BindDevice_Qrcode()) { + setToolBar(true, R.string.devicelist_title); + } else { + setToolBar(false, R.string.devicelist_title); + } + initView(); + } + + private void initView() { + navigation = (BottomNavigationView) findViewById(R.id.navigation); + setThemeColor(GosDeploy.appConfig_Background()); + navigation.setOnNavigationItemSelectedListener(this); + viewPager = (NoScrollViewPager) findViewById(R.id.content); + viewPager.setNoScroll(true); + viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { + @Override + public Fragment getItem(int position) { + return TabFragment.values()[position].fragment(); + } + + @Override + public int getCount() { + return TabFragment.values().length; + } + }); + + viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + viewPagerSelected = position; + supportInvalidateOptionsMenu(); + navigation.setSelectedItemId(TabFragment.values()[position].menuId); + } + }); + } + + //config-all-start + @Override + public boolean onCreateOptionsMenu(Menu menu) { + switch (viewPagerSelected) { + case 0: + if (GosDeploy.appConfig_Config_Airlink()) { + if (GosDeploy.appConfig_Config_Softap()) { + getMenuInflater().inflate(R.menu.gosdeviceconfig, menu); + } else { + getMenuInflater().inflate(R.menu.gosnull, menu); + MenuItem menuItem = menu.findItem(R.id.add); + menuItem.setIcon(ToolUtils.editIcon(getResources(), R.drawable.deviceonboarding_add)); + } + } else { + if (GosDeploy.appConfig_Config_Softap()) { + getMenuInflater().inflate(R.menu.gosnull, menu); + MenuItem menuItem = menu.findItem(R.id.add); + menuItem.setIcon(ToolUtils.editIcon(getResources(), R.drawable.deviceonboarding_add)); + } + } + break; + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + //bindDevice_qrcode-false-start + case android.R.id.home: + if (GosDeploy.appConfig_BindDevice_Qrcode()) { + int permission = ActivityCompat.checkSelfPermission(GosMainActivity.this, + "android.permission.CAMERA"); + if (permission != PackageManager.PERMISSION_GRANTED) { + try { + // 没有写的权限,去申请写的权限,会弹出对话框 + ActivityCompat.requestPermissions(GosMainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + intent = new Intent(GosMainActivity.this, CaptureActivity.class); + startActivity(intent); + overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left); + } + } + break; + //bindDevice_qrcode-false-end + //config_airlink-false-start config_softap-false-start + case R.id.airlink_config: + if (!checkNetwork(GosMainActivity.this)) { + Toast.makeText(GosMainActivity.this, R.string.network_error, 2000).show(); + } else { + intent = new Intent(GosMainActivity.this, GosAirlinkChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + } + break; + case R.id.softap_config: + if (!checkNetwork(GosMainActivity.this)) { + Toast.makeText(GosMainActivity.this, R.string.network_error, 2000).show(); + } else { + intent = new Intent(GosMainActivity.this, GosChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + } + break; + //config_softap-false-end config_airlink-false-end + case R.id.add: + if (GosDeploy.appConfig_Config_Airlink()) { + if (!checkNetwork(GosMainActivity.this)) { + Toast.makeText(GosMainActivity.this, R.string.network_error, 2000).show(); + } else { + intent = new Intent(GosMainActivity.this, GosAirlinkChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + } + } + if (GosDeploy.appConfig_Config_Softap()) { + if (!checkNetwork(GosMainActivity.this)) { + Toast.makeText(GosMainActivity.this, R.string.network_error, 2000).show(); + } else { + intent = new Intent(GosMainActivity.this, GosChooseDeviceWorkWiFiActivity.class); + startActivity(intent); + } + } + break; + } + return super.onOptionsItemSelected(item); + } + //config-all-end + + //bindDevice_qrcode-false-start + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (GosDeploy.appConfig_BindDevice_Qrcode()) { + if (requestCode == 22) { + intent = new Intent(GosMainActivity.this, CaptureActivity.class); + startActivity(intent); + overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left); + } + } + } + //bindDevice_qrcode-false-end + + + /** + * 菜单、返回键响应 + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + exitBy2Click(); // 调用双击退出函数 + } + return false; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == 666) { + finish(); + } else if (resultCode == 98765) { + TipsDialog dialog = new TipsDialog(GosMainActivity.this, + getResources().getString(R.string.devicedisconnected)); + dialog.show(); + } + } + + + public void exitBy2Click() { + Timer tExit = null; + if (isExit == false) { + isExit = true; // 准备退出; + String doubleClick; + if (!TextUtils.isEmpty(spf.getString("UserName", "")) + && !TextUtils.isEmpty(spf.getString("PassWord", ""))) { + doubleClick = (String) getText(R.string.doubleclick_logout); + } else { + if (getIntent().getBooleanExtra("ThredLogin", false)) { + doubleClick = (String) getText(R.string.doubleclick_logout); + } else { + doubleClick = (String) getText(R.string.doubleclick_back); + } + } + + Toast.makeText(this, doubleClick, 2000).show(); + tExit = new Timer(); + tExit.schedule(new TimerTask() { + @Override + public void run() { + isExit = false; // 取消退出 + } + }, 2000); // 如果2秒钟内没有按下返回键,则启动定时器取消掉刚才执行的任务 + + } else { + logoutToClean(); + } + } + + /** + * 注销函数 + */ + void logoutToClean() { + spf.edit().putString("UserName", "").commit(); + spf.edit().putString("PassWord", "").commit(); + spf.edit().putString("Uid", "").commit(); + //push-all-start + GosPushManager.pushUnBindService(spf.getString("Token", "")); + //push-all-end + spf.edit().putString("Token", "").commit(); + + finish(); + if (GosDeviceListFragment.loginStatus == 1) { + GosDeviceListFragment.loginStatus = 0; + } else { + GosDeviceListFragment.loginStatus = 4; + } + } + + /** + * 双击退出函数 + */ + private static Boolean isExit = false; + + /** + * 更改主题 + * + * @param colorPrimary 标题栏背景颜色 + */ + private void setThemeColor(int colorPrimary) { + final Drawable add = getResources().getDrawable(R.drawable.deviceonboarding_add); + int color = GosDeploy.appConfig_Contrast(); + add.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + mToolbar.setOverflowIcon(add); + // bindDevice_qrcode-false-start + if (GosDeploy.appConfig_BindDevice_Qrcode()) { + final Drawable upArrow = getResources().getDrawable(R.drawable.common_qrcode_button); + upArrow.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); + mToolbar.setNavigationIcon(upArrow); + } + // bindDevice_qrcode-false-end + //动态设置底部导航栏的颜色 + int[][] states = new int[][]{ + new int[]{-android.R.attr.state_checked}, + new int[]{android.R.attr.state_checked} + }; + + int[] colors = new int[]{ToolUtils.editTextAlpha(), color}; + ColorStateList csl = new ColorStateList(states, colors); + // 背景颜色 + navigation.setBackgroundColor(colorPrimary); + // 文字颜色 + navigation.setItemIconTintList(csl); + // 图片颜色 + navigation.setItemTextColor(csl); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosMessageHandler.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosMessageHandler.java new file mode 100644 index 0000000..41fcbbf --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosMessageHandler.java @@ -0,0 +1,108 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.wifi.ScanResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.widget.RemoteViews; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.utils.NetUtils; + +import java.util.ArrayList; +import java.util.List; + +public class GosMessageHandler { + + NotificationManager nm; + + protected static final int SHOWDIALOG = 999; + + private Context mcContext; + + private ArrayList newDeviceList = new ArrayList(); + + private Handler mainHandler; + // 做一个单例 + private static GosMessageHandler mInstance = new GosMessageHandler(); + + public static GosMessageHandler getSingleInstance() { + return mInstance; + } + + public void SetHandler(Handler handler) { + this.mainHandler = handler; + } + + public void StartLooperWifi(Context context) { + this.mcContext = context; + HandlerThread looperwifi = new HandlerThread("looperwifi"); + looperwifi.start(); + looper = new MyLooperHandler(looperwifi.getLooper()); + looper.post(mRunnable); + } + + class MyLooperHandler extends Handler { + public MyLooperHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + } + + } + + /** + * 子线程实现 + */ + private Runnable mRunnable = new Runnable() { + + public void run() { + if (mcContext == null) { + return; + } + newDeviceList.clear(); + List currentWifiScanResult = NetUtils + .getCurrentWifiScanResult(mcContext); + GosConstant.ssidList = currentWifiScanResult; + int flog = 0; + if (currentWifiScanResult != null) { + for (ScanResult scanResult : currentWifiScanResult) { + String ssid = scanResult.SSID; + // 获取系统的NotificationManager服务 + nm = (NotificationManager) mcContext + .getSystemService(Context.NOTIFICATION_SERVICE); + if (ssid.contains(GosBaseActivity.SoftAP_Start) + && ssid.length() > GosBaseActivity.SoftAP_Start.length() + && !newDeviceList.toString().contains(ssid)) { + newDeviceList.add(ssid); + flog++; + } + } + } + + if (mainHandler != null && newDeviceList.size() > 0) { + mainHandler.sendEmptyMessage(SHOWDIALOG); + } + + looper.postDelayed(mRunnable, 2000); + } + }; + private MyLooperHandler looper; + + + public ArrayList getNewDeviceList() { + return newDeviceList; + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/GosSettiingsFragment.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosSettiingsFragment.java new file mode 100644 index 0000000..81ca79f --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/GosSettiingsFragment.java @@ -0,0 +1,136 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.SettingsModule.GosAboutActivity; +import com.gizwits.opensource.appkit.UserModule.GosUserManager; +import com.gizwits.opensource.appkit.sharingdevice.SharedDeviceListAcitivity; + +public class GosSettiingsFragment extends GosBaseFragment implements OnClickListener { + + private static final int SETTINGS = 123; + /** + * The ll About + */ + private LinearLayout llAbout; + + /** + * The Intent + */ + Intent intent; + + private LinearLayout usermanager; + + private RelativeLayout lllogin; + private LinearLayout llDeviceShared; + + private TextView phoneusername; + private View allView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + allView = inflater.inflate(R.layout.activity_gos_settings, container, false); + initView(); + initEvent(); + return allView; + } + + private void initView() { + llAbout = (LinearLayout) allView.findViewById(R.id.llAbout); + usermanager = (LinearLayout) allView.findViewById(R.id.usermanager); + lllogin = (RelativeLayout) allView.findViewById(R.id.lllogin); + phoneusername = (TextView) allView.findViewById(R.id.phoneusername); + llDeviceShared = (LinearLayout) allView.findViewById(R.id.deviceshared); + } + + private void initEvent() { + llAbout.setOnClickListener(this); + usermanager.setOnClickListener(this); + lllogin.setOnClickListener(this); + llDeviceShared.setOnClickListener(this); + + if (!TextUtils.isEmpty(spf.getString("UserName", "")) && !TextUtils.isEmpty(spf.getString("PassWord", ""))) { + usermanager.setVisibility(View.VISIBLE); + lllogin.setVisibility(View.GONE); + phoneusername.setText(spf.getString("UserName", "")); + } else if (TextUtils.isEmpty(spf.getString("UserName", "")) && TextUtils.isEmpty(spf.getString("PassWord", "")) + && !TextUtils.isEmpty(spf.getString("thirdUid", ""))) { + usermanager.setVisibility(View.VISIBLE); + String uid = spf.getString("thirdUid", ""); + + lllogin.setVisibility(View.GONE); + String myuid = uid.substring(0, 2) + "***" + uid.substring(uid.length() - 4, uid.length()); + phoneusername.setText(myuid); + } else { + usermanager.setVisibility(View.GONE); + lllogin.setVisibility(View.VISIBLE); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.llAbout: + intent = new Intent(getContext(), GosAboutActivity.class); + startActivity(intent); + llAbout.setEnabled(false); + llAbout.postDelayed(new Runnable() { + @Override + public void run() { + llAbout.setEnabled(true); + } + }, 1000); + break; + + case R.id.usermanager: + intent = null; + if (intent == null) { + intent = new Intent(getContext(), GosUserManager.class); + } + startActivityForResult(intent, SETTINGS); + usermanager.setEnabled(false); + usermanager.postDelayed(new Runnable() { + @Override + public void run() { + usermanager.setEnabled(true); + } + }, 1000); + break; + case R.id.lllogin: + lllogin.setEnabled(false); + lllogin.postDelayed(new Runnable() { + @Override + public void run() { + lllogin.setEnabled(true); + } + }, 1000); + getActivity().finish(); + break; + case R.id.deviceshared: + Intent deviceshared1 = new Intent(getContext(), SharedDeviceListAcitivity.class); + startActivity(deviceshared1); + llDeviceShared.setEnabled(false); + llDeviceShared.postDelayed(new Runnable() { + @Override + public void run() { + llDeviceShared.setEnabled(true); + } + }, 1000); + break; + default: + break; + } + + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/DeviceModule/MessageCenterFragment.java b/src/java/com/gizwits/opensource/appkit/DeviceModule/MessageCenterFragment.java new file mode 100644 index 0000000..6b309be --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/DeviceModule/MessageCenterFragment.java @@ -0,0 +1,136 @@ +package com.gizwits.opensource.appkit.DeviceModule; + +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizMessage; +import com.gizwits.gizwifisdk.enumration.GizMessageStatus; +import com.gizwits.gizwifisdk.enumration.GizMessageType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizDeviceSharingListener; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.sharingdevice.MsgNoticeActivity; +import com.gizwits.opensource.appkit.sharingdevice.deviceSharedMessageActivity; + +import java.util.List; + +//personalCenter_deviceSharing-false-start +//personalCenter_deviceSharing-false-end + +public class MessageCenterFragment extends GosBaseFragment { + + + private LinearLayout llGizwitsmes; + //personalCenter_deviceSharing-false-start + private View redpoint; + private LinearLayout llDevicesShared; + //personalCenter_deviceSharing-false-end + private View allView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + allView = inflater.inflate(R.layout.activity_gos_message, container, false); + initView(); + initEvent(); + return allView; + } + + //界面可见时再加载数据 + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (isVisibleToUser) { + //请求网络数据 + //personalCenter_deviceSharing-false-start + String token = spf.getString("Token", ""); + GizDeviceSharing.queryMessageList(token, GizMessageType.GizMessageSharing); + //GizDeviceSharing.queryMessageList(token, GizMessageType.GizMessageSystem); + + GizDeviceSharing.setListener(new GizDeviceSharingListener() { + + @Override + public void didQueryMessageList(GizWifiErrorCode result, List messageList) { + super.didQueryMessageList(result, messageList); + + if (messageList.size() > 0) { + isShowRedPoint(messageList); + } else { + redpoint.setVisibility(View.GONE); + } + + if (result.ordinal() != 0) { + Toast.makeText(getContext(), toastError(result), 2).show(); + } + } + }); + //personalCenter_deviceSharing-false-end + } + } + + //personalCenter_deviceSharing-false-start + private void isShowRedPoint(List messageList) { + + boolean isshow = false; + redpoint.setVisibility(View.GONE); + for (int i = 0; i < messageList.size(); i++) { + + GizMessage gizMessage = messageList.get(i); + GizMessageStatus status = gizMessage.getStatus(); + if (status.ordinal() == 0) { + isshow = true; + redpoint.setVisibility(View.VISIBLE); + } + } + } + //personalCenter_deviceSharing-false-end + + private void initView() { + llGizwitsmes = (LinearLayout) allView.findViewById(R.id.gizwitsmes); + //personalCenter_deviceSharing-false-start + // 判断当前的view 是否需要显示这个红点 + redpoint = allView.findViewById(R.id.redpoint); + llDevicesShared = (LinearLayout) allView.findViewById(R.id.deviceshared); + //personalCenter_deviceSharing-false-end + } + + private void initEvent() { + llGizwitsmes.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 跳转到机智云公告页面 + Intent intent = new Intent(getContext(), MsgNoticeActivity.class); + startActivity(intent); + llGizwitsmes.setEnabled(false); + llGizwitsmes.postDelayed(new Runnable() { + @Override + public void run() { + llGizwitsmes.setEnabled(true); + } + }, 1000); + } + }); + //personalCenter_deviceSharing-false-start + llDevicesShared.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent tent = new Intent(getContext(), deviceSharedMessageActivity.class); + startActivity(tent); + llDevicesShared.setEnabled(false); + llDevicesShared.postDelayed(new Runnable() { + @Override + public void run() { + llDevicesShared.setEnabled(true); + } + }, 1000); + } + }); + //personalCenter_deviceSharing-false-end + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/GosApplication.java b/src/java/com/gizwits/opensource/appkit/GosApplication.java new file mode 100644 index 0000000..e2497d1 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/GosApplication.java @@ -0,0 +1,13 @@ +package com.gizwits.opensource.appkit; + +import android.app.Application; +public class GosApplication extends Application { + + public static int flag = 0; + + public void onCreate() { + super.onCreate(); + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/MessageCenter.java b/src/java/com/gizwits/opensource/appkit/MessageCenter.java new file mode 100644 index 0000000..b17da1a --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/MessageCenter.java @@ -0,0 +1,112 @@ +package com.gizwits.opensource.appkit; + +import android.content.Context; +import android.os.Handler; +import android.text.TextUtils; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizLogPrintLevel; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +public class MessageCenter { + private static MessageCenter mCenter; + int flag = 0; + + GosDeploy gosDeploy; + + private int SETCLOUD = 1111; + + private MessageCenter(Context c) { + if (mCenter == null) { + init(c); + } + } + + private void init(Context c) { + gosDeploy = new GosDeploy(c); + //config-all-start + if (GosDeploy.appConfig_UseOnboardingDeploy()) { + if (GosDeploy.appConfig_OnboardingBind()) { + GosConstant.mNew = 3; + } else { + GosConstant.mNew = 2; + } + } else { + if (GosDeploy.appConfig_OnboardingBind()) { + GosConstant.mNew = 1; + } else { + GosConstant.mNew = 0; + } + } + //config-all-end + String AppID = GosDeploy.appConfig_GizwitsInfoAppID(); + String AppSecret = GosDeploy.appConfig_GizwitsInfoAppSecret(); + List> productInfoList = GosDeploy.appConfig_ProductInfoList(); + if (productInfoList.size() == 0) { + productInfoList = null; + } + + if (AppID == null || AppSecret == null || TextUtils.isEmpty(AppID) || AppID.contains("BeJson") + || TextUtils.isEmpty(AppSecret) || AppSecret.contains("BeJson") + || AppID.length() != 32 || AppSecret.length() != 32) { + String AppID_Toast = c.getString(R.string.AppID_Toast); + if (flag == 0) { + Toast.makeText(c, AppID_Toast, Toast.LENGTH_LONG).show(); + } + flag++; + } else { + // 启动SDK + ConcurrentHashMap serverMap = new ConcurrentHashMap(); + ConcurrentHashMap appInfo = new ConcurrentHashMap(); + appInfo.put("appId", AppID); + appInfo.put("appSecret", AppSecret); + + String api = GosDeploy.appConfig_CloudServiceApi(); + String site = GosDeploy.appConfig_CloudServiceSite(); + String push = GosDeploy.appConfig_CloudServicePush(); + Pattern pattern = Pattern.compile("(^[a-zA-Z0-9\\-]{1,}\\.[a-zA-Z0-9]{1,}\\.[a-zA-Z0-9]{1,}\\:(\\d){1,}\\&(\\d){1,}$)|(^[a-zA-Z0-9\\-]{1,}\\.[a-zA-Z0-9]{1,}\\.[a-zA-Z0-9]{1,}$)"); + Pattern pattern1 = Pattern.compile("(^([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}\\:(\\d){1,}\\&(\\d){1,}$)|(^([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}$)"); + if (api != null) { + if (pattern.matcher(api).matches() || pattern1.matcher(api).matches()) { + serverMap.put("openAPIInfo", api); + if (site != null) { + serverMap.put("siteInfo", site); + } + if (push != null && !push.isEmpty()) { + serverMap.put("pushInfo", GosDeploy.appConfig_CloudServicePush()); + } + GizWifiSDK.sharedInstance().startWithAppInfo(c, appInfo, productInfoList, serverMap, false); + } else { + GizWifiSDK.sharedInstance().startWithAppInfo(c, appInfo, + productInfoList, null, false); + } + } else { + GizWifiSDK.sharedInstance().startWithAppInfo(c, appInfo, + productInfoList, null, false); + } + } + hand.sendEmptyMessageDelayed(SETCLOUD, 3000); + } + + public static MessageCenter getInstance(Context c) { + if (mCenter == null) { + mCenter = new MessageCenter(c); + } + return mCenter; + } + + Handler hand = new Handler() { + public void handleMessage(android.os.Message msg) { + GizWifiSDK.sharedInstance().setLogLevel( + GizLogPrintLevel.GizLogPrintAll); + + } + }; + +} diff --git a/src/java/com/gizwits/opensource/appkit/PushModule/.DS_Store b/src/java/com/gizwits/opensource/appkit/PushModule/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c657f767fc2bc94ca1b4c4dfeef854bae8abc95e GIT binary patch literal 6148 zcmeHKO-lno41Lia3SNqWdYq#t!LyfTSrG+6>L0MJ#Se-L%J#f}$6u*0leE%y5l=-V zf#ju`Bs=?{GaCR>HVOmVo3LXh!P__ zqvGDb_dmr1Q%2{sZ#cyZbLJRb&FaZ`R*zYyq@7bwKC{pR4seN@3@rNGuh0p8gv{XN65!9Xw&3@jPY^C3|c3&++l zA00G#1R(Yp&O%>5i?t>>7LKhUS14koL@N~^F~rIlPo7sewuV*?@!>=K$&2Ad^3&Nr z<#b447&aIP238r+*_SfV`~QM}na&|Ur-TUxf`R|afb^=ns^r`G-MaCfde arg2, List arg3, String arg4) { + // TODO Auto-generated method stub + + } + + @Override + public void onListTags(Context arg0, int arg1, List arg2, String arg3) { + // TODO Auto-generated method stub + + } + + @Override + public void onMessage(Context arg0, String arg1, String arg2) { + // TODO Auto-generated method stub + + } + + @Override + public void onNotificationArrived(Context arg0, String arg1, String arg2, String arg3) { + // TODO Auto-generated method stub + String notifyString = "通知到达 onNotificationArrived title=\"" + arg1 + + "\" description=\"" + arg2 + "\" customContent=" + + arg3; + Log.i(TAG, notifyString); + } + + @Override + public void onNotificationClicked(Context arg0, String arg1, String arg2, String arg3) { + // TODO Auto-generated method stub + + } + + @Override + public void onSetTags(Context arg0, int arg1, List arg2, List arg3, String arg4) { + // TODO Auto-generated method stub + + } + + @Override + public void onUnbind(Context arg0, int arg1, String arg2) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/PushModule/GosPushManager.java b/src/java/com/gizwits/opensource/appkit/PushModule/GosPushManager.java new file mode 100644 index 0000000..f4d12d5 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/PushModule/GosPushManager.java @@ -0,0 +1,136 @@ +package com.gizwits.opensource.appkit.PushModule; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; +//push_baidu-false-start +import com.baidu.android.pushservice.PushConstants; +import com.baidu.android.pushservice.PushManager; +import com.baidu.android.pushservice.PushSettings; +//push_baidu-false-end +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizPushType; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; + +import java.util.Set; +//push_jiguang-false-start +import cn.jpush.android.api.JPushInterface; +import cn.jpush.android.api.TagAliasCallback; +//push_jiguang-false-end + + +public class GosPushManager { + + static GizPushType gizPushType; + + static Context context; + + public GosPushManager(int PushType, Context context) { + super(); + GosPushManager.context = context; + //push_jiguang-false-start + if (PushType == 1) { + GosPushManager.gizPushType = GizPushType.GizPushJiGuang; + jPush(); + } + //push_jiguang-false-end + //push_baidu-false-start + if (PushType == 2) { + GosPushManager.gizPushType = GizPushType.GizPushBaiDu; + bDPush(); + } + //push_baidu-false-end + } + + /** + * Channel_ID + */ + public static String Channel_ID; + + //push_jiguang-false-start + + /** + * 此方法完成了初始化JPush SDK等功能 但仍需在MainActivity的onResume和onPause添加相应方法 + * JPushInterface.onResume(context); JPushInterface.onPause(context); + */ + public void jPush() { + // 设置JPush调试模式 + JPushInterface.setDebugMode(true); + // 初始化JPushSDK + JPushInterface.init(context); + } + //push_jiguang-false-end + + //push_baidu-false-start + public void bDPush() { + final String BDPushAppKey = GosDeploy.appConfig_BpushAppKey(); + if (BDPushAppKey != null) { + if (TextUtils.isEmpty(BDPushAppKey) || BDPushAppKey.contains("your_bpush_api_key")) { + GosBaseActivity.noIDAlert(context, R.string.BDPushAppID_Toast); + } else { + PushManager.startWork(context, PushConstants.LOGIN_TYPE_API_KEY, BDPushAppKey); + PushSettings.enableDebugMode(context, true); + } + } + } + //push_baidu-false-end + + /** + * 向云端绑定推送 + * + * @param userId + * @param token + */ + public static void pushBindService(String userId, String token) { + //push_jiguang-false-start + if (GizPushType.GizPushJiGuang == gizPushType) { + // 获取JPush的RegistrationID,即Channel_ID + Channel_ID = JPushInterface.getRegistrationID(context); + // 设定JPush类型 + JPushInterface.setAlias(context, Channel_ID, new TagAliasCallback() { + @Override + public void gotResult(int arg0, String arg1, Set arg2) { + if (arg0 == 0) { + Log.i("Apptest", "Alias: " + arg1); + } else { + Log.i("Apptest", "Result: " + arg0); + } + } + }); + } + //push_jiguang-false-end + //push_baidu-false-start + if (GizPushType.GizPushBaiDu == gizPushType) { + // 获取BDPush的Channel_ID + Channel_ID = BaiDuPushReceiver.BaiDuPush_Channel_ID; + Log.e("Manager", "pushBindService----: " + Channel_ID); + } + //push_baidu-false-end + // TODO 绑定推送 + GizWifiSDK.sharedInstance().channelIDBind(token, Channel_ID, userId, gizPushType); + } + + public static void pushUnBindService(String token) { + if (token.isEmpty()) { + return; + } + //push_jiguang-false-start + if (GizPushType.GizPushJiGuang == gizPushType) { + // 获取JPush的RegistrationID,即Channel_ID + Channel_ID = JPushInterface.getRegistrationID(context); + } + //push_jiguang-false-end + //push_baidu-false-start + if (GizPushType.GizPushBaiDu == gizPushType) { + // 获取BDPush的Channel_ID + Channel_ID = BaiDuPushReceiver.BaiDuPush_Channel_ID; + } + //push_baidu-false-end + // TODO 绑定推送 + //Log.i("Apptest", Channel_ID + "\n" + gizPushType.toString() + "\n" + token); + GizWifiSDK.sharedInstance().channelIDUnBind(token, Channel_ID); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/PushModule/JPushReceiver.java b/src/java/com/gizwits/opensource/appkit/PushModule/JPushReceiver.java new file mode 100644 index 0000000..e775c21 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/PushModule/JPushReceiver.java @@ -0,0 +1,125 @@ +package com.gizwits.opensource.appkit.PushModule; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Iterator; + +import cn.jpush.android.api.JPushInterface; + +public class JPushReceiver extends BroadcastReceiver { + + private static final String TAG = "JPushReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + + try { + Bundle bundle = intent.getExtras(); + Log.i(TAG, "[MyReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle)); + + if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) { + String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID); + Log.i(TAG, "[MyReceiver] 接收Registration Id : " + regId); + //send the Registration Id to your server... + + } else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) { + Log.i(TAG, "[MyReceiver] 接收到推送下来的自定义消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE)); + //processCustomMessage(context, bundle); + + } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) { + Log.i(TAG, "[MyReceiver] 接收到推送下来的通知"); + int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID); + Log.i(TAG, "[MyReceiver] 接收到推送下来的通知的ID: " + notifactionId); + String title = bundle.getString(JPushInterface.EXTRA_NOTIFICATION_TITLE); + String content = bundle.getString(JPushInterface.EXTRA_ALERT); + Log.i(TAG, "Title 标题:: " + title + " " + "Content : 内容:" + content); + } else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) { +// Log.d(TAG, "[MyReceiver] 用户点击打开了通知"); +// +// //打开自定义的Activity +// Intent i = new Intent(context, TestActivity.class); +// i.putExtras(bundle); +// //i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); +// i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP ); +// context.startActivity(i); + + } else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) { + Log.i(TAG, "[MyReceiver] 用户收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA)); + //在这里根据 JPushInterface.EXTRA_EXTRA 的内容处理代码,比如打开新的Activity, 打开一个网页等.. + + } else if (JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) { + boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false); + Log.i(TAG, "[MyReceiver]" + intent.getAction() + " connected state change to " + connected); + } else { + Log.i(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction()); + } + } catch (Exception e) { + + } + } + + // 打印所有的 intent extra 数据 + private static String printBundle(Bundle bundle) { + StringBuilder sb = new StringBuilder(); + for (String key : bundle.keySet()) { + if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) { + sb.append("\nkey:" + key + ", value:" + bundle.getInt(key)); + } else if (key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)) { + sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key)); + } else if (key.equals(JPushInterface.EXTRA_EXTRA)) { + if (TextUtils.isEmpty(bundle.getString(JPushInterface.EXTRA_EXTRA))) { + Log.i(TAG, "This message has no Extra data"); + continue; + } + + try { + JSONObject json = new JSONObject(bundle.getString(JPushInterface.EXTRA_EXTRA)); + Iterator it = json.keys(); + + while (it.hasNext()) { + String myKey = it.next(); + sb.append("\nkey:" + key + ", value: [" + + myKey + " - " + json.optString(myKey) + "]"); + } + } catch (JSONException e) { + Log.i(TAG, "Get message extra JSON error!"); + } + + } else { + sb.append("\nkey:" + key + ", value:" + bundle.getString(key)); + } + } + return sb.toString(); + } + + //send msg to MainActivity +// private void processCustomMessage(Context context, Bundle bundle) { +// if (MainActivity.isForeground) { +// String message = bundle.getString(JPushInterface.EXTRA_MESSAGE); +// String extras = bundle.getString(JPushInterface.EXTRA_EXTRA); +// Intent msgIntent = new Intent(MainActivity.MESSAGE_RECEIVED_ACTION); +// msgIntent.putExtra(MainActivity.KEY_MESSAGE, message); +// if (!ExampleUtil.isEmpty(extras)) { +// try { +// JSONObject extraJson = new JSONObject(extras); +// if (extraJson.length() > 0) { +// msgIntent.putExtra(MainActivity.KEY_EXTRAS, extras); +// } +// } catch (JSONException e) { +// +// } +// +// } +// LocalBroadcastManager.getInstance(context).sendBroadcast(msgIntent); +// } +// } + +} diff --git a/src/java/com/gizwits/opensource/appkit/SettingsModule/GosAboutActivity.java b/src/java/com/gizwits/opensource/appkit/SettingsModule/GosAboutActivity.java new file mode 100644 index 0000000..6abc361 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/SettingsModule/GosAboutActivity.java @@ -0,0 +1,135 @@ +package com.gizwits.opensource.appkit.SettingsModule; + +import android.app.ActionBar; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.utils.AssetsUtils; + +public class GosAboutActivity extends GosBaseActivity { + + /** + * The tv SDKVersion. + */ + TextView tv_SDKVersion; + + /** + * the tv appCode + */ + TextView tv_AppVersion; + + /** + * The ActionBar + */ + ActionBar actionBar; + private LinearLayout llApp; + private LinearLayout llSDK; + private LinearLayout llAbout; + private TextView tvAbout; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_about); + // 设置ActionBar + setToolBar(true, R.string.about); + + initView(); + initEvent(); + } + + private void initEvent() { + if (!GosDeploy.appConfig_ShowAPPVersion() && !GosDeploy.appConfig_ShowSDKVersion()) { + llApp.setVisibility(View.VISIBLE); + llSDK.setVisibility(View.VISIBLE); + llAbout.setVisibility(View.VISIBLE); + } else { + if (!GosDeploy.appConfig_ShowAPPVersion()) { + llApp.setVisibility(View.GONE); + } + if (!GosDeploy.appConfig_ShowSDKVersion()) { + llSDK.setVisibility(View.GONE); + } + if (GosDeploy.appConfig_AboutInfoCH() != null) { + if (GosDeploy.appConfig_AboutInfoEN() != null) { + if (AssetsUtils.isZh(this)) { + tvAbout.setText(GosDeploy.appConfig_AboutInfoCH()); + } else { + tvAbout.setText(GosDeploy.appConfig_AboutInfoEN()); + } + } else { + tvAbout.setText(GosDeploy.appConfig_AboutInfoCH()); + } + llAbout.setVisibility(View.VISIBLE); + } else { + if (GosDeploy.appConfig_AboutInfoEN() != null) { + tvAbout.setText(GosDeploy.appConfig_AboutInfoEN()); + llAbout.setVisibility(View.VISIBLE); + } else { + llAbout.setVisibility(View.GONE); + } + } + } + } + + /** + * Inits the view. + */ + private void initView() { + llApp = (LinearLayout) findViewById(R.id.llAPP); + llSDK = (LinearLayout) findViewById(R.id.llSDK); + llAbout = (LinearLayout) findViewById(R.id.llAbout); + tvAbout = (TextView) findViewById(R.id.tvAbout); + tv_SDKVersion = (TextView) findViewById(R.id.versionCode); + tv_AppVersion = (TextView) findViewById(R.id.appCode); + + } + + @Override + public void onResume() { + super.onResume(); + tv_SDKVersion.setText(GizWifiSDK.sharedInstance().getVersion().toString()); + tv_AppVersion.setText(getAppVersionName(this)); + } + + /** + * 返回当前程序版本名 + */ + public static String getAppVersionName(Context context) { + String versionName = ""; + try { + // ---get the package info--- + PackageManager pm = context.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0); + versionName = pi.versionName; + if (versionName == null || versionName.length() <= 0) { + return ""; + } + } catch(Exception e) { + Log.i("Apptest", "Exception", e); + } + return versionName; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + break; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/ThirdAccountModule/BaseUiListener.java b/src/java/com/gizwits/opensource/appkit/ThirdAccountModule/BaseUiListener.java new file mode 100644 index 0000000..175cfc5 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/ThirdAccountModule/BaseUiListener.java @@ -0,0 +1,28 @@ +package com.gizwits.opensource.appkit.ThirdAccountModule; + +import com.tencent.tauth.IUiListener; +import com.tencent.tauth.UiError; + +import org.json.JSONObject; + +public class BaseUiListener implements IUiListener { + + @Override + public void onCancel() { + // TODO Auto-generated method stub + } + + @Override + public void onComplete(Object arg0) { + doComplete((JSONObject)arg0); + } + + protected void doComplete(JSONObject values) { + } + + @Override + public void onError(UiError arg0) { + // TODO Auto-generated method stu + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/UserModule/GosChangeUserPasswordActivity.java b/src/java/com/gizwits/opensource/appkit/UserModule/GosChangeUserPasswordActivity.java new file mode 100644 index 0000000..713b0a3 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/UserModule/GosChangeUserPasswordActivity.java @@ -0,0 +1,226 @@ +package com.gizwits.opensource.appkit.UserModule; + +import android.os.Bundle; +import android.text.TextUtils; +import android.text.method.HideReturnsTransformationMethod; +import android.text.method.PasswordTransformationMethod; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.listener.GizWifiSDKListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; + +public class GosChangeUserPasswordActivity extends GosBaseActivity { + + private EditText oldpass; + private EditText newpass; + private EditText confrimpass; + private Button btnConfirm; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_gos_change_password); + setToolBar(true, R.string.edit_password); + initView(); + } + + @Override + protected void onResume() { + // TODO Auto-generated method stub + super.onResume(); + + GizWifiSDK.sharedInstance().setListener(listener); + } + + GizWifiSDKListener listener = new GizWifiSDKListener() { + + public void didChangeUserPassword( + com.gizwits.gizwifisdk.enumration.GizWifiErrorCode result) { + + if (result.getResult() == 0) { + Toast.makeText(GosChangeUserPasswordActivity.this, + getResources().getString(R.string.passsuccess), 2000) + .show(); + + finish(); + + spf.edit().putString("PassWord", newpass.getText().toString()) + .commit(); + } else { + + if (result.getResult() == 9020) { + Toast.makeText(GosChangeUserPasswordActivity.this, + getResources().getString(R.string.oldpasserror), + 2000).show(); + } else { + Toast.makeText(GosChangeUserPasswordActivity.this, + getResources().getString(R.string.passerror), 2000) + .show(); + } + + } + + } + + ; + }; + private CheckBox oldcheck; + private CheckBox newcheck; + private CheckBox concheck; + + private void initView() { + btnConfirm = (Button) findViewById(R.id.btnLogin); + oldpass = (EditText) findViewById(R.id.oldpass); + newpass = (EditText) findViewById(R.id.newpass); + confrimpass = (EditText) findViewById(R.id.confrimpass); + confrimpass.setTransformationMethod(PasswordTransformationMethod + .getInstance()); + oldpass.setTransformationMethod(PasswordTransformationMethod + .getInstance()); + newpass.setTransformationMethod(PasswordTransformationMethod + .getInstance()); + + oldcheck = (CheckBox) findViewById(R.id.oldcheck); + newcheck = (CheckBox) findViewById(R.id.newcheck); + concheck = (CheckBox) findViewById(R.id.concheck); +// 配置文件部署 + oldcheck.setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + String psw = oldpass.getText().toString(); + + if (isChecked) { + // oldpass.setInputType(0x90); + oldpass.setTransformationMethod(HideReturnsTransformationMethod + .getInstance()); + } else { + // oldpass.setInputType(0x81); + oldpass.setTransformationMethod(PasswordTransformationMethod + .getInstance()); + } + oldpass.setSelection(psw.length()); + } + }); + + newcheck.setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + String psw = newpass.getText().toString(); + + if (isChecked) { + // newpass.setInputType(0x90); + newpass.setTransformationMethod(HideReturnsTransformationMethod + .getInstance()); + } else { + // newpass.setInputType(0x81); + newpass.setTransformationMethod(PasswordTransformationMethod + .getInstance()); + } + newpass.setSelection(psw.length()); + } + }); + + concheck.setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + String psw = confrimpass.getText().toString(); + + if (isChecked) { + // confrimpass.setInputType(0x90); + confrimpass + .setTransformationMethod(HideReturnsTransformationMethod + .getInstance()); + } else { + // confrimpass.setInputType(0x81); + confrimpass + .setTransformationMethod(PasswordTransformationMethod + .getInstance()); + } + confrimpass.setSelection(psw.length()); + } + }); + } + + public void confirm(View v) { + + if (TextUtils.isEmpty(oldpass.getText().toString()) + || TextUtils.isEmpty(newpass.getText().toString()) + || TextUtils.isEmpty(confrimpass.getText().toString())) { + + if (TextUtils.isEmpty(oldpass.getText().toString())) { + + Toast.makeText( + this, + getResources().getString( + R.string.enter_current_password), 2000).show(); + + return; + } + + if (TextUtils.isEmpty(newpass.getText().toString())) { + Toast.makeText(this, + getResources().getString(R.string.enter_new_password), + 2000).show(); + + return; + } + + if (TextUtils.isEmpty(confrimpass.getText().toString())) { + Toast.makeText( + this, + getResources() + .getString(R.string.re_enter_new_password), + 2000).show(); + return; + } + + } else { + //oldpass.getText().length() < 6 || + if (newpass.getText().length() < 6 || confrimpass.getText().length() < 6) { + Toast.makeText(this, + getResources().getString(R.string.toast_psw_short), + 2000).show(); + } + + String npass = newpass.getText().toString(); + String cpass = confrimpass.getText().toString(); + if (npass.equals(cpass)) { + GizWifiSDK.sharedInstance().changeUserPassword( + spf.getString("Token", ""), + oldpass.getText().toString(), npass); + } else { + Toast.makeText(this, + getResources().getString(R.string.nosamepass), 2000) + .show(); + } + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + + finish(); + break; + } + return true; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/UserModule/GosForgetPasswordActivity.java b/src/java/com/gizwits/opensource/appkit/UserModule/GosForgetPasswordActivity.java new file mode 100644 index 0000000..3c3bf29 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/UserModule/GosForgetPasswordActivity.java @@ -0,0 +1,385 @@ +package com.gizwits.opensource.appkit.UserModule; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.InputType; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizUserAccountType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +@SuppressLint("HandlerLeak") +public class GosForgetPasswordActivity extends GosUserModuleBaseActivity implements + OnClickListener { + + /** + * The et Name + */ + private EditText etName; + /** + * The ll phone + */ + private LinearLayout llPhone; + + /** + * The btn GetCode + */ + private TextView tvGetCode; + + /** + * The et Code + */ + private EditText etCode; + + /** + * The et Psw + */ + private EditText etPsw; + + /** + * The et ConfirmPsw + */ + private EditText etConfirmPsw; + /** + * 验证码重发倒计时 + */ + int secondleft = 60; + + /** + * The timer. + */ + Timer timer; + //resetPassword_phoneUser-false-end + /** + * The btn Register + */ + private Button btnReset; + + /** + * 数据变量 + */ + String name, code, psw, confirmpsw; + + + private enum handler_key { + //resetPassword_phoneUser-false-start + /** + * 获取验证码. + */ + GETCODE, + + /** + * 手机验证码发送成功. + */ + SENDSUCCESSFUL, + + /** + * 倒计时通知 + */ + TICK_TIME, + //resetPassword_phoneUser-false-end + + /** + * 提示信息 + */ + TOAST, + + /** + * 重置密码 + */ + RESET, + } + + Handler handler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + //resetPassword_phoneUser-false-start + case GETCODE: + progressDialog.show(); + String AppSecret = GosDeploy.appConfig_GizwitsInfoAppSecret(); + GizWifiSDK.sharedInstance().requestSendPhoneSMSCode(AppSecret, + msg.obj.toString()); + break; + case SENDSUCCESSFUL: + etName.setEnabled(false); + etName.setTextColor(getResources().getColor( + R.color.text_gray_light)); + isStartTimer(); + + break; + + case TICK_TIME: + String getCodeAgain = getString(R.string.getcode_again); + String timerMessage = getString(R.string.timer_message); + secondleft--; + if (secondleft <= 0) { + timer.cancel(); + tvGetCode.setTextColor(getResources().getColor(R.color.tomato)); + tvGetCode.setEnabled(true); + tvGetCode.setText(getCodeAgain); + } else { + tvGetCode.setText(secondleft + timerMessage); + } + break; + //resetPassword_phoneUser-false-end + case TOAST: + String successfulText = (String) getText(R.string.reset_successful); + Toast.makeText(GosForgetPasswordActivity.this, msg.obj + "", + toastTime).show(); + if (msg.obj.toString().equals(successfulText)) { + // spf.edit().putString("UserName", name).commit(); + // spf.edit().putString("PassWord", psw).commit(); + isclean = true; + //resetPassword_phoneUser-false-start + if (llPhone.getVisibility() == View.GONE) { + //resetPassword_phoneUser-false-end + Intent intent = new Intent(GosForgetPasswordActivity.this, GosSendEmailPasswordActivity.class); + startActivity(intent); + spf.edit().putString("Email", name).commit(); + //resetPassword_phoneUser-false-start + } else { + finish(); + } + //resetPassword_phoneUser-false-end + } + break; + case RESET: + progressDialog.show(); + GizWifiSDK.sharedInstance().resetPassword(name, code, psw, + GizUserAccountType.GizUserPhone); + break; + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_forget_password); + // 设置ActionBar + setToolBar(true, R.string.forget_pass); + + initView(); + initEvent(); + } + + private void initView() { + etName = (EditText) findViewById(R.id.etName); + //resetPassword_phoneUser-false-start + llPhone = (LinearLayout) findViewById(R.id.llPhone); + tvGetCode = (TextView) findViewById(R.id.tvGetCode); + etCode = (EditText) findViewById(R.id.etCode); + etPsw = (EditText) findViewById(R.id.etPsw); + etConfirmPsw = (EditText) findViewById(R.id.etConfirmPsw); + //resetPassword_phoneUser-false-end + btnReset = (Button) findViewById(R.id.btnReset); + setPhoneOrEmailIsVisable(); + } + + private void setPhoneOrEmailIsVisable() { + //resetPassword_phoneUser-true-start resetPassword_phoneUser-false-start + if (GosDeploy.appConfig_ResetPassword_PhoneUser()) { + //resetPassword_phoneUser-true-end + etName.setHint(getResources().getString(R.string.name_phone)); + llPhone.setVisibility(View.VISIBLE); + etName.setInputType(InputType.TYPE_CLASS_PHONE); + btnReset.setText(getResources().getString(R.string.reset)); + //resetPassword_phoneUser-true-start + } else { + //resetPassword_phoneUser-false-end + //resetPassword_phoneUser-false-start + } + //resetPassword_phoneUser-true-end resetPassword_phoneUser-false-end + } + + private void initEvent() { + + final Timer etTimer = new Timer(); + etTimer.schedule(new TimerTask() { + + @Override + public void run() { + etName.requestFocus(); + InputMethodManager imm = (InputMethodManager) etName + .getContext().getSystemService( + Context.INPUT_METHOD_SERVICE); + imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED); + etTimer.cancel(); + + } + }, 500); + //resetPassword_phoneUser-false-start + tvGetCode.setOnClickListener(this); + //resetPassword_phoneUser-false-end + btnReset.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + //resetPassword_phoneUser-false-start + case R.id.tvGetCode: + name = etName.getText().toString(); + if (TextUtils.isEmpty(name)) { + Toast.makeText(GosForgetPasswordActivity.this, + R.string.toast_name_wrong, toastTime).show(); + return; + } + Message msg = new Message(); + msg.obj = name; + msg.what = handler_key.GETCODE.ordinal(); + handler.sendMessage(msg); + break; + //resetPassword_phoneUser-false-end + case R.id.btnReset: + name = etName.getText().toString(); + //resetPassword_phoneUser-false-start + code = etCode.getText().toString(); + psw = etPsw.getText().toString(); + confirmpsw = etConfirmPsw.getText().toString(); + if (TextUtils.isEmpty(name)) { + Toast.makeText(GosForgetPasswordActivity.this, + R.string.toast_name_wrong, toastTime).show(); + return; + } + + if (llPhone.getVisibility() == View.VISIBLE) { + if (code.length() != 6) { + Toast.makeText(GosForgetPasswordActivity.this, R.string.no_getcode, toastTime).show(); + return; + } + if (TextUtils.isEmpty(psw)) { + Toast.makeText(GosForgetPasswordActivity.this, + R.string.toast_psw_wrong, toastTime).show(); + return; + } + if (psw.length() < 6) { + Toast.makeText(GosForgetPasswordActivity.this, + R.string.toast_psw_short, toastTime).show(); + return; + } + if (!psw.equals(confirmpsw)) { + Toast.makeText(GosForgetPasswordActivity.this, R.string.toast_psw_confirm_failed, toastTime).show(); + return; + } + } else { + //resetPassword_phoneUser-false-end + if (!name.contains("@")) { + Toast.makeText(GosForgetPasswordActivity.this, R.string.toase_name_email_fault, toastTime).show(); + return; + } + //resetPassword_phoneUser-false-start + } + //resetPassword_phoneUser-false-end + + /* + * if (psw.length() < 6) { + * Toast.makeText(GosForgetPasswordActivity.this, + * R.string.toast_psw_short, toastTime).show(); return; } + */ + handler.sendEmptyMessage(handler_key.RESET.ordinal()); + + break; + } + } + + + /** + * 倒计时 + */ + public void isStartTimer() { + tvGetCode.setEnabled(false); + tvGetCode.setTextColor(getResources().getColor(R.color.hint_color)); + secondleft = 60; + timer = new Timer(); + timer.schedule(new TimerTask() { + + @Override + public void run() { + handler.sendEmptyMessage(handler_key.TICK_TIME.ordinal()); + } + }, 1000, 1000); + } + + /** + * 手机验证码回调 + */ + @Override + protected void didRequestSendPhoneSMSCode(GizWifiErrorCode result, + String token) { + if (progressDialog != null) { + progressDialog.cancel(); + } + Message msg = new Message(); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + // String sendFailed = (String) getText(R.string.send_failed); + msg.what = handler_key.TOAST.ordinal(); + msg.obj = toastError(result);// sendFailed + "\n" + + // errorMessage;toastError(errorCode) + handler.sendMessage(msg); + } else { + handler.sendEmptyMessage(handler_key.SENDSUCCESSFUL.ordinal()); + msg.what = handler_key.TOAST.ordinal(); + String sendSuccessful = (String) getText(R.string.send_successful); + msg.obj = sendSuccessful; + handler.sendMessage(msg); + } + } + //resetPassword_phoneUser-false-end + + /** + * 重置密码回调 + */ + @Override + public void didChangeUserPassword(GizWifiErrorCode result) { + if (progressDialog != null) { + progressDialog.cancel(); + } + Message msg = new Message(); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + // String resetFailed = (String) getText(R.string.reset_failed); + msg.what = handler_key.TOAST.ordinal(); + msg.obj = toastError(result);// resetFailed + "\n" + errorMessage; + handler.sendMessage(msg); + } else { + msg.what = handler_key.TOAST.ordinal(); + String resetSuccessful = (String) getText(R.string.reset_successful); + msg.obj = resetSuccessful; + handler.sendMessage(msg); + } + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + progressDialog = null; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/UserModule/GosRegisterUserActivity.java b/src/java/com/gizwits/opensource/appkit/UserModule/GosRegisterUserActivity.java new file mode 100644 index 0000000..9eab499 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/UserModule/GosRegisterUserActivity.java @@ -0,0 +1,359 @@ +package com.gizwits.opensource.appkit.UserModule; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.InputType; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizUserAccountType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@SuppressLint("HandlerLeak") +public class GosRegisterUserActivity extends GosUserModuleBaseActivity implements OnClickListener, AdapterView.OnItemSelectedListener { + + /** + * The et Name + */ + private EditText etName; + //register_phoneUser-false-start + /** + * The ll code + */ + private LinearLayout llCode; + + /** + * The btn GetCode + */ + private TextView tvGetCode; + + /** + * The et Code + */ + private EditText etCode; + /** + * 验证码重发倒计时 + */ + int secondleft = 60; + + /** + * The timer. + */ + Timer timer; + + //register_phoneUser-false-end + /** + * The et Psw + */ + private EditText etPsw; + + /** + * The et ConfirmPsw + */ + private EditText etConfirmPsw; + + /** + * The btn Rrgister + */ + private Button btnRrgister; + + /** + * 数据变量 + */ + String name, code, psw, confirmpsw; + + private int usertype = 0; + + private enum handler_key { + //register_phoneUser-false-start + /** + * 获取验证码. + */ + GETCODE, + /** + * 手机验证码发送成功. + */ + SENDSUCCESSFUL, + //register_phoneUser-false-end + + /** + * 提示信息 + */ + TOAST, + /** + * 倒计时通知 + */ + TICK_TIME, + + /** + * 注册 + */ + REGISTER, + } + + Handler handler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + //register_phoneUser-false-start + case GETCODE: + progressDialog.show(); + String AppSecret = GosDeploy.appConfig_GizwitsInfoAppSecret(); + GizWifiSDK.sharedInstance().requestSendPhoneSMSCode(AppSecret, msg.obj.toString()); + break; + case SENDSUCCESSFUL: + etName.setEnabled(false); + etName.setTextColor(getResources().getColor(R.color.text_gray_light)); + isStartTimer(); + break; + case TICK_TIME: + String getCodeAgain = getString(R.string.getcode_again); + String timerMessage = getString(R.string.timer_message); + secondleft--; + if (secondleft <= 0) { + timer.cancel(); + tvGetCode.setTextColor(getResources().getColor(R.color.tomato)); + tvGetCode.setEnabled(true); + tvGetCode.setText(getCodeAgain); + } else { + tvGetCode.setText(secondleft + timerMessage); + } + break; + //register_phoneUser-false-end + case TOAST: + Toast.makeText(GosRegisterUserActivity.this, msg.obj.toString(), toastTime).show(); + String successfulText = (String) getText(R.string.register_successful); + + if (msg.obj.toString().equals(successfulText)) { + spf.edit().putString("UserName", name).commit(); + spf.edit().putString("PassWord", psw).commit(); + isclean = true; + finish(); + } + break; + case REGISTER: + progressDialog.show(); + GizWifiSDK.sharedInstance().registerUser(name, psw, code, GizUserAccountType.GizUserPhone); + break; + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_register_user); + // 设置ActionBar + setToolBar(true, R.string.register); + initView(); + initEvent(); + } + + private void initView() { + etName = (EditText) findViewById(R.id.etName); + //register_phoneUser-false-start + tvGetCode = (TextView) findViewById(R.id.tvGetCode); + etCode = (EditText) findViewById(R.id.etCode); + llCode = (LinearLayout) findViewById(R.id.llCode); + //register_phoneUser-false-end + etPsw = (EditText) findViewById(R.id.etPsw); + etConfirmPsw = (EditText) findViewById(R.id.etConfirmPsw); + btnRrgister = (Button) findViewById(R.id.btnRrgister); + setPhoneOrEmailOrNormalIsVisable(); + } + + private void setPhoneOrEmailOrNormalIsVisable() { + etName.setHint(getResources().getString(R.string.name_phone)); + usertype = 0; + } + + + private void initEvent() { + final Timer etTimer = new Timer(); + etTimer.schedule(new TimerTask() { + + @Override + public void run() { + etName.requestFocus(); + InputMethodManager imm = (InputMethodManager) etName.getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED); + etTimer.cancel(); + + } + }, 500); + //register_phoneUser-false-start + tvGetCode.setOnClickListener(this); + //register_phoneUser-false-end + btnRrgister.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + //register_phoneUser-false-start + case R.id.tvGetCode: + name = etName.getText().toString(); + if (TextUtils.isEmpty(name)) { + Toast.makeText(GosRegisterUserActivity.this, R.string.toast_name_wrong, toastTime).show(); + return; + } + Message msg = new Message(); + msg.obj = name; + msg.what = handler_key.GETCODE.ordinal(); + handler.sendMessage(msg); + break; + //register_phoneUser-false-end + case R.id.btnRrgister: + name = etName.getText().toString(); + //register_phoneUser-false-start + code = etCode.getText().toString(); + //register_phoneUser-false-end + psw = etPsw.getText().toString(); + confirmpsw = etConfirmPsw.getText().toString(); + if (TextUtils.isEmpty(name)) { + Toast.makeText(GosRegisterUserActivity.this, R.string.toast_name_wrong, toastTime).show(); + return; + } + if (usertype == 0) { + if (code.length() != 6) { + Toast.makeText(GosRegisterUserActivity.this, R.string.no_getcode, toastTime).show(); + return; + } + } + if (TextUtils.isEmpty(psw)) { + Toast.makeText(GosRegisterUserActivity.this, R.string.toast_psw_wrong, toastTime).show(); + return; + } + + if (psw.length() < 6) { + Toast.makeText(GosRegisterUserActivity.this, R.string.toast_psw_short, toastTime).show(); + return; + } + + if (TextUtils.isEmpty(confirmpsw)) { + Toast.makeText(GosRegisterUserActivity.this, R.string.toast_psw_confirm, toastTime).show(); + return; + } + if (!psw.equals(confirmpsw)) { + Toast.makeText(GosRegisterUserActivity.this, R.string.toast_psw_confirm_failed, toastTime).show(); + return; + } + + /* + * if (psw.length() < 6) { + * Toast.makeText(GosRegisterUserActivity.this, + * R.string.toast_psw_short, toastTime).show(); return; } + */ + handler.sendEmptyMessage(handler_key.REGISTER.ordinal()); + break; + } + } + + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + etName.setText(""); + etName.setEnabled(true); + etName.setTextColor(getResources().getColor(R.color.text_color)); + //register_phoneUser-false-start + etCode.setText(""); + //register_phoneUser-false-end + etPsw.setText(""); + etConfirmPsw.setText(""); + etName.setHint(getResources().getString(R.string.name_phone)); + llCode.setVisibility(View.VISIBLE); + etName.setInputType(InputType.TYPE_CLASS_PHONE); + + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + //register_phoneUser-false-start + + /** + * 手机验证码回调 + */ + @Override + protected void didRequestSendPhoneSMSCode(GizWifiErrorCode result, String token) { + progressDialog.cancel(); + Message msg = new Message(); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + msg.what = handler_key.TOAST.ordinal(); + msg.obj = toastError(result); + handler.sendMessage(msg); + } else { + handler.sendEmptyMessage(handler_key.SENDSUCCESSFUL.ordinal()); + msg.what = handler_key.TOAST.ordinal(); + String sendSuccessful = (String) getText(R.string.send_successful); + msg.obj = sendSuccessful; + handler.sendMessage(msg); + } + } + + /** + * 倒计时 + */ + public void isStartTimer() { + tvGetCode.setEnabled(false); + tvGetCode.setTextColor(getResources().getColor(R.color.hint_color)); + secondleft = 60; + timer = new Timer(); + timer.schedule(new TimerTask() { + + @Override + public void run() { + handler.sendEmptyMessage(handler_key.TICK_TIME.ordinal()); + } + }, 1000, 1000); + } + //register_phoneUser-false-end + + /** + * 用户注册回调 + */ + @Override + protected void didRegisterUser(GizWifiErrorCode result, String uid, String token) { + progressDialog.cancel(); + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + Message msg = new Message(); + msg.what = handler_key.TOAST.ordinal(); + msg.obj = toastError(result); + handler.sendMessage(msg); + } else { + Message msg = new Message(); + msg.what = handler_key.TOAST.ordinal(); + String registerSuccessful = (String) getText(R.string.register_successful); + msg.obj = registerSuccessful; + handler.sendMessage(msg); + } + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/UserModule/GosSendEmailPasswordActivity.java b/src/java/com/gizwits/opensource/appkit/UserModule/GosSendEmailPasswordActivity.java new file mode 100644 index 0000000..b090248 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/UserModule/GosSendEmailPasswordActivity.java @@ -0,0 +1,69 @@ +package com.gizwits.opensource.appkit.UserModule; + +import android.content.Intent; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; + + +public class GosSendEmailPasswordActivity extends GosBaseActivity { + + private TextView tvEmail; + private Button btnReturn; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_send_email_password); + // 设置ActionBar + setToolBar(true, R.string.forget_pass); + initView(); + initEvent(); + } + + private static final String TAG = "GosSendEmailPasswordAct"; + + private void initView() { + tvEmail = (TextView) findViewById(R.id.tvEmail); + btnReturn = (Button) findViewById(R.id.btnReturn); + } + + private void initEvent() { + String email = spf.getString("Email", "xxx@xxx.xx"); + String s = getResources().getString(R.string.send_email_pass); + //字符串截取 + String bb = s.substring(10, 20); + //字符串替换 + String cc = s.replace(bb, email); + SpannableString spannableString = new SpannableString(cc); + spannableString.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.tomato)), 10, 10 + email.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + tvEmail.setText(spannableString); + btnReturn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(GosSendEmailPasswordActivity.this, GosUserLoginActivity.class); + startActivity(intent); + } + }); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + break; + } + return true; + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/UserModule/GosUserLoginActivity.java b/src/java/com/gizwits/opensource/appkit/UserModule/GosUserLoginActivity.java new file mode 100644 index 0000000..7825ee4 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/UserModule/GosUserLoginActivity.java @@ -0,0 +1,626 @@ +package com.gizwits.opensource.appkit.UserModule; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizThirdAccountType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosDeviceListFragment; +import com.gizwits.opensource.appkit.DeviceModule.GosMainActivity; +//push-all-start +import com.gizwits.opensource.appkit.PushModule.GosPushManager; +//push_jiguang-false-start + +import cn.jpush.android.api.JPushInterface; +//push_jiguang-false-end +//push-all-end + +import com.gizwits.opensource.appkit.utils.ToolUtils; +//login_weChat-false-start +import com.tencent.mm.sdk.modelmsg.SendAuth; +import com.tencent.mm.sdk.openapi.IWXAPI; +import com.tencent.mm.sdk.openapi.WXAPIFactory; +//login_weChat-false-end +//login_qq-false-start +import com.gizwits.opensource.appkit.ThirdAccountModule.BaseUiListener; +import com.tencent.tauth.IUiListener; +import com.tencent.tauth.Tencent; +//login_qq-false-end +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Timer; +import java.util.TimerTask; + + +@SuppressLint("HandlerLeak") +public class GosUserLoginActivity extends com.gizwits.opensource.appkit.UserModule.GosUserModuleBaseActivity implements + OnClickListener { + + //GosPushManager gosPushManager; + + /** + * The et Name + */ + private static EditText etName; + + /** + * The et Psw + */ + private static EditText etPsw; + + /** + * The btn Login + */ + private Button btnLogin; + + /** + * The tv Register + */ + private TextView tvRegister; + + /** + * The tv Forget + */ + private TextView tvForget; + //login_anonymous-false-start + /** + * The tv Pass + */ + private TextView tvPass; + //login_anonymous-false-end + /** + * The cb Laws + */ + + private CheckBox cbLaws; + + /** + * The ll QQ + */ + private LinearLayout llQQ; + + /** + * The ll Wechat + */ + private LinearLayout llWechat; + + private LinearLayout llFacebook; + private LinearLayout llTwitter; + private LinearLayout llWechat1; + //login_qq-false-start + /** + * The Tencent + */ + private Tencent mTencent; + //login_qq-false-end + //login_weChat-false-start + /** + * The Wechat + */ + public static IWXAPI mIwxapi; + //login_weChat-false-end + + /** + * The Scope + */ + private String Scope = "get_user_info,add_t"; + //login_qq-false-start + /** + * The IUiListener + */ + IUiListener listener; + //login_qq-false-end + Intent intent; + + /** + * The GizThirdAccountType + */ + public static GizThirdAccountType gizThirdAccountType; + + /** + * The THRED_LOGIN UID&TOKEN + */ + public static String thirdUid, thirdToken; + private LinearLayout llInland; + private LinearLayout llForeign; + + + private View viewLine; + + + public static enum handler_key { + + /** + * 登录 + */ + LOGIN, + + /** + * 自动登录 + */ + AUTO_LOGIN, + + /** + * 第三方登录 + */ + THRED_LOGIN, + + /** + * 国外域名登录 + */ + FOREIGN + } + + /** + * 与WXEntryActivity共用Handler + */ + private Handler baseHandler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + // 登录 + case LOGIN: + progressDialog.show(); + GosDeviceListFragment.loginStatus = 0; + GizWifiSDK.sharedInstance() + .userLogin(etName.getText().toString(), + etPsw.getText().toString()); + break; + // 自动登录 + case AUTO_LOGIN: + progressDialog.show(); + GosDeviceListFragment.loginStatus = 0; + GizWifiSDK.sharedInstance().userLogin( + spf.getString("UserName", ""), + spf.getString("PassWord", "")); + break; + // 第三方登录 + case THRED_LOGIN: + progressDialog.show(); + GosDeviceListFragment.loginStatus = 0; + GizWifiSDK.sharedInstance().loginWithThirdAccount( + gizThirdAccountType, thirdUid, thirdToken); + spf.edit().putString("thirdUid", thirdUid).commit(); + break; + case FOREIGN: + llForeign.setVisibility(View.VISIBLE); + llInland.setVisibility(View.GONE); + break; + } + } + + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setTheme(R.style.AppTheme); +// requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏 + setContentView(R.layout.activity_gos_user_login); + // 设置actionBaru + //setActionBar(false, false, R.string.app_company); + initView(); + initEvent(); + } + + @Override + protected void onResume() { + super.onResume(); + //push-all-start + //push_jiguang-false-start + JPushInterface.onResume(this); + //push_jiguang-false-end + //push-all-end + autoLogin(); + cleanuserthing(); + } + + + private void cleanuserthing() { + if (isclean) { + etName.setText(""); + etPsw.setText(""); + } + } + + private void autoLogin() { + if (TextUtils.isEmpty(spf.getString("UserName", "")) + || TextUtils.isEmpty(spf.getString("PassWord", ""))) { + return; + } + baseHandler.sendEmptyMessageDelayed(handler_key.AUTO_LOGIN.ordinal(), + 1000); + } + + private void initView() { + etName = (EditText) findViewById(R.id.etName); + etPsw = (EditText) findViewById(R.id.etPsw); + btnLogin = (Button) findViewById(R.id.btnLogin); + //register-all-start + tvRegister = (TextView) findViewById(R.id.tvRegister); + //register-all-end + //resetPassword-all-start + tvForget = (TextView) findViewById(R.id.tvForget); + //resetPassword-all-end + //login_anonymous-false-start + tvPass = (TextView) findViewById(R.id.tvPass); + //login_anonymous-false-end + cbLaws = (CheckBox) findViewById(R.id.cbLaws); + + llInland = (LinearLayout) findViewById(R.id.llInland); + llForeign = (LinearLayout) findViewById(R.id.llForeign); + + + //login_qq-false-start + llQQ = (LinearLayout) findViewById(R.id.llQQ); + //login_qq-false-end + //login_qq-false-start login_qq-true-start + viewLine = (View) findViewById(R.id.view_line); + //login_qq-false-end login_qq-true-end + //login_weChat-false-start + llWechat = (LinearLayout) findViewById(R.id.llWechat); + //login_weChat-false-end + //login_weChat-false-start + llWechat1 = (LinearLayout) findViewById(R.id.llWechat1); + //login_weChat-false-end + if (!GosDeploy.appConfig_Login_Anonymous()) { + tvPass.setVisibility(View.GONE); + } + if (!GosDeploy.appConfig_Register_PhoneUser()) { + tvRegister.setVisibility(View.GONE); + } + if (!GosDeploy.appConfig_ResetPassword_PhoneUser()) { + tvForget.setVisibility(View.GONE); + } + // 配置文件部署 + btnLogin.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + btnLogin.setTextColor(GosDeploy.appConfig_Contrast()); + //btnLogin.setTextColor( Color.argb(255, 0, 167, 186)); + } + + private void initEvent() { + btnLogin.setOnClickListener(this); + //register-all-start + tvRegister.setOnClickListener(this); + //register-all-end + //resetPassword-all-start + tvForget.setOnClickListener(this); + //resetPassword-all-end + //login_anonymous-false-start + tvPass.setOnClickListener(this); + //login_anonymous-false-end + //login_qq-false-start + llQQ.setOnClickListener(this); + //login_qq-false-end + //login_weChat-false-start + llWechat.setOnClickListener(this); + //login_weChat-false-end + //login_weChat-false-start + llWechat1.setOnClickListener(this); + //login_weChat-false-end + + //login_qq-true-start login_qq-false-start + if (!GosDeploy.appConfig_Login_QQ()) { + llQQ.setVisibility(View.GONE); + viewLine.setVisibility(View.GONE); + } + //login_qq-true-end login_qq-true-end + //login_weChat-true-start login_weChat-false-start + if (!GosDeploy.appConfig_Login_Wechat()) { + llWechat.setVisibility(View.GONE); + llWechat1.setVisibility(View.GONE); + viewLine.setVisibility(View.GONE); + } + //login_weChat-false-end login_weChat-true-end + + cbLaws.setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + String psw = etPsw.getText().toString(); + if (isChecked) { + etPsw.setInputType(0x90); + } else { + etPsw.setInputType(0x81); + } + etPsw.setSelection(psw.length()); + } + }); + GizWifiSDK.sharedInstance().getCurrentCloudService(); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btnLogin: + if (TextUtils.isEmpty(etName.getText().toString())) { + Toast.makeText(GosUserLoginActivity.this, + R.string.toast_name_wrong, toastTime).show(); + return; + } + if (TextUtils.isEmpty(etPsw.getText().toString())) { + Toast.makeText(GosUserLoginActivity.this, + R.string.toast_psw_wrong, toastTime).show(); + return; + } + baseHandler.sendEmptyMessage(handler_key.LOGIN.ordinal()); + break; + // register-all-start + case R.id.tvRegister: + if (ToolUtils.noDoubleClick()) { + intent = new Intent(GosUserLoginActivity.this, + com.gizwits.opensource.appkit.UserModule.GosRegisterUserActivity.class); + startActivity(intent); + } + break; + //register-all-end + //resetPassword-all-start + case R.id.tvForget: + if (ToolUtils.noDoubleClick()) { + intent = new Intent(GosUserLoginActivity.this, + com.gizwits.opensource.appkit.UserModule.GosForgetPasswordActivity.class); + startActivity(intent); + } + break; + //resetPassword-all-end + //login_anonymous-false-start + case R.id.tvPass: + intent = null; + if (GosDeploy.appConfig_GizwitsInfoAppID() != null && GosDeploy.appConfig_GizwitsInfoAppSecret() != null) { + } + if (intent == null) { + intent = new Intent(GosUserLoginActivity.this, GosMainActivity.class); + } + startActivity(intent); + break; + //login_anonymous-false-end + //login_qq-false-start + case R.id.llQQ: + if (ToolUtils.noDoubleClick()) { + //login_qq-true-start + if (GosDeploy.appConfig_Login_QQ()) { + // login_qq-true-end + String tencentAPPID = GosDeploy.appConfig_TencentAppID(); + if (TextUtils.isEmpty(tencentAPPID)) { + noIDAlert(this, R.string.TencentAPPID_Toast); + return; + } else { + // 启动QQ登录SDK + mTencent = Tencent.createInstance(GosDeploy.appConfig_TencentAppID(), + this.getApplicationContext()); + } + listener = new BaseUiListener() { + protected void doComplete(JSONObject values) { + Message msg = new Message(); + try { + if (values.getInt("ret") == 0) { + gizThirdAccountType = GizThirdAccountType.GizThirdQQ; + thirdUid = values.getString("openid").toString(); + thirdToken = values.getString("access_token") + .toString(); + msg.what = handler_key.THRED_LOGIN.ordinal(); + baseHandler.sendMessage(msg); + } else { + Toast.makeText(GosUserLoginActivity.this, + msg.obj.toString(), toastTime).show(); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + }; + //使用qq登录将此处放开 并且到AndroidManifest 放开activity service + mTencent.login(this, Scope, listener); + //login_qq-true-start + } + // login_qq-true-end + } + break; + //login_qq-false-end + //login_weChat-false-start + case R.id.llWechat: + if (ToolUtils.noDoubleClick()) { + // login_weChat-true-start + if (GosDeploy.appConfig_Login_Wechat()) { + // login_weChat-true-end + String wechatAppID = GosDeploy.appConfig_WechatAppID(); + String wechatAppSecret = GosDeploy.appConfig_WechatAppSecret(); + if (TextUtils.isEmpty(wechatAppID) + || TextUtils.isEmpty(wechatAppSecret) + || wechatAppID.contains("your_wechat_app_id") + || wechatAppSecret.contains("your_wechat_app_secret")) { + noIDAlert(this, R.string.WechatAppID_Toast); + return; + } else { + // 设置与WXEntryActivity共用Handler + setBaseHandler(baseHandler); + // 启动微信登录SDK + mIwxapi = WXAPIFactory.createWXAPI(this, wechatAppID, false); + // 将应用的AppID注册到微信 + mIwxapi.registerApp(wechatAppID); + } + if (!(mIwxapi.isWXAppInstalled() && mIwxapi.isWXAppSupportAPI())) { + noIDAlert(this, R.string.No_WXApp); + return; + } + SendAuth.Req req = new SendAuth.Req(); + req.scope = "snsapi_userinfo"; + req.state = "wechat_sdk_demo"; + mIwxapi.sendReq(req); + //login_weChat-true-start + } + // login_weChat-true-end + } + break; + //login_weChat-false-end + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + + //login_qq-false-start + if (requestCode == 11101) { + Tencent.onActivityResultData(requestCode, resultCode, data, listener); + } + //login_qq-false-end + } + + /** + * 设置云端服务回调 + */ + protected void didGetCurrentCloudService(GizWifiErrorCode result, + java.util.concurrent.ConcurrentHashMap cloudServiceInfo) { + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + Toast.makeText(this, toastError(result), toastTime).show(); + } else { + if (cloudServiceInfo != null) { + String api = cloudServiceInfo.get("openAPIDomain"); + if (api != null) { + if (api.equals("usapi.gizwits.com") || api.equals("euapi.gizwits.com")) { + baseHandler.sendEmptyMessage(handler_key.FOREIGN.ordinal()); + } + } + } + } + } + + /** + * 用户登录回调 + */ + @Override + protected void didUserLogin(GizWifiErrorCode result, String uid, + String token) { + progressDialog.cancel(); + Log.i("Apptest", GosDeviceListFragment.loginStatus + "\t" + "User"); + if (GosDeviceListFragment.loginStatus == 4 + || GosDeviceListFragment.loginStatus == 3) { + return; + } + + Log.i("Apptest", GosDeviceListFragment.loginStatus + "\t" + "UserLogin"); + + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) {// 登录失败 + Toast.makeText(GosUserLoginActivity.this, toastError(result), + toastTime).show(); + } else {// 登录成功 + GosDeviceListFragment.loginStatus = 1; + Toast.makeText(GosUserLoginActivity.this, + R.string.toast_login_successful, toastTime).show(); + // TODO 绑定推送\ + //push-all-start + //push_baidu-false-start push_baidu-true-start + if (GosDeploy.appConfig_Push_BaiDu()) { + //push_baidu-true-end + GosPushManager.pushBindService(uid, token); + //push_baidu-true-start + } + //push_baidu-false-end push_baidu-true-end + //push_jiguang-false-start push_jiguang-true-start + if (GosDeploy.appConfig_Push_JiGuang()) { + //push_jiguang-true-end + GosPushManager.pushBindService(uid, token); + //push_jiguang-true-start + } + //push_jiguang-false-end push_jiguang-true-end + //push-all-end +// PushManager.startWork(getApplicationContext(), PushConstants.LOGIN_TYPE_API_KEY, "T45LbeyAo3muOzMHztipttr8"); + if (!TextUtils.isEmpty(etName.getText().toString()) + && !TextUtils.isEmpty(etPsw.getText().toString())) { + spf.edit().putString("UserName", etName.getText().toString()) + .commit(); + spf.edit().putString("PassWord", etPsw.getText().toString()) + .commit(); + } + spf.edit().putString("Uid", uid).commit(); + spf.edit().putString("Token", token).commit(); + + intent = null; + if (intent == null) { + intent = new Intent(GosUserLoginActivity.this, + GosMainActivity.class); + } + intent.putExtra("ThredLogin", true); + startActivity(intent); + } + } + + /** + * 解绑推送回调 + * + * @param result + */ + protected void didChannelIDUnBind(GizWifiErrorCode result) { + if (GizWifiErrorCode.GIZ_SDK_SUCCESS != result) { + Toast.makeText(this, toastError(result), toastTime).show(); + } + + Log.i("Apptest", "UnBind:" + result.toString()); + } + + ; + + /** + * 菜单、返回键响应 + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + exitBy2Click(); // 调用双击退出函数 + } + return false; + } + + /** + * 双击退出函数 + */ + private static Boolean isExit = false; + + private void exitBy2Click() { + Timer tExit = null; + if (isExit == false) { + isExit = true; // 准备退出 + String doubleClick = (String) getText(R.string.double_click); + Toast.makeText(this, doubleClick, toastTime).show(); + tExit = new Timer(); + tExit.schedule(new TimerTask() { + @Override + public void run() { + isExit = false; // 取消退出 + } + }, 2000); // 如果2秒钟内没有按下返回键,则启动定时器取消掉刚才执行的任务 + + } else { + this.finish(); + System.exit(0); + } + } + + @Override + public void onPause() { + super.onPause(); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/UserModule/GosUserManager.java b/src/java/com/gizwits/opensource/appkit/UserModule/GosUserManager.java new file mode 100644 index 0000000..10fffa0 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/UserModule/GosUserManager.java @@ -0,0 +1,163 @@ +package com.gizwits.opensource.appkit.UserModule; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.DeviceModule.GosDeviceListFragment; +import com.gizwits.opensource.appkit.PushModule.GosPushManager; +import com.gizwits.opensource.appkit.R; + +//push-all-start +//push-all-end + +public class GosUserManager extends GosBaseActivity { + + private static final int GOSUSERMANAGER = 234; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_usermanager); + setToolBar(true, R.string.user_management); + initView(); + } + + private void initView() { + TextView phoneusernumber = (TextView) findViewById(R.id.phoneusernumber); + //personalCenter_changePassword-false-start + LinearLayout changeuserpassword = (LinearLayout) findViewById(R.id.changeuserpassword); + if (!GosDeploy.appConfig_PersonalCenter_ChangePassword()) { + changeuserpassword.setVisibility(View.GONE); + } + //personalCenter_changePassword-false-end + if (!TextUtils.isEmpty(spf.getString("UserName", ""))) { + phoneusernumber.setText(spf.getString("UserName", "")); + } else { + //personalCenter_changePassword-false-start + String uid = spf.getString("thirdUid", ""); + if (!TextUtils.isEmpty(uid) && uid.length() != 0) { + String myuid = uid.substring(0, 2) + "***" + uid.substring(uid.length() - 4, uid.length()); + phoneusernumber.setText(myuid); + changeuserpassword.setVisibility(View.GONE); + } + //personalCenter_changePassword-false-end + } + + } + + public void userlogout(View v) { + setResult(GOSUSERMANAGER); + logoutToClean(); + + Intent intent = new Intent(GosUserManager.this, GosUserLoginActivity.class); + quitAlert(intent, getString(R.string.exit_login)); + + } + + //personalCenter_changePassword-false-start + public void changeuserpassword(View v) { + Intent tent = new Intent(this, GosChangeUserPasswordActivity.class); + startActivity(tent); + } + //personalCenter_changePassword-false-end + + private void logoutToClean() { + //push-all-start + GosPushManager.pushUnBindService(spf.getString("Token", "")); + //push-all-end + spf.edit().putString("UserName", "").commit(); + isclean = true; + spf.edit().putString("PassWord", "").commit(); + spf.edit().putString("Uid", "").commit(); + spf.edit().putString("Token", "").commit(); + + spf.edit().putString("thirdUid", "").commit(); + + if (GosDeviceListFragment.loginStatus == 1) { + GosDeviceListFragment.loginStatus = 0; + } else { + GosDeviceListFragment.loginStatus = 4; + } + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + isclean = false; + finish(); + break; + } + return true; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + isclean = false; + finish(); + return true; + } + return false; + } + + /** + * 推出提示 + * + * @param + */ + protected void quitAlert(final Intent intent, String content) { + final Dialog dialog = new AlertDialog.Builder(this, R.style.alert_dialog_style) + .setView(new EditText(this)).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + TextView tvContent; + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + tvContent = (TextView) window.findViewById(R.id.tv_prompt); + + tvContent.setText(content); + + llNo.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + + dialog.cancel(); + + startActivity(intent); + + } + }); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/UserModule/GosUserModuleBaseActivity.java b/src/java/com/gizwits/opensource/appkit/UserModule/GosUserModuleBaseActivity.java new file mode 100644 index 0000000..275d9fd --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/UserModule/GosUserModuleBaseActivity.java @@ -0,0 +1,132 @@ +package com.gizwits.opensource.appkit.UserModule; + +import android.view.MenuItem; + +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizWifiSDKListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; + +public class GosUserModuleBaseActivity extends GosBaseActivity { + + private GizWifiSDKListener gizWifiSDKListener = new GizWifiSDKListener() { + + /** 用于用户登录 */ + public void didUserLogin(GizWifiErrorCode result, String uid, String token) { + GosUserModuleBaseActivity.this.didUserLogin(result, uid, token); + }; + + /** 用于手机验证码 */ + public void didRequestSendPhoneSMSCode(GizWifiErrorCode result, String token) { + GosUserModuleBaseActivity.this.didRequestSendPhoneSMSCode(result, token); + + }; + + /** 用于用户注册 */ + public void didRegisterUser(GizWifiErrorCode result, String uid, String token) { + GosUserModuleBaseActivity.this.didRegisterUser(result, uid, token); + }; + + /** 用于重置密码 */ + public void didChangeUserPassword(GizWifiErrorCode result) { + GosUserModuleBaseActivity.this.didChangeUserPassword(result); + }; + + /** 用于解绑推送 */ + public void didChannelIDUnBind(GizWifiErrorCode result) { + GosUserModuleBaseActivity.this.didChannelIDUnBind(result); + }; + + /** 用于设置云端服务环境 */ + public void didGetCurrentCloudService(GizWifiErrorCode result, + java.util.concurrent.ConcurrentHashMap cloudServiceInfo) { + GosUserModuleBaseActivity.this.didGetCurrentCloudService(result, cloudServiceInfo); + }; + + }; + + /** + * 用户登录回调 + * + * @param result + * 错误码 + * @param uid + * 用户ID + * @param token + * 授权令牌 + */ + protected void didUserLogin(GizWifiErrorCode result, String uid, String token) { + }; + + /** + * 手机验证码回调 + * + * @param result + * 错误码 + * @param token + * 口令 + */ + protected void didRequestSendPhoneSMSCode(GizWifiErrorCode result, String token) { + }; + + /** + * 用户注册回调 + * + * @param result + * 错误码 + * @param uid + * 用户ID + * @param token + * 授权令牌 + */ + protected void didRegisterUser(GizWifiErrorCode result, String uid, String token) { + }; + + /** + * 重置密码回调 + * + * @param result + * 错误码 + */ + protected void didChangeUserPassword(GizWifiErrorCode result) { + }; + + /** + * 解绑推送回调 + * + * @param result + * 错误码 + */ + protected void didChannelIDUnBind(GizWifiErrorCode result) { + }; + + /** + * 设置云端服务环境回调 + * + * @param result + * 错误码 + * @param cloudServiceInfo + * 云端服务信息 + */ + protected void didGetCurrentCloudService(GizWifiErrorCode result, + java.util.concurrent.ConcurrentHashMap cloudServiceInfo) { + } + + @Override + protected void onResume() { + super.onResume(); + // 每次返回activity都要注册一次sdk监听器,保证sdk状态能正确回调 + GizWifiSDK.sharedInstance().setListener(gizWifiSDKListener); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + break; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/InvitedFragment.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/InvitedFragment.java new file mode 100644 index 0000000..474ccdc --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/InvitedFragment.java @@ -0,0 +1,272 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizDeviceSharingInfo; +import com.gizwits.gizwifisdk.api.GizUserInfo; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingStatus; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.DateUtil; + +public class InvitedFragment extends Fragment { + + // 定义俩个整形值用来区分当前要显示的是哪个view对象 + // 如果是1的话就共享列表, 2的话就是受邀列表 + private int mytpye = -1; + +// private List mydeviceSharingInfos = new ArrayList(); + + private String token; + + private myadapter myadapter; + + private TextView myview; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + initdata(); + // 动态找到布局文件,再从这个布局中find出TextView对象 + View contextView = inflater.inflate(R.layout.activity_gos_shared_list, container, false); + ListView mListView = (ListView) contextView.findViewById(R.id.mysharedlist); + myview = (TextView) contextView.findViewById(R.id.shareddeviceproductname); + myview.setText(getString(R.string.no_guest_users)); + if (GosConstant.newmydeviceSharingInfos != null) { + myadapter = new myadapter(); + mListView.setAdapter(myadapter); + } + + + return contextView; + } + + + public TextView getmyview() { + return myview; + } + + // 初始化接口数据 + private void initdata() { + SharedPreferences spf = getActivity().getSharedPreferences("set", Context.MODE_PRIVATE); + token = spf.getString("Token", ""); +// GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingToMe, null); +// +// GizDeviceSharing.setListener(new GizDeviceSharingListener() { +// +// @Override +// public void didGetDeviceSharingInfos(GizWifiErrorCode result, String deviceID, +// List deviceSharingInfos) { +// super.didGetDeviceSharingInfos(result, deviceID, deviceSharingInfos); +// mydeviceSharingInfos = deviceSharingInfos; +// +// if (mydeviceSharingInfos.size() == 0) { +// myview.setVisibility(View.VISIBLE); +// myview.setText(getResources().getString(R.string.you_have_no_invited_message)); +// } else { +// myview.setVisibility(View.GONE); +// } +// myadapter.notifyDataSetChanged(); +// } +// +// @Override +// public void didAcceptDeviceSharing(GizWifiErrorCode result, String sharingID) { +// super.didAcceptDeviceSharing(result, sharingID); +// +// SharedDeviceListAcitivity activity = (SharedDeviceListAcitivity) getActivity(); +// if (result.ordinal() != 0) { +// Toast.makeText(activity, activity.toastError(result), 2).show(); +// } +// +// GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingToMe, null); +// } +// +// }); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + // listview的adapter,通过刷新的bound对象的属性值来判断当前应该现实的是什么 + class myadapter extends BaseAdapter { + + @Override + public int getCount() { + return GosConstant.newmydeviceSharingInfos.size(); + } + + @Override + public Object getItem(int arg0) { + return null; + } + + @Override + public long getItemId(int arg0) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + View view = View.inflate(getActivity(), R.layout.gos_shared_to_me_activity, null); + + TextView mess = (TextView) view.findViewById(R.id.mess); + + View redpoint = view.findViewById(R.id.redpoint); + + TextView timemess = (TextView) view.findViewById(R.id.timemess); + + TextView mystatues = (TextView) view.findViewById(R.id.mystatues); + + LinearLayout buttionline = (LinearLayout) view.findViewById(R.id.buttionline); + + TextView accept = (TextView) view.findViewById(R.id.accept); + + TextView refuse = (TextView) view.findViewById(R.id.refuse); + + + final GizDeviceSharingInfo gizDeviceSharingInfo = GosConstant.newmydeviceSharingInfos.get(position); + + GizUserInfo userInfo = gizDeviceSharingInfo.getUserInfo(); + + String username = userInfo.getUsername(); + + String email = userInfo.getEmail(); + + String phone = userInfo.getPhone(); + + String remark = userInfo.getRemark(); + String uid = userInfo.getUid(); + + + accept.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.acceptDeviceSharing(token, gizDeviceSharingInfo.getId(), true); + } + }); + + refuse.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.acceptDeviceSharing(token, gizDeviceSharingInfo.getId(), false); + } + }); + String passs = getResources().getString(R.string.tomeshareddevice); + + String[] split = passs.split("xxx"); + + if (!TextUtils.isEmpty(uid) && !uid.equals("null")) { + uid = uid.substring(0, 3) + "***" + uid.substring(uid.length() - 4, uid.length()); + + if (split.length > 2) { + mess.setText(split[0] + uid + split[split.length - 1]); + } else { + + mess.setText(uid + split[split.length - 1]); + } + + } + if (!TextUtils.isEmpty(email) && !email.equals("null")) { + if (split.length > 2) { + mess.setText(split[0] + email + split[split.length - 1]); + } else { + mess.setText(email + split[split.length - 1]); + } + } + + if (!TextUtils.isEmpty(phone) && !phone.equals("null")) { + if (split.length > 2) { + mess.setText(split[0] + phone + split[split.length - 1]); + } else { + + mess.setText(phone + split[split.length - 1]); + } + } + + if (!TextUtils.isEmpty(username) && !username.equals("null")) { + if (split.length > 2) { + mess.setText(split[0] + username + split[split.length - 1]); + } else { + + mess.setText(username + split[split.length - 1]); + } + } + + if (!TextUtils.isEmpty(remark) && !remark.equals("null")) { + if (split.length > 2) { + mess.setText(split[0] + remark + split[split.length - 1]); + } else { + + mess.setText(remark + split[split.length - 1]); + } + } + + GizDeviceSharingStatus status = gizDeviceSharingInfo.getStatus(); + + String updatedAt = gizDeviceSharingInfo.getUpdatedAt(); + updatedAt = DateUtil.utc2Local(updatedAt); + + String expiredAt = gizDeviceSharingInfo.getExpiredAt(); + expiredAt = DateUtil.utc2Local(expiredAt); + + timemess.setText(updatedAt + " " + gizDeviceSharingInfo.getProductName()); + int myintstatus = status.ordinal(); + + + if (myintstatus == 0) { + String timeByFormat = DateUtil.getCurTimeByFormat("yyyy-MM-dd HH:mm:ss"); + long diff = DateUtil.getDiff(timeByFormat, expiredAt); + + if (diff > 0) { + redpoint.setVisibility(View.GONE); + mystatues.setVisibility(View.VISIBLE); + buttionline.setVisibility(View.GONE); + mystatues.setText(getResources().getString(R.string.requsettimeout)); + } else { + redpoint.setVisibility(View.VISIBLE); + buttionline.setVisibility(View.VISIBLE); + mystatues.setVisibility(View.GONE); + } + + } else { + redpoint.setVisibility(View.GONE); + mystatues.setVisibility(View.VISIBLE); + buttionline.setVisibility(View.GONE); + if (myintstatus == 1) { + mystatues.setText(getResources().getString(R.string.accept)); + } else if (myintstatus == 2) { + mystatues.setText(getResources().getString(R.string.refuse)); + } else if (myintstatus == 3) { + mystatues.setText(getResources().getString(R.string.cancelled)); + } + + } + + return view; + } + + } + + + public myadapter getmyadapter() { + return myadapter; + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/MsgNoticeActivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/MsgNoticeActivity.java new file mode 100644 index 0000000..03e45b9 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/MsgNoticeActivity.java @@ -0,0 +1,82 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.os.Bundle; +import android.view.MenuItem; +import android.widget.ListView; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.R; + + +/** + * Created by Sunny on 2015年6月25日 + * + * @author Sunny + */ +public class MsgNoticeActivity extends GosBaseActivity { + + private ListView lvNotice; + private TextView tvNoNotice; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_notice); + +// setActionBar(true, true, R.string.msg_xnotice); + initView(); +// initData(); + } + + private void initView(){ + lvNotice=(ListView) findViewById(R.id.lvNotice); + tvNoNotice=(TextView) findViewById(R.id.tvNoNotice); + } + +// private void initData(){ +// NoticeDBService dbService= new NoticeDBService(this); +// ArrayList lsNotice=dbService.getNoticeList(); +// +// if(lsNotice!=null&&lsNotice.size()>0){ +// lvNotice.setVisibility(View.VISIBLE); +// tvNoNotice.setVisibility(View.GONE); +// +// NoticeAdapter na=new NoticeAdapter(this, lsNotice); +// lvNotice.setAdapter(na); +// }else{ +// lvNotice.setVisibility(View.GONE); +// tvNoNotice.setVisibility(View.VISIBLE); +// } +// } + + @Override + public void onResume() { + super.onResume(); +// initData(); + } + + @Override + public void onPause() { + super.onPause(); + } + + public boolean onOptionsItemSelected(MenuItem menu) { + super.onOptionsItemSelected(menu); + switch (menu.getItemId()) { + case android.R.id.home: + finish(); + break; + default: + break; + } + + return true; + } + + @Override + public void onBackPressed() { + finish(); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceListAcitivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceListAcitivity.java new file mode 100644 index 0000000..5524467 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceListAcitivity.java @@ -0,0 +1,233 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizDeviceSharingInfo; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizDeviceSharingListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.CommonModule.NoScrollViewPager; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.DateUtil; +import com.gizwits.opensource.appkit.view.ViewPagerIndicator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class SharedDeviceListAcitivity extends GosBaseActivity { + + private List tabList; + private List myfragmentlist; + private String token; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_gos_shared_device_list); + + setToolBar(true, R.string.sharedlist); + initData(); + initView(); + } + + // 初始化tab标签中应该显示的文字 + private void initData() { + + token = spf.getString("Token", ""); + + myfragmentlist = new ArrayList(); + + SharedFragment ment1 = new SharedFragment(); + + InvitedFragment ment2 = new InvitedFragment(); + + + myfragmentlist.add(ment1); + myfragmentlist.add(ment2); + + tabList = new ArrayList(); + tabList.add(getResources().getString(R.string.shared)); + tabList.add(getResources().getString(R.string.invited)); + } + + private void initView() { + + ViewPagerIndicator indicator = (ViewPagerIndicator) findViewById( + R.id.vpi_indicator); + + indicator.setVisibleTabCount(2); + indicator.setTabItemTitles(tabList); + NoScrollViewPager vp_shared = (NoScrollViewPager) findViewById(R.id.vp_shared_list); + + vp_shared.setNoScroll(true); + + vp_shared.setAdapter(new myFragmentAdapter(getSupportFragmentManager())); + + indicator.setViewPager(vp_shared, 0); + + indicator.setOnPageChangeListener(new ViewPagerIndicator.PageChangeListener() { + + @Override + public void onPageSelected(int position) { + GosConstant.nowPager = position; + + switch (GosConstant.nowPager) { + case 0: + + break; + + case 1: + GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingToMe, null); + break; + + default: + break; + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + } + + class myFragmentAdapter extends FragmentStatePagerAdapter { + + public myFragmentAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int arg0) { + + if (arg0 == 0) { + SharedFragment shared = new SharedFragment(); + + return shared; + } else { + InvitedFragment shared = (InvitedFragment) myfragmentlist.get(arg0); + + return shared; + + } + + } + + @Override + public int getCount() { + return 2; + } + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + + } + + return super.onOptionsItemSelected(item); + } + + @Override + protected void onResume() { + // TODO Auto-generated method stub + super.onResume(); + + initListener(); + } + + // 初始化接口数据 + private void initListener() { + + GizDeviceSharing.setListener(new GizDeviceSharingListener() { + + @Override + public void didGetDeviceSharingInfos(GizWifiErrorCode result, String deviceID, + List deviceSharingInfos) { + super.didGetDeviceSharingInfos(result, deviceID, deviceSharingInfos); + + + if (deviceSharingInfos != null) { + Collections.sort(deviceSharingInfos, new Comparator() { + + @Override + public int compare(GizDeviceSharingInfo arg0, GizDeviceSharingInfo arg1) { + + String updatedAt = DateUtil.utc2Local(arg0.getUpdatedAt()); + String updatedAt2 = DateUtil.utc2Local(arg1.getUpdatedAt()); + + int diff = (int) DateUtil.getDiff(updatedAt2, updatedAt); + + return diff; + } + + }); + } + + GosConstant.newmydeviceSharingInfos = deviceSharingInfos; + + InvitedFragment fragment = (InvitedFragment) myfragmentlist.get(1); + TextView myview = fragment.getmyview(); + if (deviceSharingInfos.size() == 0) { + + myview.setVisibility(View.VISIBLE); + myview.setText(getResources().getString(R.string.no_guest_users)); + } else { + myview.setVisibility(View.GONE); + } + + InvitedFragment.myadapter getmyadapter = fragment.getmyadapter(); + getmyadapter.notifyDataSetChanged(); + + if (result.ordinal() != 0) { + Toast.makeText(SharedDeviceListAcitivity.this, toastError(result), 2).show(); + } + + + } + + @Override + public void didAcceptDeviceSharing(GizWifiErrorCode result, int sharingID) { + super.didAcceptDeviceSharing(result, sharingID); + + if (result.ordinal() != 0) { + Toast.makeText(SharedDeviceListAcitivity.this, toastError(result), 2).show(); + } + + GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingToMe, null); + } + + }); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceManagerActivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceManagerActivity.java new file mode 100644 index 0000000..d21fe3b --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedDeviceManagerActivity.java @@ -0,0 +1,282 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.os.Message; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.view.MenuItem; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizDeviceSharingInfo; +import com.gizwits.gizwifisdk.api.GizUserInfo; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizDeviceSharingListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.CommonModule.NoScrollViewPager; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.DateUtil; +import com.gizwits.opensource.appkit.view.ViewPagerIndicator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class SharedDeviceManagerActivity extends GosBaseActivity { + + private List tabList; + private String productname; + private String deviceid; + private List myfragmentlist; + private int viewPagerSelected = 0; + private boolean isgetsharing; + private String token; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_gos_shared_device_list); + + setToolBar(true, R.string.sharedmanager); + GosConstant.isEdit = false; + initData(); + initView(); + token = spf.getString("Token", ""); + + } + + @Override + protected void onResume() { + super.onResume(); + + GizDeviceSharing.setListener(new GizDeviceSharingListener() { + + @Override + public void didSharingDevice(GizWifiErrorCode result, String deviceID, int sharingID, Bitmap QRCodeImage) { + super.didSharingDevice(result, deviceID, sharingID, QRCodeImage); + + if (result.ordinal() != 0) { + Toast.makeText(SharedDeviceManagerActivity.this, toastError(result), 1).show(); + } + GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingByMe, deviceid); + } + + + @Override + public void didModifySharingInfo(GizWifiErrorCode result, int sharingID) { + super.didModifySharingInfo(result, sharingID); + + if (result.ordinal() != 0) { + Toast.makeText(SharedDeviceManagerActivity.this, toastError(result), 1).show(); + } + GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingByMe, deviceid); + + } + + @Override + public void didGetDeviceSharingInfos(GizWifiErrorCode result, String deviceID, + List deviceSharingInfos) { + super.didGetDeviceSharingInfos(result, deviceID, deviceSharingInfos); + + if (deviceSharingInfos != null) { + Collections.sort(deviceSharingInfos, new Comparator() { + + @Override + public int compare(GizDeviceSharingInfo arg0, GizDeviceSharingInfo arg1) { + + String updatedAt = DateUtil.utc2Local(arg0.getUpdatedAt()); + String updatedAt2 = DateUtil.utc2Local(arg1.getUpdatedAt()); + + int diff = (int) DateUtil.getDiff(updatedAt2, updatedAt); + + return diff; + } + + }); + } + GosConstant.mydeviceSharingInfos = deviceSharingInfos; + SharedStateFragment fragment = (SharedStateFragment) myfragmentlist.get(0); + Message msg = new Message(); + msg.what = 1; + fragment.handler.sendMessage(msg); + SharedUserFragment fragment1 = (SharedUserFragment) myfragmentlist.get(1); + Message msg1 = new Message(); + msg1.what = 1; + fragment1.handler.sendMessage(msg1); + if (result.ordinal() != 0) { + Toast.makeText(SharedDeviceManagerActivity.this, toastError(result), 1).show(); + } + + } + + @Override + public void didGetBindingUsers(GizWifiErrorCode result, String deviceID, List bindUsers) { + super.didGetBindingUsers(result, deviceID, bindUsers); + GosConstant.mybindUsers = bindUsers; + SharedUserFragment fragment = (SharedUserFragment) myfragmentlist.get(1); + SharedUserFragment.myadapter getmyadapter = fragment.getmyadapter(); + + if (getmyadapter != null) { + getmyadapter.notifyDataSetChanged(); + } + if (result.ordinal() != 0) { + Toast.makeText(SharedDeviceManagerActivity.this, toastError(result), 1).show(); + } + + } + + @Override + public void didUnbindUser(GizWifiErrorCode result, String deviceID, String guestUID) { + // TODO Auto-generated method stub + super.didUnbindUser(result, deviceID, guestUID); + + GizDeviceSharing.getBindingUsers(token, deviceid); + + if (result.ordinal() != 0) { + Toast.makeText(SharedDeviceManagerActivity.this, toastError(result), 1).show(); + } + } + + @Override + public void didRevokeDeviceSharing(GizWifiErrorCode result, int sharingID) { + // TODO Auto-generated method stub + super.didRevokeDeviceSharing(result, sharingID); + + if (result.ordinal() == 0) { + GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingByMe, deviceid); + } else { + + Toast.makeText(SharedDeviceManagerActivity.this, toastError(result), 1).show(); + } + } + }); + + + } + + // 初始化tab标签中应该显示的文字 + private void initData() { + productname = getIntent().getStringExtra("productname"); + deviceid = getIntent().getStringExtra("deviceid"); + isgetsharing = getIntent().getBooleanExtra("isgetsharing", false); + + tabList = new ArrayList(); + tabList.add(getResources().getString(R.string.sharedstated)); + tabList.add(getResources().getString(R.string.boundusers)); + + SharedStateFragment shared = new SharedStateFragment(); + + SharedUserFragment shared1 = new SharedUserFragment(); + + myfragmentlist = new ArrayList(); + + myfragmentlist.add(shared); + myfragmentlist.add(shared1); + } + + private void initView() { + + ViewPagerIndicator indicator = (ViewPagerIndicator) findViewById( + R.id.vpi_indicator); + + indicator.setVisibleTabCount(2); + indicator.setTabItemTitles(tabList); + NoScrollViewPager vp_shared = (NoScrollViewPager) findViewById( + R.id.vp_shared_list); + + vp_shared.setNoScroll(true); + + vp_shared.setAdapter(new myFragmentAdapter(getSupportFragmentManager())); + + indicator.setViewPager(vp_shared, 0); + indicator.setOnPageChangeListener(new ViewPagerIndicator.PageChangeListener() { + + @Override + public void onPageSelected(int position) { + + viewPagerSelected = position; + + if (position == 0 && isgetsharing) { + SharedPreferences spf = getSharedPreferences("set", Context.MODE_PRIVATE); + String token = spf.getString("Token", ""); + GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingByMe, deviceid); + + } else if (position == 1 && isgetsharing) { + SharedStateFragment fragment3 = (SharedStateFragment) myfragmentlist.get(0); + Message msg = new Message(); + msg.what = 2; + fragment3.handler.sendMessage(msg); + SharedPreferences spf = getSharedPreferences("set", Context.MODE_PRIVATE); + String token = spf.getString("Token", ""); + GizDeviceSharing.getBindingUsers(token, deviceid); + } + + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + } + + class myFragmentAdapter extends FragmentStatePagerAdapter { + + public myFragmentAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int arg0) { + + Bundle b = new Bundle(); + b.putString("productname", productname); + b.putString("deviceid", deviceid); + + Fragment fragment = myfragmentlist.get(arg0); + + fragment.setArguments(b); + + return fragment; + + } + + @Override + public int getCount() { + return myfragmentlist.size(); + } + + } + + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + + finish(); + break; + + } + + return super.onOptionsItemSelected(item); + } + + // 刷新menu的方法 + private void refreshMenu() { + // 核心是Activity这个方法 + supportInvalidateOptionsMenu(); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedFragment.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedFragment.java new file mode 100644 index 0000000..1f4c85d --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedFragment.java @@ -0,0 +1,212 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import com.gizwits.gizwifisdk.api.GizWifiDevice; +import com.gizwits.gizwifisdk.api.GizWifiSDK; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingUserRole; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.R; + +import java.util.ArrayList; +import java.util.List; + +public class SharedFragment extends Fragment { + + // 定义俩个整形值用来区分当前要显示的是哪个view对象 + // 如果是1的话就共享列表, 2的话就是受邀列表 + private int mytpye = -1; + private List list; + private TextView myview; + private myadapter myadapter1; + private ListView mListView; + + private View contextView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + // 动态找到布局文件,再从这个布局中find出TextView对象 + contextView = inflater.inflate(R.layout.activity_gos_shared_list, container, false); + + initView(); + initData(); + initEvent(); + return contextView; + } + + private void initView() { + mListView = (ListView) contextView.findViewById(R.id.mysharedlist); + myview = (TextView) contextView.findViewById(R.id.shareddeviceproductname); + } + + + private void initEvent() { + myadapter1 = new myadapter(); + + mListView.setAdapter(myadapter1); + + mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + @Override + public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { + + GizWifiDevice wifiDevice = list.get(arg2); + + GizDeviceSharingUserRole sharingRole = wifiDevice.getSharingRole(); + int role = sharingRole.ordinal(); + boolean isgetsharing = false; + + if (role == 2) { + isgetsharing = true; + } + + mListView.setEnabled(false); + mListView.postDelayed(new Runnable() { + @Override + public void run() { + mListView.setEnabled(true); + } + }, 1000); + + Intent tent = new Intent(getActivity(), SharedDeviceManagerActivity.class); + + GosConstant.mybindUsers.clear(); + GosConstant.mydeviceSharingInfos.clear(); + tent.putExtra("productname", wifiDevice.getProductName()); + tent.putExtra("deviceid", wifiDevice.getDid()); + tent.putExtra("isgetsharing", isgetsharing); + startActivity(tent); + } + }); + } + + // 获取当前的设备列表 + private void initData() { + + list = new ArrayList(); + List deviceList = GizWifiSDK.sharedInstance().getDeviceList(); + + for (GizWifiDevice gizWifiDevice : deviceList) { + + GizDeviceSharingUserRole sharingRole = gizWifiDevice.getSharingRole(); + + if (sharingRole != null) { + + if (sharingRole.ordinal() == 1 || sharingRole.ordinal() == 2) { + list.add(gizWifiDevice); + } + } + + } + + if (list.size() == 0) { + myview.setVisibility(View.VISIBLE); + myview.setText(getResources().getString(R.string.you_have_no_device)); + + } else { + myview.setVisibility(View.GONE); + } + + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + // listview的adapter,通过刷新的bound对象的属性值来判断当前应该现实的是什么 + class myadapter extends BaseAdapter { + + @Override + public int getCount() { + return list.size(); + } + + @Override + public Object getItem(int arg0) { + return null; + } + + @Override + public long getItemId(int arg0) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + View view = convertView; + Holder holder; + + if (view == null) { + view = View.inflate(getActivity(), R.layout.item_gos_device_shared_list, null); + holder = new Holder(view); + view.setTag(holder); + } else { + holder = (Holder) view.getTag(); + } + + holder.getTvDeviceName().setText(list.get(position).getProductName()); + holder.getTvDeviceMac().setText(list.get(position).getMacAddress()); + GizDeviceSharingUserRole sharingRole = list.get(position).getSharingRole(); + if (sharingRole.ordinal() == 1) { + holder.getTvDeviceStatus().setVisibility(View.VISIBLE); + holder.getTvDeviceStatus().setText(getString(R.string.not_sharing)); + } else if (sharingRole.ordinal() == 2) { + holder.getTvDeviceStatus().setVisibility(View.GONE); + } + return view; + } + + } + + public myadapter getmyadapter() { + return myadapter1; + } + + // 设备列表对应的holder + class Holder { + View view; + + public Holder(View view) { + this.view = view; + } + + private TextView tvDeviceMac, tvDeviceStatus, tvDeviceName; + + + public TextView getTvDeviceMac() { + if (null == tvDeviceMac) { + tvDeviceMac = (TextView) view.findViewById(R.id.tvDeviceMac); + } + return tvDeviceMac; + } + + public TextView getTvDeviceStatus() { + if (null == tvDeviceStatus) { + tvDeviceStatus = (TextView) view.findViewById(R.id.tvDeviceStatus); + } + return tvDeviceStatus; + } + + public TextView getTvDeviceName() { + if (null == tvDeviceName) { + tvDeviceName = (TextView) view.findViewById(R.id.tvDeviceName); + } + return tvDeviceName; + } + + } +} + + diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedStateFragment.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedStateFragment.java new file mode 100644 index 0000000..daff47c --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedStateFragment.java @@ -0,0 +1,600 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizDeviceSharingInfo; +import com.gizwits.gizwifisdk.api.GizUserInfo; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingStatus; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingType; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingWay; +import com.gizwits.gizwifisdk.enumration.GizUserAccountType; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.AssetsUtils; +import com.gizwits.opensource.appkit.utils.DateUtil; +import com.gizwits.opensource.appkit.view.SlideListView2; + + +public class SharedStateFragment extends Fragment { + + // 定义俩个整形值用来区分当前要显示的是哪个view对象 + // 如果是1的话就共享列表, 2的话就是受邀列表 + private int mytpye = -1; + + + View contextView; + private String deviceID; + private myadapter myadapter; + + private String token; + + private LinearLayout addshared; + + private SlideListView2 mListView; + + private String productname; + + private TextView shareddeviceproductname; + private TextView tvSharedTo; + private LinearLayout llSharedTo; + private LinearLayout llAddShared; + private LinearLayout rename; + private SharedPreferences spf; + private LinearLayout cancel; + private RelativeLayout rlCancel; + + private static final String TAG = "mySharedFragment3"; + Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + // 当GosConstant.mydeviceSharingInfos 在Activity中被赋值后执行 + case 1: + if (GosConstant.mydeviceSharingInfos.size() == 0) { + String s = getResources().getString(R.string.have_not_been_shared); + String ss = s.substring(3, s.length()); + StringBuilder sb = new StringBuilder(productname); + shareddeviceproductname.setText(sb.append(ss)); + shareddeviceproductname.setVisibility(View.VISIBLE); + llSharedTo.setVisibility(View.GONE); + rename.setVisibility(View.GONE); + llAddShared.setVisibility(View.VISIBLE); + } else { + tvSharedTo.setText(productname + getResources().getString(R.string.sharedto)); + llSharedTo.setVisibility(View.VISIBLE); + shareddeviceproductname.setVisibility(View.GONE); + if (rlCancel.getVisibility() == View.GONE) { + rename.setVisibility(View.VISIBLE); + llAddShared.setVisibility(View.VISIBLE); + } + + } + + if (myadapter == null) { + myadapter = new myadapter(true); + mListView.setAdapter(myadapter); + } else { + mListView.setAdapter(myadapter); + } + + break; + case 2: + mListView.initSlideMode(SlideListView2.MOD_RIGHT); + mListView.setOnItemClickListener(null); + rlCancel.setVisibility(View.GONE); + llAddShared.setVisibility(View.VISIBLE); + break; + } + } + }; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + // 动态找到布局文件,再从这个布局中find出TextView对象 + contextView = inflater.inflate(R.layout.activity_gos_shared_manage, container, false); + initView(); + initData(); + initEvent(); + return contextView; + } + + private void initView() { + mListView = (SlideListView2) contextView.findViewById(R.id.mysharedlist); + mListView.initSlideMode(SlideListView2.MOD_RIGHT); + llAddShared = (LinearLayout) contextView.findViewById(R.id.llAddShared); + rlCancel = (RelativeLayout) contextView.findViewById(R.id.rlCancel); + addshared = (LinearLayout) contextView.findViewById(R.id.addshared); + rename = (LinearLayout) contextView.findViewById(R.id.rename); + cancel = (LinearLayout) contextView.findViewById(R.id.cancel); + shareddeviceproductname = (TextView) contextView.findViewById(R.id.shareddeviceproductname); + tvSharedTo = (TextView) contextView.findViewById(R.id.tvSharedTo); + llSharedTo = (LinearLayout) contextView.findViewById(R.id.llSharedTo); + + } + + private void initData() { + Bundle arguments = getArguments(); + productname = arguments.getString("productname"); + spf = getActivity().getSharedPreferences("set", Context.MODE_PRIVATE); + token = spf.getString("Token", ""); + deviceID = getArguments().getString("deviceid"); + } + + @Override + public void onResume() { + super.onResume(); + GizDeviceSharing.getDeviceSharingInfos(token, GizDeviceSharingType.GizDeviceSharingByMe, deviceID); + } + + private void initEvent() { + addshared.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + if (!TextUtils.isEmpty(spf.getString("UserName", "")) && !TextUtils.isEmpty(spf.getString("PassWord", ""))) { + Intent tent = new Intent(getActivity(), addSharedActivity.class); + tent.putExtra("productname", productname); + tent.putExtra("did", deviceID); + startActivity(tent); + } else { + Toast.makeText(getContext(), getString(R.string.please_login), 2000).show(); + } + } + }); + rename.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mListView.initSlideMode(SlideListView2.MOD_FORBID); + llAddShared.setVisibility(View.GONE); + rlCancel.setVisibility(View.VISIBLE); + myadapter = new myadapter(false); + mListView.setAdapter(myadapter); + mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, final int position, long id) { + TextView name = (TextView) view.findViewById(R.id.tvDeviceName); + + final Dialog dialog = new AlertDialog.Builder(getContext(), R.style.edit_dialog_style) + .setView(new EditText(getContext())).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_rename); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + final EditText remarkname = (EditText) window.findViewById(R.id.remarkname); + + remarkname.setText(name.getText().toString()); + remarkname.setSelection(name.getText().toString().length()); + RelativeLayout rlClear = (RelativeLayout) window.findViewById(R.id.rlClear); + LinearLayout llyes = (LinearLayout) window.findViewById(R.id.llSure); + LinearLayout llno = (LinearLayout) window.findViewById(R.id.llNo); + + llno.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + dialog.dismiss(); + } + }); + + rlClear.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + remarkname.setText(""); + } + }); + + llyes.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + String token = spf.getString("Token", ""); + GizDeviceSharingInfo gizDeviceSharingInfo = GosConstant.mydeviceSharingInfos.get(position); + GizDeviceSharing.modifySharingInfo(token, gizDeviceSharingInfo.getId(), + remarkname.getText().toString()); + dialog.dismiss(); + + } + }); + } + }); + } + }); + + cancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mListView.initSlideMode(SlideListView2.MOD_RIGHT); + mListView.setOnItemClickListener(null); + rlCancel.setVisibility(View.GONE); + llAddShared.setVisibility(View.VISIBLE); + myadapter = new myadapter(true); + mListView.setAdapter(myadapter); + } + }); + + + } + + public myadapter getmyadapter() { + return myadapter; + } + + public RelativeLayout getRelativeLayout() { + return rlCancel; + } + + public SlideListView2 getListview() { + return mListView; + } + + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + // listview的adapter,通过刷新的bound对象的属性值来判断当前应该现实的是什么 + class myadapter extends BaseAdapter { + + private String uid; + + private boolean isShow; + + @Override + public int getCount() { + return GosConstant.mydeviceSharingInfos.size(); + } + + public myadapter(boolean isShow) { + this.isShow = isShow; + } + + @Override + public Object getItem(int arg0) { + return null; + } + + @Override + public long getItemId(int arg0) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + + ViewHolder holder; + + if (convertView == null) { + convertView = LayoutInflater.from(getContext()).inflate( + R.layout.gos_shared_by_me_activity, null); + holder = new ViewHolder(); + holder.rlmyhome = (RelativeLayout) convertView.findViewById(R.id.rlmyhome); + holder.tvDeviceName = (TextView) convertView.findViewById(R.id.tvDeviceName); + holder.tvDeviceMac = (TextView) convertView.findViewById(R.id.tvDeviceMac); + holder.tvDeviceStatus = (TextView) convertView.findViewById(R.id.tvDeviceStatus); + holder.delete2name = (TextView) convertView.findViewById(R.id.delete2name); + holder.delete3name = (TextView) convertView.findViewById(R.id.delete3name); + holder.delete2 = (LinearLayout) convertView.findViewById(R.id.delete2); + holder.delete3 = (LinearLayout) convertView.findViewById(R.id.delete3); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + + holder.delete2.setVisibility(View.INVISIBLE); + + holder.delete2name.setText(getResources().getString(R.string.cancel_sharing)); + + holder.delete3name.setText(getResources().getString(R.string.sharedagain)); + + GizDeviceSharingInfo gizDeviceSharingInfo = GosConstant.mydeviceSharingInfos.get(position); + + final int id = gizDeviceSharingInfo.getId(); + + final String myid = gizDeviceSharingInfo.getDeviceID(); + + GizUserInfo userInfo = gizDeviceSharingInfo.getUserInfo(); + + // 更新时间 + String updatedAt = gizDeviceSharingInfo.getUpdatedAt(); + + // 超时时间 + String expiredAt = gizDeviceSharingInfo.getExpiredAt(); + + uid = userInfo.getUid(); + + String email = userInfo.getEmail(); + + String phone = userInfo.getPhone(); + + String username = userInfo.getUsername(); + + String remark = userInfo.getRemark(); + + if (!TextUtils.isEmpty(uid) && !uid.equals("null")) { + String myuid = uid.substring(0, 3) + "***" + uid.substring(uid.length() - 4, uid.length()); + + holder.tvDeviceName.setText(myuid); + + } + + if (!TextUtils.isEmpty(email) && !email.equals("null")) { + + holder.tvDeviceName.setText(email); + + } + + if (!TextUtils.isEmpty(phone) && !phone.equals("null")) { + + holder.tvDeviceName.setText(phone); + + } + + if (!TextUtils.isEmpty(username) && !username.equals("null")) { + + holder.tvDeviceName.setText(username); + + } + + if (!TextUtils.isEmpty(remark) && !remark.equals("null")) { + + holder.tvDeviceName.setText(remark); + + } + + updatedAt = DateUtil.utc2Local(updatedAt); + + expiredAt = DateUtil.utc2Local(expiredAt); + + holder.tvDeviceMac.setText(updatedAt); + + GizDeviceSharingStatus status = gizDeviceSharingInfo.getStatus(); + + int ordinal = status.ordinal(); + if (isShow) { + holder.tvDeviceStatus.setVisibility(View.VISIBLE); + } else { + holder.tvDeviceStatus.setVisibility(View.GONE); + } + switch (ordinal) { + case 0: + + String timeByFormat = DateUtil.getCurTimeByFormat("yyyy-MM-dd HH:mm:ss"); + long diff = DateUtil.getDiff(timeByFormat, expiredAt); + + if (diff > 0) { + holder.delete3name.setText(getResources().getString(R.string.delete)); + + holder.delete2name.setText(getResources().getString(R.string.sharedagain)); + + holder.rlmyhome.setPadding(0, 0, AssetsUtils.diptopx(getContext(), -181), 0); + holder.delete2.setVisibility(View.VISIBLE); + holder.delete3.setVisibility(View.VISIBLE); + holder.delete2.setBackgroundColor(getResources().getColor(R.color.back_gray)); + holder.delete3.setBackgroundColor(getResources().getColor(R.color.unbind)); + + holder.delete2.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.sharingDevice(token, myid, GizDeviceSharingWay.GizDeviceSharingByNormal, + GosConstant.mydeviceSharingInfos.get(position).getUserInfo().getUid(), + GizUserAccountType.GizUserOther); + } + }); + + holder.delete3.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.revokeDeviceSharing(token, id); + } + }); + + holder.tvDeviceStatus.setText(getResources().getString(R.string.timeout)); + } else { + holder.delete3.setVisibility(View.GONE); + holder.rlmyhome.setPadding(0, 0, AssetsUtils.diptopx(getContext(), -91), 0); + holder.delete2.setVisibility(View.VISIBLE); + holder.delete2.setBackgroundColor(getResources().getColor(R.color.unbind)); + holder.delete2name.setText(getResources().getString(R.string.cancel_sharing)); + final String s = holder.tvDeviceName.getText().toString(); + holder.delete2.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + + quitAlert(getActivity(), s, id); + } + }); + holder.tvDeviceStatus.setText(getResources().getString(R.string.waitforaccept)); + } + break; + + case 1: + holder.tvDeviceStatus.setText(getResources().getString(R.string.accept)); + holder.delete3.setVisibility(View.GONE); + holder.rlmyhome.setPadding(0, 0, AssetsUtils.diptopx(getContext(), -91), 0); + holder.delete2.setVisibility(View.VISIBLE); + holder.delete2.setBackgroundColor(getResources().getColor(R.color.unbind)); + holder.delete2name.setText(getResources().getString(R.string.cancel_sharing)); + final String s = holder.tvDeviceName.getText().toString(); + holder.delete2.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + + quitAlert(getActivity(), s, id); + } + }); + + break; + + case 2: + holder.rlmyhome.setPadding(0, 0, AssetsUtils.diptopx(getContext(), -181), 0); + holder.delete2.setVisibility(View.VISIBLE); + holder.delete3.setVisibility(View.VISIBLE); + holder.delete2.setBackgroundColor(getResources().getColor(R.color.back_gray)); + holder.delete3.setBackgroundColor(getResources().getColor(R.color.unbind)); + holder.tvDeviceStatus.setText(getResources().getString(R.string.refuse)); + + holder.delete3name.setText(getResources().getString(R.string.delete)); + + holder.delete2name.setText(getResources().getString(R.string.sharedagain)); + + + holder.delete2.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.sharingDevice(token, myid, GizDeviceSharingWay.GizDeviceSharingByNormal, + GosConstant.mydeviceSharingInfos.get(position).getUserInfo().getUid(), + GizUserAccountType.GizUserOther); + } + }); + + holder.delete3.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.revokeDeviceSharing(token, id); + } + }); + + // tvDeviceStatus.setText(getResources().getString(R.string.timeout)); + + break; + + case 3: + holder.rlmyhome.setPadding(0, 0, AssetsUtils.diptopx(getContext(), -181), 0); + holder.delete2.setVisibility(View.VISIBLE); + holder.delete3.setVisibility(View.VISIBLE); + holder.delete2.setBackgroundColor(getResources().getColor(R.color.back_gray)); + holder.delete3.setBackgroundColor(getResources().getColor(R.color.unbind)); + holder.tvDeviceStatus.setText(getResources().getString(R.string.cancelled)); + + holder.delete3name.setText(getResources().getString(R.string.delete)); + + + holder.delete2name.setText(getResources().getString(R.string.sharedagain)); + + // delete2name.setGravity(Gravity.CENTER); + + holder.delete2.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.sharingDevice(token, myid, GizDeviceSharingWay.GizDeviceSharingByNormal, + GosConstant.mydeviceSharingInfos.get(position).getUserInfo().getUid(), + GizUserAccountType.GizUserOther); + } + }); + + holder.delete3.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + GizDeviceSharing.revokeDeviceSharing(token, id); + } + }); + + break; + + default: + break; + } + + + return convertView; + } + + } + + class ViewHolder { + TextView tvDeviceName; + TextView tvDeviceMac; + TextView tvDeviceStatus; + TextView delete2name; + TextView delete3name; + LinearLayout delete2; + LinearLayout delete3; + RelativeLayout rlmyhome; + } + + protected void quitAlert(Context context, String username, final int uid2) { + final Dialog dialog = new AlertDialog.Builder(getActivity(), R.style.alert_dialog_style) + .setView(new EditText(getActivity())).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + TextView view3 = (TextView) window.findViewById(R.id.textView3); + view3.setVisibility(View.VISIBLE); + TextView tv = (TextView) window.findViewById(R.id.tv_prompt); + + String userstring = getResources().getString(R.string.deleteuserpremiss); + String[] split = userstring.split("xxx"); + + tv.setText(split[0] + username + split[1]); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + // GizDeviceSharing.unbindGuestUser(token, deviceID, uid2); + + GizDeviceSharing.revokeDeviceSharing(token, uid2); + dialog.cancel(); + } + }); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedUserFragment.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedUserFragment.java new file mode 100644 index 0000000..1b42953 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/SharedUserFragment.java @@ -0,0 +1,275 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.BaseAdapter; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizUserInfo; +import com.gizwits.opensource.appkit.CommonModule.GosConstant; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.AssetsUtils; +import com.gizwits.opensource.appkit.utils.DateUtil; +import com.gizwits.opensource.appkit.view.SlideListView2; + + +public class SharedUserFragment extends Fragment { + + // 定义俩个整形值用来区分当前要显示的是哪个view对象 + // 如果是1的话就共享列表, 2的话就是受邀列表 + private int mytpye = -1; + private myadapter myadapter; + private String deviceID; + private String token; + private String uid; + private String productname; + private TextView shareddeviceproductname; + private SlideListView2 mListView; + + Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case 1: + if (GosConstant.mydeviceSharingInfos.size() == 0) { + String s = getResources().getString(R.string.have_not_been_shared); + String ss = s.substring(3, s.length()); + StringBuilder sb = new StringBuilder(productname); + shareddeviceproductname.setText(sb.append(ss)); + shareddeviceproductname.setVisibility(View.VISIBLE); + llSharedTo.setVisibility(View.GONE); + } else { + tvSharedTo.setText(productname + getResources().getString(R.string.sharedto)); + llSharedTo.setVisibility(View.VISIBLE); + shareddeviceproductname.setVisibility(View.GONE); + } + myadapter = new myadapter(); + mListView.setAdapter(myadapter); + break; + } + } + }; + private TextView tvSharedTo; + private LinearLayout llSharedTo; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + // 动态找到布局文件,再从这个布局中find出TextView对象 + View contextView = inflater.inflate(R.layout.activity_gos_shared_list, container, false); + mListView = (SlideListView2) contextView.findViewById(R.id.mysharedlist); + mListView.initSlideMode(SlideListView2.MOD_RIGHT); + + shareddeviceproductname = (TextView) contextView.findViewById(R.id.shareddeviceproductname); + tvSharedTo = (TextView) contextView.findViewById(R.id.tvSharedTo); + llSharedTo = (LinearLayout) contextView.findViewById(R.id.llSharedTo); + Bundle arguments = getArguments(); + productname = arguments.getString("productname"); + + + initdata(); + return contextView; + } + + public myadapter getmyadapter() { + return myadapter; + } + + private void initdata() { + SharedPreferences spf = getActivity().getSharedPreferences("set", Context.MODE_PRIVATE); + token = spf.getString("Token", ""); + uid = spf.getString("Uid", ""); + + deviceID = getArguments().getString("deviceid"); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + // listview的adapter,通过刷新的bound对象的属性值来判断当前应该现实的是什么 + class myadapter extends BaseAdapter { + + private String uid; + + @Override + public int getCount() { + return GosConstant.mybindUsers.size(); + } + + @Override + public Object getItem(int arg0) { + return null; + } + + @Override + public long getItemId(int arg0) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + ViewHolder holder; + + if (convertView == null) { + convertView = LayoutInflater.from(getContext()).inflate( + R.layout.gos_shared_by_me_activity, null); + holder = new ViewHolder(); + holder.rlmyhome = (RelativeLayout) convertView.findViewById(R.id.rlmyhome); + holder.tvDeviceName = (TextView) convertView.findViewById(R.id.tvDeviceName); + holder.tvDeviceMac = (TextView) convertView.findViewById(R.id.tvDeviceMac); + holder.tvDeviceStatus = (TextView) convertView.findViewById(R.id.tvDeviceStatus); + holder.delete2name = (TextView) convertView.findViewById(R.id.delete2name); + holder.delete3name = (TextView) convertView.findViewById(R.id.delete3name); + holder.delete2 = (LinearLayout) convertView.findViewById(R.id.delete2); + holder.delete3 = (LinearLayout) convertView.findViewById(R.id.delete3); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + holder.rlmyhome.setPadding(0, 0, AssetsUtils.diptopx(getContext(), -90), 0); + holder.delete3.setVisibility(View.GONE); + + holder.delete2name.setText(getResources().getString(R.string.cancel_sharing)); + + holder.delete2.setVisibility(View.VISIBLE); + + holder.delete2name.setText(getResources().getString(R.string.cancel_sharing)); + + holder.tvDeviceStatus.setVisibility(View.GONE); + + GizUserInfo userInfo = GosConstant.mybindUsers.get(position); + + uid = userInfo.getUid(); + + String email = userInfo.getEmail(); + + String phone = userInfo.getPhone(); + + String username = userInfo.getUsername(); + + String remark = userInfo.getRemark(); + String deviceBindTime = userInfo.getDeviceBindTime(); + + deviceBindTime = DateUtil.utc2Local(deviceBindTime); + holder.tvDeviceMac.setText(deviceBindTime); + + if (!TextUtils.isEmpty(uid) && !uid.equals("null")) { + String myuid = uid.substring(0, 3) + "***" + uid.substring(uid.length() - 4, uid.length()); + holder.tvDeviceName.setText(myuid); + + } + + if (!TextUtils.isEmpty(email) && !email.equals("null")) { + + holder.tvDeviceName.setText(email); + + } + + if (!TextUtils.isEmpty(phone) && !phone.equals("null")) { + + holder.tvDeviceName.setText(phone); + + } + + if (!TextUtils.isEmpty(username) && !username.equals("null")) { + + holder.tvDeviceName.setText(username); + + } + + if (!TextUtils.isEmpty(remark) && !remark.equals("null")) { + + holder.tvDeviceName.setText(remark); + + } + final String s = holder.tvDeviceName.getText().toString(); + holder.delete2name.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View arg0) { + + quitAlert(getActivity(), s, GosConstant.mybindUsers.get(position).getUid()); + } + }); + + return convertView; + } + + } + + class ViewHolder { + TextView tvDeviceName; + TextView tvDeviceMac; + TextView tvDeviceStatus; + TextView delete2name; + TextView delete3name; + LinearLayout delete2; + LinearLayout delete3; + RelativeLayout rlmyhome; + } + + protected void quitAlert(Context context, String username, final String uid2) { + final Dialog dialog = new AlertDialog.Builder(getActivity(),R.style.alert_dialog_style) + .setView(new EditText(getActivity())).create(); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.alert_gos_quit); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + LinearLayout llNo, llSure; + llNo = (LinearLayout) window.findViewById(R.id.llNo); + llSure = (LinearLayout) window.findViewById(R.id.llSure); + + TextView view3 = (TextView) window.findViewById(R.id.textView3); + view3.setVisibility(View.VISIBLE); + TextView tv = (TextView) window.findViewById(R.id.tv_prompt); + + String userstring = getResources().getString(R.string.deleteuserpremiss); + String[] split = userstring.split("xxx"); + + tv.setText(split[0] + username + split[1]); + + llNo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + dialog.cancel(); + } + }); + + llSure.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + GizDeviceSharing.unbindUser(token, deviceID, uid2); + dialog.cancel(); + } + }); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/addSharedActivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/addSharedActivity.java new file mode 100644 index 0000000..7577934 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/addSharedActivity.java @@ -0,0 +1,88 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.widget.LinearLayout; + +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.R; + + +public class addSharedActivity extends GosBaseActivity { + + private String productname; + private String did; + private LinearLayout devicetwoshared; + private LinearLayout usershared; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_gos_addshared); + setToolBar(true, R.string.addshared); + + initData(); + initView(); + } + + private void initView() { + usershared = (LinearLayout) findViewById(R.id.usershared); + devicetwoshared = (LinearLayout) findViewById(R.id.devicetwoshared); + } + + private void initData() { + Intent tent = getIntent(); + productname = tent.getStringExtra("productname"); + did = tent.getStringExtra("did"); + } + + // personalCenter_deviceSharing_qrcode-false-start + // 二维码分享 + public void devicetwoshared(View v) { + Intent tent = new Intent(this, twoSharedActivity.class); + tent.putExtra("productname", productname); + tent.putExtra("did", did); + startActivity(tent); + + devicetwoshared.setEnabled(false); + devicetwoshared.postDelayed(new Runnable() { + @Override + public void run() { + devicetwoshared.setEnabled(true); + } + }, 1000); + + } + //personalCenter_deviceSharing_qrcode-false-end + + // 用户账号分享 + + public void usershared(View v) { + + Intent tent = new Intent(this, userSharedActivity.class); + tent.putExtra("productname", productname); + tent.putExtra("did", did); + startActivity(tent); + + usershared.setEnabled(false); + usershared.postDelayed(new Runnable() { + @Override + public void run() { + usershared.setEnabled(true); + } + }, 1000); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + break; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/deviceSharedMessageActivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/deviceSharedMessageActivity.java new file mode 100644 index 0000000..bf04326 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/deviceSharedMessageActivity.java @@ -0,0 +1,276 @@ +package com.gizwits.opensource.appkit.sharingdevice; + + +import android.app.ProgressDialog; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.v4.widget.SwipeRefreshLayout; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.api.GizMessage; +import com.gizwits.gizwifisdk.enumration.GizMessageStatus; +import com.gizwits.gizwifisdk.enumration.GizMessageType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizDeviceSharingListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.DateUtil; +import com.gizwits.opensource.appkit.view.SlideListView2; +import com.gizwits.opensource.appkit.view.VerticalSwipeRefreshLayout; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class deviceSharedMessageActivity extends GosBaseActivity implements SwipeRefreshLayout.OnRefreshListener { + + private List mymessageList = new ArrayList(); + private myadapter myadapter; + private String token; + private String myid = ""; + private int myposition = -1; + // 删除时需要用到的对话框 + private ProgressDialog progressDialog; + private TextView tvNoMessage; + private VerticalSwipeRefreshLayout mSwipeLayout; + + Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case 1: + mSwipeLayout.setRefreshing(false); + GizDeviceSharing.queryMessageList(token, GizMessageType.GizMessageSharing); + break; + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_device_shared_message_list); + setToolBar(true, R.string.devicesharedmess); + initView(); + initData(); + initProgressBar(); + } + + private void initProgressBar() { + progressDialog = new ProgressDialog(this); + String loadingText = getString(R.string.loadingtext); + progressDialog.setMessage(loadingText); + progressDialog.setCanceledOnTouchOutside(false); + } + + // 初始化分享设备的数据 + private void initData() { + // + // GizDeviceSharing.setListener(new GizDeviceSharingListener() { + // + // @Override + // public void didQueryMessageList(GizWifiErrorCode result, + // List messageList) { + // super.didQueryMessageList(result, messageList); + // + // mymessageList = messageList; + // myadapter.notifyDataSetChanged(); + // } + // + // }); + token = spf.getString("Token", ""); + GizDeviceSharing.queryMessageList(token, GizMessageType.GizMessageSharing); + // GizDeviceSharing.queryMessageList(token, + // GizMessageType.GizMessageSystem); + + } + + private void initView() { + + SlideListView2 devicelist = (SlideListView2) findViewById(R.id.devicelist); + tvNoMessage = (TextView) findViewById(R.id.tvNoMessage); + devicelist.initSlideMode(SlideListView2.MOD_RIGHT); + + myadapter = new myadapter(); + devicelist.setAdapter(myadapter); + + // 下拉刷新 + + mSwipeLayout = (VerticalSwipeRefreshLayout) findViewById(R.id.id_swipe_ly); + + mSwipeLayout.setOnRefreshListener(this); + mSwipeLayout.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, + android.R.color.holo_orange_light, android.R.color.holo_red_light); + + devicelist.setOnItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { + + View redpoint = arg1.findViewById(R.id.redpoint); + + if (redpoint.getVisibility() == 0) { + redpoint.setVisibility(View.GONE); + GizMessage gizMessage = mymessageList.get(arg2); + + GizDeviceSharing.markMessageStatus(token, gizMessage.getId(), GizMessageStatus.GizMessageRead); + } + + } + }); + + } + + @Override + public void onRefresh() { + Message msg = new Message(); + msg.what = 1; + handler.sendMessageDelayed(msg, 2000); + } + + class myadapter extends BaseAdapter { + + @Override + public int getCount() { + + return mymessageList.size(); + } + + @Override + public Object getItem(int arg0) { + return null; + } + + @Override + public long getItemId(int arg0) { + return 0; + } + + @Override + public View getView(final int arg0, View arg1, ViewGroup arg2) { + + View view = View.inflate(deviceSharedMessageActivity.this, R.layout.activity_device_item, null); + + TextView mess = (TextView) view.findViewById(R.id.mess); + TextView timemess = (TextView) view.findViewById(R.id.timemess); + + View redpoint = view.findViewById(R.id.redpoint); + + RelativeLayout delete2 = (RelativeLayout) view.findViewById(R.id.delete2); + + delete2.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View c) { + GizMessage gizMessage = mymessageList.get(arg0); + + String id = gizMessage.getId(); + myid = id; + myposition = arg0; + GizDeviceSharing.markMessageStatus(token, gizMessage.getId(), GizMessageStatus.GizMessageDeleted); + progressDialog.show(); + } + }); + + GizMessage gizMessage = mymessageList.get(arg0); + + mess.setText(gizMessage.getContent()); + + timemess.setText(DateUtil.utc2Local(gizMessage.getUpdatedAt())); + + int ordinal = gizMessage.getStatus().ordinal(); + + if (ordinal == 0) { + redpoint.setVisibility(View.VISIBLE); + } else { + redpoint.setVisibility(View.GONE); + } + + return view; + } + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + + } + + return super.onOptionsItemSelected(item); + } + + @Override + protected void onResume() { + super.onResume(); + //GizDeviceSharing.queryMessageList + + GizDeviceSharing.setListener(new GizDeviceSharingListener() { + + @Override + public void didMarkMessageStatus(GizWifiErrorCode result, String messageID) { + super.didMarkMessageStatus(result, messageID); + + if (result.ordinal() == 0 && myid.equals(messageID)) { + + if (mymessageList.size() > myposition && myposition != -1) { + + GizDeviceSharing.queryMessageList(token, GizMessageType.GizMessageSharing); + } + } else { + + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.cancel(); + } + } + } + + @Override + public void didQueryMessageList(GizWifiErrorCode result, List messageList) { + super.didQueryMessageList(result, messageList); + + if (messageList != null) { + Collections.sort(messageList, new Comparator() { + + @Override + public int compare(GizMessage arg0, GizMessage arg1) { + + String updatedAt = DateUtil.utc2Local(arg0.getUpdatedAt()); + String updatedAt2 = DateUtil.utc2Local(arg1.getUpdatedAt()); + + int diff = (int) DateUtil.getDiff(updatedAt2, updatedAt); + + return diff; + } + + }); + } + + if (progressDialog.isShowing()) { + progressDialog.cancel(); + } + mymessageList = messageList; + if (mymessageList.size() != 0) { + tvNoMessage.setVisibility(View.GONE); + } + myadapter.notifyDataSetChanged(); + } + + }); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/gosZxingDeviceSharingActivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/gosZxingDeviceSharingActivity.java new file mode 100644 index 0000000..497019d --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/gosZxingDeviceSharingActivity.java @@ -0,0 +1,235 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizDeviceSharingListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.utils.DateUtil; + +public class gosZxingDeviceSharingActivity extends GosBaseActivity { + + private String code; + private int time = 15; + private String[] split2s; + private String tip; + private TextView tiptext; + private String token; + private Button yes; + private Button no; + private TextView zxingtext; + private String whoshared; + private String[] splits; + private String userName; + private String productName; + private String deviceAlias; + private String expiredAt; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.gos_devicesharing_zxing_activity); + setToolBar(true, R.string.QR_code); + initData(); + initView(); + } + + private void initView() { + + zxingtext = (TextView) findViewById(R.id.zxingtext); + + yes = (Button) findViewById(R.id.yes); + + no = (Button) findViewById(R.id.no); + + whoshared = getResources().getString(R.string.whoshared); + + splits = whoshared.split("xxx"); + // [, 向你共享, ,你接受并绑定设备吗?] + whoshared = userName + splits[1] + productName + splits[splits.length - 1]; + zxingtext.setText(whoshared); + + String timeByFormat = DateUtil.getCurTimeByFormat("yyyy-MM-dd HH:mm:ss"); + expiredAt = DateUtil.utc2Local(expiredAt); + long diff = DateUtil.getDiff(expiredAt, timeByFormat); + if (diff >= 0) { + double c = diff / 60.0; + time = (int) Math.ceil(c); + } else { + tiptext.setText(getResources().getString(R.string.requestoutoftime)); + yes.setClickable(false); + yes.setTextColor(getResources().getColor(R.color.gray)); + return; + } + tiptext = (TextView) findViewById(R.id.tiptext); + tip = getResources().getString(R.string.tipthings); + split2s = tip.split("xx"); + + tip = split2s[0] + time + split2s[1]; + + tiptext.setText(tip); + + hand.sendEmptyMessageDelayed(1, diff % 60 * 1000); + + yes.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + GizDeviceSharing.acceptDeviceSharingByQRCode(spf.getString("Token", ""), code); + } + }); + + no.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + + private void initData() { + + Intent intent = getIntent(); + code = intent.getStringExtra("code"); + userName = intent.getStringExtra("userName"); + productName = intent.getStringExtra("productName"); + deviceAlias = intent.getStringExtra("deviceAlias"); + expiredAt = intent.getStringExtra("expiredAt"); + + token = spf.getString("Token", ""); + + } + + @Override + protected void onResume() { + super.onResume(); + + if (time > 0) { + tip = split2s[0] + time + split2s[1]; + + tiptext.setText(tip); + } else { + tiptext.setText(getResources().getString(R.string.requestoutoftime)); + yes.setClickable(false); + yes.setTextColor(getResources().getColor(R.color.gray)); + } + + GizDeviceSharing.setListener(new GizDeviceSharingListener() { + + @Override + public void didAcceptDeviceSharing(GizWifiErrorCode result, int sharingID) { + super.didAcceptDeviceSharing(result, sharingID); + if (result.ordinal() == 0) { + finish(); + } else { + Toast.makeText(gosZxingDeviceSharingActivity.this, toastError(result), 1).show(); + finish(); + } + } + + @Override + public void didAcceptDeviceSharingByQRCode(GizWifiErrorCode result) { + super.didAcceptDeviceSharingByQRCode(result); + if (result.ordinal() == 0) { + Toast.makeText(gosZxingDeviceSharingActivity.this, "success", 1).show(); + + finish(); + } else { + Toast.makeText(gosZxingDeviceSharingActivity.this, toastError(result), 1).show(); + + finish(); + } + } + + @Override + public void didCheckDeviceSharingInfoByQRCode(GizWifiErrorCode result, String userName, String productName, + String deviceAlias, String expiredAt) { + super.didCheckDeviceSharingInfoByQRCode(result, userName, productName, deviceAlias, expiredAt); + + int errorcode = result.ordinal(); + + if (8041 <= errorcode && errorcode <= 8050 || errorcode == 8308) { + tiptext.setVisibility(View.GONE); + yes.setClickable(false); + no.setClickable(false); + yes.setTextColor(getResources().getColor(R.color.gray)); + no.setTextColor(getResources().getColor(R.color.gray)); + zxingtext.setText(getResources().getString(R.string.sorry)); + } else if (errorcode != 0) { + tiptext.setVisibility(View.GONE); + yes.setClickable(false); + no.setClickable(false); + yes.setTextColor(getResources().getColor(R.color.gray)); + no.setTextColor(getResources().getColor(R.color.gray)); + zxingtext.setText(getResources().getString(R.string.verysorry)); + } else { + tiptext.setVisibility(View.VISIBLE); + yes.setClickable(true); + no.setClickable(true); + yes.setTextColor(getResources().getColor(R.color.text_color)); + no.setTextColor(getResources().getColor(R.color.text_color)); + + whoshared = userName + splits[1] + productName + splits[splits.length - 1]; + zxingtext.setText(whoshared); + + String timeByFormat = DateUtil.getCurTimeByFormat("yyyy-MM-dd HH:mm:ss"); + expiredAt = DateUtil.utc2Local(expiredAt); + long diff = DateUtil.getDiff(expiredAt, timeByFormat); + + if (diff >= 0) { + time = (int) Math.ceil(diff / 60); + } else { + + } + Toast.makeText(gosZxingDeviceSharingActivity.this, diff % 60 + "", 1).show(); + + } + } + }); + + } + + + Handler hand = new Handler() { + public void handleMessage(android.os.Message msg) { + + time = time - 1; + + if (time > 0) { + tip = split2s[0] + time + split2s[1]; + + tiptext.setText(tip); + hand.sendEmptyMessageDelayed(1, 60000); + } else { + tiptext.setText(getResources().getString(R.string.requestoutoftime)); + yes.setClickable(false); + yes.setTextColor(getResources().getColor(R.color.gray)); + } + + } + + ; + }; + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + this.finish(); + break; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/twoSharedActivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/twoSharedActivity.java new file mode 100644 index 0000000..8494466 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/twoSharedActivity.java @@ -0,0 +1,175 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.os.Handler; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingWay; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizDeviceSharingListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.R; + +import java.util.Timer; +import java.util.TimerTask; + +public class twoSharedActivity extends GosBaseActivity { + + private String productname; + private String did; + private ImageView myimage; + private TextView timeout; + private TextView bottomtext; + private int time = 15; + + @Override + protected void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_gos_two_shared); + + setToolBar(true, R.string.scan_code_sharing); + + initData(); + initView(); + } + + private void initView() { + TextView usersharedtext = (TextView) findViewById(R.id.usersharedtext); + + myimage = (ImageView) findViewById(R.id.myimageview); + + timeout = (TextView) findViewById(R.id.timeout); + + timeout2 = splits[0] + time + splits[1]; + + timeout.setText(timeout2); + + bottomtext = (TextView) findViewById(R.id.bottomtext); + + usersharedtext.setText(getResources().getString(R.string.shared) + " " + productname + + getResources().getString(R.string.friends)); + } + + private void initData() { + + Intent tent = getIntent(); + productname = tent.getStringExtra("productname"); + did = tent.getStringExtra("did"); + + timeout2 = getResources().getString(R.string.zxingtimeout); + splits = timeout2.split("15"); + GizDeviceSharing.sharingDevice(spf.getString("Token", ""), did, GizDeviceSharingWay.GizDeviceSharingByQRCode, + null, null); + + } + + private void startTimer() { + timer = new Timer(); + timer.schedule(new TimerTask() { + + @Override + public void run() { + + time = time - 1; + hand.sendEmptyMessage(1); + } + }, 60000, 60000); + } + + @Override + protected void onResume() { + super.onResume(); + if (time > 0) { + timeout2 = splits[0] + time + splits[1]; + + timeout.setText(timeout2); + } else { + timeout.setText(getResources().getString(R.string.twofailed)); + } + GizDeviceSharing.setListener(new GizDeviceSharingListener() { + + @Override + public void didSharingDevice(GizWifiErrorCode result, String deviceID, int sharingID, + Bitmap QRCodeImage) { + super.didSharingDevice(result, deviceID, sharingID, QRCodeImage); + + if (QRCodeImage != null) { + myimage.setImageBitmap(QRCodeImage); + bottomtext.setVisibility(View.VISIBLE); + + // hand.sendEmptyMessageDelayed(1, 60000); + startTimer(); + } else { + int errorcode = result.ordinal(); + + if (8041 <= errorcode && errorcode <= 8050 || errorcode == 8308) { + + timeout.setText(getResources().getString(R.string.twosharedtimeout)); + bottomtext.setVisibility(View.GONE); + + } else { + timeout.setText(getResources().getString(R.string.sharedfailed)); + bottomtext.setVisibility(View.GONE); + } + } + + } + }); + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + + finish(); + break; + + } + return super.onOptionsItemSelected(item); + } + + Handler hand = new Handler() { + public void handleMessage(android.os.Message msg) { + + // time = time - 1; + + if (time > 0) { + timeout2 = splits[0] + time + splits[1]; + + timeout.setText(timeout2); + // hand.sendEmptyMessageDelayed(1, 60000); + } else { + timeout.setText(getResources().getString(R.string.twofailed)); + } + + }; + }; + + @Override + protected void onDestroy() { + // TODO Auto-generated method stub + super.onDestroy(); + + time = 15; + + hand.removeMessages(1); + if (timer != null) { + timer.cancel(); + } + + } + + private String timeout2; + private String[] splits; + private Timer timer; +} diff --git a/src/java/com/gizwits/opensource/appkit/sharingdevice/userSharedActivity.java b/src/java/com/gizwits/opensource/appkit/sharingdevice/userSharedActivity.java new file mode 100644 index 0000000..0323389 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/sharingdevice/userSharedActivity.java @@ -0,0 +1,145 @@ +package com.gizwits.opensource.appkit.sharingdevice; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.gizwifisdk.api.GizDeviceSharing; +import com.gizwits.gizwifisdk.enumration.GizDeviceSharingWay; +import com.gizwits.gizwifisdk.enumration.GizUserAccountType; +import com.gizwits.gizwifisdk.enumration.GizWifiErrorCode; +import com.gizwits.gizwifisdk.listener.GizDeviceSharingListener; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.CommonModule.TipsDialog; +import com.gizwits.opensource.appkit.R; + +public class userSharedActivity extends GosBaseActivity { + + private String productname; + private EditText username; + private int chooseitem = 0; + private String did; + + @Override + protected void onCreate(Bundle savedInstanceState) { + // TODO Auto-generated method stub + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gos_user_shared); + + setToolBar(true, R.string.account_shared); + + initData(); + initView(); + } + + private void initView() { + TextView usersharedtext = (TextView) findViewById(R.id.usersharedtext); + Button button = (Button) findViewById(R.id.button); + button.setBackgroundDrawable(GosDeploy.appConfig_BackgroundColor()); + button.setTextColor(GosDeploy.appConfig_Contrast()); + + username = (EditText) findViewById(R.id.username); + usersharedtext.setText( + getResources().getString(R.string.shared) + productname + getResources().getString(R.string.friends)); + } + + private void initData() { + + Intent tent = getIntent(); + productname = tent.getStringExtra("productname"); + did = tent.getStringExtra("did"); + } + + public void usershared(View v) { + + final String usernametext = username.getText().toString(); + if (TextUtils.isEmpty(usernametext)) { + + // Toast.makeText(this, + // getResources().getString(R.string.toast_name_empet), 0).show(); + + TipsDialog dia = new TipsDialog(this, getResources().getString(R.string.toast_name_empet)); + dia.show(); + return; + } + + SharedPreferences spf = getSharedPreferences("set", Context.MODE_PRIVATE); + String token = spf.getString("Token", ""); + if (usernametext.length() < 32) { + if (usernametext.matches("[0-9]+")) { + GizDeviceSharing.sharingDevice(token, did, GizDeviceSharingWay.GizDeviceSharingByNormal, usernametext, + GizUserAccountType.GizUserPhone); + return; + } + + } + if (usernametext.contains("@")) { + GizDeviceSharing.sharingDevice(token, did, GizDeviceSharingWay.GizDeviceSharingByNormal, usernametext, + GizUserAccountType.GizUserEmail); + return; + } + if (usernametext.length() == 32) { + if (usernametext.matches("[a-zA-Z0-9]+")) { + GizDeviceSharing.sharingDevice(token, did, GizDeviceSharingWay.GizDeviceSharingByNormal, usernametext, + GizUserAccountType.GizUserOther); + return; + } + + } + Toast.makeText(this, getString(R.string.account_incorrect), Toast.LENGTH_LONG).show(); + + + } + + @Override + protected void onResume() { + super.onResume(); + + GizDeviceSharing.setListener(new GizDeviceSharingListener() { + + @Override + public void didSharingDevice(GizWifiErrorCode result, String deviceID, int sharingID, + Bitmap QRCodeImage) { + super.didSharingDevice(result, deviceID, sharingID, QRCodeImage); + + if (result.ordinal() == 0) { + Toast.makeText(userSharedActivity.this, getResources().getString(R.string.alawyssend), 1).show(); + finish(); + } else if (result == GizWifiErrorCode.GIZ_OPENAPI_GUEST_ALREADY_BOUND) { + Toast.makeText(userSharedActivity.this, getResources().getString(R.string.account_shared2), toastTime).show(); + } else if (result == GizWifiErrorCode.GIZ_OPENAPI_NOT_FOUND_GUEST) { + Toast.makeText(userSharedActivity.this, getResources().getString(R.string.user_not_exist), toastTime).show(); + } else if (result == GizWifiErrorCode.GIZ_OPENAPI_CANNOT_SHARE_TO_SELF) { + Toast.makeText(userSharedActivity.this, getResources().getString(R.string.not_shared_self), toastTime).show(); + } else { + Toast.makeText(userSharedActivity.this, getResources().getString(R.string.send_failed1), 2).show(); + } + + } + + }); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + + finish(); + break; + + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/utils/.DS_Store b/src/java/com/gizwits/opensource/appkit/utils/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..69a3990a0f6c380a394b232c28b4f24760c87afd GIT binary patch literal 6148 zcmeHKyH3ME5S$GW3PPY12q;}rAyLzqC`iyy5a>xlkN^v#Bs@wt`~$zh_wfNRyLSmB z#-fW5+Ku++yx!T%%~?Jl0BJp3?g32z4Z31&h0PD9_ti^Qi;-obSdB48IL8>*$V%BB z_=^hY+BI>&bsJ&8mHS%15q5EdE*{Z6&hmaQ%X^j!>=SoB%xp?)Xftn2{$%Z|m~SQK ziH$npRgNiJbIc8#l6l4FY=FK!aXId$<5$;tnX9vj4sP+x84NjxCwk9n9O_+u7E4x3QQHy_d`NgOd}Qn z?bX4?jsV0u!)EO3SwcBU#57_NkauVjsKh{(c*KxEXFQ2{X~ZI6phM!}L*mF1Pbgxe zvwmXfkTjsTu7E2rtH4sYZ0i1hSbhGVCHa*r;0pXJ1*G2Yv|F4~+*?bN)4evKU(nSw nuLwA$uwz>>b9F1;rkgRIXor|aECMn@^A7=&!5dd#p$dEgA~9~V literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/opensource/appkit/utils/AssetsUtils.java b/src/java/com/gizwits/opensource/appkit/utils/AssetsUtils.java new file mode 100644 index 0000000..62bcabe --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/utils/AssetsUtils.java @@ -0,0 +1,111 @@ +package com.gizwits.opensource.appkit.utils; + +import android.content.Context; +import android.util.DisplayMetrics; +import android.view.WindowManager; + +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Locale; + +public class AssetsUtils { + + public static void assetsDataToSD(String fileOutPutName, + String fileInPutName, Context context) throws IOException { + InputStream myInput; + File file = new File(fileOutPutName); + if (!file.exists()) { + file.createNewFile(); + }else { + return; + } + OutputStream myOutput = new FileOutputStream(fileOutPutName); + myInput = context.getAssets().open(fileInPutName); + byte[] buffer = new byte[1024]; + int length = myInput.read(buffer); + while (length > 0) { + myOutput.write(buffer, 0, length); + length = myInput.read(buffer); + } + + myOutput.flush(); + myInput.close(); + myOutput.close(); + } + + + + public static void saveFile(String str) { + String filePath = null; + + + filePath = GosDeploy.fileOutName; + try { + if(filePath!=null){ + File file = new File(filePath); + if (!file.exists()) { + File dir = new File(file.getParent()); + dir.mkdirs(); + file.createNewFile(); + } + FileOutputStream outStream = new FileOutputStream(file); + outStream.write(str.getBytes()); + outStream.close(); + } + + } catch (Exception e) { + e.printStackTrace(); + } +} + /** + * 将dip或dp值转换为px值,保证尺寸大小不变 + * + * @param dipValue + * @param scale + * (DisplayMetrics类中属性density) + * @return + */ + public static int diptopx(Context context, float dipValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dipValue * scale + 0.5f); + } + + + /** + * 将sp值转换为px值,保证文字大小不变 + * + * @param spValue + * @param fontScale + * (DisplayMetrics类中属性scaledDensity) + * @return + */ + public static int sptopx(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + + public static boolean isZh(Context context) { + Locale locale = context.getResources().getConfiguration().locale; + String language = locale.getLanguage(); + if (language.endsWith("zh")) + return true; + else + return false; + } + + public static int getScreenWidth(Context context) + { + WindowManager wm = (WindowManager) context + .getSystemService(Context.WINDOW_SERVICE ); + DisplayMetrics outMetrics = new DisplayMetrics(); + wm.getDefaultDisplay().getMetrics( outMetrics); + return outMetrics .widthPixels ; + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/utils/DateUtil.java b/src/java/com/gizwits/opensource/appkit/utils/DateUtil.java new file mode 100644 index 0000000..a347d0e --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/utils/DateUtil.java @@ -0,0 +1,1331 @@ +package com.gizwits.opensource.appkit.utils; + +import android.annotation.SuppressLint; + +import java.io.Serializable; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +/** + * 日期操作工具类,主要实现了日期的常用操作。 + *

+ * 在工具类中经常使用到工具类的格式化描述,这个主要是一个日期的操作类,所以日志格式主要使用 SimpleDateFormat的定义格式. + *

+ * 格式的意义如下: 日期和时间模式
+ * 日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中,未加引号的字母 'A' 到 'Z' 和 'a' 到 'z' + * 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。"''" + * 表示单引号。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串,或者在分析时与输入字符串进行匹配。 + *

+ * 定义了以下模式字母(所有其他字符 'A' 到 'Z' 和 'a' 到 'z' 都被保留):
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
字母日期或时间元素表示示例 + *
GEra标志符TextAD + *
yYear1996;96 + *
M年中的月份MonthJuly;Jul;07 + *
w年中的周数Number27 + *
W月份中的周数Number2 + *
D年中的天数Number189 + *
d月份中的天数Number10 + *
F月份中的星期Number2 + *
E星期中的天数TextTuesday;Tue + *
aAm/pm标记TextPM + *
H一天中的小时数(0-23)Number0 + *
k一天中的小时数(1-24)Number24 + *
Kam/pm中的小时数(0-11)Number0 + *
ham/pm中的小时数(1-12)Number12 + *
m小时中的分钟数Number30 + *
s分钟中的秒数Number55 + *
S毫秒数Number978 + *
z时区GeneraltimezonePacificStandardTime;PST;GMT-08:00 + *
Z时区RFC822timezone-0800 + *
+ * + * 模式字母通常是重复的,其数量确定其精确表示: + * + */ +public final class DateUtil implements Serializable { + /** + * + */ + private static final long serialVersionUID = -3098985139095632110L; + + private DateUtil() { + } + + /** + * 格式化日期显示格式yyyy-MM-dd + * + * @param sdate + * 原始日期格式 + * @return yyyy-MM-dd格式化后的日期显示 + */ + public static String dateFormat(String sdate) { + return dateFormat(sdate, "yyyy-MM-dd"); + } + + /** + * 格式化日期显示格式 + * + * @param sdate + * 原始日期格式 + * @param format + * 格式化后日期格式 + * @return 格式化后的日期显示 + */ + public static String dateFormat(String sdate, String format) { + SimpleDateFormat formatter = new SimpleDateFormat(format); + java.sql.Date date = java.sql.Date.valueOf(sdate); + String dateString = formatter.format(date); + + return dateString; + } + + /** + * 求两个日期相差天数 + * + * @param sd + * 起始日期,格式yyyy-MM-dd + * @param ed + * 终止日期,格式yyyy-MM-dd + * @return 两个日期相差天数 + */ + public static long getIntervalDays(String sd, String ed) { + return ((java.sql.Date.valueOf(ed)).getTime() - (java.sql.Date.valueOf(sd)).getTime()) / (3600 * 24 * 1000); + } + + /** + * 起始年月yyyy-MM与终止月yyyy-MM之间跨度的月数 + * + * @return int + */ + public static int getInterval(String beginMonth, String endMonth) { + int intBeginYear = Integer.parseInt(beginMonth.substring(0, 4)); + int intBeginMonth = Integer.parseInt(beginMonth.substring(beginMonth.indexOf("-") + 1)); + int intEndYear = Integer.parseInt(endMonth.substring(0, 4)); + int intEndMonth = Integer.parseInt(endMonth.substring(endMonth.indexOf("-") + 1)); + + return ((intEndYear - intBeginYear) * 12) + (intEndMonth - intBeginMonth) + 1; + } + + public static Date getDate(String sDate, String dateFormat) { + SimpleDateFormat fmt = new SimpleDateFormat(dateFormat); + ParsePosition pos = new ParsePosition(0); + + return fmt.parse(sDate, pos); + } + + /** + * 取得当前日期的年份,以yyyy格式返回. + * + * @return 当年 yyyy + */ + public static String getCurrentYear() { + return getFormatCurrentTime("yyyy"); + } + + /** + * 自动返回上一年。例如当前年份是2007年,那么就自动返回2006 + * + * @return 返回结果的格式为 yyyy + */ + public static String getBeforeYear() { + String currentYear = getFormatCurrentTime("yyyy"); + int beforeYear = Integer.parseInt(currentYear) - 1; + return "" + beforeYear; + } + + /** + * 取得当前日期的月份,以MM格式返回. + * + * @return 当前月份 MM + */ + public static String getCurrentMonth() { + return getFormatCurrentTime("MM"); + } + + /** + * 取得当前日期的天数,以格式"dd"返回. + * + * @return 当前月中的某天dd + */ + public static String getCurrentDay() { + return getFormatCurrentTime("dd"); + } + + /** + * 返回当前时间字符串。 + *

+ * 格式:yyyy-MM-dd + * + * @return String 指定格式的日期字符串. + */ + public static String getCurrentDate() { + return getFormatDateTime(new Date(), "yyyy-MM-dd"); + } + + /** + * 返回给定时间字符串。 + *

+ * 格式:yyyy-MM-dd + * + * @param date + * 日期 + * @return String 指定格式的日期字符串. + */ + public static String getFormatDate(Date date) { + return getFormatDateTime(date, "yyyy-MM-dd"); + } + + /** + * 根据制定的格式,返回日期字符串。例如2007-05-05 + * + * @param format + * "yyyy-MM-dd" 或者 "yyyy/MM/dd" + * @return 指定格式的日期字符串。 + */ + public static String getFormatDate(String format) { + return getFormatDateTime(new Date(), format); + } + + /** + * 返回当前时间字符串。 + *

+ * 格式:yyyy-MM-dd HH:mm:ss + * + * @return String 指定格式的日期字符串. + */ + public static String getCurrentTime() { + return getFormatDateTime(new Date(), "yyyy-MM-dd HH:mm:ss"); + } + + /** + * 返回给定时间字符串。 + *

+ * 格式:yyyy-MM-dd HH:mm:ss + * + * @param date + * 日期 + * @return String 指定格式的日期字符串. + */ + public static String getFormatTime(Date date) { + return getFormatDateTime(date, "yyyy-MM-dd HH:mm:ss"); + } + + /** + * 根据给定的格式,返回时间字符串。 + *

+ * 格式参照类描绘中说明. + * + * @param format + * 日期格式字符串 + * @return String 指定格式的日期字符串. + */ + public static String getFormatCurrentTime(String format) { + return getFormatDateTime(new Date(), format); + } + + /** + * 根据给定的格式与时间(Date类型的),返回时间字符串
+ * + * @param date + * 指定的日期 + * @param format + * 日期格式字符串 + * @return String 指定格式的日期字符串. + */ + public static String getFormatDateTime(Date date, String format) { + SimpleDateFormat sdf = new SimpleDateFormat(format); + return sdf.format(date); + } + + /** + * 取得指定年月日的日期对象. + * + * @param year + * 年 + * @param month + * 月注意是从1到12 + * @param day + * 日 + * @return 一个java.util.Date()类型的对象 + */ + public static Date getDateObj(int year, int month, int day) { + Calendar c = new GregorianCalendar(); + c.set(year, month - 1, day); + return c.getTime(); + } + + /** + * 取得指定分隔符分割的年月日的日期对象. + * + * @param args + * 格式为"yyyy-MM-dd" + * @param split + * 时间格式的间隔符,例如“-”,“/” + * @return 一个java.util.Date()类型的对象 + */ + public static Date getDateObj(String args, String split) { + String[] temp = args.split(split); + int year = new Integer(temp[0]).intValue(); + int month = new Integer(temp[1]).intValue(); + int day = new Integer(temp[2]).intValue(); + return getDateObj(year, month, day); + } + + /** + * 取得给定字符串描述的日期对象,描述模式采用pattern指定的格式. + * + * @param dateStr + * 日期描述 + * @param pattern + * 日期模式 + * @return 给定字符串描述的日期对象。 + */ + public static Date getDateFromString(String dateStr, String pattern) { + SimpleDateFormat sdf = new SimpleDateFormat(pattern); + Date resDate = null; + try { + resDate = sdf.parse(dateStr); + } catch (Exception e) { + e.printStackTrace(); + } + return resDate; + } + + /** + * 取得当前Date对象. + * + * @return Date 当前Date对象. + */ + public static Date getDateObj() { + Calendar c = new GregorianCalendar(); + return c.getTime(); + } + + /** + * + * @return 当前月份有多少天; + */ + public static int getDaysOfCurMonth() { + int curyear = new Integer(getCurrentYear()).intValue(); // 当前年份 + int curMonth = new Integer(getCurrentMonth()).intValue();// 当前月份 + int mArray[] = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + // 判断闰年的情况 ,2月份有29天; + if ((curyear % 400 == 0) || ((curyear % 100 != 0) && (curyear % 4 == 0))) { + mArray[1] = 29; + } + return mArray[curMonth - 1]; + // 如果要返回下个月的天数,注意处理月份12的情况,防止数组越界; + // 如果要返回上个月的天数,注意处理月份1的情况,防止数组越界; + } + + /** + * 根据指定的年月 返回指定月份(yyyy-MM)有多少天。 + * + * @param time + * yyyy-MM + * @return 天数,指定月份的天数。 + */ + public static int getDaysOfCurMonth(final String time) { + String[] timeArray = time.split("-"); + int curyear = new Integer(timeArray[0]).intValue(); // 当前年份 + int curMonth = new Integer(timeArray[1]).intValue();// 当前月份 + int mArray[] = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + // 判断闰年的情况 ,2月份有29天; + if ((curyear % 400 == 0) || ((curyear % 100 != 0) && (curyear % 4 == 0))) { + mArray[1] = 29; + } + if (curMonth == 12) { + return mArray[0]; + } + return mArray[curMonth - 1]; + // 如果要返回下个月的天数,注意处理月份12的情况,防止数组越界; + // 如果要返回上个月的天数,注意处理月份1的情况,防止数组越界; + } + + /** + * 返回指定为年度为year月度为month的月份内,第weekOfMonth个星期的第dayOfWeek天。
+ * 00 00 00 01 02 03 04
+ * 05 06 07 08 09 10 11
+ * 12 13 14 15 16 17 18
+ * 19 20 21 22 23 24 25
+ * 26 27 28 29 30 31
+ * 2006年的第一个周的1到7天为:05 06 07 01 02 03 04
+ * 2006年的第二个周的1到7天为:12 13 14 08 09 10 11
+ * 2006年的第三个周的1到7天为:19 20 21 15 16 17 18
+ * 2006年的第四个周的1到7天为:26 27 28 22 23 24 25
+ * 2006年的第五个周的1到7天为:02 03 04 29 30 31 01 。本月没有就自动转到下个月了。 + * + * @param year + * 形式为yyyy
+ * @param month + * 形式为MM,参数值在[1-12]。
+ * @param weekOfMonth + * 在[1-6],因为一个月最多有6个周。
+ * @param dayOfWeek + * 数字在1到7之间,包括1和7。1表示星期天,7表示星期六
+ * -6为星期日-1为星期五,0为星期六
+ * @return int + */ + public static int getDayofWeekInMonth(String year, String month, String weekOfMonth, String dayOfWeek) { + Calendar cal = new GregorianCalendar(); + // 在具有默认语言环境的默认时区内使用当前时间构造一个默认的 GregorianCalendar。 + int y = new Integer(year).intValue(); + int m = new Integer(month).intValue(); + cal.clear();// 不保留以前的设置 + cal.set(y, m - 1, 1);// 将日期设置为本月的第一天。 + cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, new Integer(weekOfMonth).intValue()); + cal.set(Calendar.DAY_OF_WEEK, new Integer(dayOfWeek).intValue()); + // System.out.print(cal.get(Calendar.MONTH)+" "); + // System.out.print("当"+cal.get(Calendar.WEEK_OF_MONTH)+"\t"); + // WEEK_OF_MONTH表示当天在本月的第几个周。不管1号是星期几,都表示在本月的第一个周 + return cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 根据指定的年月日小时分秒,返回一个java.Util.Date对象。 + * + * @param year + * 年 + * @param month + * 月 0-11 + * @param date + * 日 + * @param hourOfDay + * 小时 0-23 + * @param minute + * 分 0-59 + * @param second + * 秒 0-59 + * @return 一个Date对象。 + */ + public static Date getDate(int year, int month, int date, int hourOfDay, int minute, int second) { + Calendar cal = new GregorianCalendar(); + cal.set(year, month, date, hourOfDay, minute, second); + return cal.getTime(); + } + + /** + * 根据指定的年、月、日返回当前是星期几。1表示星期天、2表示星期一、7表示星期六。 + * + * @param year + * @param month + * month是从1开始的12结束 + * @param day + * @return 返回一个代表当期日期是星期几的数字。1表示星期天、2表示星期一、7表示星期六。 + */ + public static int getDayOfWeek(String year, String month, String day) { + Calendar cal = new GregorianCalendar(new Integer(year).intValue(), new Integer(month).intValue() - 1, + new Integer(day).intValue()); + return cal.get(Calendar.DAY_OF_WEEK); + } + + /** + * 根据指定的年、月、日返回当前是星期几。1表示星期天、2表示星期一、7表示星期六。 + * + * @param date + * "yyyy/MM/dd",或者"yyyy-MM-dd" + * @return 返回一个代表当期日期是星期几的数字。1表示星期天、2表示星期一、7表示星期六。 + */ + public static int getDayOfWeek(String date) { + String[] temp = null; + if (date.indexOf("/") > 0) { + temp = date.split("/"); + } + if (date.indexOf("-") > 0) { + temp = date.split("-"); + } + return getDayOfWeek(temp[0], temp[1], temp[2]); + } + + /** + * 返回当前日期是星期几。例如:星期日、星期一、星期六等等。 + * + * @param date + * 格式为 yyyy/MM/dd 或者 yyyy-MM-dd + * @return 返回当前日期是星期几 + */ + public static String getChinaDayOfWeek(String date) { + String[] weeks = new String[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" }; + int week = getDayOfWeek(date); + return weeks[week - 1]; + } + + /** + * 根据指定的年、月、日返回当前是星期几。1表示星期天、2表示星期一、7表示星期六。 + * + * @param date + * + * @return 返回一个代表当期日期是星期几的数字。1表示星期天、2表示星期一、7表示星期六。 + */ + public static int getDayOfWeek(Date date) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + return cal.get(Calendar.DAY_OF_WEEK); + } + + /** + * 返回制定日期所在的周是一年中的第几个周。
+ * created by wangmj at 20060324.
+ * + * @param year + * @param month + * 范围1-12
+ * @param day + * @return int + */ + public static int getWeekOfYear(String year, String month, String day) { + Calendar cal = new GregorianCalendar(); + cal.clear(); + cal.set(new Integer(year).intValue(), new Integer(month).intValue() - 1, new Integer(day).intValue()); + return cal.get(Calendar.WEEK_OF_YEAR); + } + + /** + * 取得给定日期加上一定天数后的日期对象. + * + * @param date + * 给定的日期对象 + * @param amount + * 需要添加的天数,如果是向前的天数,使用负数就可以. + * @return Date 加上一定天数以后的Date对象. + */ + public static Date getDateAdd(Date date, int amount) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + cal.add(GregorianCalendar.DATE, amount); + return cal.getTime(); + } + + /** + * 取得给定日期加上一定天数后的日期对象. + * + * @param date + * 给定的日期对象 + * @param amount + * 需要添加的天数,如果是向前的天数,使用负数就可以. + * @param format + * 输出格式. + * @return Date 加上一定天数以后的Date对象. + */ + public static String getFormatDateAdd(Date date, int amount, String format) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + cal.add(GregorianCalendar.DATE, amount); + return getFormatDateTime(cal.getTime(), format); + } + + /** + * 获得当前日期固定间隔天数的日期,如前60天dateAdd(-60) + * + * @param amount + * 距今天的间隔日期长度,向前为负,向后为正 + * @param format + * 输出日期的格式. + * @return java.lang.String 按照格式输出的间隔的日期字符串. + */ + public static String getFormatCurrentAdd(int amount, String format) { + + Date d = getDateAdd(new Date(), amount); + + return getFormatDateTime(d, format); + } + + /** + * 取得给定格式的昨天的日期输出 + * + * @param format + * 日期输出的格式 + * @return String 给定格式的日期字符串. + */ + public static String getFormatYestoday(String format) { + return getFormatCurrentAdd(-1, format); + } + + /** + * 返回指定日期的前一天。
+ * + * @param sourceDate + * @param format + * yyyy MM dd hh mm ss + * @return 返回日期字符串,形式和formcat一致。 + */ + public static String getYestoday(String sourceDate, String format) { + return getFormatDateAdd(getDateFromString(sourceDate, format), -1, format); + } + + /** + * 返回明天的日期,
+ * + * @param format + * @return 返回日期字符串,形式和formcat一致。 + */ + public static String getFormatTomorrow(String format) { + return getFormatCurrentAdd(1, format); + } + + /** + * 返回指定日期的后一天。
+ * + * @param sourceDate + * @param format + * @return 返回日期字符串,形式和formcat一致。 + */ + public static String getFormatDateTommorrow(String sourceDate, String format) { + return getFormatDateAdd(getDateFromString(sourceDate, format), 1, format); + } + + /** + * 根据主机的默认 TimeZone,来获得指定形式的时间字符串。 + * + * @param dateFormat + * @return 返回日期字符串,形式和formcat一致。 + */ + public static String getCurrentDateString(String dateFormat) { + Calendar cal = Calendar.getInstance(TimeZone.getDefault()); + SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); + sdf.setTimeZone(TimeZone.getDefault()); + + return sdf.format(cal.getTime()); + } + + /** + * @deprecated 不鼓励使用。 返回当前时间串 格式:yyMMddhhmmss,在上传附件时使用 + * + * @return String + */ + public static String getCurDate() { + GregorianCalendar gcDate = new GregorianCalendar(); + int year = gcDate.get(GregorianCalendar.YEAR); + int month = gcDate.get(GregorianCalendar.MONTH) + 1; + int day = gcDate.get(GregorianCalendar.DAY_OF_MONTH); + int hour = gcDate.get(GregorianCalendar.HOUR_OF_DAY); + int minute = gcDate.get(GregorianCalendar.MINUTE); + int sen = gcDate.get(GregorianCalendar.SECOND); + String y; + String m; + String d; + String h; + String n; + String s; + y = new Integer(year).toString(); + + if (month < 10) { + m = "0" + new Integer(month).toString(); + } else { + m = new Integer(month).toString(); + } + + if (day < 10) { + d = "0" + new Integer(day).toString(); + } else { + d = new Integer(day).toString(); + } + + if (hour < 10) { + h = "0" + new Integer(hour).toString(); + } else { + h = new Integer(hour).toString(); + } + + if (minute < 10) { + n = "0" + new Integer(minute).toString(); + } else { + n = new Integer(minute).toString(); + } + + if (sen < 10) { + s = "0" + new Integer(sen).toString(); + } else { + s = new Integer(sen).toString(); + } + + return "" + y + m + d + h + n + s; + } + + /** + * 根据给定的格式,返回时间字符串。 和getFormatDate(String format)相似。 + * + * @param format + * yyyy MM dd hh mm ss + * @return 返回一个时间字符串 + */ + public static String getCurTimeByFormat(String format) { + Date newdate = new Date(System.currentTimeMillis()); + SimpleDateFormat sdf = new SimpleDateFormat(format); + return sdf.format(newdate); + } + + /** + * 获取两个时间串时间的差值,单位为秒 + * + * @param startTime + * 开始时间 yyyy-MM-dd HH:mm:ss + * @param endTime + * 结束时间 yyyy-MM-dd HH:mm:ss + * @return 两个时间的差值(秒) + */ + public static long getDiff(String startTime, String endTime) { + long diff = 0; + SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + Date startDate = ft.parse(startTime); + Date endDate = ft.parse(endTime); + diff = startDate.getTime() - endDate.getTime(); + diff = diff / 1000; + } catch (ParseException e) { + e.printStackTrace(); + } + return diff; + } + + /** + * 获取小时/分钟/秒 + * + * @param second + * 秒 + * @return 包含小时、分钟、秒的时间字符串,例如3小时23分钟13秒。 + */ + public static String getHour(long second) { + long hour = second / 60 / 60; + long minute = (second - hour * 60 * 60) / 60; + long sec = (second - hour * 60 * 60) - minute * 60; + + return hour + "小时" + minute + "分钟" + sec + "秒"; + + } + + /** + * 返回指定时间字符串。 + *

+ * 格式:yyyy-MM-dd HH:mm:ss + * + * @return String 指定格式的日期字符串. + */ + public static String getDateTime(long microsecond) { + return getFormatDateTime(new Date(microsecond), "yyyy-MM-dd HH:mm:ss"); + } + + /** + * 返回当前时间加实数小时后的日期时间。 + *

+ * 格式:yyyy-MM-dd HH:mm:ss + * + * @return Float 加几实数小时. + */ + public static String getDateByAddFltHour(float flt) { + int addMinute = (int) (flt * 60); + Calendar cal = new GregorianCalendar(); + cal.setTime(new Date()); + cal.add(GregorianCalendar.MINUTE, addMinute); + return getFormatDateTime(cal.getTime(), "yyyy-MM-dd HH:mm:ss"); + } + + /** + * 返回指定时间加指定小时数后的日期时间。 + *

+ * 格式:yyyy-MM-dd HH:mm:ss + * + * @return 时间. + */ + public static String getDateByAddHour(String datetime, int minute) { + String returnTime = null; + Calendar cal = new GregorianCalendar(); + SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date date; + try { + date = ft.parse(datetime); + cal.setTime(date); + cal.add(GregorianCalendar.MINUTE, minute); + returnTime = getFormatDateTime(cal.getTime(), "yyyy-MM-dd HH:mm:ss"); + } catch (ParseException e) { + e.printStackTrace(); + } + return returnTime; + + } + + /** + * 获取两个时间串时间的差值,单位为小时 + * + * @param startTime + * 开始时间 yyyy-MM-dd HH:mm:ss + * @param endTime + * 结束时间 yyyy-MM-dd HH:mm:ss + * @return 两个时间的差值(秒) + */ + public static int getDiffHour(String startTime, String endTime) { + long diff = 0; + SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + Date startDate = ft.parse(startTime); + Date endDate = ft.parse(endTime); + diff = startDate.getTime() - endDate.getTime(); + diff = diff / (1000 * 60 * 60); + } catch (ParseException e) { + e.printStackTrace(); + } + return new Long(diff).intValue(); + } + + /** + * 返回年份的下拉框。 + * + * @param selectName + * 下拉框名称 + * @param value + * 当前下拉框的值 + * @param startYear + * 开始年份 + * @param endYear + * 结束年份 + * @return 年份下拉框的html + */ + public static String getYearSelect(String selectName, String value, int startYear, int endYear) { + int start = startYear; + int end = endYear; + if (startYear > endYear) { + start = endYear; + end = startYear; + } + StringBuffer sb = new StringBuffer(""); + sb.append(""); + return sb.toString(); + } + + /** + * 返回年份的下拉框。 + * + * @param selectName + * 下拉框名称 + * @param value + * 当前下拉框的值 + * @param startYear + * 开始年份 + * @param endYear + * 结束年份 + * 例如开始年份为2001结束年份为2005那么下拉框就有五个值。(2001、2002、2003、2004、2005)。 + * @return 返回年份的下拉框的html。 + */ + public static String getYearSelect(String selectName, String value, int startYear, int endYear, boolean hasBlank) { + int start = startYear; + int end = endYear; + if (startYear > endYear) { + start = endYear; + end = startYear; + } + StringBuffer sb = new StringBuffer(""); + sb.append(""); + return sb.toString(); + } + + /** + * 返回年份的下拉框。 + * + * @param selectName + * 下拉框名称 + * @param value + * 当前下拉框的值 + * @param startYear + * 开始年份 + * @param endYear + * 结束年份 + * @param js + * 这里的js为js字符串。例如 " onchange=\"changeYear()\" " + * ,这样任何js的方法就可以在jsp页面中编写,方便引入。 + * @return 返回年份的下拉框。 + */ + public static String getYearSelect(String selectName, String value, int startYear, int endYear, boolean hasBlank, + String js) { + int start = startYear; + int end = endYear; + if (startYear > endYear) { + start = endYear; + end = startYear; + } + StringBuffer sb = new StringBuffer(""); + + sb.append(""); + return sb.toString(); + } + + /** + * 返回年份的下拉框。 + * + * @param selectName + * 下拉框名称 + * @param value + * 当前下拉框的值 + * @param startYear + * 开始年份 + * @param endYear + * 结束年份 + * @param js + * 这里的js为js字符串。例如 " onchange=\"changeYear()\" " + * ,这样任何js的方法就可以在jsp页面中编写,方便引入。 + * @return 返回年份的下拉框。 + */ + public static String getYearSelect(String selectName, String value, int startYear, int endYear, String js) { + int start = startYear; + int end = endYear; + if (startYear > endYear) { + start = endYear; + end = startYear; + } + StringBuffer sb = new StringBuffer(""); + sb.append(""); + return sb.toString(); + } + + /** + * 获取月份的下拉框 + * + * @param selectName + * @param value + * @param hasBlank + * @return 返回月份的下拉框。 + */ + public static String getMonthSelect(String selectName, String value, boolean hasBlank) { + StringBuffer sb = new StringBuffer(""); + sb.append(""); + return sb.toString(); + } + + /** + * 获取月份的下拉框 + * + * @param selectName + * @param value + * @param hasBlank + * @param js + * @return 返回月份的下拉框。 + */ + public static String getMonthSelect(String selectName, String value, boolean hasBlank, String js) { + StringBuffer sb = new StringBuffer(""); + sb.append(""); + return sb.toString(); + } + + /** + * 获取天的下拉框,默认的为1-31。 注意:此方法不能够和月份下拉框进行联动。 + * + * @param selectName + * @param value + * @param hasBlank + * @return 获得天的下拉框 + */ + public static String getDaySelect(String selectName, String value, boolean hasBlank) { + StringBuffer sb = new StringBuffer(""); + sb.append(""); + return sb.toString(); + } + + /** + * 获取天的下拉框,默认的为1-31 + * + * @param selectName + * @param value + * @param hasBlank + * @param js + * @return 获取天的下拉框 + */ + public static String getDaySelect(String selectName, String value, boolean hasBlank, String js) { + StringBuffer sb = new StringBuffer(""); + sb.append(""); + return sb.toString(); + } + + /** + * 计算两天之间有多少个周末(这个周末,指星期六和星期天,一个周末返回结果为2,两个为4,以此类推。) (此方法目前用于统计司机用车记录。) + * + * @param startDate + * 开始日期 ,格式"yyyy/MM/dd" + * @param endDate + * 结束日期 ,格式"yyyy/MM/dd" + * @return int + */ + public static int countWeekend(String startDate, String endDate) { + int result = 0; + Date sdate = null; + Date edate = null; + sdate = getDateObj(startDate, "/"); // 开始日期 + edate = getDateObj(endDate, "/");// 结束日期 + // 首先计算出都有那些日期,然后找出星期六星期天的日期 + int sumDays = Math.abs(getDiffDays(startDate, endDate)); + int dayOfWeek = 0; + for (int i = 0; i <= sumDays; i++) { + dayOfWeek = getDayOfWeek(getDateAdd(sdate, i)); // 计算每过一天的日期 + if (dayOfWeek == 1 || dayOfWeek == 7) { // 1 星期天 7星期六 + result++; + } + } + return result; + } + + /** + * 返回两个日期之间相差多少天。 + * + * @param startDate + * 格式"yyyy/MM/dd" + * @param endDate + * 格式"yyyy/MM/dd" + * @return 整数。 + */ + public static int getDiffDays(String startDate, String endDate) { + long diff = 0; + SimpleDateFormat ft = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + try { + Date sDate = ft.parse(startDate + " 00:00:00"); + Date eDate = ft.parse(endDate + " 00:00:00"); + diff = eDate.getTime() - sDate.getTime(); + diff = diff / 86400000;// 1000*60*60*24; + } catch (ParseException e) { + e.printStackTrace(); + } + return (int) diff; + + } + + /** + * 返回两个日期之间的详细日期数组(包括开始日期和结束日期)。 例如:2007/07/01 到2007/07/03 ,那么返回数组 + * {"2007/07/01","2007/07/02","2007/07/03"} + * + * @param startDate + * 格式"yyyy/MM/dd" + * @param endDate + * 格式"yyyy/MM/dd" + * @return 返回一个字符串数组对象 + */ + public static String[] getArrayDiffDays(String startDate, String endDate) { + int LEN = 0; // 用来计算两天之间总共有多少天 + // 如果结束日期和开始日期相同 + if (startDate.equals(endDate)) { + return new String[] { startDate }; + } + Date sdate = null; + sdate = getDateObj(startDate, "/"); // 开始日期 + LEN = getDiffDays(startDate, endDate); + String[] dateResult = new String[LEN + 1]; + dateResult[0] = startDate; + for (int i = 1; i < LEN + 1; i++) { + dateResult[i] = getFormatDateTime(getDateAdd(sdate, i), "yyyy/MM/dd"); + } + + return dateResult; + } + + public static int getTimeZone() { + + TimeZone tz = TimeZone.getDefault(); + String displayName = tz.getDisplayName(); + int dstSavings = tz.getDSTSavings(); + String id = tz.getID(); + String displayName2 = tz.getDisplayName(false, TimeZone.SHORT); + + return 1; + } + + /* + * 当前时间组转换utc时间 + * + * @param time 当前时间的字符串 + * + * @param formart 需要转换的格式 + * + * @return 转换后的字符串 + */ + public static String getUtc(String time, String formart) { + // 1、获得当前所在的令时偏移量-(zoneOffset + dstOffset) + String date = null; + Calendar cal = Calendar.getInstance(); + int zoneOffset = cal.get(Calendar.ZONE_OFFSET); + int dstOffset = cal.get(Calendar.DST_OFFSET); + // 2、生成Calendar,并传入对应的时间 + // 使用GMT时区进行时间计算,防止令时切换导致的微调整 + Calendar cal1 = Calendar.getInstance(); + cal1.setTimeZone(TimeZone.getTimeZone("GMT")); + + Date stringToDate = stringToDate(time, formart); + if (stringToDate != null) { + cal1.setTime(stringToDate); + cal1.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset)); + // 3、获取对应的UTC时间 + + date = dateToString(cal1.getTime(), formart); + } + + return date; + + } + + @SuppressLint("SimpleDateFormat") + public static Date stringToDate(String str, String formart) { + DateFormat format = new SimpleDateFormat(formart); + Date date = null; + try { + // Fri Feb 24 00:00:00 CST 2012 + date = format.parse(str); + } catch (ParseException e) { + e.printStackTrace(); + } + // 2012-02-24 + // date = java.sql.Date.valueOf(str); + + return date; + } + + @SuppressLint("SimpleDateFormat") + public static String dateToString(Date date, String type) { + String str = null; + SimpleDateFormat format = new SimpleDateFormat(type); + + str = format.format(date); + + return str; + } + + // utc时间转换当地时间 + public static String utc2Local(String utcTime) { + + utcTime = utcTime.substring(0, utcTime.length()-1); + + String[] split = utcTime.split("T"); + + utcTime = split[0]+" "+split[1]; + + SimpleDateFormat utcFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + utcFormater.setTimeZone(TimeZone.getTimeZone("UTC"));// 时区定义并进行时间获取 + Date gpsUTCDate = null; + try { + gpsUTCDate = utcFormater.parse(utcTime); + } catch (ParseException e) { + e.printStackTrace(); + } + SimpleDateFormat localFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + localFormater.setTimeZone(TimeZone.getDefault()); + String localTime = localFormater.format(gpsUTCDate.getTime()); + return localTime; + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/utils/HexStrUtils.java b/src/java/com/gizwits/opensource/appkit/utils/HexStrUtils.java new file mode 100644 index 0000000..6b53e54 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/utils/HexStrUtils.java @@ -0,0 +1,58 @@ +package com.gizwits.opensource.appkit.utils; + +import java.util.Locale; + +public class HexStrUtils { + + public static byte[] hexStringToBytes(String hexString) { + if (hexString == null || hexString.equals("")) { + return null; + } + hexString = hexString.toUpperCase(Locale.getDefault()); + int length = hexString.length() / 2; + char[] hexChars = hexString.toCharArray(); + byte[] d = new byte[length]; + for (int i = 0; i < length; i++) { + int pos = i * 2; + d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); + } + return d; + } + + private static byte charToByte(char c) { + return (byte) "0123456789ABCDEF".indexOf(c); + } + + /** + * 数组转换成十六进制字符串 + * + * @param byte[] + * @return HexString + */ + public static final String bytesToHexString(byte[] bArray) { + if (bArray == null) { + return ""; + } + StringBuffer sb = new StringBuffer(bArray.length); + String sTemp; + for (int i = 0; i < bArray.length; i++) { + sTemp = Integer.toHexString(0xFF & bArray[i]); + if (sTemp.length() < 2) + sb.append(0); + sb.append(sTemp.toUpperCase(Locale.getDefault())); + } + return sb.toString(); + } + + public static final String splitBytesString(String byteString) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byteString.length(); i++) { + sb.append(byteString.charAt(i)); + if (sb.length() % 3 == 0 && sb.charAt(sb.length() - 1) != ' ') { + sb.insert(sb.length() - 1, ' '); + } + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/utils/NetUtils.java b/src/java/com/gizwits/opensource/appkit/utils/NetUtils.java new file mode 100644 index 0000000..e0c6389 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/utils/NetUtils.java @@ -0,0 +1,226 @@ +/** + * Project Name:Gokit + * File Name:NetUtils.java + * Package Name:com.xpg.gokit.utils + * Date:2014-11-18 10:06:37 + * Copyright (c) 2014~2015 Xtreme Programming Group, Inc. + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.gizwits.opensource.appkit.utils; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.Log; + +import java.util.List; + +/** + * 网络工具类. + * + * @author Sunny Ding + * + * * + */ +public class NetUtils { + + /** + * 判断当前手机是否连上Wifi. + * + * @param context + * 上下文 + * @return boolean 是否连上网络 + * + * * + */ + static public boolean isWifiConnected(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mWiFiNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (mWiFiNetworkInfo != null) { + if (mWiFiNetworkInfo.isAvailable()) { + return mWiFiNetworkInfo.isConnected(); + } else { + return false; + } + } + } + return false; + } + + /** + * 判断当前手机的网络是否可用. + * + * @param context + * 上下文 + * @return boolean 是否连上网络 + * + * * + */ + static public boolean isMobileConnected(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mMobileNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); + if (mMobileNetworkInfo != null) { + if (mMobileNetworkInfo.isAvailable()) { + return mMobileNetworkInfo.isConnected(); + } else { + return false; + } + } + } + return false; + } + + /** + * 判断当前网络是手机网络还是WIFI. + * + * @param context + * 上下文 + * @return ConnectedType 数据类型 + * + * * + */ + public static int getConnectedType(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + // 获取代表联网状态的NetWorkInfo对象 + NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); + // 判断NetWorkInfo对象是否为空;判断当前的网络连接是否可用 + if (mNetworkInfo != null && mNetworkInfo.isAvailable()) { + return mNetworkInfo.getType(); + } + } + return -1; + } + + /** + * 获取当前WIFI的SSID. + * + * @param context + * 上下文 + * @return ssid + * + * * + */ + public static String getCurentWifiSSID(Context context) { + String ssid = ""; + if (context != null) { + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + + if (wifiInfo != null) { + ssid = wifiInfo.getSSID(); + + if (!TextUtils.isEmpty(ssid) && ssid.substring(0, 1).equals("\"") + && ssid.substring(ssid.length() - 1).equals("\"")) { + ssid = ssid.substring(1, ssid.length() - 1); + } + } + + } + return ssid; + } + + /** + * 用来获得手机扫描到的所有wifi的信息. + * + * @param c + * 上下文 + * @return the current wifi scan result + */ + public static List getCurrentWifiScanResult(Context c) { + WifiManager wifiManager = (WifiManager) c.getSystemService(Context.WIFI_SERVICE); + wifiManager.startScan(); + + return wifiManager.getScanResults(); + + } + + public interface WifiSsidList { + + public void ssidList(List list); + } + + static public String getConnectWifiSsid(Context c) { + String ssid = ""; + WifiManager wifiManager = (WifiManager) c.getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + if (wifiInfo != null) { + ssid = wifiInfo.getSSID(); + } + return ssid; + } + + // 以下是获得版本信息的工具方法 + + // 版本名 + public static String getVersionName(Context context) { + return getPackageInfo(context).versionName; + } + + // 版本号 + public static int getVersionCode(Context context) { + return getPackageInfo(context).versionCode; + } + + private static PackageInfo getPackageInfo(Context context) { + PackageInfo pi = null; + + try { + PackageManager pm = context.getPackageManager(); + pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_CONFIGURATIONS); + + return pi; + } catch (Exception e) { + e.printStackTrace(); + } + + return pi; + } + + // 检测android 应用在前台还是后台 + + public static boolean isBackground(Context context) { + ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List appProcesses = activityManager.getRunningAppProcesses(); + for (RunningAppProcessInfo appProcess : appProcesses) { + if (appProcess.processName.equals(context.getPackageName())) { + /* + * BACKGROUND=400 EMPTY=500 FOREGROUND=100 GONE=1000 + * PERCEPTIBLE=130 SERVICE=300 ISIBLE=200 + */ + Log.i(context.getPackageName(), "此appimportace =" + appProcess.importance + + ",context.getClass().getName()=" + context.getClass().getName()); + if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + Log.i(context.getPackageName(), "处于后台" + appProcess.processName); + return true; + } else { + Log.i(context.getPackageName(), "处于前台" + appProcess.processName); + return false; + } + } + } + return false; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/utils/ReflectionUtils.java b/src/java/com/gizwits/opensource/appkit/utils/ReflectionUtils.java new file mode 100644 index 0000000..592b199 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/utils/ReflectionUtils.java @@ -0,0 +1,138 @@ +package com.gizwits.opensource.appkit.utils; + +import android.text.TextUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Created by zhaopan on 2016/11/7. + * e-mail: kangqiao610@gmail.com + */ +public class ReflectionUtils { + + /** + * 循环向上转型, 获取对象的 DeclaredMethod + * + * @param object : 子类对象 + * @param methodName : 父类中的方法名 + * @param parameterTypes : 父类中的方法参数类型 + * @return 父类中的方法对象 + */ + + public static Method getDeclaredMethod(Object object, String methodName, Class... parameterTypes) { + Method method = null; + + for (Class clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) { + try { + method = clazz.getDeclaredMethod(methodName, parameterTypes); + return method; + } catch (Exception e) { + //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。 + //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了 + + } + } + + return null; + } + + /** + * 直接调用对象方法, 而忽略修饰符(private, protected, default) + * + * @param object : 子类对象 + * @param methodName : 父类中的方法名 + * @param parameterTypes : 父类中的方法参数类型 + * @param parameters : 父类中的方法参数 + * @return 父类中方法的执行结果 + */ + + public static Object invokeMethod(Object object, String methodName, Class[] parameterTypes, + Object[] parameters) { + //根据 对象、方法名和对应的方法参数 通过反射 调用上面的方法获取 Method 对象 + Method method = getDeclaredMethod(object, methodName, parameterTypes); + + //抑制Java对方法进行检查,主要是针对私有方法而言 + method.setAccessible(true); + + try { + if (null != method) { + + //调用object 的 method 所代表的方法,其方法的参数是 parameters + return method.invoke(object, parameters); + } + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + return null; + } + + /** + * 循环向上转型, 获取对象的 DeclaredField + * + * @param object : 子类对象 + * @param fieldName : 父类中的属性名 + * @return 父类中的属性对象 + */ + + public static Field getDeclaredField(Object object, String fieldName) { + Field field = null; + + Class clazz = object.getClass(); + + for (; clazz != Object.class; clazz = clazz.getSuperclass()) { + try { + field = clazz.getDeclaredField(fieldName); + return field; + } catch (Exception e) { + //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。 + //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了 + + } + } + + return null; + } + + public static Object getFieldValue(Object obj, String fieldName) { + if (obj == null || TextUtils.isEmpty(fieldName)) { + return null; + } + + Class clazz = obj.getClass(); + while (clazz != Object.class) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(obj); + } catch (Exception e) { + } + clazz = clazz.getSuperclass(); + } + return null; + } + + public static void setFieldValue(Object obj, String fieldName, Object value) { + if (obj == null || TextUtils.isEmpty(fieldName)) { + return; + } + Class clazz = obj.getClass(); + while (clazz != Object.class) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + return; + } catch (Exception e) { + } + clazz = clazz.getSuperclass(); + } + } +} + diff --git a/src/java/com/gizwits/opensource/appkit/utils/SkxDrawableHelper.java b/src/java/com/gizwits/opensource/appkit/utils/SkxDrawableHelper.java new file mode 100644 index 0000000..8545e03 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/utils/SkxDrawableHelper.java @@ -0,0 +1,66 @@ +package com.gizwits.opensource.appkit.utils; + +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; +import android.support.v4.graphics.drawable.DrawableCompat; + +public class SkxDrawableHelper { + + /** + * 对目标Drawable 进行着色 + * + * @param drawable 目标Drawable + * @param color 着色的颜色值 + * @return 着色处理后的Drawable + */ + public static Drawable tintDrawable(Drawable drawable, int color) { + // 获取此drawable的共享状态实例 + Drawable wrappedDrawable = getCanTintDrawable(drawable); + // 进行着色 + DrawableCompat.setTint(wrappedDrawable, color); + return wrappedDrawable; + } + + /** + * 对目标Drawable 进行着色。 + * 通过ColorStateList 指定单一颜色 + * + * @param drawable 目标Drawable + * @param color 着色值 + * @return 着色处理后的Drawable + */ + public static Drawable tintListDrawable(Drawable drawable, int color) { + return tintListDrawable(drawable, ColorStateList.valueOf(color)); + } + + /** + * 对目标Drawable 进行着色 + * + * @param drawable 目标Drawable + * @param colors 着色值 + * @return 着色处理后的Drawable + */ + public static Drawable tintListDrawable( Drawable drawable, ColorStateList colors) { + Drawable wrappedDrawable = getCanTintDrawable(drawable); + // 进行着色 + DrawableCompat.setTintList(wrappedDrawable, colors); + return wrappedDrawable; + } + + /** + * 获取可以进行tint 的Drawable + *

+ * 对原drawable进行重新实例化 newDrawable() + * 包装 warp() + * 可变操作 mutate() + * + * @param drawable 原始drawable + * @return 可着色的drawable + */ + private static Drawable getCanTintDrawable(Drawable drawable) { + // 获取此drawable的共享状态实例 + Drawable.ConstantState state = drawable.getConstantState(); + // 对drawable 进行重新实例化、包装、可变操作 + return DrawableCompat.wrap(state == null ? drawable : state.newDrawable()).mutate(); + } +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/utils/ToolUtils.java b/src/java/com/gizwits/opensource/appkit/utils/ToolUtils.java new file mode 100644 index 0000000..577e18a --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/utils/ToolUtils.java @@ -0,0 +1,146 @@ +package com.gizwits.opensource.appkit.utils; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.R; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by admin on 2017/7/25. + */ + +public class ToolUtils { + public static float getHue(int color) { + float[] HSV = new float[3]; + Color.colorToHSV(color, HSV); + return (HSV[0] * 255 / 360); + } + + public static int getInnerColor(float hue) { + float[] HSV = new float[3]; + HSV[0] = hue * 360 / 255; + HSV[1] = 255; + HSV[2] = 255; + return Color.HSVToColor(HSV); + } + + private static long lastClickTime = 0; + public static final int MIN_CLICK_DELAY_TIME = 800; + + public static boolean noDoubleClick() { + long currentTime = Calendar.getInstance().getTimeInMillis(); + if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) { + lastClickTime = currentTime; + return true; + } else { + return false; + } + } + + public static List> parseJson(Context context, String str) throws JSONException { + if (str == null || str.equals("")) { + Toast.makeText(context, context.getString(R.string.download_fail), Toast.LENGTH_SHORT).show(); + } + JSONObject uiJsonObject = new JSONObject(str); + JSONObject jsonObject = uiJsonObject.has("object") ? uiJsonObject.getJSONObject("object") : null; + List> list = new ArrayList>(); + if (uiJsonObject != null) { + JSONArray sessionJsonArrays = uiJsonObject.getJSONArray("sections"); + if (sessionJsonArrays != null) { + for (int i = 0; i < sessionJsonArrays.length(); i++) { + JSONObject session = sessionJsonArrays.getJSONObject(i); + JSONArray elementjJsonArray = session.getJSONArray("elements"); + if (elementjJsonArray != null) { + for (int j = 0; j < elementjJsonArray.length(); j++) { + Map map = new HashMap(); + JSONObject elementObject = elementjJsonArray.getJSONObject(j); + String type = elementObject.getString("type"); + String title = elementObject.has("title") ? elementObject.getString("title") : ""; + map.put("title", title); + map.put("type", type); + String value = null; + if (type.equals("QBooleanElement")) { + value = elementObject.has("boolValue") ? elementObject.getString("boolValue") : ""; + } else if (type.equals("QFloatElement")) { + value = elementObject.has("value") ? elementObject.getString("value") : ""; + } + map.put("value", value); + list.add(map); + } + } + } + + } + } + + return list; + } + + + public static Drawable editIconAlpha(Resources res, int id) { + int color = GosDeploy.appConfig_Contrast(); + Drawable drawable = SkxDrawableHelper.tintDrawable(res.getDrawable(id), color); + drawable.setAlpha(60); + return drawable; + } + + public static Drawable editIcon(Resources res, int id) { + int color = GosDeploy.appConfig_Contrast(); + return SkxDrawableHelper.tintDrawable(res.getDrawable(id), color); + } + + public static int editTextAlpha() { + int color = GosDeploy.appConfig_Contrast(); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + int color1 = Color.argb(160, red, green, blue); + return color1; + } + + public static int editStatusBarColor(int color) { + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + int color1 = Color.argb(255, red, green, blue); + return color1; + } +// // 需要点击几次 就设置几 +// static long[] mHits = null; +// //public static boolean mShow = false; +// +// public static void onDisplaySettingButton() { +// if (mHits == null) { +// mHits = new long[5]; +// } +// System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);//把从第二位至最后一位之间的数字复制到第一位至倒数第一位 +// mHits[mHits.length - 1] = SystemClock.uptimeMillis();//记录一个时间 +// if (SystemClock.uptimeMillis() - mHits[0] <= 1000) {//一秒内连续点击。 +// mHits = null; //这里说明一下,我们在进来以后需要还原状态,否则如果点击过快,第六次,第七次 都会不断进来触发该效果。重新开始计数即可 +//// if (mShow) { +//// mShow = false; +//// } else { +//// mShow = true; +//// } +// mShow = true; +// Log.e("Tool", "onDisplaySettingButton: 连点五次进入deploy模式"); +// //这里一般会把mShow存储到sp中。 +// } +// } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/view/.DS_Store b/src/java/com/gizwits/opensource/appkit/view/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d3aa66b796679ceb66d2777a3872ef1697be1b88 GIT binary patch literal 6148 zcmeHK%Sr<=6g|-{iWaOCQBZJ}t_0n>8EQp}E=mi!weKo}m3C@zHyi)KU-0|<06jMe zWv1ge3qgwHLUJ;h+>@Jg$z%dRRcE~upbVhMB3Rg9^^M7UDJfgCJtd;j99QV$1s#mh zPK|aQP64ODswp6QcNRUq9CRZ`TBQvqAgk)@zr3XaSI8%jj1dOQ1Xs(IVm^P?m z?}Nu8=v#~o>Q4tNeFY#E*sYCi`9TmL&!TTJGRQYHWn78IRoN?sGVbj6>^R?IWYD-n z*~^ErGb?*TQF?ardwMvOZ_w3F0jEGxfpzm(mh=B2`~IJFa!*bHr@+5bKox4OT9r$( zXKQM4a@Kk*cPwHuE;6WHSlQ!PH{>YZW6{QUo-~NQ#mFFgXzoWq%it=fz@IAc1#H&k A9{>OV literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/opensource/appkit/view/BaseKeyboard.java b/src/java/com/gizwits/opensource/appkit/view/BaseKeyboard.java new file mode 100644 index 0000000..01a60c7 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/BaseKeyboard.java @@ -0,0 +1,210 @@ +package com.gizwits.opensource.appkit.view; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.KeyboardView; +import android.text.Editable; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.View; +import android.widget.EditText; + +/** + * Created by xud on 2017/3/2. + */ + +public abstract class BaseKeyboard extends Keyboard implements KeyboardView.OnKeyboardActionListener { + + private EditText mEditText; + + private View mNextFocusView; + + private KeyStyle mKeyStyle; + + protected Context mContext; + + public BaseKeyboard(Context context, int xmlLayoutResId) { + super(context, xmlLayoutResId); + mContext = context; + } + + public BaseKeyboard(Context context, int xmlLayoutResId, int modeId, int width, int height) { + super(context, xmlLayoutResId, modeId, width, height); + mContext = context; + } + + public BaseKeyboard(Context context, int xmlLayoutResId, int modeId) { + super(context, xmlLayoutResId, modeId); + mContext = context; + } + + public BaseKeyboard(Context context, int layoutTemplateResId, CharSequence characters, int columns, int horizontalPadding) { + super(context, layoutTemplateResId, characters, columns, horizontalPadding); + mContext = context; + } + + public void setEditText(EditText editText) { + mEditText = editText; + } + + public void setNextFocusView(View nextFocusView) { + mNextFocusView = nextFocusView; + } + + public void setKeyStyle(KeyStyle keyStyle) { + mKeyStyle = keyStyle; + } + + public EditText getEditText() { + return mEditText; + } + + public View getNextFocusView() { + return mNextFocusView; + } + + public KeyStyle getKeyStyle() { + return mKeyStyle; + } + + public int getKeyCode( int redId) { + return mContext.getResources().getInteger(redId); + } + + @Override + public void onPress(int primaryCode) { + + } + + @Override + public void onRelease(int primaryCode) { + + } + + @Override + public void onKey(int primaryCode, int[] keyCodes) { + if (null != mEditText && mEditText.hasFocus() && !handleSpecialKey(primaryCode)) { + Editable editable = mEditText.getText(); + int start = mEditText.getSelectionStart(); + int end = mEditText.getSelectionEnd(); + if (end > start) { + editable.delete(start, end); + } + if (primaryCode == KEYCODE_DELETE) { + if (!TextUtils.isEmpty(editable)) { + if (start > 0) { + editable.delete(start - 1, start); + } + } + } else if (primaryCode == KEYCODE_CANCEL) { + hideKeyboard(); + } else { + editable.insert(start, Character.toString((char) primaryCode)); + } + } + } + + @Override + public void onText(CharSequence text) { + + } + + @Override + public void swipeLeft() { + + } + + @Override + public void swipeRight() { + + } + + @Override + public void swipeDown() { + + } + + @Override + public void swipeUp() { + + } + + public void hideKeyboard() { + if (mNextFocusView != null) { + mNextFocusView.requestFocus(); + } + } + + /** + * @param primaryCode + * @return true if handle the key + * false no handle and dispatch + */ + public abstract boolean handleSpecialKey(int primaryCode); + + public interface KeyStyle { + + public Drawable getKeyBackound(Key key); + + public Float getKeyTextSize(Key key); + + public Integer getKeyTextColor(Key key); + + public CharSequence getKeyLabel(Key key); + } + + public Padding getPadding() { + return new Padding(0, 0, 0, 0); + } + + public static class DefaultKeyStyle implements KeyStyle { + + @Override + public Drawable getKeyBackound(Key key) { + return key.iconPreview; + } + + @Override + public Float getKeyTextSize(Key key) { + return null; + } + + @Override + public Integer getKeyTextColor(Key key) { + return null; + } + + @Override + public CharSequence getKeyLabel(Key key) { + return key.label; + } + } + + public static class Padding { + public int top; + public int left; + public int bottom; + public int right; + + /** + * px + * + * @param top + * @param left + * @param bottom + * @param right + */ + public Padding(int top, int left, int bottom, int right) { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + } + + public float convertSpToPixels(Context context, float sp) { + float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()); + return px; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/view/BaseKeyboardView.java b/src/java/com/gizwits/opensource/appkit/view/BaseKeyboardView.java new file mode 100644 index 0000000..c8fc434 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/BaseKeyboardView.java @@ -0,0 +1,202 @@ +package com.gizwits.opensource.appkit.view; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.KeyboardView; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.EditText; + +import com.gizwits.opensource.appkit.utils.ReflectionUtils; + +import java.util.List; + +/** + * Created by xud on 2017/3/2. + */ + +public class BaseKeyboardView extends KeyboardView { + + private static final String TAG = "BaseKeyboardView"; + private Drawable rKeyBackground; + private int rLabelTextSize; + private int rKeyTextSize; + private int rKeyTextColor; + private float rShadowRadius; + private int rShadowColor; + + private Rect rClipRegion; + private Keyboard.Key rInvalidatedKey; + + public BaseKeyboardView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0, 0); + } + + public BaseKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr, 0); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public BaseKeyboardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs, defStyleAttr, defStyleRes); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + rKeyBackground = (Drawable) ReflectionUtils.getFieldValue(this, "mKeyBackground"); + rLabelTextSize = (Integer) ReflectionUtils.getFieldValue(this, "mLabelTextSize"); + rKeyTextSize = (Integer) ReflectionUtils.getFieldValue(this, "mKeyTextSize"); + rKeyTextColor = (Integer) ReflectionUtils.getFieldValue(this, "mKeyTextColor"); + rShadowColor = (Integer) ReflectionUtils.getFieldValue(this, "mShadowColor"); + rShadowRadius = (Float) ReflectionUtils.getFieldValue(this, "mShadowRadius"); + } + + @Override + public void onDraw(Canvas canvas) { + //说明CustomKeyboardView只针对CustomBaseKeyboard键盘进行重绘, + // 且CustomBaseKeyboard必需有设置CustomKeyStyle的回调接口实现, 才进行重绘, 这才有意义 + if (null == getKeyboard() || !(getKeyboard() instanceof BaseKeyboard) || null == ((BaseKeyboard) getKeyboard()).getKeyStyle()) { + super.onDraw(canvas); + return; + } + rClipRegion = (Rect) ReflectionUtils.getFieldValue(this, "mClipRegion"); + rInvalidatedKey = (Keyboard.Key) ReflectionUtils.getFieldValue(this, "mInvalidatedKey"); + super.onDraw(canvas); + onRefreshKey(canvas); + } + + /** + * onRefreshKey是对父类的private void onBufferDraw()进行的重写. 只是在对key的绘制过程中进行了重新设置. + * + * @param canvas + */ + private void onRefreshKey(Canvas canvas) { + final Paint paint = (Paint) ReflectionUtils.getFieldValue(this, "mPaint"); + final Rect padding = (Rect) ReflectionUtils.getFieldValue(this, "mPadding"); + + paint.setColor(rKeyTextColor); + final int kbdPaddingLeft = getPaddingLeft(); + final int kbdPaddingTop = getPaddingTop(); + Drawable keyBackground = null; + + final Rect clipRegion = rClipRegion; + final Keyboard.Key invalidKey = rInvalidatedKey; + boolean drawSingleKey = false; + if (invalidKey != null && canvas.getClipBounds(clipRegion)) { + // Is clipRegion completely contained within the invalidated key? + if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left && + invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top && + invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right && + invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) { + drawSingleKey = true; + } + } + + //拿到当前键盘被弹起的输入源 和 键盘为每个key的定制实现customKeyStyle + EditText etCur = ((BaseKeyboard) getKeyboard()).getEditText(); + BaseKeyboard.KeyStyle customKeyStyle = ((BaseKeyboard) getKeyboard()).getKeyStyle(); + + List keys = getKeyboard().getKeys(); + final int keyCount = keys.size(); + //canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + for (int i = 0; i < keyCount; i++) { + final Keyboard.Key key = keys.get(i); + if (drawSingleKey && invalidKey != key) { + continue; + } + + //获取为Key自定义的背景, 若没有定制, 使用KeyboardView的默认属性keyBackground设置 + keyBackground = customKeyStyle.getKeyBackound(key); + if (null == keyBackground) { + keyBackground = rKeyBackground; + } + + int[] drawableState = key.getCurrentDrawableState(); + keyBackground.setState(drawableState); + + //获取为Key自定义的Label, 若没有定制, 使用xml布局中指定的 + CharSequence keyLabel = customKeyStyle.getKeyLabel(key); + if (null == keyLabel) { + keyLabel = key.label; + } + // Switch the character to uppercase if shift is pressed + String label = keyLabel == null ? null : adjustCase(keyLabel).toString(); + + final Rect bounds = keyBackground.getBounds(); + if (key.width != bounds.right || + key.height != bounds.bottom) { + keyBackground.setBounds(0, 0, key.width, key.height); + } + canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop); + keyBackground.draw(canvas); + + if (label != null) { + //获取为Key的Label的字体大小, 若没有定制, 使用KeyboardView的默认属性keyTextSize设置 + Float customKeyTextSize = customKeyStyle.getKeyTextSize(key); + // For characters, use large font. For labels like "Done", use small font. + if (null != customKeyTextSize) { + paint.setTextSize(customKeyTextSize); + paint.setTypeface(Typeface.DEFAULT); + //paint.setTypeface(Typeface.DEFAULT_BOLD); + } else { + if (label.length() > 1 && key.codes.length < 2) { + paint.setTextSize(rLabelTextSize); + paint.setTypeface(Typeface.DEFAULT); + //paint.setTypeface(Typeface.DEFAULT_BOLD); + } else { + paint.setTextSize(rKeyTextSize); + paint.setTypeface(Typeface.DEFAULT); + //paint.setTypeface(Typeface.DEFAULT); + } + } + + //获取为Key的Label的字体颜色, 若没有定制, 使用KeyboardView的默认属性keyTextColor设置 + Integer customKeyTextColor = customKeyStyle.getKeyTextColor(key); + if (null != customKeyTextColor) { + paint.setColor(customKeyTextColor); + } else { + paint.setColor(rKeyTextColor); + } + // Draw a drop shadow for the text + paint.setShadowLayer(rShadowRadius, 0, 0, rShadowColor); + // Draw the text + canvas.drawText(label, + (key.width - padding.left - padding.right) / 2 + + padding.left, + (key.height - padding.top - padding.bottom) / 2 + + (paint.getTextSize() - paint.descent()) / 2 + padding.top, + paint); + // Turn off drop shadow + paint.setShadowLayer(0, 0, 0, 0); + } else if (key.icon != null) { + final int drawableX = (key.width - padding.left - padding.right + - key.icon.getIntrinsicWidth()) / 2 + padding.left; + final int drawableY = (key.height - padding.top - padding.bottom + - key.icon.getIntrinsicHeight()) / 2 + padding.top; + canvas.translate(drawableX, drawableY); + key.icon.setBounds(0, 0, + key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight()); + key.icon.draw(canvas); + canvas.translate(-drawableX, -drawableY); + } + canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); + } + rInvalidatedKey = null; + } + + private CharSequence adjustCase(CharSequence label) { + if (getKeyboard().isShifted() && label != null && label.length() < 3 + && Character.isLowerCase(label.charAt(0))) { + label = label.toString().toUpperCase(); + } + return label; + } +} diff --git a/src/java/com/gizwits/opensource/appkit/view/CircleProgress.java b/src/java/com/gizwits/opensource/appkit/view/CircleProgress.java new file mode 100644 index 0000000..f793c4e --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/CircleProgress.java @@ -0,0 +1,130 @@ +package com.gizwits.opensource.appkit.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import com.gizwits.opensource.appkit.R; + + + +/** + * Created by qiaoning on 2017/8/9. + */ + +public class CircleProgress extends View { + + //小圆的个数 + private int numOfCircles; + //最大圆半径 + private int maxRadius; + //最小圆半径 + private int minRadius; + //旋转速度 + private int rotateSpeedInMillis; + //是否顺时针旋转 + private boolean isClockwise; + //小圆的颜色 + private int circleColor; + + private Paint paint; + + private float rotateDegrees; + private int numOfRotate; + + public CircleProgress(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + // TODO Auto-generated constructor stub + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CircleProgress); + + numOfCircles = array.getInt(R.styleable.CircleProgress_numOfCircles, 10); + maxRadius = array.getDimensionPixelSize(R.styleable.CircleProgress_maxRadius, dp2px(10)); + minRadius = array.getDimensionPixelSize(R.styleable.CircleProgress_minRadius, dp2px(2)); + rotateSpeedInMillis = array.getInt(R.styleable.CircleProgress_rotateSpeedInMillis, 200); + isClockwise = array.getBoolean(R.styleable.CircleProgress_isClockwise, true); + circleColor = array.getColor(R.styleable.CircleProgress_circleColor, Color.BLACK); + + array.recycle(); + + paint = new Paint(); + paint.setStyle(Paint.Style.FILL); + paint.setAntiAlias(true); + paint.setColor(circleColor); + + //view每次旋转的角度 + rotateDegrees = 360 / numOfCircles; + //旋转的周期为小圆的个数 + numOfRotate = 0; + + } + + public CircleProgress(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircleProgress(Context context) { + this(context, null); + } + + @Override + protected void onDraw(Canvas canvas) { + + //按一定角度旋转画布canvas,当旋转周期==小圆个数时重置 + if (numOfRotate == numOfCircles) { + numOfRotate = 0; + } + + //根据旋转的方向旋转画布canvas,然后再画小圆 + if (isClockwise) { + canvas.rotate(rotateDegrees * numOfRotate, getWidth() / 2, getHeight() / 2); + } else { + canvas.rotate(-rotateDegrees * numOfRotate, getWidth() / 2, getHeight() / 2); + } + + //记录旋转的次数,下次invalidat()重绘时就可以使用新的角度旋转canvas,使小圆产生旋转的感觉 + numOfRotate++; + + //取View最短边,并减去最大圆的半径,得到所有圆所在的圆路径的半径 + int radius = (getWidth() > getHeight() ? getHeight() : getWidth()) / 2 - maxRadius; + //每个小圆的半径增量 + float radiusIncrement = (float) (maxRadius - minRadius) / numOfCircles; + //每隔多少度绘制一个小圆,弧度制 + double angle = 2 * Math.PI / numOfCircles; + + //按位置画小圆 + //每个小圆的位置可以由正弦余弦函数求出,并且每个小圆半径依次递增,若反方向则依次递减 + if (isClockwise) { + for (int i = 0; i < numOfCircles; i++) { + float x = (float) (getWidth() / 2 + Math.cos(i * angle) * radius); + float y = (float) (getHeight() / 2 - Math.sin(i * angle) * radius); + canvas.drawCircle(x, y, maxRadius - radiusIncrement * i, paint); + } + } else { + for (int i = 0; i < numOfCircles; i++) { + float x = (float) (getWidth() / 2 + Math.cos(i * angle) * radius); + float y = (float) (getHeight() / 2 - Math.sin(i * angle) * radius); + canvas.drawCircle(x, y, minRadius + radiusIncrement * i, paint); + } + } + + + //旋转间隔,即progressBar的旋转速度 + postDelayed(new Runnable() { + + @Override + public void run() { + // TODO Auto-generated method stub + invalidate(); + } + }, rotateSpeedInMillis); + } + + //dp转px函数 + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/view/DotView.java b/src/java/com/gizwits/opensource/appkit/view/DotView.java new file mode 100644 index 0000000..d83123a --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/DotView.java @@ -0,0 +1,59 @@ +package com.gizwits.opensource.appkit.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.util.AttributeSet; +import android.view.View; + +import com.gizwits.opensource.appkit.R; + + +public class DotView extends View { + private Paint p; + private int width; + private int height; + private int dash; + + public DotView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public DotView(Context context) { + super(context); + init(context); + } + private void init(Context context){ + p = new Paint(Paint.ANTI_ALIAS_FLAG); + p.setStyle(Style.FILL); + p.setColor(context.getResources().getColor(R.color.line_gray)); + + final float scale = context.getResources().getDisplayMetrics().density; + dash=(int) (3 * scale + 0.5f); + } + @Override + protected void onDraw(Canvas canvas) { + + if(width>10){ + for(int i=0;i= Build.VERSION_CODES.HONEYCOMB) { + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + // 从描述文件中读出gif的值,创建出Movie实例 + final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.GifView, defStyle, + R.style.Widget_GifView); + mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1); + mPaused = array.getBoolean(R.styleable.GifView_paused, false); + array.recycle(); + if (mMovieResourceId != -1) { + mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId)); + } + } + + /** + * 设置gif图资源 + * + * @param movieResId + */ + public void setMovieResource(int movieResId) { + this.mMovieResourceId = movieResId; + mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId)); + requestLayout(); + } + + public void setMovie(Movie movie) { + this.mMovie = movie; + requestLayout(); + } + + public Movie getMovie() { + return mMovie; + } + + public void setMovieTime(int time) { + mCurrentAnimationTime = time; + invalidate(); + } + + /** + * 设置暂停 + * + * @param paused + */ + public void setPaused(boolean paused) { + this.mPaused = paused; + if (!paused) { + mMovieStart = android.os.SystemClock.uptimeMillis() - mCurrentAnimationTime; + } + invalidate(); + } + + /** + * 判断gif图是否停止了 + * + * @return + */ + public boolean isPaused() { + return this.mPaused; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mMovie != null) { + int movieWidth = mMovie.width(); + int movieHeight = mMovie.height(); + int maximumWidth = MeasureSpec.getSize(widthMeasureSpec); + float scaleW = (float) movieWidth / (float) maximumWidth; + mScale = 1f / scaleW; + mMeasuredMovieWidth = maximumWidth; + mMeasuredMovieHeight = (int) (movieHeight * mScale); + setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight); + } else { + setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight()); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + mLeft = (getWidth() - mMeasuredMovieWidth) / 2f; + mTop = (getHeight() - mMeasuredMovieHeight) / 2f; + mVisible = getVisibility() == View.VISIBLE; + } + + @Override + protected void onDraw(Canvas canvas) { + if (mMovie != null) { + if (!mPaused) { + updateAnimationTime(); + drawMovieFrame(canvas); + invalidateView(); + } else { + drawMovieFrame(canvas); + } + } + } + + private void invalidateView() { + if (mVisible) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE) { + postInvalidate(); + } else { + invalidate(); + } + } + } + + private void updateAnimationTime() { + long now = android.os.SystemClock.uptimeMillis(); + // 如果第一帧,记录起始时间 + if (mMovieStart == 0) { + mMovieStart = now; + } + // 取出动画的时长 + int dur = mMovie.duration(); + if (dur == 0) { + dur = DEFAULT_MOVIE_DURATION; + } + // 算出需要显示第几帧 + mCurrentAnimationTime = (int) ((now - mMovieStart) % dur); + } + + private void drawMovieFrame(Canvas canvas) { + // 设置要显示的帧,绘制即可 + mMovie.setTime(mCurrentAnimationTime); + canvas.saveLayer(0, 0, getWidth(), getHeight(), null); + canvas.scale(mScale, mScale); + mMovie.draw(canvas, mLeft / mScale, mTop / mScale); + canvas.restore(); + } + + public void onScreenStateChanged(int screenState) { + mVisible = screenState == DEFAULT_MOVIE_DURATION; + invalidateView(); + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + mVisible = visibility == View.VISIBLE; + invalidateView(); + } + + @Override + protected void onWindowVisibilityChanged(int visibility) { + super.onWindowVisibilityChanged(visibility); + mVisible = visibility == View.VISIBLE; + invalidateView(); + } + +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/view/HexWatcher.java b/src/java/com/gizwits/opensource/appkit/view/HexWatcher.java new file mode 100644 index 0000000..d911693 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/HexWatcher.java @@ -0,0 +1,63 @@ +package com.gizwits.opensource.appkit.view; + +import java.util.Locale; + +import android.text.Editable; +import android.text.TextWatcher; +import android.widget.EditText; + +public class HexWatcher implements TextWatcher { + private EditText _text; + + public HexWatcher(EditText _text) { + this._text = _text; + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (s == null || s.length() == 0) + return; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == ' ' && i < s.length() - 1) { + continue; + } else { + sb.append(s.charAt(i)); + if (sb.length() % 3 == 0 && sb.charAt(sb.length() - 1) != ' ') { + sb.insert(sb.length() - 1, ' '); + } + } + } + + if (!sb.toString().equals(s.toString())) { + int index = start + 1; + if (sb.charAt(start) == ' ') { + if (before == 0) { + index++; + } else { + index--; + } + } else { + if (before == 1) { + index--; + } + } + _text.setText(sb.toString().toUpperCase(Locale.getDefault())); + _text.setSelection(index); + } + + // _text.removeTextChangedListener(this); + // _text.setText(s.toString().toUpperCase(Locale.getDefault())); + // _text.addTextChangedListener(this); + + } + + @Override + public void afterTextChanged(Editable s) { + } + +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/view/KeyboardWithSearchView.java b/src/java/com/gizwits/opensource/appkit/view/KeyboardWithSearchView.java new file mode 100644 index 0000000..a004cd7 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/KeyboardWithSearchView.java @@ -0,0 +1,123 @@ +package com.gizwits.opensource.appkit.view; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import com.gizwits.opensource.appkit.R; + + +/** + * Created by xud on 2017/3/9. + */ + +public class KeyboardWithSearchView extends LinearLayout { + + + private Context mContext; + + + private BaseKeyboardView mBaseKeyboardView; + + private LinearLayout mKeyboadViewContainer; + + //private OnSizeChangedListener mOnSizeChangedListener; + + + public KeyboardWithSearchView(Context context) { + super(context); + init(context); + } + + public KeyboardWithSearchView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public KeyboardWithSearchView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public KeyboardWithSearchView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context); + } + +// protected RecyclerView getRecyclerView() { +// return mRecyclerView; +// } + + public BaseKeyboardView getBaseKeyboardView() { + return mBaseKeyboardView; + } + + +// public void setOnSizeChangedListener(OnSizeChangedListener onSizeChangedListener) { +// mOnSizeChangedListener = onSizeChangedListener; +// } + + public LinearLayout getKeyboadViewContainer() { + return mKeyboadViewContainer; + } + + + private void init(Context context) { + mContext = context; + View view = LayoutInflater.from(context).inflate(R.layout.layout_recycler_keyboard_view, this, true); +// mRecyclerView = (RecyclerView) view.findViewById(R.id.search_recycler_view); + mBaseKeyboardView = (BaseKeyboardView) view.findViewById(R.id.keyboard_view); + mKeyboadViewContainer = (LinearLayout) view.findViewById(R.id.keyboard_container); + } + +// public void initRecyclerView(KeyboardSearchBaseAdapter adapter, RecyclerView.LayoutManager manager, RecyclerView.ItemDecoration itemDecoration) { +// mRecyclerView.setAdapter(adapter); +// mRecyclerView.setLayoutManager(manager); +// mRecyclerView.addItemDecoration(itemDecoration); +// } +// +// public void setSearchResult(List list, boolean hasFixedSize) { +// if(mRecyclerView.getAdapter() == null) { +// throw new RuntimeException("this view has not invoked init method"); +// } +// mRecyclerView.getLayoutManager().scrollToPosition(0); +// if(list == null || list.size() ==0) { +// mRecyclerView.setVisibility(GONE); +// } else { +// int height = AssetsUtils.diptopx(mContext, Math.min(3,list.size()) * 49) + +// Math.min(3,list.size()); +// ViewGroup.LayoutParams params = mRecyclerView.getLayoutParams(); +// if(params != null) { +// params.height = height; +// }else { +// LinearLayout.LayoutParams newParams = +// new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, +// height); +// mRecyclerView.setLayoutParams(newParams); +// } +// mRecyclerView.setVisibility(VISIBLE); +// } +// mRecyclerView.setHasFixedSize(hasFixedSize); +// +// KeyboardSearchBaseAdapter adapter = (KeyboardSearchBaseAdapter) mRecyclerView.getAdapter(); +// adapter.setAdapterData(list); +// adapter.notifyDataSetChanged(); +// } + +// @Override +// protected void onSizeChanged(int w, int h, int oldw, int oldh) { +// super.onSizeChanged(w, h, oldw, oldh); +// if(mOnSizeChangedListener != null) { +// mOnSizeChangedListener.sizeChanged(w,h,oldw,oldh); +// } +// } +// +// protected interface OnSizeChangedListener { +// void sizeChanged(int w, int h, int oldw, int oldh); +// } +} diff --git a/src/java/com/gizwits/opensource/appkit/view/RoundProgressBar.java b/src/java/com/gizwits/opensource/appkit/view/RoundProgressBar.java new file mode 100644 index 0000000..b6d69f2 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/RoundProgressBar.java @@ -0,0 +1,266 @@ +package com.gizwits.opensource.appkit.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.view.View; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.utils.AssetsUtils; + + +/** + * 仿iphone带进度的进度条,线程安全的View,可直接在线程中更新进度 + * + * @author xiaanming + */ +public class RoundProgressBar extends View { + /** + * 画笔对象的引用 + */ + private Paint paint; + + /** + * 圆环的颜色 + */ + private int roundColor; + + /** + * 圆环进度的颜色 + */ + private int roundProgressColor; + + /** + * 中间进度百分比的字符串的颜色 + */ + private int textColor; + + /** + * 中间进度百分比的字符串的字体 + */ + private float textSize; + + /** + * 中间进度的字体 + */ + private String text; + + /** + * 圆环的宽度 + */ + private float roundWidth; + + /** + * 最大进度 + */ + private int max; + + + /** + * 当前进度 + */ + private float progress; + /** + * 是否显示中间的进度 + */ + private boolean textIsDisplayable; + + /** + * 进度的风格,实心或者空心 + */ + private int style; + + public static final int STROKE = 0; + public static final int FILL = 1; + + public RoundProgressBar(Context context) { + this(context, null); + } + + public RoundProgressBar(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RoundProgressBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + paint = new Paint(); + + TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBar); + + // 获取自定义属性和默认值 + int color = GosDeploy.appConfig_Background(); + roundColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundColor, getResources().getColor(R.color.roundcolor)); + roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, color); + textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, getResources().getColor(R.color.text_state)); + textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, AssetsUtils.sptopx(context, 20)); + roundWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth, 3); + max = mTypedArray.getInteger(R.styleable.RoundProgressBar_max, 100); + text = mTypedArray.getString(R.styleable.RoundProgressBar_text); + if (text == null) { + text = "%"; + } + textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplayable, true); + style = mTypedArray.getInt(R.styleable.RoundProgressBar_style, 0); + + mTypedArray.recycle(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + /** + * 画最外层的大圆环 + */ + int centre = getWidth() / 2; // 获取圆心的x坐标 + int radius = (int) (centre - 1 - roundWidth / 2); // 圆环的半径 + paint.setColor(roundColor); // 设置圆环的颜色 + paint.setStyle(Paint.Style.STROKE); // 设置空心 + paint.setStrokeWidth(roundWidth); // 设置圆环的宽度 + paint.setAntiAlias(true); // 消除锯齿 + canvas.drawCircle(centre, centre, radius, paint); // 画出圆环 + + + /** + * 画进度百分比 + */ + paint.setStrokeWidth(0); + paint.setColor(textColor); + paint.setTextSize(textSize); + paint.setTypeface(Typeface.DEFAULT_BOLD); // 设置字体 + if (text.equals("s")) { + int percent = 180 - (int) progress; // 中间的进度百分比,先转换成float在进行除法运算,不然都为0 + + float textWidth = paint.measureText(percent + "s"); // 测量字体宽度,我们需要根据字体的宽度设置在圆环中间 + + if (textIsDisplayable && percent != 0 && style == STROKE) { + canvas.drawText(percent + "s", centre - textWidth / 2, centre + textSize / 2, paint); // 画出进度百分比 + } + } else { + int percent = (int) (((float) progress / (float) max) * 100); // 中间的进度百分比,先转换成float在进行除法运算,不然都为0 + float textWidth = paint.measureText(percent + "%"); // 测量字体宽度,我们需要根据字体的宽度设置在圆环中间 + + if (textIsDisplayable && percent != 0 && style == STROKE) { + canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize / 2, paint); // 画出进度百分比 + } + } + + + /** + * 画圆弧 ,画圆环的进度 + */ + + // 设置进度是实心还是空心 + paint.setStrokeWidth(roundWidth * 2); // 设置圆环的宽度 + paint.setColor(roundProgressColor); // 设置进度的颜色 + paint.setAntiAlias(true); // 消除锯齿 + RectF oval = new RectF(centre - radius + 1.5f, centre - radius + 1.5f, centre + radius - 1.5f, + centre + radius - 1.5f); // 用于定义的圆弧的形状和大小的界限 + + switch (style) { + case STROKE: { + paint.setStyle(Paint.Style.STROKE); + canvas.drawArc(oval, -90, 360 * progress / max, false, paint); // 根据进度画圆弧 + break; + } + case FILL: { + paint.setStyle(Paint.Style.FILL_AND_STROKE); + if (progress != 0) + canvas.drawArc(oval, -90, 360 * progress / max, true, paint); // 根据进度画圆弧 + break; + } + } + + } + + public synchronized int getMax() { + return max; + } + + /** + * 设置进度的最大值 + * + * @param max + */ + public synchronized void setMax(int max) { + if (max < 0) { + throw new IllegalArgumentException("max not less than 0"); + } + this.max = max; + } + + /** + * 获取进度.需要同步 + * + * @return + */ + public synchronized float getProgress() { + return progress; + } + + /** + * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步 刷新界面调用postInvalidate()能在非UI线程刷新 + * + * @param progress + */ + public synchronized void setProgress(double progress) { + if (progress < 0) { + throw new IllegalArgumentException("progress not less than 0"); + } + if (progress > max) { + progress = max; + } + if (progress <= max) { + this.progress = (float) progress; + postInvalidate(); + } + + } + + public int getCricleColor() { + return roundColor; + } + + public void setCricleColor(int cricleColor) { + this.roundColor = cricleColor; + } + + public int getCricleProgressColor() { + return roundProgressColor; + } + + public void setCricleProgressColor(int cricleProgressColor) { + this.roundProgressColor = cricleProgressColor; + } + + public int getTextColor() { + return textColor; + } + + public void setTextColor(int textColor) { + this.textColor = textColor; + } + + public float getTextSize() { + return textSize; + } + + public void setTextSize(float textSize) { + this.textSize = textSize; + } + + public float getRoundWidth() { + return roundWidth; + } + + public void setRoundWidth(float roundWidth) { + this.roundWidth = roundWidth; + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/view/SlideListView2.java b/src/java/com/gizwits/opensource/appkit/view/SlideListView2.java new file mode 100644 index 0000000..671bba6 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/SlideListView2.java @@ -0,0 +1,309 @@ +package com.gizwits.opensource.appkit.view; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.Scroller; + +/** + * 侧向滑出菜单的ListView 使用请注意与ListView的Item的布局配合, + * 该效果的实现是基于在Item的布局中通过设置PaddingLeft和PaddingRight来隐藏左右菜单的, + * 所以使用此ListView时,请务必在布局Item时使用PaddingLeft和PaddingRight; + * 或者自己改写此ListView,已达到想要的实现方式 + * + * @author zhangshuo + */ +@SuppressLint({"ClickableViewAccessibility", "Recycle"}) +public class SlideListView2 extends ListView { + + /** + * 禁止侧滑模式 + */ + public static int MOD_FORBID = 0; + /** + * 从左向右滑出菜单模式 + */ + public static int MOD_LEFT = 1; + /** + * 从右向左滑出菜单模式 + */ + public static int MOD_RIGHT = 2; + /** + * 左右均可以滑出菜单模式 + */ + public static int MOD_BOTH = 3; + /** + * 当前的模式 + */ + private int mode = MOD_FORBID; + /** + * 左侧菜单的长度 + */ + private int leftLength = 0; + /** + * 右侧菜单的长度 + */ + private int rightLength = 0; + + /** + * 当前滑动的ListView position + */ + private int slidePosition; + /** + * 手指按下X的坐标 + */ + private int downY; + /** + * 手指按下Y的坐标 + */ + private int downX; + /** + * ListView的item + */ + private View itemView; + /** + * 滑动类 + */ + private Scroller scroller; + /** + * 认为是用户滑动的最小距离 + */ + private int mTouchSlop; + + /** + * 判断是否可以侧向滑动 + */ + private boolean canMove = false; + /** + * 标示是否完成侧滑 + */ + private boolean isSlided = false; + + public SlideListView2(Context context) { + this(context, null); + } + + public SlideListView2(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlideListView2(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + scroller = new Scroller(context); + mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + /** + * 初始化菜单的滑出模式 + * + * @param mode + */ + public void initSlideMode(int mode) { + this.mode = mode; + } + + /** + * 处理我们拖动ListView item的逻辑 + */ + @Override + public boolean onTouchEvent(MotionEvent ev) { + + final int action = ev.getAction(); + int lastX = (int) ev.getX(); + + switch (action) { + case MotionEvent.ACTION_DOWN: + System.out.println("touch-->" + "down"); + + /* 当前模式不允许滑动,则直接返回,交给ListView自身去处理 */ + if (this.mode == MOD_FORBID) { + return super.onTouchEvent(ev); + } + + // 如果处于侧滑完成状态,侧滑回去,并直接返回 + if (isSlided) { + scrollBack(); + return false; + } + // 假如scroller滚动还没有结束,我们直接返回 + if (!scroller.isFinished()) { + return false; + } + downX = (int) ev.getX(); + downY = (int) ev.getY(); + + slidePosition = pointToPosition(downX, downY); + + // 无效的position, 不做任何处理 + if (slidePosition == AdapterView.INVALID_POSITION) { + return super.onTouchEvent(ev); + } + + // 获取我们点击的item view + itemView = getChildAt(slidePosition - getFirstVisiblePosition()); + + /* 此处根据设置的滑动模式,自动获取左侧或右侧菜单的长度 */ + if (this.mode == MOD_BOTH) { + this.leftLength = -itemView.getPaddingLeft(); + this.rightLength = -itemView.getPaddingRight(); + } else if (this.mode == MOD_LEFT) { + this.leftLength = -itemView.getPaddingLeft(); + } else if (this.mode == MOD_RIGHT) { + this.rightLength = -itemView.getPaddingRight(); + } + + break; + case MotionEvent.ACTION_MOVE: + System.out.println("touch-->" + "move"); + + if (!canMove && slidePosition != AdapterView.INVALID_POSITION + && (Math.abs(ev.getX() - downX) > mTouchSlop && Math.abs(ev.getY() - downY) < mTouchSlop)) { + int offsetX = downX - lastX; + if (offsetX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)) { + /* 从右向左滑 */ + canMove = true; + } /* + * else if(offsetX < 0 && (this.mode == MOD_BOTH || + * this.mode == MOD_LEFT)){ 从左向右滑 canMove = true; } + */ else { + canMove = false; + } + /* 此段代码是为了避免我们在侧向滑动时同时出发ListView的OnItemClickListener时间 */ + MotionEvent cancelEvent = MotionEvent.obtain(ev); + cancelEvent.setAction( + MotionEvent.ACTION_CANCEL | (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); + onTouchEvent(cancelEvent); + } + if (canMove) { + /* 设置此属性,可以在侧向滑动时,保持ListView不会上下滚动 */ + requestDisallowInterceptTouchEvent(true); + + // 手指拖动itemView滚动, deltaX大于0向左滚动,小于0向右滚 + int deltaX = downX - lastX; + if (deltaX < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)) { + /* 向左滑 */ + itemView.scrollTo(deltaX, 0); + } else if (deltaX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)) { + /* 向右滑 */ + itemView.scrollTo(deltaX, 0); + } else { + itemView.scrollTo(0, 0); + } + return true; // 拖动的时候ListView不滚动 + } + case MotionEvent.ACTION_UP: + System.out.println("touch-->" + "up"); + if (canMove) { + canMove = false; + scrollByDistanceX(); + } + break; + } + + // 否则直接交给ListView来处理onTouchEvent事件 + return super.onTouchEvent(ev); + } + + /** + * 根据手指滚动itemView的距离来判断是滚动到开始位置还是向左或者向右滚动 + */ + private void scrollByDistanceX() { + /* 当前模式不允许滑动,则直接返回 */ + if (this.mode == MOD_FORBID) { + return; + } + if (itemView.getScrollX() > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)) { + /* 从右向左滑 */ + if (itemView.getScrollX() >= rightLength / 2) { + scrollLeft(); + } else { + // 滚回到原始位置 + scrollBack(); + } + } else if (itemView.getScrollX() < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)) { + /* 从左向右滑 */ + if (itemView.getScrollX() <= -leftLength / 2) { + scrollRight(); + } else { + // 滚回到原始位置 + scrollBack(); + } + } else { + // 滚回到原始位置 + scrollBack(); + } + + } + + /** + * 往右滑动,getScrollX()返回的是左边缘的距离,就是以View左边缘为原点到开始滑动的距离,所以向右边滑动为负值 + */ + private void scrollRight() { + isSlided = true; + final int delta = (leftLength + itemView.getScrollX()); + // 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item + scroller.startScroll(itemView.getScrollX(), 0, -delta, 0, Math.abs(delta)); + postInvalidate(); // 刷新itemView + } + + /** + * 向左滑动,根据上面我们知道向左滑动为正值 + */ + private void scrollLeft() { + isSlided = true; + final int delta = (rightLength - itemView.getScrollX()); + // 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item + scroller.startScroll(itemView.getScrollX(), 0, delta, 0, Math.abs(delta)); + postInvalidate(); // 刷新itemView + } + + /** + * 滑动会原来的位置 + */ + private void scrollBack() { + isSlided = false; + if (itemView != null) { + scroller.startScroll(itemView.getScrollX(), 0, -itemView.getScrollX(), 0, Math.abs(itemView.getScrollX())); + } + postInvalidate(); // 刷新itemView + } + + @Override + public void computeScroll() { + // 调用startScroll的时候scroller.computeScrollOffset()返回true, + if (scroller.computeScrollOffset()) { + // 让ListView item根据当前的滚动偏移量进行滚动 + itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY()); + + postInvalidate(); + } + } + + // TODO 此处方法使ListView或GridView与ScrollView相适应 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, + + MeasureSpec.AT_MOST); + + super.onMeasure(widthMeasureSpec, expandSpec); + + } + + /** + * 提供给外部调用,用以将侧滑出来的滑回去 + */ + public void slideBack() { + this.scrollBack(); + } + + public boolean isSlided() { + return isSlided; + } + +} \ No newline at end of file diff --git a/src/java/com/gizwits/opensource/appkit/view/SuperSwipeRefreshLayout.java b/src/java/com/gizwits/opensource/appkit/view/SuperSwipeRefreshLayout.java new file mode 100644 index 0000000..bf9928a --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/SuperSwipeRefreshLayout.java @@ -0,0 +1,1466 @@ +package com.gizwits.opensource.appkit.view; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.os.Build; +import android.os.Handler; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.ViewCompat; +import android.support.v4.widget.NestedScrollView; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.LayoutManager; +import android.support.v7.widget.StaggeredGridLayoutManager; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.Animation.AnimationListener; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Transformation; +import android.widget.AbsListView; +import android.widget.RelativeLayout; +import android.widget.ScrollView; + +/* + * @Description 自定义CustomeSwipeRefreshLayout
+ * 支持下拉刷新和上拉加载更多
+ * 非侵入式,对原来的ListView、RecyclerView没有任何影响,用法和SwipeRefreshLayout类似。
+ * 可自定义头部View的样式,调用setHeaderView方法即可
+ * 可自定义页尾View的样式,调用setFooterView方法即可
+ * 支持RecyclerView,ListView,ScrollView,GridView等等。
+ * 被包含的View(RecyclerView,ListView etc.)可跟随手指的滑动而滑动
+ * 默认是跟随手指的滑动而滑动,也可以设置为不跟随:setTargetScrollWithLayout(false) 回调方法更多
+ * 比如:onRefresh() onPullDistance(int distance)和onPullEnable(boolean + * enable)
+ */ +@SuppressLint("ClickableViewAccessibility") +public class SuperSwipeRefreshLayout extends ViewGroup { + private static final String LOG_TAG = "CustomeSwipeRefreshLayout"; + private static final int HEADER_VIEW_HEIGHT = 50;// HeaderView height (dp) + + private static final float DECELERATE_INTERPOLATION_FACTOR = 2f; + private static final int INVALID_POINTER = -1; + private static final float DRAG_RATE = .5f; + + private static final int SCALE_DOWN_DURATION = 150; + private static final int ANIMATE_TO_TRIGGER_DURATION = 200; + private static final int ANIMATE_TO_START_DURATION = 200; + private static final int DEFAULT_CIRCLE_TARGET = 64; + + // SuperSwipeRefreshLayout内的目标View,比如RecyclerView,ListView,ScrollView,GridView + // etc. + private View mTarget; + + private OnPullRefreshListener mListener;// 下拉刷新listener + private OnPushLoadMoreListener mOnPushLoadMoreListener;// 上拉加载更多 + + private boolean mRefreshing = false; + private boolean mLoadMore = false; + private int mTouchSlop; + private float mTotalDragDistance = -1; + private int mMediumAnimationDuration; + private int mCurrentTargetOffsetTop; + private boolean mOriginalOffsetCalculated = false; + + private float mInitialMotionY; + private boolean mIsBeingDragged; + private int mActivePointerId = INVALID_POINTER; + private boolean mScale; + + private boolean mReturningToStart; + private final DecelerateInterpolator mDecelerateInterpolator; + private static final int[] LAYOUT_ATTRS = new int[]{android.R.attr.enabled}; + + private HeadViewContainer mHeadViewContainer; + private RelativeLayout mFooterViewContainer; + private int mHeaderViewIndex = -1; + private int mFooterViewIndex = -1; + + protected int mFrom; + + private float mStartingScale; + + protected int mOriginalOffsetTop; + + private Animation mScaleAnimation; + + private Animation mScaleDownAnimation; + + private Animation mScaleDownToStartAnimation; + + // 最后停顿时的偏移量px,与DEFAULT_CIRCLE_TARGET正比 + private float mSpinnerFinalOffset; + + private boolean mNotify; + + private int mHeaderViewWidth;// headerView的宽度 + + private int mFooterViewWidth; + + private int mHeaderViewHeight; + + private int mFooterViewHeight; + + private boolean mUsingCustomStart; + + private boolean targetScrollWithLayout = true; + + private int pushDistance = 0; + + private CircleProgressView defaultProgressView = null; + + private boolean usingDefaultHeader = true; + + private float density = 1.0f; + + private boolean isProgressEnable = true; + + /** + * 下拉时,超过距离之后,弹回来的动画监听器 + */ + private AnimationListener mRefreshListener = new AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + isProgressEnable = false; + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + isProgressEnable = true; + if (mRefreshing) { + if (mNotify) { + if (usingDefaultHeader) { + ViewCompat.setAlpha(defaultProgressView, 1.0f); + defaultProgressView.setOnDraw(true); + new Thread(defaultProgressView).start(); + } + if (mListener != null) { + mListener.onRefresh(); + } + } + } else { + mHeadViewContainer.setVisibility(View.GONE); + if (mScale) { + setAnimationProgress(0); + } else { + setTargetOffsetTopAndBottom(mOriginalOffsetTop + - mCurrentTargetOffsetTop, true); + } + } + mCurrentTargetOffsetTop = mHeadViewContainer.getTop(); + updateListenerCallBack(); + } + }; + + /** + * 更新回调 + */ + private void updateListenerCallBack() { + int distance = mCurrentTargetOffsetTop + mHeadViewContainer.getHeight(); + if (mListener != null) { + mListener.onPullDistance(distance); + } + if (usingDefaultHeader && isProgressEnable) { + defaultProgressView.setPullDistance(distance); + } + } + + /** + * 添加头布局 + * + * @param child + */ + public void setHeaderView(View child) { + if (child == null) { + return; + } + if (mHeadViewContainer == null) { + return; + } + usingDefaultHeader = false; + mHeadViewContainer.removeAllViews(); + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( + mHeaderViewWidth, mHeaderViewHeight); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + mHeadViewContainer.addView(child, layoutParams); + } + + public void setFooterView(View child) { + if (child == null) { + return; + } + if (mFooterViewContainer == null) { + return; + } + mFooterViewContainer.removeAllViews(); + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( + mFooterViewWidth, mFooterViewHeight); + mFooterViewContainer.addView(child, layoutParams); + } + + public SuperSwipeRefreshLayout(Context context) { + this(context, null); + } + + @SuppressWarnings("deprecation") + public SuperSwipeRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + /** + * getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件 + */ + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + + mMediumAnimationDuration = getResources().getInteger( + android.R.integer.config_mediumAnimTime); + + setWillNotDraw(false); + mDecelerateInterpolator = new DecelerateInterpolator( + DECELERATE_INTERPOLATION_FACTOR); + + final TypedArray a = context + .obtainStyledAttributes(attrs, LAYOUT_ATTRS); + setEnabled(a.getBoolean(0, true)); + a.recycle(); + + WindowManager wm = (WindowManager) context + .getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + final DisplayMetrics metrics = getResources().getDisplayMetrics(); + mHeaderViewWidth = (int) display.getWidth(); + mFooterViewWidth = (int) display.getWidth(); + mHeaderViewHeight = (int) (HEADER_VIEW_HEIGHT * metrics.density); + mFooterViewHeight = (int) (HEADER_VIEW_HEIGHT * metrics.density); + defaultProgressView = new CircleProgressView(getContext()); + createHeaderViewContainer(); + createFooterViewContainer(); + ViewCompat.setChildrenDrawingOrderEnabled(this, true); + mSpinnerFinalOffset = DEFAULT_CIRCLE_TARGET * metrics.density; + density = metrics.density; + mTotalDragDistance = mSpinnerFinalOffset; + } + + /* + * 孩子节点绘制的顺序 + * + * @param childCount + * @param i + * @return + */ + @Override + protected int getChildDrawingOrder(int childCount, int i) { + // 将新添加的View,放到最后绘制 + if (mHeaderViewIndex < 0 && mFooterViewIndex < 0) { + return i; + } + if (i == childCount - 2) { + return mHeaderViewIndex; + } + if (i == childCount - 1) { + return mFooterViewIndex; + } + int bigIndex = mFooterViewIndex > mHeaderViewIndex ? mFooterViewIndex + : mHeaderViewIndex; + int smallIndex = mFooterViewIndex < mHeaderViewIndex ? mFooterViewIndex + : mHeaderViewIndex; + if (i >= smallIndex && i < bigIndex - 1) { + return i + 1; + } + if (i >= bigIndex || (i == bigIndex - 1)) { + return i + 2; + } + return i; + } + + /* + * 创建头布局的容器 + */ + private void createHeaderViewContainer() { + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( + (int) (mHeaderViewHeight * 0.8), + (int) (mHeaderViewHeight * 0.8)); + layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + mHeadViewContainer = new HeadViewContainer(getContext()); + mHeadViewContainer.setVisibility(View.GONE); + defaultProgressView.setVisibility(View.VISIBLE); + defaultProgressView.setOnDraw(false); + mHeadViewContainer.addView(defaultProgressView, layoutParams); + addView(mHeadViewContainer); + } + + /* + * 添加底部布局 + */ + private void createFooterViewContainer() { + mFooterViewContainer = new RelativeLayout(getContext()); + mFooterViewContainer.setVisibility(View.GONE); + addView(mFooterViewContainer); + } + + /* + * 设置 + * + * @param listener + */ + public void setOnPullRefreshListener(OnPullRefreshListener listener) { + mListener = listener; + } + + public void setHeaderViewBackgroundColor(int color) { + mHeadViewContainer.setBackgroundColor(color); + } + + /* + * 设置上拉加载更多的接口 + * + * @param onPushLoadMoreListener + */ + public void setOnPushLoadMoreListener( + OnPushLoadMoreListener onPushLoadMoreListener) { + this.mOnPushLoadMoreListener = onPushLoadMoreListener; + } + + /* + * Notify the widget that refresh state has changed. Do not call this when + * refresh is triggered by a swipe gesture. + * + * @param refreshing Whether or not the view should show refresh progress. + */ + public void setRefreshing(boolean refreshing) { + if (refreshing && mRefreshing != refreshing) { + // scale and show + mRefreshing = refreshing; + int endTarget = 0; + if (!mUsingCustomStart) { + endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop); + } else { + endTarget = (int) mSpinnerFinalOffset; + } + setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop, + true /* requires update */); + mNotify = false; + startScaleUpAnimation(mRefreshListener); + } else { + setRefreshing(refreshing, false /* notify */); + if (usingDefaultHeader) { + defaultProgressView.setOnDraw(false); + } + } + } + + private void startScaleUpAnimation(AnimationListener listener) { + mHeadViewContainer.setVisibility(View.VISIBLE); + mScaleAnimation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, + Transformation t) { + setAnimationProgress(interpolatedTime); + } + }; + mScaleAnimation.setDuration(mMediumAnimationDuration); + if (listener != null) { + mHeadViewContainer.setAnimationListener(listener); + } + mHeadViewContainer.clearAnimation(); + mHeadViewContainer.startAnimation(mScaleAnimation); + } + + private void setAnimationProgress(float progress) { + if (!usingDefaultHeader) { + progress = 1; + } + ViewCompat.setScaleX(mHeadViewContainer, progress); + ViewCompat.setScaleY(mHeadViewContainer, progress); + } + + private void setRefreshing(boolean refreshing, final boolean notify) { + if (mRefreshing != refreshing) { + mNotify = notify; + ensureTarget(); + mRefreshing = refreshing; + if (mRefreshing) { + animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, + mRefreshListener); + } else { + //startScaleDownAnimation(mRefreshListener); + animateOffsetToStartPosition(mCurrentTargetOffsetTop, mRefreshListener); + } + } + } + + private void startScaleDownAnimation(AnimationListener listener) { + mScaleDownAnimation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, + Transformation t) { + setAnimationProgress(1 - interpolatedTime); + } + }; + mScaleDownAnimation.setDuration(SCALE_DOWN_DURATION); + mHeadViewContainer.setAnimationListener(listener); + mHeadViewContainer.clearAnimation(); + mHeadViewContainer.startAnimation(mScaleDownAnimation); + } + + public boolean isRefreshing() { + return mRefreshing; + } + + /** + * 确保mTarget不为空
+ * mTarget一般是可滑动的ScrollView,ListView,RecyclerView等 + */ + private void ensureTarget() { + if (mTarget == null) { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (!child.equals(mHeadViewContainer) + && !child.equals(mFooterViewContainer)) { + mTarget = child; + break; + } + } + } + } + + /** + * Set the distance to trigger a sync in dips + * + * @param distance + */ + public void setDistanceToTriggerSync(int distance) { + mTotalDragDistance = distance; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, + int bottom) { + final int width = getMeasuredWidth(); + final int height = getMeasuredHeight(); + if (getChildCount() == 0) { + return; + } + if (mTarget == null) { + ensureTarget(); + } + if (mTarget == null) { + return; + } + int distance = mCurrentTargetOffsetTop + mHeadViewContainer.getMeasuredHeight(); + if (!targetScrollWithLayout) { + // 判断标志位,如果目标View不跟随手指的滑动而滑动,将下拉偏移量设置为0 + distance = 0; + } + final View child = mTarget; + final int childLeft = getPaddingLeft(); + final int childTop = getPaddingTop() + distance - pushDistance;// 根据偏移量distance更新 + final int childWidth = width - getPaddingLeft() - getPaddingRight(); + final int childHeight = height - getPaddingTop() - getPaddingBottom(); + Log.d(LOG_TAG, "debug:onLayout childHeight = " + childHeight); + child.layout(childLeft, childTop, childLeft + childWidth, childTop + + childHeight);// 更新目标View的位置 + int headViewWidth = mHeadViewContainer.getMeasuredWidth(); + int headViewHeight = mHeadViewContainer.getMeasuredHeight(); + mHeadViewContainer.layout((width / 2 - headViewWidth / 2), + mCurrentTargetOffsetTop, (width / 2 + headViewWidth / 2), + mCurrentTargetOffsetTop + headViewHeight);// 更新头布局的位置 + int footViewWidth = mFooterViewContainer.getMeasuredWidth(); + int footViewHeight = mFooterViewContainer.getMeasuredHeight(); + mFooterViewContainer.layout((width / 2 - footViewWidth / 2), height + - pushDistance, (width / 2 + footViewWidth / 2), height + + footViewHeight - pushDistance); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (mTarget == null) { + ensureTarget(); + } + if (mTarget == null) { + return; + } + mTarget.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() + - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(getMeasuredHeight() + - getPaddingTop() - getPaddingBottom(), + MeasureSpec.EXACTLY)); + mHeadViewContainer.measure(MeasureSpec.makeMeasureSpec( + mHeaderViewWidth, MeasureSpec.EXACTLY), MeasureSpec + .makeMeasureSpec(3 * mHeaderViewHeight, MeasureSpec.EXACTLY)); + mFooterViewContainer.measure(MeasureSpec.makeMeasureSpec( + mFooterViewWidth, MeasureSpec.EXACTLY), MeasureSpec + .makeMeasureSpec(mFooterViewHeight, MeasureSpec.EXACTLY)); + if (!mUsingCustomStart && !mOriginalOffsetCalculated) { + mOriginalOffsetCalculated = true; + mCurrentTargetOffsetTop = mOriginalOffsetTop = -mHeadViewContainer + .getMeasuredHeight(); + updateListenerCallBack(); + } + mHeaderViewIndex = -1; + for (int index = 0; index < getChildCount(); index++) { + if (getChildAt(index) == mHeadViewContainer) { + mHeaderViewIndex = index; + break; + } + } + mFooterViewIndex = -1; + for (int index = 0; index < getChildCount(); index++) { + if (getChildAt(index) == mFooterViewContainer) { + mFooterViewIndex = index; + break; + } + } + } + + /** + * 判断目标View是否滑动到顶部-还能否继续滑动 + * + * @return + */ + public boolean isChildScrollToTop() { + if (Build.VERSION.SDK_INT < 14) { + if (mTarget instanceof AbsListView) { + final AbsListView absListView = (AbsListView) mTarget; + return !(absListView.getChildCount() > 0 && (absListView + .getFirstVisiblePosition() > 0 || absListView + .getChildAt(0).getTop() < absListView.getPaddingTop())); + } else { + return !(mTarget.getScrollY() > 0); + } + } else { + return !ViewCompat.canScrollVertically(mTarget, -1); + } + } + + /** + * 是否滑动到底部 + * + * @return + */ + public boolean isChildScrollToBottom() { + if (isChildScrollToTop()) { + return false; + } + if (mTarget instanceof RecyclerView) { + RecyclerView recyclerView = (RecyclerView) mTarget; + LayoutManager layoutManager = recyclerView.getLayoutManager(); + int count = recyclerView.getAdapter().getItemCount(); + if (layoutManager instanceof LinearLayoutManager && count > 0) { + LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; + if (linearLayoutManager.findLastCompletelyVisibleItemPosition() == count - 1) { + return true; + } + } else if (layoutManager instanceof StaggeredGridLayoutManager) { + StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager; + int[] lastItems = new int[2]; + staggeredGridLayoutManager + .findLastCompletelyVisibleItemPositions(lastItems); + int lastItem = Math.max(lastItems[0], lastItems[1]); + if (lastItem == count - 1) { + return true; + } + } + return false; + } else if (mTarget instanceof AbsListView) { + final AbsListView absListView = (AbsListView) mTarget; + int count = absListView.getAdapter().getCount(); + int fristPos = absListView.getFirstVisiblePosition(); + if (fristPos == 0 + && absListView.getChildAt(0).getTop() >= absListView + .getPaddingTop()) { + return false; + } + int lastPos = absListView.getLastVisiblePosition(); + if (lastPos > 0 && count > 0 && lastPos == count - 1) { + return true; + } + return false; + } else if (mTarget instanceof ScrollView) { + ScrollView scrollView = (ScrollView) mTarget; + View view = (View) scrollView + .getChildAt(scrollView.getChildCount() - 1); + if (view != null) { + int diff = (view.getBottom() - (scrollView.getHeight() + scrollView + .getScrollY())); + if (diff == 0) { + return true; + } + } + } else if (mTarget instanceof NestedScrollView) { + NestedScrollView nestedScrollView = (NestedScrollView) mTarget; + View view = (View) nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1); + if (view != null) { + int diff = (view.getBottom() - (nestedScrollView.getHeight() + nestedScrollView.getScrollY())); + if (diff == 0) { + return true; + } + } + } + return false; + } + + /** + * 主要判断是否应该拦截子View的事件
+ * 如果拦截,则交给自己的OnTouchEvent处理
+ * 否者,交给子View处理
+ */ + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + ensureTarget(); + + final int action = MotionEventCompat.getActionMasked(ev); + + if (mReturningToStart && action == MotionEvent.ACTION_DOWN) { + mReturningToStart = false; + } + if (!isEnabled() || mReturningToStart || mRefreshing || mLoadMore + || (!isChildScrollToTop() && !isChildScrollToBottom())) { + // 如果子View可以滑动,不拦截事件,交给子View处理-下拉刷新 + // 或者子View没有滑动到底部不拦截事件-上拉加载更多 + return false; + } + + // 下拉刷新判断 + switch (action) { + case MotionEvent.ACTION_DOWN: + setTargetOffsetTopAndBottom( + mOriginalOffsetTop - mHeadViewContainer.getTop(), true);// 恢复HeaderView的初始位置 + mActivePointerId = MotionEventCompat.getPointerId(ev, 0); + mIsBeingDragged = false; + final float initialMotionY = getMotionEventY(ev, mActivePointerId); + if (initialMotionY == -1) { + return false; + } + mInitialMotionY = initialMotionY;// 记录按下的位置 + + case MotionEvent.ACTION_MOVE: + if (mActivePointerId == INVALID_POINTER) { + Log.e(LOG_TAG, + "Got ACTION_MOVE event but don't have an active pointer id."); + return false; + } + + final float y = getMotionEventY(ev, mActivePointerId); + if (y == -1) { + return false; + } + float yDiff = 0; + if (isChildScrollToBottom()) { + yDiff = mInitialMotionY - y;// 计算上拉距离 + if (yDiff > mTouchSlop && !mIsBeingDragged) {// 判断是否下拉的距离足够 + mIsBeingDragged = true;// 正在上拉 + } + } else { + yDiff = y - mInitialMotionY;// 计算下拉距离 + if (yDiff > mTouchSlop && !mIsBeingDragged) {// 判断是否下拉的距离足够 + mIsBeingDragged = true;// 正在下拉 + } + } + break; + + case MotionEventCompat.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mIsBeingDragged = false; + mActivePointerId = INVALID_POINTER; + break; + } + + return mIsBeingDragged;// 如果正在拖动,则拦截子View的事件 + } + + private float getMotionEventY(MotionEvent ev, int activePointerId) { + final int index = MotionEventCompat.findPointerIndex(ev, + activePointerId); + if (index < 0) { + return -1; + } + return MotionEventCompat.getY(ev, index); + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean b) { + // Nope. + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + final int action = MotionEventCompat.getActionMasked(ev); + + if (mReturningToStart && action == MotionEvent.ACTION_DOWN) { + mReturningToStart = false; + } + if (!isEnabled() || mReturningToStart + || (!isChildScrollToTop() && !isChildScrollToBottom())) { + // 如果子View可以滑动,不拦截事件,交给子View处理 + return false; + } + + if (isChildScrollToBottom()) {// 上拉加载更多 + return handlerPushTouchEvent(ev, action); + } else {// 下拉刷新 + return handlerPullTouchEvent(ev, action); + } + } + + + //下拉刷新 + private boolean handlerPullTouchEvent(MotionEvent ev, int action) { + switch (action) { + case MotionEvent.ACTION_DOWN: + mActivePointerId = MotionEventCompat.getPointerId(ev, 0); + mIsBeingDragged = false; + break; + + case MotionEvent.ACTION_MOVE: { + final int pointerIndex = MotionEventCompat.findPointerIndex(ev, + mActivePointerId); + if (pointerIndex < 0) { + Log.e(LOG_TAG, + "Got ACTION_MOVE event but have an invalid active pointer id."); + return false; + } + + final float y = MotionEventCompat.getY(ev, pointerIndex); + final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE; + if (mIsBeingDragged) { + float originalDragPercent = overscrollTop / mTotalDragDistance; + if (originalDragPercent < 0) { + return false; + } + float dragPercent = Math.min(1f, Math.abs(originalDragPercent)); + float extraOS = Math.abs(overscrollTop) - mTotalDragDistance; + float slingshotDist = mUsingCustomStart ? mSpinnerFinalOffset + - mOriginalOffsetTop : mSpinnerFinalOffset; + float tensionSlingshotPercent = Math.max(0, + Math.min(extraOS, slingshotDist * 2) / slingshotDist); + float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math + .pow((tensionSlingshotPercent / 4), 2)) * 2f; + float extraMove = (slingshotDist) * tensionPercent * 2; + + int targetY = mOriginalOffsetTop + + (int) ((slingshotDist * dragPercent) + extraMove); + if (mHeadViewContainer.getVisibility() != View.VISIBLE) { + mHeadViewContainer.setVisibility(View.VISIBLE); + } + if (!mScale) { + ViewCompat.setScaleX(mHeadViewContainer, 1f); + ViewCompat.setScaleY(mHeadViewContainer, 1f); + } + if (usingDefaultHeader) { + float alpha = overscrollTop / mTotalDragDistance; + if (alpha >= 1.0f) { + alpha = 1.0f; + } + ViewCompat.setScaleX(defaultProgressView, alpha); + ViewCompat.setScaleY(defaultProgressView, alpha); + ViewCompat.setAlpha(defaultProgressView, alpha); + } + if (overscrollTop < mTotalDragDistance) { + if (mScale) { + setAnimationProgress(overscrollTop / mTotalDragDistance); + } + if (mListener != null) { + mListener.onPullEnable(false); + } + } else { + if (mListener != null) { + mListener.onPullEnable(true); + } + } + setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop, + true); + } + break; + } + case MotionEventCompat.ACTION_POINTER_DOWN: { + final int index = MotionEventCompat.getActionIndex(ev); + mActivePointerId = MotionEventCompat.getPointerId(ev, index); + break; + } + + case MotionEventCompat.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + if (mActivePointerId == INVALID_POINTER) { + if (action == MotionEvent.ACTION_UP) { + Log.e(LOG_TAG, + "Got ACTION_UP event but don't have an active pointer id."); + } + return false; + } + final int pointerIndex = MotionEventCompat.findPointerIndex(ev, + mActivePointerId); + final float y = MotionEventCompat.getY(ev, pointerIndex); + final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE; + mIsBeingDragged = false; + if (overscrollTop > mTotalDragDistance) { + setRefreshing(true, true /* notify */); + } else { + mRefreshing = false; + AnimationListener listener = null; + if (!mScale) { + listener = new AnimationListener() { + + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + if (!mScale) { + startScaleDownAnimation(null); + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + }; + } + animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener); + } + mActivePointerId = INVALID_POINTER; + return false; + } + } + + return true; + } + + /** + * 处理上拉加载更多的Touch事件 + * + * @param ev + * @param action + * @return + */ + private boolean handlerPushTouchEvent(MotionEvent ev, int action) { + switch (action) { + case MotionEvent.ACTION_DOWN: + mActivePointerId = MotionEventCompat.getPointerId(ev, 0); + mIsBeingDragged = false; + Log.d(LOG_TAG, "debug:onTouchEvent ACTION_DOWN"); + break; + case MotionEvent.ACTION_MOVE: { + final int pointerIndex = MotionEventCompat.findPointerIndex(ev, + mActivePointerId); + if (pointerIndex < 0) { + Log.e(LOG_TAG, + "Got ACTION_MOVE event but have an invalid active pointer id."); + return false; + } + final float y = MotionEventCompat.getY(ev, pointerIndex); + final float overscrollBottom = (mInitialMotionY - y) * DRAG_RATE; + if (mIsBeingDragged) { + pushDistance = (int) overscrollBottom; + updateFooterViewPosition(); + if (mOnPushLoadMoreListener != null) { + mOnPushLoadMoreListener + .onPushEnable(pushDistance >= mFooterViewHeight); + } + } + break; + } + case MotionEventCompat.ACTION_POINTER_DOWN: { + final int index = MotionEventCompat.getActionIndex(ev); + mActivePointerId = MotionEventCompat.getPointerId(ev, index); + break; + } + + case MotionEventCompat.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + if (mActivePointerId == INVALID_POINTER) { + if (action == MotionEvent.ACTION_UP) { + Log.e(LOG_TAG, + "Got ACTION_UP event but don't have an active pointer id."); + } + return false; + } + final int pointerIndex = MotionEventCompat.findPointerIndex(ev, + mActivePointerId); + final float y = MotionEventCompat.getY(ev, pointerIndex); + final float overscrollBottom = (mInitialMotionY - y) * DRAG_RATE;// 松手是下拉的距离 + mIsBeingDragged = false; + mActivePointerId = INVALID_POINTER; + if (overscrollBottom < mFooterViewHeight + || mOnPushLoadMoreListener == null) {// 直接取消 + pushDistance = 0; + } else {// 下拉到mFooterViewHeight + pushDistance = mFooterViewHeight; + } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + updateFooterViewPosition(); + if (pushDistance == mFooterViewHeight + && mOnPushLoadMoreListener != null) { + mLoadMore = true; + mOnPushLoadMoreListener.onLoadMore(); + } + } else { + animatorFooterToBottom((int) overscrollBottom, pushDistance); + } + return false; + } + } + return true; + } + + /** + * 松手之后,使用动画将Footer从距离start变化到end + * + * @param start + * @param end + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void animatorFooterToBottom(int start, final int end) { + ValueAnimator valueAnimator = ValueAnimator.ofInt(start, end); + valueAnimator.setDuration(150); + valueAnimator.addUpdateListener(new AnimatorUpdateListener() { + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + // update + pushDistance = (Integer) valueAnimator.getAnimatedValue(); + updateFooterViewPosition(); + } + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (end > 0 && mOnPushLoadMoreListener != null) { + // start loading more + mLoadMore = true; + mOnPushLoadMoreListener.onLoadMore(); + } else { + resetTargetLayout(); + mLoadMore = false; + } + } + }); + valueAnimator.setInterpolator(mDecelerateInterpolator); + valueAnimator.start(); + } + + /** + * 设置停止加载 + * + * @param loadMore + */ + public void setLoadMore(boolean loadMore) { + if (!loadMore && mLoadMore) {// 停止加载 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + mLoadMore = false; + pushDistance = 0; + updateFooterViewPosition(); + } else { + animatorFooterToBottom(mFooterViewHeight, 0); + } + } + } + + private void animateOffsetToCorrectPosition(int from, + AnimationListener listener) { + mFrom = from; + mAnimateToCorrectPosition.reset(); + mAnimateToCorrectPosition.setDuration(ANIMATE_TO_TRIGGER_DURATION); + mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator); + if (listener != null) { + mHeadViewContainer.setAnimationListener(listener); + } + mHeadViewContainer.clearAnimation(); + mHeadViewContainer.startAnimation(mAnimateToCorrectPosition); + } + + private void animateOffsetToStartPosition(int from, + AnimationListener listener) { + if (mScale) { + startScaleDownReturnToStartAnimation(from, listener); + } else { + mFrom = from; + mAnimateToStartPosition.reset(); + mAnimateToStartPosition.setDuration(ANIMATE_TO_START_DURATION); + mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator); + if (listener != null) { + mHeadViewContainer.setAnimationListener(listener); + } + mHeadViewContainer.clearAnimation(); + mHeadViewContainer.startAnimation(mAnimateToStartPosition); + } + resetTargetLayoutDelay(ANIMATE_TO_START_DURATION); + } + + /** + * 重置Target位置 + * + * @param delay + */ + public void resetTargetLayoutDelay(int delay) { + new Handler().postDelayed(new Runnable() { + + @Override + public void run() { + resetTargetLayout(); + } + }, delay); + } + + /** + * 重置Target的位置 + */ + public void resetTargetLayout() { + final int width = getMeasuredWidth(); + final int height = getMeasuredHeight(); + final View child = mTarget; + final int childLeft = getPaddingLeft(); + final int childTop = getPaddingTop(); + final int childWidth = child.getWidth() - getPaddingLeft() + - getPaddingRight(); + final int childHeight = child.getHeight() - getPaddingTop() + - getPaddingBottom(); + child.layout(childLeft, childTop, childLeft + childWidth, childTop + + childHeight); + + int headViewWidth = mHeadViewContainer.getMeasuredWidth(); + int headViewHeight = mHeadViewContainer.getMeasuredHeight(); + mHeadViewContainer.layout((width / 2 - headViewWidth / 2), + -headViewHeight, (width / 2 + headViewWidth / 2), 0);// 更新头布局的位置 + int footViewWidth = mFooterViewContainer.getMeasuredWidth(); + int footViewHeight = mFooterViewContainer.getMeasuredHeight(); + mFooterViewContainer.layout((width / 2 - footViewWidth / 2), height, + (width / 2 + footViewWidth / 2), height + footViewHeight); + } + + private final Animation mAnimateToCorrectPosition = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + int targetTop = 0; + int endTarget = 0; + if (!mUsingCustomStart) { + endTarget = (int) (mSpinnerFinalOffset - Math + .abs(mOriginalOffsetTop)); + } else { + endTarget = (int) mSpinnerFinalOffset; + } + targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime)); + int offset = targetTop - mHeadViewContainer.getTop(); + setTargetOffsetTopAndBottom(offset, false /* requires update */); + } + + @Override + public void setAnimationListener(AnimationListener listener) { + super.setAnimationListener(listener); + } + }; + + private void moveToStart(float interpolatedTime) { + int targetTop = 0; + targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime)); + int offset = targetTop - mHeadViewContainer.getTop(); + setTargetOffsetTopAndBottom(offset, false /* requires update */); + } + + private final Animation mAnimateToStartPosition = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + moveToStart(interpolatedTime); + } + }; + + private void startScaleDownReturnToStartAnimation(int from, + AnimationListener listener) { + mFrom = from; + mStartingScale = ViewCompat.getScaleX(mHeadViewContainer); + mScaleDownToStartAnimation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, + Transformation t) { + float targetScale = (mStartingScale + (-mStartingScale * interpolatedTime)); + setAnimationProgress(targetScale); + moveToStart(interpolatedTime); + } + }; + mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION); + if (listener != null) { + mHeadViewContainer.setAnimationListener(listener); + } + mHeadViewContainer.clearAnimation(); + mHeadViewContainer.startAnimation(mScaleDownToStartAnimation); + } + + private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) { + mHeadViewContainer.bringToFront(); + mHeadViewContainer.offsetTopAndBottom(offset); + mCurrentTargetOffsetTop = mHeadViewContainer.getTop(); + if (requiresUpdate && Build.VERSION.SDK_INT < 11) { + invalidate(); + } + updateListenerCallBack(); + } + + /** + * 修改底部布局的位置-敏感pushDistance + */ + private void updateFooterViewPosition() { + mFooterViewContainer.setVisibility(View.VISIBLE); + mFooterViewContainer.bringToFront(); + //针对4.4及之前版本的兼容 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + mFooterViewContainer.getParent().requestLayout(); + } + mFooterViewContainer.offsetTopAndBottom(-pushDistance); + updatePushDistanceListener(); + } + + private void updatePushDistanceListener() { + if (mOnPushLoadMoreListener != null) { + mOnPushLoadMoreListener.onPushDistance(pushDistance); + } + } + + private void onSecondaryPointerUp(MotionEvent ev) { + final int pointerIndex = MotionEventCompat.getActionIndex(ev); + final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); + if (pointerId == mActivePointerId) { + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + mActivePointerId = MotionEventCompat.getPointerId(ev, + newPointerIndex); + } + } + + /** + * @Description 下拉刷新布局头部的容器 + */ + private class HeadViewContainer extends RelativeLayout { + + private AnimationListener mListener; + + public HeadViewContainer(Context context) { + super(context); + } + + public void setAnimationListener(AnimationListener listener) { + mListener = listener; + } + + @Override + public void onAnimationStart() { + super.onAnimationStart(); + if (mListener != null) { + mListener.onAnimationStart(getAnimation()); + } + } + + @Override + public void onAnimationEnd() { + super.onAnimationEnd(); + if (mListener != null) { + mListener.onAnimationEnd(getAnimation()); + } + } + } + + /** + * 判断子View是否跟随手指的滑动而滑动,默认跟随 + * + * @return + */ + public boolean isTargetScrollWithLayout() { + return targetScrollWithLayout; + } + + /** + * 设置子View是否跟谁手指的滑动而滑动 + * + * @param targetScrollWithLayout + */ + public void setTargetScrollWithLayout(boolean targetScrollWithLayout) { + this.targetScrollWithLayout = targetScrollWithLayout; + } + + /** + * 下拉刷新回调 + */ + public interface OnPullRefreshListener { + public void onRefresh(); + + public void onPullDistance(int distance); + + public void onPullEnable(boolean enable); + } + + /** + * 上拉加载更多 + */ + public interface OnPushLoadMoreListener { + public void onLoadMore(); + + public void onPushDistance(int distance); + + public void onPushEnable(boolean enable); + } + + /** + * Adapter + */ + public class OnPullRefreshListenerAdapter implements OnPullRefreshListener { + + @Override + public void onRefresh() { + + } + + @Override + public void onPullDistance(int distance) { + + } + + @Override + public void onPullEnable(boolean enable) { + + } + + } + + public class OnPushLoadMoreListenerAdapter implements + OnPushLoadMoreListener { + + @Override + public void onLoadMore() { + + } + + @Override + public void onPushDistance(int distance) { + + } + + @Override + public void onPushEnable(boolean enable) { + + } + + } + + /** + * 设置默认下拉刷新进度条的颜色 + * + * @param color + */ + public void setDefaultCircleProgressColor(int color) { + if (usingDefaultHeader) { + defaultProgressView.setProgressColor(color); + } + } + + /** + * 设置圆圈的背景色 + * + * @param color + */ + public void setDefaultCircleBackgroundColor(int color) { + if (usingDefaultHeader) { + defaultProgressView.setCircleBackgroundColor(color); + } + } + + public void setDefaultCircleShadowColor(int color) { + if (usingDefaultHeader) { + defaultProgressView.setShadowColor(color); + } + } + + /** + * 默认的下拉刷新样式 + */ + public class CircleProgressView extends View implements Runnable { + + private static final int PEROID = 16;// 绘制周期 + private Paint progressPaint; + private Paint bgPaint; + private int width;// view的高度 + private int height;// view的宽度 + + private boolean isOnDraw = false; + private boolean isRunning = false; + private int startAngle = 0; + private int speed = 8; + private RectF ovalRect = null; + private RectF bgRect = null; + private int swipeAngle; + private int progressColor = 0xffcccccc; + private int circleBackgroundColor = 0xffffffff; + private int shadowColor = 0xff999999; + + public CircleProgressView(Context context) { + super(context); + } + + public CircleProgressView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CircleProgressView(Context context, AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawArc(getBgRect(), 0, 360, false, createBgPaint()); + int index = startAngle / 360; + if (index % 2 == 0) { + swipeAngle = (startAngle % 720) / 2; + } else { + swipeAngle = 360 - (startAngle % 720) / 2; + } + canvas.drawArc(getOvalRect(), startAngle, swipeAngle, false, + createPaint()); + } + + private RectF getBgRect() { + width = getWidth(); + height = getHeight(); + if (bgRect == null) { + int offset = (int) (density * 2); + bgRect = new RectF(offset, offset, width - offset, height + - offset); + } + return bgRect; + } + + private RectF getOvalRect() { + width = getWidth(); + height = getHeight(); + if (ovalRect == null) { + int offset = (int) (density * 8); + ovalRect = new RectF(offset, offset, width - offset, height + - offset); + } + return ovalRect; + } + + public void setProgressColor(int progressColor) { + this.progressColor = progressColor; + } + + public void setCircleBackgroundColor(int circleBackgroundColor) { + this.circleBackgroundColor = circleBackgroundColor; + } + + public void setShadowColor(int shadowColor) { + this.shadowColor = shadowColor; + } + + /** + * 根据画笔的颜色,创建画笔 + * + * @return + */ + private Paint createPaint() { + if (this.progressPaint == null) { + progressPaint = new Paint(); + progressPaint.setStrokeWidth((int) (density * 3)); + progressPaint.setStyle(Paint.Style.STROKE); + progressPaint.setAntiAlias(true); + } + progressPaint.setColor(progressColor); + return progressPaint; + } + + private Paint createBgPaint() { + if (this.bgPaint == null) { + bgPaint = new Paint(); + bgPaint.setColor(circleBackgroundColor); + bgPaint.setStyle(Paint.Style.FILL); + bgPaint.setAntiAlias(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + this.setLayerType(LAYER_TYPE_SOFTWARE, bgPaint); + } + bgPaint.setShadowLayer(4.0f, 0.0f, 2.0f, shadowColor); + } + return bgPaint; + } + + public void setPullDistance(int distance) { + this.startAngle = distance * 2; + postInvalidate(); + } + + @Override + public void run() { + while (isOnDraw) { + isRunning = true; + long startTime = System.currentTimeMillis(); + startAngle += speed; + postInvalidate(); + long time = System.currentTimeMillis() - startTime; + if (time < PEROID) { + try { + Thread.sleep(PEROID - time); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public void setOnDraw(boolean isOnDraw) { + this.isOnDraw = isOnDraw; + } + + public void setSpeed(int speed) { + this.speed = speed; + } + + public boolean isRunning() { + return isRunning; + } + + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + } + + @Override + protected void onDetachedFromWindow() { + isOnDraw = false; + super.onDetachedFromWindow(); + } + + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/view/SwitchView.java b/src/java/com/gizwits/opensource/appkit/view/SwitchView.java new file mode 100644 index 0000000..d9f4ba7 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/SwitchView.java @@ -0,0 +1,473 @@ +package com.gizwits.opensource.appkit.view; + + +/** + * Created by qiaoning on 2017/8/16. + */ + + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RadialGradient; +import android.graphics.RectF; +import android.graphics.Shader; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateInterpolator; + +import com.gizwits.opensource.appkit.R; + + +public class SwitchView extends View { + + + private final int DEFAULT_COLOR_PRIMARY = 0xFF4BD763; + private final int DEFAULT_COLOR_PRIMARY_DARK = 0xFF3AC652; + private final float RATIO_ASPECT = 0.68f; + private final float ANIMATION_SPEED = 0.1f; // (0,1] + private static final int STATE_SWITCH_ON = 4; // you change value you die + private static final int STATE_SWITCH_ON2 = 3; + private static final int STATE_SWITCH_OFF2 = 2; + private static final int STATE_SWITCH_OFF = 1; + + private final AccelerateInterpolator interpolator = new AccelerateInterpolator(2); + private final Paint paint = new Paint(); + private final Path sPath = new Path(); + private final Path bPath = new Path(); + private final RectF bRectF = new RectF(); + private float sAnim, bAnim; + private RadialGradient shadowGradient; + + private int state; + private int lastState; + private boolean isCanVisibleDrawing = false; + private OnClickListener mOnClickListener; + private int colorPrimary; + private int colorPrimaryDark; + private boolean hasShadow; + private boolean isOpened; + + private int mWidth, mHeight; + private int actuallyDrawingAreaLeft; + private int actuallyDrawingAreaRight; + private int actuallyDrawingAreaTop; + private int actuallyDrawingAreaBottom; + + private float sWidth, sHeight; + private float sLeft, sTop, sRight, sBottom; + private float sCenterX, sCenterY; + private float sScale; + + private float bOffset; + private float bRadius, bStrokeWidth; + private float bWidth; + private float bLeft, bTop, bRight, bBottom; + private float bOnLeftX, bOn2LeftX, bOff2LeftX, bOffLeftX; + + private float shadowReservedHeight; + + public SwitchView(Context context) { + this(context, null); + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public SwitchView(Context context, AttributeSet attrs) { + super(context, attrs); + setLayerType(LAYER_TYPE_SOFTWARE, null); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwitchView); + colorPrimary = a.getColor(R.styleable.SwitchView_primaryColor, DEFAULT_COLOR_PRIMARY); + colorPrimaryDark = a.getColor(R.styleable.SwitchView_primaryColorDark, DEFAULT_COLOR_PRIMARY_DARK); + hasShadow = a.getBoolean(R.styleable.SwitchView_hasShadow, true); + isOpened = a.getBoolean(R.styleable.SwitchView_isOpened, false); + state = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + lastState = state; + a.recycle(); + + if (colorPrimary == DEFAULT_COLOR_PRIMARY && colorPrimaryDark == DEFAULT_COLOR_PRIMARY_DARK) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + TypedValue primaryColorTypedValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.colorPrimary, primaryColorTypedValue, true); + if (primaryColorTypedValue.data > 0) colorPrimary = primaryColorTypedValue.data; + TypedValue primaryColorDarkTypedValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.colorPrimaryDark, primaryColorDarkTypedValue, true); + if (primaryColorDarkTypedValue.data > 0) + colorPrimaryDark = primaryColorDarkTypedValue.data; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void setColor(int newColorPrimary, int newColorPrimaryDark) { + colorPrimary = newColorPrimary; + colorPrimaryDark = newColorPrimaryDark; + invalidate(); + } + + public void setShadow(boolean shadow) { + hasShadow = shadow; + invalidate(); + } + + public boolean isOpened() { + return isOpened; + } + + public void setOpened(boolean isOpened) { + int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + if (wishState == state) { + return; + } + refreshState(wishState); + } + + public void toggleSwitch(boolean isOpened) { + int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + if (wishState == state) { + return; + } + if ((wishState == STATE_SWITCH_ON && (state == STATE_SWITCH_OFF || state == STATE_SWITCH_OFF2)) + || (wishState == STATE_SWITCH_OFF && (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2))) { + sAnim = 1; + } + bAnim = 1; + refreshState(wishState); + } + + private void refreshState(int newState) { + if (!isOpened && newState == STATE_SWITCH_ON) { + isOpened = true; + } else if (isOpened && newState == STATE_SWITCH_OFF) { + isOpened = false; + } + lastState = state; + state = newState; + postInvalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int resultWidth; + if (widthMode == MeasureSpec.EXACTLY) { + resultWidth = widthSize; + } else { + resultWidth = (int) (56 * getResources().getDisplayMetrics().density + 0.5f) + + getPaddingLeft() + getPaddingRight(); + if (widthMode == MeasureSpec.AT_MOST) { + resultWidth = Math.min(resultWidth, widthSize); + } + } + + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int resultHeight; + if (heightMode == MeasureSpec.EXACTLY) { + resultHeight = heightSize; + } else { + int selfExpectedResultHeight = (int) (resultWidth * RATIO_ASPECT) + getPaddingTop() + getPaddingBottom(); + resultHeight = selfExpectedResultHeight; + if (heightMode == MeasureSpec.AT_MOST) { + resultHeight = Math.min(resultHeight, heightSize); + } + } + setMeasuredDimension(resultWidth, resultHeight); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mWidth = w; + mHeight = h; + isCanVisibleDrawing = mWidth > getPaddingLeft() + getPaddingRight() && mHeight > getPaddingTop() + getPaddingBottom(); + + if (isCanVisibleDrawing) { + int actuallyDrawingAreaWidth = mWidth - getPaddingLeft() - getPaddingRight(); + int actuallyDrawingAreaHeight = mHeight - getPaddingTop() - getPaddingBottom(); + + if (actuallyDrawingAreaWidth * RATIO_ASPECT < actuallyDrawingAreaHeight) { + actuallyDrawingAreaLeft = getPaddingLeft(); + actuallyDrawingAreaRight = mWidth - getPaddingRight(); + int heightExtraSize = (int) (actuallyDrawingAreaHeight - actuallyDrawingAreaWidth * RATIO_ASPECT); + actuallyDrawingAreaTop = getPaddingTop() + heightExtraSize / 2; + actuallyDrawingAreaBottom = getHeight() - getPaddingBottom() - heightExtraSize / 2; + } else { + int widthExtraSize = (int) (actuallyDrawingAreaWidth - actuallyDrawingAreaHeight / RATIO_ASPECT); + actuallyDrawingAreaLeft = getPaddingLeft() + widthExtraSize / 2; + actuallyDrawingAreaRight = getWidth() - getPaddingRight() - widthExtraSize / 2; + actuallyDrawingAreaTop = getPaddingTop(); + actuallyDrawingAreaBottom = getHeight() - getPaddingBottom(); + } + + shadowReservedHeight = (int) ((actuallyDrawingAreaBottom - actuallyDrawingAreaTop) * 0.09f); + sLeft = actuallyDrawingAreaLeft; + sTop = actuallyDrawingAreaTop + shadowReservedHeight; + sRight = actuallyDrawingAreaRight; + sBottom = actuallyDrawingAreaBottom - shadowReservedHeight; + + sWidth = sRight - sLeft; + sHeight = sBottom - sTop; + sCenterX = (sRight + sLeft) / 2; + sCenterY = (sBottom + sTop) / 2; + + bLeft = sLeft; + bTop = sTop; + bBottom = sBottom; + bWidth = sBottom - sTop; + bRight = sLeft + bWidth; + final float halfHeightOfS = bWidth / 2; // OfB + bRadius = halfHeightOfS * 0.95f; + bOffset = bRadius * 0.2f; // offset of switching + bStrokeWidth = (halfHeightOfS - bRadius) * 2; + bOnLeftX = sRight - bWidth; + bOn2LeftX = bOnLeftX - bOffset; + bOffLeftX = sLeft; + bOff2LeftX = bOffLeftX + bOffset; + sScale = 1 - bStrokeWidth / sHeight; + + sPath.reset(); + RectF sRectF = new RectF(); + sRectF.top = sTop; + sRectF.bottom = sBottom; + sRectF.left = sLeft; + sRectF.right = sLeft + sHeight; + sPath.arcTo(sRectF, 90, 180); + sRectF.left = sRight - sHeight; + sRectF.right = sRight; + sPath.arcTo(sRectF, 270, 180); + sPath.close(); + + bRectF.left = bLeft; + bRectF.right = bRight; + bRectF.top = bTop + bStrokeWidth / 2; + bRectF.bottom = bBottom - bStrokeWidth / 2; + float bCenterX = (bRight + bLeft) / 2; + float bCenterY = (bBottom + bTop) / 2; + + shadowGradient = new RadialGradient(bCenterX, bCenterY, bRadius, 0xff000000, 0x00000000, Shader.TileMode.CLAMP); + } + } + + private void calcBPath(float percent) { + bPath.reset(); + bRectF.left = bLeft + bStrokeWidth / 2; + bRectF.right = bRight - bStrokeWidth / 2; + bPath.arcTo(bRectF, 90, 180); + bRectF.left = bLeft + percent * bOffset + bStrokeWidth / 2; + bRectF.right = bRight + percent * bOffset - bStrokeWidth / 2; + bPath.arcTo(bRectF, 270, 180); + bPath.close(); + } + + private float calcBTranslate(float percent) { + float result = 0; + switch (state - lastState) { + case 1: + if (state == STATE_SWITCH_OFF2) { + result = bOffLeftX; // off -> off2 + } else if (state == STATE_SWITCH_ON) { + result = bOnLeftX - (bOnLeftX - bOn2LeftX) * percent; // on2 -> on + } + break; + case 2: + if (state == STATE_SWITCH_ON) { + result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off2 -> on + } else if (state == STATE_SWITCH_ON) { + result = bOn2LeftX - (bOn2LeftX - bOffLeftX) * percent; // off -> on2 + } + break; + case 3: + result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off -> on + break; + case -1: + if (state == STATE_SWITCH_ON2) { + result = bOn2LeftX + (bOnLeftX - bOn2LeftX) * percent; // on -> on2 + } else if (state == STATE_SWITCH_OFF) { + result = bOffLeftX; // off2 -> off + } + break; + case -2: + if (state == STATE_SWITCH_OFF) { + result = bOffLeftX + (bOn2LeftX - bOffLeftX) * percent; // on2 -> off + } else if (state == STATE_SWITCH_OFF2) { + result = bOff2LeftX + (bOnLeftX - bOff2LeftX) * percent; // on -> off2 + } + break; + case -3: + result = bOffLeftX + (bOnLeftX - bOffLeftX) * percent; // on -> off + break; + default: // init + case 0: + if (state == STATE_SWITCH_OFF) { + result = bOffLeftX; // off -> off + } else if (state == STATE_SWITCH_ON) { + result = bOnLeftX; // on -> on + } + break; + } + return result - bOffLeftX; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (!isCanVisibleDrawing) return; + + paint.setAntiAlias(true); + final boolean isOn = (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2); + // Draw background + paint.setStyle(Paint.Style.FILL); + paint.setColor(isOn ? colorPrimary : 0xffE3E3E3); + canvas.drawPath(sPath, paint); + + sAnim = sAnim - ANIMATION_SPEED > 0 ? sAnim - ANIMATION_SPEED : 0; + bAnim = bAnim - ANIMATION_SPEED > 0 ? bAnim - ANIMATION_SPEED : 0; + + final float dsAnim = interpolator.getInterpolation(sAnim); + final float dbAnim = interpolator.getInterpolation(bAnim); + // Draw background animation + final float scale = sScale * (isOn ? dsAnim : 1 - dsAnim); + final float scaleOffset = (sRight - sCenterX - bRadius) * (isOn ? 1 - dsAnim : dsAnim); + canvas.save(); + canvas.scale(scale, scale, sCenterX + scaleOffset, sCenterY); + paint.setColor(0xFFFFFFFF); + canvas.drawPath(sPath, paint); + canvas.restore(); + // To prepare center bar path + canvas.save(); + canvas.translate(calcBTranslate(dbAnim), shadowReservedHeight); + final boolean isState2 = (state == STATE_SWITCH_ON2 || state == STATE_SWITCH_OFF2); + calcBPath(isState2 ? 1 - dbAnim : dbAnim); + // Use center bar path to draw shadow + if (hasShadow) { + paint.setStyle(Paint.Style.FILL); + paint.setColor(0xFF333333); + paint.setShader(shadowGradient); + canvas.drawPath(bPath, paint); + paint.setShader(null); + } + canvas.translate(0, -shadowReservedHeight); + // draw bar + canvas.scale(0.98f, 0.98f, bWidth / 2, bWidth / 2); + paint.setStyle(Paint.Style.FILL); + paint.setColor(0xffffffff); + canvas.drawPath(bPath, paint); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(bStrokeWidth * 0.5f); + paint.setColor(isOn ? colorPrimaryDark : 0xFFBFBFBF); + canvas.drawPath(bPath, paint); + canvas.restore(); + + paint.reset(); + if (sAnim > 0 || bAnim > 0) invalidate(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if ((state == STATE_SWITCH_ON || state == STATE_SWITCH_OFF) && (sAnim * bAnim == 0)) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + return true; + case MotionEvent.ACTION_UP: + lastState = state; + + bAnim = 1; + if (state == STATE_SWITCH_OFF) { + refreshState(STATE_SWITCH_OFF2); + listener.toggleToOn(this); + } else if (state == STATE_SWITCH_ON) { + refreshState(STATE_SWITCH_ON2); + listener.toggleToOff(this); + } + + if (mOnClickListener != null) { + mOnClickListener.onClick(this); + } + break; + } + } + return super.onTouchEvent(event); + } + + @Override + public void setOnClickListener(OnClickListener l) { + super.setOnClickListener(l); + mOnClickListener = l; + } + + public interface OnStateChangedListener { + void toggleToOn(SwitchView view); + + void toggleToOff(SwitchView view); + } + + private OnStateChangedListener listener = new OnStateChangedListener() { + @Override + public void toggleToOn(SwitchView view) { + toggleSwitch(true); + } + + @Override + public void toggleToOff(SwitchView view) { + toggleSwitch(false); + } + }; + + public void setOnStateChangedListener(OnStateChangedListener listener) { + if (listener == null) throw new IllegalArgumentException("empty listener"); + this.listener = listener; + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.isOpened = isOpened; + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + this.isOpened = ss.isOpened; + this.state = this.isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + invalidate(); + } + + @SuppressLint("ParcelCreator") + static final class SavedState extends BaseSavedState { + private boolean isOpened; + + SavedState(Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + isOpened = 1 == in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(isOpened ? 1 : 0); + } + } + + +} diff --git a/src/java/com/gizwits/opensource/appkit/view/VerticalSwipeRefreshLayout.java b/src/java/com/gizwits/opensource/appkit/view/VerticalSwipeRefreshLayout.java new file mode 100644 index 0000000..92b3c24 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/VerticalSwipeRefreshLayout.java @@ -0,0 +1,42 @@ +package com.gizwits.opensource.appkit.view; + +import android.content.Context; +import android.support.v4.widget.SwipeRefreshLayout; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +public class VerticalSwipeRefreshLayout extends SwipeRefreshLayout { + private int mTouchSlop; + // 上一次触摸时的X坐标 + private float mPrevX; + + public VerticalSwipeRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + // 触发移动事件的最短距离,如果小于这个距离就不触发移动控件 + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mPrevX = event.getX(); + break; + + case MotionEvent.ACTION_MOVE: + final float eventX = event.getX(); + float xDiff = Math.abs(eventX - mPrevX); + // Log.d("refresh" ,"move----" + eventX + " " + mPrevX + " " + + // mTouchSlop); + // 增加60的容差,让下拉刷新在竖直滑动时就可以触发 + if (xDiff > mTouchSlop + 60) { + return false; + } + } + + return super.onInterceptTouchEvent(event); + } +} diff --git a/src/java/com/gizwits/opensource/appkit/view/ViewPagerIndicator.java b/src/java/com/gizwits/opensource/appkit/view/ViewPagerIndicator.java new file mode 100644 index 0000000..d3931b8 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/view/ViewPagerIndicator.java @@ -0,0 +1,415 @@ +package com.gizwits.opensource.appkit.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.Path; +import android.support.v4.view.ViewPager; +import android.support.v4.view.ViewPager.OnPageChangeListener; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.R; + +import java.util.List; + +/** + * http://blog.csdn.net/lmj623565791/article/details/42160391 + * + * @author zhy + */ +public class ViewPagerIndicator extends LinearLayout { + /** + * 绘制三角形的画笔 + */ + private Paint mPaint; + /** + * path构成一个三角形 + */ + private Path mPath; + /** + * 线的宽度 + */ + private int mTriangleWidth; + /** + * 线的高度 + */ + private int mTriangleHeight; + + /** + * 三角形的宽度为单个Tab的1/6 + */ + //private static final float RADIO_TRIANGEL = 1.0f / 6; + /** + * 线的最大宽度 + */ + private final int DIMENSION_TRIANGEL_WIDTH = (int) (getScreenWidth() / 2); + + /** + * 初始时,线指示器的偏移量 + */ + private int mInitTranslationX; + /** + * 手指滑动时的偏移量 + */ + private float mTranslationX; + + /** + * 默认的Tab数量 + */ + private static final int COUNT_DEFAULT_TAB = 2; + /** + * tab数量 + */ + private int mTabVisibleCount = 2; + + /** + * tab上的内容 + */ + private List mTabTitles; + /** + * 与之绑定的ViewPager + */ + public ViewPager mViewPager; + + /** + * 标题正常时的颜色(并没有使用 使用的是getContext().getResources().getColor(R.color.text_color) ) + */ + private static final int COLOR_TEXT_NORMAL = 0xFFC6CBCC; + /** + * 标题选中时的颜色 + */ + private static final int COLOR_TEXT_HIGHLIGHTCOLOR = 0xFFFF9A23; + + public ViewPagerIndicator(Context context) { + this(context, null); + } + + public ViewPagerIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + + // 获得自定义属性,tab的数量 + mTabVisibleCount = 2; + if (mTabVisibleCount < 0) + mTabVisibleCount = COUNT_DEFAULT_TAB; + + // 初始化画笔 + mPaint = new Paint(); + mPaint.setAntiAlias(true); +// mPaint.setColor(Color.parseColor("#ffff9a23")); +// mPaint.setColor(getContext().getResources().getColor(R.color.yellow)); + mPaint.setColor(GosDeploy.appConfig_Background()); + mPaint.setStyle(Style.FILL); + mPaint.setPathEffect(new CornerPathEffect(3)); + + } + + /** + * 绘制指示器 + */ + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + + + // 画笔平移到正确的位置 + canvas.translate(mInitTranslationX + mTranslationX, getHeight() + 1); + Path path = new Path(); + int height = 6; + path.moveTo(-(mInitTranslationX + mTranslationX), 0); + path.lineTo(getScreenWidth(), 0); + path.lineTo(getScreenWidth(), -height); + path.lineTo(-(mInitTranslationX + mTranslationX), -height); + path.close(); + mPaint.setColor(getResources().getColor(R.color.background_color)); + canvas.drawPath(path, mPaint); + + //mPaint.setColor(getResources().getColor(R.color.yellow)); + mPaint.setColor(GosDeploy.appConfig_Background()); + canvas.drawPath(mPath, mPaint); + + canvas.restore(); + + super.dispatchDraw(canvas); + } + + /** + * 初始化三角形的宽度 + */ + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mTriangleWidth = (int) (w / mTabVisibleCount);// 1/6 of + // width + mTriangleWidth = Math.min(DIMENSION_TRIANGEL_WIDTH, mTriangleWidth); + + // 初始化三角形 + initTriangle(); + + // 初始时的偏移量 + mInitTranslationX = getWidth() / mTabVisibleCount / 2 - mTriangleWidth + / 2; + } + + /** + * 设置可见的tab的数量 + * + * @param count + */ + public void setVisibleTabCount(int count) { + this.mTabVisibleCount = count; + } + + /** + * 设置tab的标题内容 可选,可以自己在布局文件中写死 + * + * @param datas + */ + public void setTabItemTitles(List datas) { + // 如果传入的list有值,则移除布局文件中设置的view + if (datas != null && datas.size() > 0) { + this.removeAllViews(); + this.mTabTitles = datas; + + for (String title : mTabTitles) { + // 添加view + addView(generateTextView(title)); + } + // 设置item的click事件 + setItemClickEvent(); + } + + } + + /** + * 对外的ViewPager的回调接口 + * + * @author zhy + */ + public interface PageChangeListener { + public void onPageScrolled(int position, float positionOffset, + int positionOffsetPixels); + + public void onPageSelected(int position); + + public void onPageScrollStateChanged(int state); + } + + // 对外的ViewPager的回调接口 + private PageChangeListener onPageChangeListener; + + // 对外的ViewPager的回调接口的设置 + public void setOnPageChangeListener(PageChangeListener pageChangeListener) { + this.onPageChangeListener = pageChangeListener; + } + + // 设置关联的ViewPager + public void setViewPager(ViewPager mViewPager, int pos) { + this.mViewPager = mViewPager; + + mViewPager.setOnPageChangeListener(new OnPageChangeListener() { + @Override + public void onPageSelected(int position) { + // 设置字体颜色高亮 + resetTextViewColor(); + highLightTextView(position); + + // 回调 + if (onPageChangeListener != null) { + onPageChangeListener.onPageSelected(position); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, + int positionOffsetPixels) { + // 滚动 + scroll(position, positionOffset); + + // 回调 + if (onPageChangeListener != null) { + onPageChangeListener.onPageScrolled(position, + positionOffset, positionOffsetPixels); + } + + } + + @Override + public void onPageScrollStateChanged(int state) { + // 回调 + if (onPageChangeListener != null) { + onPageChangeListener.onPageScrollStateChanged(state); + } + + } + }); + // 设置当前页 + mViewPager.setCurrentItem(pos); + // 高亮 + highLightTextView(pos); + } + + /** + * 高亮文本 + * + * @param position + */ + protected void highLightTextView(int position) { + View view = getChildAt(position); + if (view instanceof TextView) { + ((TextView) view).setTextColor(getContext().getResources().getColor(R.color.text_color)); + } + + } + + /** + * 重置文本颜色 + */ + private void resetTextViewColor() { + for (int i = 0; i < getChildCount(); i++) { + View view = getChildAt(i); + if (view instanceof TextView) { + ((TextView) view).setTextColor(getContext().getResources().getColor(R.color.text_state)); + } + } + } + + /** + * 设置点击事件 + */ + public void setItemClickEvent() { + int cCount = getChildCount(); + for (int i = 0; i < cCount; i++) { + final int j = i; + View view = getChildAt(i); + view.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mViewPager.setCurrentItem(j); + } + }); + } + } + + /** + * 根据标题生成我们的TextView + * + * @param text + * @return + */ + private TextView generateTextView(String text) { + TextView tv = new TextView(getContext()); + LayoutParams lp = new LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + lp.width = getScreenWidth() / mTabVisibleCount; + lp.bottomMargin = 25; + lp.topMargin = 15; + tv.setGravity(Gravity.CENTER); + tv.setTextColor(getContext().getResources().getColor(R.color.text_state)); + tv.setText(text); + tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + tv.setLayoutParams(lp); + return tv; + } + + /** + * 初始化三角形指示器 + */ + private void initTriangle() { + mPath = new Path(); + + mTriangleHeight = 10; + mPath.moveTo(0, 0); + mPath.lineTo(mTriangleWidth, 0); + mPath.lineTo(mTriangleWidth, -mTriangleHeight); + mPath.lineTo(0, -mTriangleHeight); + mPath.close(); + } + + private void initLine() { + + } + + + /** + * 指示器跟随手指滚动,以及容器滚动 + * + * @param position + * @param offset + */ + public void scroll(int position, float offset) { + /** + *

+         *  0-1:position=0 ;1-0:postion=0;
+         * 
+ */ + // 不断改变偏移量,invalidate + mTranslationX = getWidth() / mTabVisibleCount * (position + offset); + + int tabWidth = getScreenWidth() / mTabVisibleCount; + + // 容器滚动,当移动到倒数最后一个的时候,开始滚动 + if (offset > 0 && position >= (mTabVisibleCount - 2) + && getChildCount() > mTabVisibleCount) { + if (mTabVisibleCount != 1) { + this.scrollTo((position - (mTabVisibleCount - 2)) * tabWidth + + (int) (tabWidth * offset), 0); + } else + // 为count为1时 的特殊处理 + { + this.scrollTo( + position * tabWidth + (int) (tabWidth * offset), 0); + } + } + + invalidate(); + } + + /** + * 设置布局中view的一些必要属性;如果设置了setTabTitles,布局中view则无效 + */ + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + int cCount = getChildCount(); + + if (cCount == 0) + return; + + for (int i = 0; i < cCount; i++) { + View view = getChildAt(i); + LayoutParams lp = (LayoutParams) view + .getLayoutParams(); + lp.weight = 0; + lp.width = getScreenWidth() / mTabVisibleCount; + view.setLayoutParams(lp); + } + // 设置点击事件 + setItemClickEvent(); + + } + + /** + * 获得屏幕的宽度 + * + * @return + */ + public int getScreenWidth() { + WindowManager wm = (WindowManager) getContext().getSystemService( + Context.WINDOW_SERVICE); + DisplayMetrics outMetrics = new DisplayMetrics(); + wm.getDefaultDisplay().getMetrics(outMetrics); + return outMetrics.widthPixels; + } + +} diff --git a/src/java/com/gizwits/opensource/appkit/wxapi/.DS_Store b/src/java/com/gizwits/opensource/appkit/wxapi/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f4fc62e437d8537e35a4eccc12d9d8b7e3c08aa1 GIT binary patch literal 6148 zcmeHK!A`xVF4#I`vBRWaykV`t2s$03#1d=tkfLlv8?lcH$le{} z7Izq8#$Ef`zYMR)$gFXSDaLG#7vIhl<8@#mYdmTF#%XB}n5 zveb85;Z5^1#{6!rS7EI`)@L6#*xtz$Fa=D39SZQw7V8{&w9*tX1x$gB0`h%`=z>YW z+M|9tSm+gi*e0#Uy4)osCkmJZtUa=a=6ovAr@C;(a6X-U6ylPAwMU;0r!#Y$FtZCc z6sNP3k2D-E@o1$fU>-~YFhtYr$A0{=<@*B*=peJ&}St&PRWSsT$G q=wcFAd)%b3qDL`fi-3VZ;<)J^UH literal 0 HcmV?d00001 diff --git a/src/java/com/gizwits/opensource/appkit/wxapi/WXEntryActivity.java b/src/java/com/gizwits/opensource/appkit/wxapi/WXEntryActivity.java new file mode 100644 index 0000000..4b55ea3 --- /dev/null +++ b/src/java/com/gizwits/opensource/appkit/wxapi/WXEntryActivity.java @@ -0,0 +1,148 @@ +package com.gizwits.opensource.appkit.wxapi; + +import android.os.Bundle; +import android.os.Message; +import android.util.Log; + +import com.gizwits.gizwifisdk.enumration.GizThirdAccountType; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.CommonModule.GosDeploy; +import com.gizwits.opensource.appkit.UserModule.GosUserLoginActivity; +import com.tencent.mm.sdk.modelbase.BaseReq; +import com.tencent.mm.sdk.modelbase.BaseResp; +import com.tencent.mm.sdk.modelmsg.SendAuth; +import com.tencent.mm.sdk.openapi.IWXAPI; +import com.tencent.mm.sdk.openapi.IWXAPIEventHandler; +import com.tencent.mm.sdk.openapi.WXAPIFactory; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + + +public class WXEntryActivity extends GosBaseActivity implements IWXAPIEventHandler { + + private static final String TAG = "WXEntryActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + IWXAPI api = WXAPIFactory.createWXAPI(this, GosDeploy.appConfig_WechatAppID(), true); + api.handleIntent(getIntent(), this); + } + + @Override + public void onReq(BaseReq req) { + Log.i(TAG, "onReq..."); + } + + @Override + public void onResp(BaseResp resp) { + Log.i(TAG, "onResp: " + resp); + String code = null; + switch (resp.errCode) { + case BaseResp.ErrCode.ERR_OK:// 用户同意,只有这种情况的时候code是有效的 + code = ((SendAuth.Resp) resp).code; + Log.i("Apptest", code); + try { + requesUserInfo(code); + } catch (Exception e) { + e.printStackTrace(); + } + break; + case BaseResp.ErrCode.ERR_AUTH_DENIED:// 用户拒绝授权 + Log.i("Apptest", "用户拒绝授权"); + break; + case BaseResp.ErrCode.ERR_USER_CANCEL:// 用户取消 + Log.i("Apptest", "用户取消"); + break; + + default:// 发送返回 + + break; + } + finish(); + } + + public void requesUserInfo(final String code) throws Exception { + final String path = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + GosDeploy.appConfig_WechatAppID() + + "&secret=" + GosDeploy.appConfig_WechatAppSecret() + "&code=" + code + + "&grant_type=authorization_code"; + final android.os.Handler handler = new android.os.Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + Bundle b = msg.getData(); + String newsTemp = b.getString("msg"); + try { + JSONObject jsonObject = new JSONObject(newsTemp); + if (null != jsonObject) { + String openid = jsonObject.getString("openid").toString().trim(); + String access_token = jsonObject.getString("access_token").toString().trim(); + + GosUserLoginActivity.gizThirdAccountType = GizThirdAccountType.GizThirdWeChat; + GosUserLoginActivity.thirdToken = access_token; + GosUserLoginActivity.thirdUid = openid; + + Message msg1 = new Message(); + msg1.what = GosUserLoginActivity.handler_key.THRED_LOGIN.ordinal(); + baseHandler.sendMessage(msg1); + + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + }; + + new Thread(new Runnable() { + @Override + public void run() { + BufferedReader br = null; + try { + URL url = new URL(path); + HttpURLConnection httpconn = (HttpURLConnection) url.openConnection(); + httpconn.setRequestProperty("accept", "*/*"); + httpconn.setDoInput(true); + httpconn.setDoOutput(true); + httpconn.setConnectTimeout(5000); + httpconn.connect(); + int stat = 200; + String msg = ""; + if (stat == 200) { + br = new BufferedReader(new InputStreamReader(httpconn.getInputStream())); + msg = br.readLine(); + Bundle b = new Bundle(); + b.putString("msg", msg); + Message m = new Message(); + m.setData(b); + handler.sendMessage(m); + } else { + msg = "请求失败"; + Log.i(TAG, msg); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + }).start(); + } + +} + diff --git a/src/java/zxing/CaptureActivity.java b/src/java/zxing/CaptureActivity.java new file mode 100644 index 0000000..0a2cbac --- /dev/null +++ b/src/java/zxing/CaptureActivity.java @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * 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 zxing; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.TranslateAnimation; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.gizwits.opensource.appkit.R; +import com.gizwits.opensource.appkit.CommonModule.GosBaseActivity; +import com.gizwits.opensource.appkit.DeviceModule.GosDeviceListFragment; +import com.google.zxing.Result; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.lang.reflect.Field; + +import zxing.camera.CameraManager; +import zxing.decoding.DecodeThread; +import zxing.utils.CaptureActivityHandler; +import zxing.utils.InactivityTimer; + +/** + * This activity opens the camera and does the actual scanning on a background + * thread. It draws a viewfinder to help the user place the barcode correctly, + * shows feedback as the image processing is happening, and then overlays the + * results when a scan is successful. + * + * @author dswitkin@google.com (Daniel Switkin) + * @author Sean Owen + */ +public final class CaptureActivity extends GosBaseActivity implements SurfaceHolder.Callback { + + private static final String TAG = CaptureActivity.class.getSimpleName(); + + private CameraManager cameraManager; + private CaptureActivityHandler handler; + private InactivityTimer inactivityTimer; + + private SurfaceView scanPreview = null; + private RelativeLayout scanContainer; + private RelativeLayout scanCropView; + private ImageView scanLine; + private Button btnCancel; + private ImageView ivReturn; + // private String uid, token, mac, productKey, productSecret; + private String did, passcode, product_key; + private TextView tvDeviceCode; + private boolean isSetting = false; + + /** + * ClassName: Enum handler_key.
+ *
+ * date: 2014-11-26 17:51:10
+ * + * @author Lien + */ + private enum handler_key { + + START_BIND, + SEND_CODE + } + + /** + * The handler. + */ + @SuppressLint("HandlerLeak") + Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + super.handleMessage(msg); + handler_key key = handler_key.values()[msg.what]; + switch (key) { + + case START_BIND: + String[] strings = (String[]) msg.obj; + for (String string : strings) { + GosDeviceListFragment.boundMessage.add(string); + } + finish(); + break; + case SEND_CODE: + String s = (String) msg.obj; + Intent intent = new Intent(); + intent.putExtra("code", s); + setResult(33, intent); + finish(); + break; + + } + } + }; + + private Rect mCropRect = null; + + public Handler getHandler() { + return handler; + } + + public CameraManager getCameraManager() { + return cameraManager; + } + + private boolean isHasSurface = false; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + /** + * 设置为竖屏 + */ + if (getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + setContentView(R.layout.activity_gos_capture); + + scanPreview = (SurfaceView) findViewById(R.id.capture_preview); + scanContainer = (RelativeLayout) findViewById(R.id.capture_container); + scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view); + scanLine = (ImageView) findViewById(R.id.capture_scan_line); + tvDeviceCode = (TextView) findViewById(R.id.tvDeviceCode); + + inactivityTimer = new InactivityTimer(this); + + TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, -1.0f, Animation.RELATIVE_TO_PARENT, + 0.0f); + animation.setDuration(4500); + animation.setRepeatCount(-1); + animation.setRepeatMode(Animation.RESTART); + scanLine.startAnimation(animation); + + btnCancel = (Button) findViewById(R.id.btn_cancel); + ivReturn = (ImageView) findViewById(R.id.iv_return); + OnClickListener myClick = new OnClickListener() { + @Override + public void onClick(View arg0) { + CaptureActivity.this.finish(); + } + }; + btnCancel.setOnClickListener(myClick); + ivReturn.setOnClickListener(myClick); + isSetting = getIntent().getBooleanExtra("isSetting", false); + } + + @Override + public void onResume() { + super.onResume(); + + // CameraManager must be initialized here, not in onCreate(). This is + // necessary because we don't + // want to open the camera driver and measure the screen size if we're + // going to show the help on + // first launch. That led to bugs where the scanning rectangle was the + // wrong size and partially + // off screen. + cameraManager = new CameraManager(getApplication()); + + handler = null; + + if (isHasSurface) { + // The activity was paused but not stopped, so the surface still + // exists. Therefore + // surfaceCreated() won't be called, so init the camera here. + initCamera(scanPreview.getHolder()); + } else { + // Install the callback and wait for surfaceCreated() to init the + // camera. + scanPreview.getHolder().addCallback(this); + } + + inactivityTimer.onResume(); + } + + @Override + public void onPause() { + if (handler != null) { + handler.quitSynchronously(); + handler = null; + } + inactivityTimer.onPause(); + cameraManager.closeDriver(); + if (!isHasSurface) { + scanPreview.getHolder().removeCallback(this); + } + super.onPause(); + } + + @Override + protected void onDestroy() { + inactivityTimer.shutdown(); + super.onDestroy(); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + if (holder == null) { + Log.i(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!"); + } + if (!isHasSurface) { + isHasSurface = true; + initCamera(holder); + } + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + isHasSurface = false; + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + /** + * A valid barcode has been found, so give an indication of success and show + * the results. + * + * @param rawResult The contents of the barcode. + * @param bundle The extras + */ + public void handleDecode(Result rawResult, Bundle bundle) { + String text = rawResult.getText(); + boolean isJson = false; + try { + JSONObject jsonObject = new JSONObject(text); + isJson = true; + } catch(JSONException e) { + e.printStackTrace(); + } + Message msg = new Message(); + if (isSetting) { + if (isJson) { + msg.what = handler_key.SEND_CODE.ordinal(); + msg.obj = text; + mHandler.sendMessage(msg); + } else { + Toast.makeText(this, getString(R.string.code_invalid), Toast.LENGTH_LONG).show(); + } + } else { + if (text.contains("product_key=") && text.contains("did=") && text.contains("passcode=")) { + inactivityTimer.onActivity(); + product_key = getParamFomeUrl(text, "product_key"); + did = getParamFomeUrl(text, "did"); + passcode = getParamFomeUrl(text, "passcode"); + String[] strings = {did, passcode}; + msg.what = handler_key.START_BIND.ordinal(); + msg.obj = strings; + mHandler.sendMessage(msg); + Log.e(TAG, "handleDecode-------: " + strings); + } else if (text.contains("type=") && text.contains("code=")) { + //type=xxx & code=xxx + String[] split = text.split("&"); + String[] split2 = split[1].split("="); + final String code = split2[1]; + String[] strings = {"", "", code}; + + msg.what = handler_key.START_BIND.ordinal(); + msg.obj = strings; + mHandler.sendMessage(msg); + } else { + // handler = new CaptureActivityHandler(this, cameraManager, + // DecodeThread.ALL_MODE); + String[] strings = {text}; + msg.what = handler_key.START_BIND.ordinal(); + msg.obj = strings; + mHandler.sendMessage(msg); + } + } + } + + + private String getParamFomeUrl(String url, String param) { + String product_key = ""; + int startindex = url.indexOf(param + "="); + startindex += (param.length() + 1); + String subString = url.substring(startindex); + int endindex = subString.indexOf("&"); + if (endindex == -1) { + product_key = subString; + } else { + product_key = subString.substring(0, endindex); + } + return product_key; + } + + private void initCamera(SurfaceHolder surfaceHolder) { + if (surfaceHolder == null) { + throw new IllegalStateException("No SurfaceHolder provided"); + } + if (cameraManager.isOpen()) { + Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?"); + return; + } + try { + cameraManager.openDriver(surfaceHolder); + // Creating the handler starts the preview, which can also throw a + // RuntimeException. + if (handler == null) { + handler = new CaptureActivityHandler(this, cameraManager, DecodeThread.ALL_MODE); + } + + initCrop(); + } catch(IOException ioe) { + Log.w(TAG, ioe); + displayFrameworkBugMessageAndExit(); + } catch(RuntimeException e) { + // Barcode Scanner has seen crashes in the wild of this variety: + // java.?lang.?RuntimeException: Fail to connect to camera service + Log.w(TAG, "Unexpected error initializing camera", e); + displayFrameworkBugMessageAndExit(); + } + } + + private void displayFrameworkBugMessageAndExit() { + // camera error + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.app_name)); + String camera_error = getText(R.string.camera_error).toString(); + builder.setMessage(camera_error); + String shure = getText(R.string.besure).toString(); + builder.setPositiveButton(shure, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() { + + @Override + public void onCancel(DialogInterface dialog) { + finish(); + } + }); + builder.show(); + } + + public void restartPreviewAfterDelay(long delayMS) { + if (handler != null) { + handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS); + } + } + + public Rect getCropRect() { + return mCropRect; + } + + /** + * 初始化截取的矩形区域 + */ + private void initCrop() { + int cameraWidth = cameraManager.getCameraResolution().y; + int cameraHeight = cameraManager.getCameraResolution().x; + + /** 获取布局中扫描框的位置信息 */ + int[] location = new int[2]; + scanCropView.getLocationInWindow(location); + + int cropLeft = location[0]; + int cropTop = location[1] - getStatusBarHeight(); + + int cropWidth = scanCropView.getWidth(); + int cropHeight = scanCropView.getHeight(); + + /** 获取布局容器的宽高 */ + int containerWidth = scanContainer.getWidth(); + int containerHeight = scanContainer.getHeight(); + + /** 计算最终截取的矩形的左上角顶点x坐标 */ + int x = cropLeft * cameraWidth / containerWidth; + /** 计算最终截取的矩形的左上角顶点y坐标 */ + int y = cropTop * cameraHeight / containerHeight; + + /** 计算最终截取的矩形的宽度 */ + int width = cropWidth * cameraWidth / containerWidth; + /** 计算最终截取的矩形的高度 */ + int height = cropHeight * cameraHeight / containerHeight; + + /** 生成最终的截取的矩形 */ + mCropRect = new Rect(x, y, width + x, height + y); + } + + private int getStatusBarHeight() { + try { + Class c = Class.forName("com.android.internal.R$dimen"); + Object obj = c.newInstance(); + Field field = c.getField("status_bar_height"); + int x = Integer.parseInt(field.get(obj).toString()); + return getResources().getDimensionPixelSize(x); + } catch(Exception e) { + e.printStackTrace(); + } + return 0; + } + +} \ No newline at end of file diff --git a/src/java/zxing/camera/AutoFocusManager.java b/src/java/zxing/camera/AutoFocusManager.java new file mode 100644 index 0000000..914bfc8 --- /dev/null +++ b/src/java/zxing/camera/AutoFocusManager.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2012 ZXing authors + * + * 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 zxing.camera; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.RejectedExecutionException; +import android.annotation.SuppressLint; +import android.content.Context; +import android.hardware.*; +import android.os.AsyncTask; +import android.os.Build; +import android.util.Log; + +public class AutoFocusManager implements Camera.AutoFocusCallback { + + private static final String TAG = AutoFocusManager.class.getSimpleName(); + + private static final long AUTO_FOCUS_INTERVAL_MS = 2000L; + private static final Collection FOCUS_MODES_CALLING_AF; + + static { + FOCUS_MODES_CALLING_AF = new ArrayList(2); + FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO); + FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO); + } + + private boolean stopped; + private boolean focusing; + private final boolean useAutoFocus; + private final Camera camera; + private AsyncTask outstandingTask; + + public AutoFocusManager(Context context, Camera camera) { + this.camera = camera; + String currentFocusMode = camera.getParameters().getFocusMode(); + useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode); + Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus); + start(); + } + + @Override + public synchronized void onAutoFocus(boolean success, Camera theCamera) { + focusing = false; + autoFocusAgainLater(); + } + + @SuppressLint("NewApi") + private synchronized void autoFocusAgainLater() { + if (!stopped && outstandingTask == null) { + AutoFocusTask newTask = new AutoFocusTask(); + try { + if (Build.VERSION.SDK_INT >= 11) { + newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + newTask.execute(); + } + outstandingTask = newTask; + } catch (RejectedExecutionException ree) { + Log.w(TAG, "Could not request auto focus", ree); + } + } + } + + public synchronized void start() { + if (useAutoFocus) { + outstandingTask = null; + if (!stopped && !focusing) { + try { + camera.autoFocus(this); + focusing = true; + } catch (RuntimeException re) { + // Have heard RuntimeException reported in Android 4.0.x+; + // continue? + Log.w(TAG, "Unexpected exception while focusing", re); + // Try again later to keep cycle going + autoFocusAgainLater(); + } + } + } + } + + private synchronized void cancelOutstandingTask() { + if (outstandingTask != null) { + if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) { + outstandingTask.cancel(true); + } + outstandingTask = null; + } + } + + public synchronized void stop() { + stopped = true; + if (useAutoFocus) { + cancelOutstandingTask(); + // Doesn't hurt to call this even if not focusing + try { + camera.cancelAutoFocus(); + } catch (RuntimeException re) { + // Have heard RuntimeException reported in Android 4.0.x+; + // continue? + Log.w(TAG, "Unexpected exception while cancelling focusing", re); + } + } + } + + private final class AutoFocusTask extends AsyncTask { + @Override + protected Object doInBackground(Object... voids) { + try { + Thread.sleep(AUTO_FOCUS_INTERVAL_MS); + } catch (InterruptedException e) { + // continue + } + start(); + return null; + } + } + +} diff --git a/src/java/zxing/camera/CameraConfigurationManager.java b/src/java/zxing/camera/CameraConfigurationManager.java new file mode 100644 index 0000000..53a8c50 --- /dev/null +++ b/src/java/zxing/camera/CameraConfigurationManager.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * 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 zxing.camera; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Point; +import android.hardware.Camera; +import android.util.Log; +import android.view.Display; +import android.view.WindowManager; + +public final class CameraConfigurationManager { + + private static final String TAG = "CameraConfiguration"; + + private static final int MIN_PREVIEW_PIXELS = 480 * 320; + private static final double MAX_ASPECT_DISTORTION = 0.15; + + private final Context context; + + // 屏幕分辨率 + private Point screenResolution; + // 相机分辨率 + private Point cameraResolution; + + public CameraConfigurationManager(Context context) { + this.context = context; + } + + public void initFromCameraParameters(Camera camera) { + Camera.Parameters parameters = camera.getParameters(); + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + Point theScreenResolution = new Point(); + theScreenResolution = getDisplaySize(display); + + screenResolution = theScreenResolution; + Log.i(TAG, "Screen resolution: " + screenResolution); + + /** 因为换成了竖屏显示,所以不替换屏幕宽高得出的预览图是变形的 */ + Point screenResolutionForCamera = new Point(); + screenResolutionForCamera.x = screenResolution.x; + screenResolutionForCamera.y = screenResolution.y; + + if (screenResolution.x < screenResolution.y) { + screenResolutionForCamera.x = screenResolution.y; + screenResolutionForCamera.y = screenResolution.x; + } + + cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera); + Log.i(TAG, "Camera resolution x: " + cameraResolution.x); + Log.i(TAG, "Camera resolution y: " + cameraResolution.y); + } + + @SuppressLint("NewApi") + private Point getDisplaySize(final Display display) { + final Point point = new Point(); + try { + display.getSize(point); + } catch (NoSuchMethodError ignore) { + point.x = display.getWidth(); + point.y = display.getHeight(); + } + return point; + } + + public void setDesiredCameraParameters(Camera camera, boolean safeMode) { + Camera.Parameters parameters = camera.getParameters(); + + if (parameters == null) { + Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration."); + return; + } + + Log.i(TAG, "Initial camera parameters: " + parameters.flatten()); + + if (safeMode) { + Log.w(TAG, "In camera config safe mode -- most settings will not be honored"); + } + + parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); + camera.setParameters(parameters); + + Camera.Parameters afterParameters = camera.getParameters(); + Camera.Size afterSize = afterParameters.getPreviewSize(); + if (afterSize != null && (cameraResolution.x != afterSize.width || cameraResolution.y != afterSize.height)) { + Log.w(TAG, "Camera said it supported preview size " + cameraResolution.x + 'x' + cameraResolution.y + ", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height); + cameraResolution.x = afterSize.width; + cameraResolution.y = afterSize.height; + } + + /** 设置相机预览为竖屏 */ + String model=android.os.Build.MODEL; + if("Nexus 5X".equals(model)){ + camera.setDisplayOrientation(270); + }else{ + camera.setDisplayOrientation(90); + } + + } + + public Point getCameraResolution() { + return cameraResolution; + } + + public Point getScreenResolution() { + return screenResolution; + } + + /** + * 从相机支持的分辨率中计算出最适合的预览界面尺寸 + * + * @param parameters + * @param screenResolution + * @return + */ + private Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) { + List rawSupportedSizes = parameters.getSupportedPreviewSizes(); + if (rawSupportedSizes == null) { + Log.w(TAG, "Device returned no supported preview sizes; using default"); + Camera.Size defaultSize = parameters.getPreviewSize(); + return new Point(defaultSize.width, defaultSize.height); + } + + // Sort by size, descending + List supportedPreviewSizes = new ArrayList(rawSupportedSizes); + Collections.sort(supportedPreviewSizes, new Comparator() { + @Override + public int compare(Camera.Size a, Camera.Size b) { + int aPixels = a.height * a.width; + int bPixels = b.height * b.width; + if (bPixels < aPixels) { + return -1; + } + if (bPixels > aPixels) { + return 1; + } + return 0; + } + }); + + if (Log.isLoggable(TAG, Log.INFO)) { + StringBuilder previewSizesString = new StringBuilder(); + for (Camera.Size supportedPreviewSize : supportedPreviewSizes) { + previewSizesString.append(supportedPreviewSize.width).append('x').append(supportedPreviewSize.height).append(' '); + } + Log.i(TAG, "Supported preview sizes: " + previewSizesString); + } + + double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y; + + // Remove sizes that are unsuitable + Iterator it = supportedPreviewSizes.iterator(); + while (it.hasNext()) { + Camera.Size supportedPreviewSize = it.next(); + int realWidth = supportedPreviewSize.width; + int realHeight = supportedPreviewSize.height; + if (realWidth * realHeight < MIN_PREVIEW_PIXELS) { + it.remove(); + continue; + } + + boolean isCandidatePortrait = realWidth < realHeight; + int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth; + int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight; + + double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight; + double distortion = Math.abs(aspectRatio - screenAspectRatio); + if (distortion > MAX_ASPECT_DISTORTION) { + it.remove(); + continue; + } + + if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) { + Point exactPoint = new Point(realWidth, realHeight); + Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint); + return exactPoint; + } + } + + // If no exact match, use largest preview size. This was not a great + // idea on older devices because + // of the additional computation needed. We're likely to get here on + // newer Android 4+ devices, where + // the CPU is much more powerful. + if (!supportedPreviewSizes.isEmpty()) { + Camera.Size largestPreview = supportedPreviewSizes.get(0); + Point largestSize = new Point(largestPreview.width, largestPreview.height); + Log.i(TAG, "Using largest suitable preview size: " + largestSize); + return largestSize; + } + + // If there is nothing at all suitable, return current preview size + Camera.Size defaultPreview = parameters.getPreviewSize(); + Point defaultSize = new Point(defaultPreview.width, defaultPreview.height); + Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize); + + return defaultSize; + } +} diff --git a/src/java/zxing/camera/CameraManager.java b/src/java/zxing/camera/CameraManager.java new file mode 100644 index 0000000..9286c5b --- /dev/null +++ b/src/java/zxing/camera/CameraManager.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * 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 zxing.camera; + +import java.io.IOException; + +import zxing.camera.open.OpenCameraInterface; +import android.content.Context; +import android.graphics.Point; +import android.hardware.Camera; +import android.hardware.Camera.Size; +import android.os.Handler; +import android.util.Log; +import android.view.SurfaceHolder; + + +/** + * This object wraps the Camera service object and expects to be the only one + * talking to it. The implementation encapsulates the steps needed to take + * preview-sized images, which are used for both preview and decoding. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public class CameraManager { + + private static final String TAG = CameraManager.class.getSimpleName(); + + private final Context context; + private final CameraConfigurationManager configManager; + private Camera camera; + private AutoFocusManager autoFocusManager; + + private boolean initialized; + private boolean previewing; + private int requestedCameraId = -1; + /** + * Preview frames are delivered here, which we pass on to the registered + * handler. Make sure to clear the handler so it will only receive one + * message. + */ + private final PreviewCallback previewCallback; + + public CameraManager(Context context) { + this.context = context; + this.configManager = new CameraConfigurationManager(context); + previewCallback = new PreviewCallback(configManager); + } + + /** + * Opens the camera driver and initializes the hardware parameters. + * + * @param holder + * The surface object which the camera will draw preview frames + * into. + * @throws IOException + * Indicates the camera driver failed to open. + */ + public synchronized void openDriver(SurfaceHolder holder) throws IOException { + Camera theCamera = camera; + if (theCamera == null) { + + if (requestedCameraId >= 0) { + theCamera = OpenCameraInterface.open(requestedCameraId); + } else { + theCamera = OpenCameraInterface.open(); + } + + if (theCamera == null) { + throw new IOException(); + } + camera = theCamera; + } + theCamera.setPreviewDisplay(holder); + + if (!initialized) { + initialized = true; + configManager.initFromCameraParameters(theCamera); + } + + Camera.Parameters parameters = theCamera.getParameters(); + String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save + // these, + // temporarily + try { + configManager.setDesiredCameraParameters(theCamera, false); + } catch (RuntimeException re) { + // Driver failed + Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters"); + Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened); + // Reset: + if (parametersFlattened != null) { + parameters = theCamera.getParameters(); + parameters.unflatten(parametersFlattened); + try { + theCamera.setParameters(parameters); + configManager.setDesiredCameraParameters(theCamera, true); + } catch (RuntimeException re2) { + // Well, darn. Give up + Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration"); + } + } + } + + } + + public synchronized boolean isOpen() { + return camera != null; + } + + /** + * Closes the camera driver if still in use. + */ + public synchronized void closeDriver() { + if (camera != null) { + camera.release(); + camera = null; + // Make sure to clear these each time we close the camera, so that + // any scanning rect + // requested by intent is forgotten. + } + } + + /** + * Asks the camera hardware to begin drawing preview frames to the screen. + */ + public synchronized void startPreview() { + Camera theCamera = camera; + if (theCamera != null && !previewing) { + theCamera.startPreview(); + previewing = true; + autoFocusManager = new AutoFocusManager(context, camera); + } + } + + /** + * Tells the camera to stop drawing preview frames. + */ + public synchronized void stopPreview() { + if (autoFocusManager != null) { + autoFocusManager.stop(); + autoFocusManager = null; + } + if (camera != null && previewing) { + camera.stopPreview(); + previewCallback.setHandler(null, 0); + previewing = false; + } + } + + /** + * A single preview frame will be returned to the handler supplied. The data + * will arrive as byte[] in the message.obj field, with width and height + * encoded as message.arg1 and message.arg2, respectively. + * + * @param handler + * The handler to send the message to. + * @param message + * The what field of the message to be sent. + */ + public synchronized void requestPreviewFrame(Handler handler, int message) { + Camera theCamera = camera; + if (theCamera != null && previewing) { + previewCallback.setHandler(handler, message); + theCamera.setOneShotPreviewCallback(previewCallback); + } + } + + /** + * Allows third party apps to specify the camera ID, rather than determine + * it automatically based on available cameras and their orientation. + * + * @param cameraId + * camera ID of the camera to use. A negative value means + * "no preference". + */ + public synchronized void setManualCameraId(int cameraId) { + requestedCameraId = cameraId; + } + + /** + * 获取相机分辨率 + * + * @return + */ + public Point getCameraResolution() { + return configManager.getCameraResolution(); + } + + public Size getPreviewSize() { + if (null != camera) { + return camera.getParameters().getPreviewSize(); + } + return null; + } +} diff --git a/src/java/zxing/camera/PreviewCallback.java b/src/java/zxing/camera/PreviewCallback.java new file mode 100644 index 0000000..7333d87 --- /dev/null +++ b/src/java/zxing/camera/PreviewCallback.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * 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 zxing.camera; + +import android.graphics.Point; +import android.hardware.Camera; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +public class PreviewCallback implements Camera.PreviewCallback { + + private static final String TAG = PreviewCallback.class.getSimpleName(); + + private final CameraConfigurationManager configManager; + private Handler previewHandler; + private int previewMessage; + + public PreviewCallback(CameraConfigurationManager configManager) { + this.configManager = configManager; + } + + public void setHandler(Handler previewHandler, int previewMessage) { + this.previewHandler = previewHandler; + this.previewMessage = previewMessage; + } + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + Point cameraResolution = configManager.getCameraResolution(); + Handler thePreviewHandler = previewHandler; + if (cameraResolution != null && thePreviewHandler != null) { + Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x, cameraResolution.y, + data); + message.sendToTarget(); + previewHandler = null; + } else { + Log.d(TAG, "Got preview callback, but no handler or resolution available"); + } + } + +} diff --git a/src/java/zxing/camera/open/OpenCameraInterface.java b/src/java/zxing/camera/open/OpenCameraInterface.java new file mode 100644 index 0000000..553964e --- /dev/null +++ b/src/java/zxing/camera/open/OpenCameraInterface.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2012 ZXing authors + * + * 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 zxing.camera.open; + +import android.hardware.Camera; +import android.util.Log; + +public class OpenCameraInterface { + + private static final String TAG = OpenCameraInterface.class.getName(); + + /** + * Opens the requested camera with {@link Camera#open(int)}, if one exists. + * + * @param cameraId + * camera ID of the camera to use. A negative value means + * "no preference" + * @return handle to {@link Camera} that was opened + */ + public static Camera open(int cameraId) { + + int numCameras = Camera.getNumberOfCameras(); + if (numCameras == 0) { + Log.w(TAG, "No cameras!"); + return null; + } + + boolean explicitRequest = cameraId >= 0; + + if (!explicitRequest) { + // Select a camera if no explicit camera requested + int index = 0; + while (index < numCameras) { + Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); + Camera.getCameraInfo(index, cameraInfo); + if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { + break; + } + index++; + } + + cameraId = index; + } + + Camera camera; + if (cameraId < numCameras) { + Log.i(TAG, "Opening camera #" + cameraId); + camera = Camera.open(cameraId); + } else { + if (explicitRequest) { + Log.w(TAG, "Requested camera does not exist: " + cameraId); + camera = null; + } else { + Log.i(TAG, "No camera facing back; returning camera #0"); + camera = Camera.open(0); + } + } + + return camera; + } + + /** + * Opens a rear-facing camera with {@link Camera#open(int)}, if one exists, + * or opens camera 0. + * + * @return handle to {@link Camera} that was opened + */ + public static Camera open() { + return open(-1); + } + +} diff --git a/src/java/zxing/decoding/DecodeFormatManager.java b/src/java/zxing/decoding/DecodeFormatManager.java new file mode 100644 index 0000000..3ddebe9 --- /dev/null +++ b/src/java/zxing/decoding/DecodeFormatManager.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * 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 zxing.decoding; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.Set; + +import com.google.zxing.BarcodeFormat; + +public class DecodeFormatManager { + + // 1D解码 + private static final Set PRODUCT_FORMATS; + private static final Set INDUSTRIAL_FORMATS; + private static final Set ONE_D_FORMATS; + + // 二维码解码 + private static final Set QR_CODE_FORMATS; + + static { + PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A, BarcodeFormat.UPC_E, BarcodeFormat.EAN_13, BarcodeFormat.EAN_8, BarcodeFormat.RSS_14, BarcodeFormat.RSS_EXPANDED); + INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39, BarcodeFormat.CODE_93, BarcodeFormat.CODE_128, BarcodeFormat.ITF, BarcodeFormat.CODABAR); + ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS); + ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS); + + QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE); + } + + public static Collection getQrCodeFormats() { + return QR_CODE_FORMATS; + } + + public static Collection getBarCodeFormats() { + return ONE_D_FORMATS; + } +} diff --git a/src/java/zxing/decoding/DecodeHandler.java b/src/java/zxing/decoding/DecodeHandler.java new file mode 100644 index 0000000..c95ea87 --- /dev/null +++ b/src/java/zxing/decoding/DecodeHandler.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * 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 zxing.decoding; + +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.hardware.Camera.Size; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.gizwits.opensource.appkit.R; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.PlanarYUVLuminanceSource; +import com.google.zxing.ReaderException; +import com.google.zxing.Result; +import com.google.zxing.common.HybridBinarizer; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +import zxing.CaptureActivity; + + +public class DecodeHandler extends Handler { + + private final CaptureActivity activity; + private final MultiFormatReader multiFormatReader; + private boolean running = true; + + public DecodeHandler(CaptureActivity activity, Map hints) { + multiFormatReader = new MultiFormatReader(); + multiFormatReader.setHints(hints); + this.activity = activity; + } + + @Override + public void handleMessage(Message message) { + if (!running) { + return; + } + switch (message.what) { + case R.id.decode: + decode((byte[]) message.obj, message.arg1, message.arg2); + break; + case R.id.quit: + running = false; + Looper.myLooper().quit(); + break; + } + } + + /** + * Decode the data within the viewfinder rectangle, and time how long it + * took. For efficiency, reuse the same reader objects from one decode to + * the next. + * + * @param data + * The YUV preview frame. + * @param width + * The width of the preview frame. + * @param height + * The height of the preview frame. + */ + private void decode(byte[] data, int width, int height) { + Size size = activity.getCameraManager().getPreviewSize(); + + // 这里需要将获取的data翻转一下,因为相机默认拿的的横屏的数据 + byte[] rotatedData = new byte[data.length]; + for (int y = 0; y < size.height; y++) { + for (int x = 0; x < size.width; x++) + rotatedData[x * size.height + size.height - y - 1] = data[x + y * size.width]; + } + + // 宽高也要调整 + int tmp = size.width; + size.width = size.height; + size.height = tmp; + + Result rawResult = null; + PlanarYUVLuminanceSource source = buildLuminanceSource(rotatedData, size.width, size.height); + if (source != null) { + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + try { + rawResult = multiFormatReader.decodeWithState(bitmap); + } catch (ReaderException re) { + // continue + } finally { + multiFormatReader.reset(); + } + } + + Handler handler = activity.getHandler(); + if (rawResult != null) { + // Don't log the barcode contents for security. + if (handler != null) { + Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult); + Bundle bundle = new Bundle(); + bundleThumbnail(source, bundle); + message.setData(bundle); + message.sendToTarget(); + } + } else { + if (handler != null) { + Message message = Message.obtain(handler, R.id.decode_failed); + message.sendToTarget(); + } + } + + } + + private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) { + int[] pixels = source.renderThumbnail(); + int width = source.getThumbnailWidth(); + int height = source.getThumbnailHeight(); + Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out); + bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray()); + } + + /** + * A factory method to build the appropriate LuminanceSource object based on + * the format of the preview buffers, as described by Camera.Parameters. + * + * @param data + * A preview frame. + * @param width + * The width of the image. + * @param height + * The height of the image. + * @return A PlanarYUVLuminanceSource instance. + */ + public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) { + Rect rect = activity.getCropRect(); + if (rect == null) { + return null; + } + // Go ahead and assume it's YUV rather than die. + return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect.height(), + false); + } + +} diff --git a/src/java/zxing/decoding/DecodeThread.java b/src/java/zxing/decoding/DecodeThread.java new file mode 100644 index 0000000..140ef38 --- /dev/null +++ b/src/java/zxing/decoding/DecodeThread.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * 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 zxing.decoding; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import zxing.CaptureActivity; +import android.os.Handler; +import android.os.Looper; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.DecodeHintType; + +/** + * This thread does all the heavy lifting of decoding the images. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public class DecodeThread extends Thread { + + public static final String BARCODE_BITMAP = "barcode_bitmap"; + + public static final int BARCODE_MODE = 0X100; + public static final int QRCODE_MODE = 0X200; + public static final int ALL_MODE = 0X300; + + private final CaptureActivity activity; + private final Map hints; + private Handler handler; + private final CountDownLatch handlerInitLatch; + + public DecodeThread(CaptureActivity activity, int decodeMode) { + + this.activity = activity; + handlerInitLatch = new CountDownLatch(1); + + hints = new EnumMap(DecodeHintType.class); + + Collection decodeFormats = new ArrayList(); + decodeFormats.addAll(EnumSet.of(BarcodeFormat.AZTEC)); + decodeFormats.addAll(EnumSet.of(BarcodeFormat.PDF_417)); + + switch (decodeMode) { + case BARCODE_MODE: + decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); + break; + + case QRCODE_MODE: + decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); + break; + + case ALL_MODE: + decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); + decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); + break; + + default: + break; + } + + hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); + } + + public Handler getHandler() { + try { + handlerInitLatch.await(); + } catch (InterruptedException ie) { + // continue? + } + return handler; + } + + @Override + public void run() { + Looper.prepare(); + handler = new DecodeHandler(activity, hints); + handlerInitLatch.countDown(); + Looper.loop(); + } + +} diff --git a/src/java/zxing/utils/CaptureActivityHandler.java b/src/java/zxing/utils/CaptureActivityHandler.java new file mode 100644 index 0000000..fc9d696 --- /dev/null +++ b/src/java/zxing/utils/CaptureActivityHandler.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * 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 zxing.utils; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; + +import com.gizwits.opensource.appkit.R; +import com.google.zxing.Result; + +import zxing.CaptureActivity; +import zxing.camera.CameraManager; +import zxing.decoding.DecodeThread; + + +/** + * This class handles all the messaging which comprises the state machine for + * capture. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public class CaptureActivityHandler extends Handler { + + private final CaptureActivity activity; + private final DecodeThread decodeThread; + private final CameraManager cameraManager; + private State state; + + private enum State { + PREVIEW, SUCCESS, DONE + } + + public CaptureActivityHandler(CaptureActivity activity, CameraManager cameraManager, int decodeMode) { + this.activity = activity; + decodeThread = new DecodeThread(activity, decodeMode); + decodeThread.start(); + state = State.SUCCESS; + + // Start ourselves capturing previews and decoding. + this.cameraManager = cameraManager; + cameraManager.startPreview(); + restartPreviewAndDecode(); + } + + @Override + public void handleMessage(Message message) { + switch (message.what) { + case R.id.restart_preview: + restartPreviewAndDecode(); + break; + case R.id.decode_succeeded: + state = State.SUCCESS; + Bundle bundle = message.getData(); + + activity.handleDecode((Result) message.obj, bundle); + break; + case R.id.decode_failed: + // We're decoding as fast as possible, so when one decode fails, + // start another. + state = State.PREVIEW; + cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); + break; + case R.id.return_scan_result: + activity.setResult(Activity.RESULT_OK, (Intent) message.obj); + activity.finish(); + break; + } + } + + public void quitSynchronously() { + state = State.DONE; + cameraManager.stopPreview(); + Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit); + quit.sendToTarget(); + try { + // Wait at most half a second; should be enough time, and onPause() + // will timeout quickly + decodeThread.join(500L); + } catch (InterruptedException e) { + // continue + } + + // Be absolutely sure we don't send any queued up messages + removeMessages(R.id.decode_succeeded); + removeMessages(R.id.decode_failed); + } + + private void restartPreviewAndDecode() { + if (state == State.SUCCESS) { + state = State.PREVIEW; + cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); + } + } + +} diff --git a/src/java/zxing/utils/InactivityTimer.java b/src/java/zxing/utils/InactivityTimer.java new file mode 100644 index 0000000..c26733a --- /dev/null +++ b/src/java/zxing/utils/InactivityTimer.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * 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 zxing.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.BatteryManager; +import android.os.Build; +import android.util.Log; + +/** + * Finishes an activity after a period of inactivity if the device is on battery + * power. + */ +public class InactivityTimer { + + private static final String TAG = InactivityTimer.class.getSimpleName(); + + private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L; + + private Activity activity; + private BroadcastReceiver powerStatusReceiver; + private boolean registered; + private AsyncTask inactivityTask; + + public InactivityTimer(Activity activity) { + this.activity = activity; + powerStatusReceiver = new PowerStatusReceiver(); + registered = false; + onActivity(); + } + + @SuppressLint("NewApi") + public synchronized void onActivity() { + cancel(); + inactivityTask = new InactivityAsyncTask(); + if (Build.VERSION.SDK_INT >= 11) { + inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + inactivityTask.execute(); + } + } + + public synchronized void onPause() { + cancel(); + if (registered) { + activity.unregisterReceiver(powerStatusReceiver); + registered = false; + } else { + Log.w(TAG, "PowerStatusReceiver was never registered?"); + } + } + + public synchronized void onResume() { + if (registered) { + Log.w(TAG, "PowerStatusReceiver was already registered?"); + } else { + activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + registered = true; + } + onActivity(); + } + + private synchronized void cancel() { + AsyncTask task = inactivityTask; + if (task != null) { + task.cancel(true); + inactivityTask = null; + } + } + + public void shutdown() { + cancel(); + } + + private class PowerStatusReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { + // 0 indicates that we're on battery + boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0; + if (onBatteryNow) { + InactivityTimer.this.onActivity(); + } else { + InactivityTimer.this.cancel(); + } + } + } + } + + private class InactivityAsyncTask extends AsyncTask { + @Override + protected Object doInBackground(Object... objects) { + try { + Thread.sleep(INACTIVITY_DELAY_MS); + Log.i(TAG, "Finishing activity due to inactivity"); + activity.finish(); + } catch (InterruptedException e) { + // continue without killing + } + return null; + } + } + +} diff --git a/src/res/.DS_Store b/src/res/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cfe1ba1121823fedaf3703eac7390ec489e4c2af GIT binary patch literal 12292 zcmeGiZHOCHaNad-lWVV+eq66#LNJIey+U$HlloB_(-Tdr^lXlLXIroN*t=W0*-i6t z>D@IF3R3Wg)IWX{iq?W478InQNTs5siXix-R}@6Se=1ZI1%K6fZ#SELyPI5Wk8-v9 zV0YfWnR)wWW@q-z>;eFZm$N~D%>dxWgF^3efDR9UZy8<~8pYGY(iY(e!D9#y?0W%H zP{AV&5(pM*XJDaepaT~~?dQT{1!SSX*>4*hhY1|bgD7Su^Jz&*Bl)N4yd)M&fxwSm zFX>q1TD)Yb+tayhdDn_=@5)uHSFTyvv$m&qUC;Ur8#j!4SEo~%qvHjoEN6Esl2V9E zW#Qm>LChxesf;L(50`}FrKC75jCxm@NcRib=Nm&qQ+cFW(->gWJy8$@na#IvY^*4h zhDW{K#Y{nwq(P-9mPAD!F9uNvegcknckyN3O zlE;Pk)L|)=7NmW0Tq%{5+_0EYWOe1;Y+Ae=EC_T;|E}LvOZ#Jc>mBM}*u3CZI{^OJ z+pn^|+e?OIMHW2%*r1B^pu25_$KYu=07qdOUV*dlK70aS!Vho*{vk_=m)uXbk}%mx zc9AE^Gh{y*A|vEEl2IqV{tu%<%Biad-Jp~_0M z6oaVjIPRn52xA(osZeDHqOt?g?o6}{g|NFLpO29PiK);zI~s5_VAa5*IMg!tlg5L| zjFQVU){dXX=AzFj0|VJ|2{V!F)stuC3v<(F{}X+F!mu6}TUN{UPbLepq{!pA4jMYT zZS!0`(@jW9M$L3t9C{ZyUcbp2_U7c~bVW{nJ2!_xTU#!^*Umk1imtCVIXI1x)AS}w zutJl9DNvvcC0=IIi+H2V9BsN%)G7h+RlO2$ooICcHL*OL#4I~mN|nmRc&c!aUJa&7 z6KSnKq$rZ!Po)oF!iW-%)u$)RUOIjdCSw0clv^CVS-+wF0CM!oB1 zX2Q{MpD!2*R{MN2(P*I07Y=Q&Rz2?C2ZB2jM{-lsGbgGqyus88M0<1KBfz&ac*zNQ zOXZFYo9xRSdZFO%t##0<2(6qnN*u--j-lK!s4CVUvnzL;Qn7lu1M3}Hc|HG|j(+y+6aYh056zX%D46+0!F)m6N6$L1ojPj?+C>-qqGfXHF>GOpmJ8s)B zoREgN_+dTxH!lPC^sMdeS+{=u#ycDrjTK)@J$GJf!1ECo+Y5*9v0f8ZbVe z*z{nyNxiP02@RH zf?GJZVK-*OvB3Or-U6hJsJ!`3eSzk&p)wlrtzXZCn^84P*_?_qC|t&=?CxkXYp2Pq zlMsZU$*{Q1<_v4g!^;bwZgisO%S zh>+t|LE|lKHpE+u)cH&?(`_zNm<&V95=O&V=ogrQA~ZGc?~fR^qqk-ti=c)rY1@A$tlHQlRk!Zv z?%teTFFV+#>X>`mrRcTG^r-}WPpbcsU{2MOa0re;4PJxua1lO(Z{TP63vQAwEmiL$ z+ewtfNP_GkPqF_K=0 z(^%JIa?>ueo8qo@g1#_8f|Hl|r8jXMEvOCB*Q + + + + + \ No newline at end of file diff --git a/src/res/anim/in_from_right.xml b/src/res/anim/in_from_right.xml new file mode 100644 index 0000000..fe65b4e --- /dev/null +++ b/src/res/anim/in_from_right.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/res/anim/out_to_left.xml b/src/res/anim/out_to_left.xml new file mode 100644 index 0000000..79ea6ef --- /dev/null +++ b/src/res/anim/out_to_left.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/res/anim/out_to_right.xml b/src/res/anim/out_to_right.xml new file mode 100644 index 0000000..d4504cf --- /dev/null +++ b/src/res/anim/out_to_right.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/src/res/drawable-hdpi/launch.png b/src/res/drawable-hdpi/launch.png new file mode 100644 index 0000000000000000000000000000000000000000..9f9f7c31c6ca80ba57a02d8da2e3f466c12a76e6 GIT binary patch literal 35487 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
^eZSRb%i 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 YgVyL6Up)J&;ebD7c@4Qr8S~Kp2Nro;zW@LL literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/.DS_Store b/src/res/drawable-xhdpi/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a49a8d723843a239405bc5ab76e252cc24ccd697 GIT binary patch literal 6148 zcmeH~yKWRQ6o!w(A`MyPg4h7%lvI(ZX+}{}P}9(bnayPplU;II(N2TJBjgqGMmz#N z4IO;v*btB6LC{1|kNXbxGU8d2sm#Dl<%66M&lx_A{LE(aEkZs8qkSLAdwSb9 zmX_Exmg~sUTtu<*HsUJa@NDV!&qN;1qV}tdwx*Z4MW4jT6_~FPW}}C>-Y?T=^zNZ2 zjI3sys&GR|_4>z=7DW`rmYkxoj`hH}&MDV6gGbcY%)#M+{%BCd`cDR#TGX5m@-UA* zo^|@w8JyWy`1g5W-g?+aU}nt237QP*IQ|li{|T+niR}#a{E4Np{w^=lEc(^E=tiZiez>Rj_?Cvn6aJJqUoSwBM s=^aT;+jZU>ge)A#R?wsPImwK7r55m2@SXS6VEISDWXM@o;8qp*1>J!Qz5oCK literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/about_logo.png b/src/res/drawable-xhdpi/about_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc3667929791e5f5785f466b2530d21c606e902 GIT binary patch literal 5517 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 Y^s_D|gxBc_9R5dYsB5fKsf~^K4?p=_mjD0& literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/button_blue_long.png b/src/res/drawable-xhdpi/button_blue_long.png new file mode 100644 index 0000000000000000000000000000000000000000..5eba212a049c7955ddb6f339b1b3cb7b20b12607 GIT binary patch literal 1365 zcmeAS@N?(olHy`uVBq!ia0y~yV3Yx}{W;ixq~**iUIqqM8BZ6-kcwMxZ%22CmdYIX z=&5;jQAmqI%aS-R!zFQ(xL$44S@OZLICl3=t++)CxLsazg^74gOch+Jdc*dT-mW+E zEEn(0-nnbGr}&pQb1dJjTleqz|M_>TIEDUvonQRT==r9dyQB1f|2^E^c-Qi?0e^hm zf6HQ-^e5g72Y%{@)jpRGz8h1~J^SkFyE$9#%I)8FJeJ{@(e1_qH7|cH)0@iuzHGDY z_1J>MGnlE_P*h51!r|hLy>2valsn@zVUWVpJ zdOlH^i#L0mY$`AP_t9Hs-Xcx)?5wi%ltT~7v@U#}tbT;Q{jt~CHK9Kr2uL$HyB+T; zcYORN;Zxb>Y09g^SjfD2>H~%y7ap9s9b;%=CF-L8 zmHoJ9>SF%M2Q#-Gtb7=)D-80rxYfgqtL6_aY7ZK&S8Kj}Dfh|Ny*?HUZRww+r01x5 zt+MC%Y^|cNF{_}?Ki${Y$bx&)!OT}Cn||+@D0yB>@_WU@q&p!D&YkSS&l6RF(e7Rv zm~-UYQ*QkiGmQmg%r93r|2=;5pYWw^e!1yAHvfCYmV2FSky^yO;803(?ABAq(iTqI zZPr%wA?4<0>5aEnF5eq}WvXA%O)gn45zYPl)+yV=y0_nY5hDIdG=HPoS{)h2p4iF1 zq6FSI%xRx;CQ|;?x%*qT%-Qt!gSYye7ir5&ZrX>5&V3@j=yI0&+}=#x@;ySQO#QWH zZVEfOMV+B1HTb&NnRVQ$SC=RLo9Sz_V9K#$yl33c1)T1)i_0we_O$2E60YP+;rpe2 z{^*$K&(M=u$Zlt!wPfL4kJ)bz^T)bLc_&Xceg5dUsWaPgV3PmnZKW!I>i0di=MLcy z4>1UQU$AoV8|jrtN`%)IoZJ59+AF{6qV%KO3gTe~DWM4fP)c(% literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/checkmark.png b/src/res/drawable-xhdpi/checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..b1476042b3874dcea0ca79765b5d604cf15b1e26 GIT binary patch literal 1144 zcmV-;1c&>HP)z*FQJ*e2v=1-lge-8xR*XTV6J5sq@)Wevj@02 zv9Kry5jqIu$83UhX)}xY6u2w3Ix0uV(V0yUPq!gFoC);VK*<^c4l&A7Hp%bV0rB-I;B{*Vvy>~!`Xy@?!q5EeN=Y$lZM?95t4y%J?FaH%x}Y$uS|vOG5rdr2>% z%n)#`1H{)HqMZRb9;caokdiK7B${MzwT4ilUO`FzPSVUS$XadUIzB>J?f`L^F_xHK zQA;zsAill>thI)KG8&ER-=t}hK|H;aVfM$J#?qX|UibA?;5jF)@(7{4XQPP+DQG9c z4utP$p@WhP+c-&Kh?z*bq!XA1B9~wh4{f4G_pP zE}E$zo~}W7J7!cEq|6HX<*18ud|iq10Ya0tPWh0KRUm4unQ}t(^vP&wlY~>FXpLuINKqieYDV4&#he9k)l3}@>*&@TNqETM=+JfWA1_w}<63Sl=nh8_E z*B)S_wb;On(!tAeB%wN8hVm`KOhJd2`dVwt0#bp&D>WkYMSYWZrKm1$Zo zs{*rtql`q=snbPl{z3u?9W}A$)64IAgaJp#`yhJr_n4DT*+M8?PMR9VaSiba;ElvG zJQIDd_zO?<3^vPN32&Itb;< zx_zVw(?N^_PwxSCBAioaA~Vt}YQ?q#slb@`PrHDHPB6-ggyK3mIE66A_8`W(sJEkh z0-R?VX#;_{9jGiFPd9S|G3p+@g&dzDT$mVBQG_l6*;;2_&N6q9%58Qd!so!^n20A3 z9;HvVJ7?2?pgxcaj5%|dA#w6ep)!K7nm|5oAg8*d^@Esj8}w?%FeUX0#y^44Cxdlm z(x9j@5EI;dKF&oGzASkqij`TtR0000< KMNUMnLSTZheG!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4LgwdEN-j$`J5e5#W>&wk>mm$Hobop0ma5 zmVZyHd2F$n(`t9|dCUFZ?VrcK+xuaC^r0-yR}0#bwr!edsaAP3cxI>Iib|8>I|a*r zx@o;^EAK6<+^)9Z*#$@4g3jMYIh|7qI*c9oeLpFlvRo0(EOnucLy}kOLc^}b0V`ft zI>?IeRNxl0pLL|trldHa&W$0ZJM_l>WYfhIpbMSq_spplVa_Z&+Ri2Bd z<$mtnGby8U`-4SVRWc_GuI|W){F&{?`$BVf(0jxDWxb~^O9iCQaBB5?ma$p1Shn5w z30Iw!>6)iOT`T(kr03p>ThOQE<=nXT%;%i977T0=3$8L<5n44X#A(M{ zD%+Z;yj=CYdv7L_D$lIOzXz7xXtdyQ6Zj!?Ly&#Lp#+x3;2##!>>p(8miag|PJVM` zj)eLQZ%K8Q%}y_v^p3As&s)(Vs_|JSVSdEe9L}%t*hymntsatlE?qw_cq?CGIC~=?8#1>vO`DBL;3!nnoV(wPgu0( zJnWw4-njaK@l26Z(Vw%DGG_H`oGBRhg7<6(!|4mNZPHtGBsaUgiHmpN!F%WNDxTJ( z+b*9;ToCxKCH$5g$F4rLTZ|RX@{@nubl}^q$#THA{ZG`&ys5%&p9Q}KiN?HG-hKSq z%D>;gu`il*SYd)7TQD#ktCqM%l%yn~>+L(33Db1OqjD`RtQ n0}CqygYH{vm!oLN%}>cptHiD0SG%Y*Py>UftDnm{r-UW|MtOp( literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/common_arrow_right.png b/src/res/drawable-xhdpi/common_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..19d5b828d708a1fb1b829da921000306f15a3455 GIT binary patch literal 897 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 literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/common_device_lan_online.png b/src/res/drawable-xhdpi/common_device_lan_online.png new file mode 100644 index 0000000000000000000000000000000000000000..f1865b8aa4b6fcb2b7d25e748fce90ce4eb1f21d GIT binary patch literal 1702 zcmV;X23h%uP)WhWaCPuB7?Sn!{dLf23Y8y&QH5Cc% zHo<_=F2c$St*w1AR%79z+QtWhCViS^(Q*+gy#s;nj5*)Tw6opW?#y-v64LKwy4!E& zJHPLo|CyO{mf;Z@%xMl$6yKvYBuP5yp|`g;sXz&XxZQ5I%jG%>pqMNo0P+AGBgV|X z>c?ekBfcIO7~meFqoyIhEXx#fp+rK?HV6R-f^dK_=8X$*>pNib7uBw`mw>Fd90Rfp zk}$yh?R5w!E{NOh&J+Zpic%-pl$V!>y1F{^5HfloUVK;pQWRwjK#MHPt)Wne{*F0f zg6IGMsu^RMlzl2HDo|Ql8m$3402V#e(b0jnwl<#atN=xUJTQPH14V&|qWCM_%pCJT zf+1)05P)t;l6bb%hZ%^Ho}P}rzCO@#c2F8!ObEpTu;8JIi3t=G6o8JBBt_V63PSgS zKp>!ATAl*Ne^4RxA*=$HU80fSi5m zePQxv6>#Q;eFKeW(8h3scLM)ZL~qc#&wv%rB^PAy;%)Q~twq)TRHy*7^Wk}Q0(JI7fNx_ZY?V`w^l0~1p+o_RV8{u7PJ z-telrFoojCiP-ufZBb}yp>i$wBlgvNfj=&U_~sBm=_{F$o8g2<^c5zi!ti&E!gp$f zfA#u~=h4tmkCgPy>Xh+rRX_5y`q`)h0QV*?;`75T@Si!)|6Tb`HoV2Fk)G;`_NbE} z`f9`1?{V++_D}Jzj(++sUfZ>2PCq(K_WNq)k*Cpf_6YWU{4JkfxGj}?A@_-t*dh5K zK=joIF5X7%k!u*fejn?e%z&?X@0@T`LO>bhmHPVn+0N7K$#lmj58eH1K@`g%%b!&}puGa?7o|>DO-+qnIvr<> zRZEiOpTB6l+AsA0tLUV{!a`oWUcY{Qb70Z|0i?Yg@&7AV zu5bWD|Ky-7%Pp~r*;cCY)XV{9YohrC05!id33LMMP}wF?z< ztjbrj(Y!7e^%oBvI;891vMkG9t4&kOAi7Z=kB3A?A-Ax8%t}Hjn^XW39W*vJg0hmL zDC2bfU@+KX$+g-f+aPovwH{n97cInp3_v{-3OO_VC^wJurP!L?raGVyqDngr%0{v* zH^gh|m;ojPVhFb_8qjtMH%iq}`Y~Bm*8!zeN~ZwMX*#%I#|y@}ivrOvB#L6OmaaEa zUxmCAr5|lF>43bTb)qh7>9i|R0R6nAfEe^ceMV~4Wl(E^5`zA8K=DsPrgW<5pd}a# z^1fs;Mp8jE{ZP6l1G#?a{zJp?1A&uT7%kY`vY7 wWwwj-xC3BJlB7lJU?DF#<`KK0vDo?l144)=Zw02iH2?qr07*qoM6N<$f(l$ZU;qFB literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/common_device_remote_offline.png b/src/res/drawable-xhdpi/common_device_remote_offline.png new file mode 100644 index 0000000000000000000000000000000000000000..583c1def159d306a338482363bd65870800a07f2 GIT binary patch literal 4732 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 literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/common_device_remote_online.png b/src/res/drawable-xhdpi/common_device_remote_online.png new file mode 100644 index 0000000000000000000000000000000000000000..6d7110e51d8166d50114b8147699b0318928bd62 GIT binary patch literal 6084 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 afjyfzdN|G6#|<9K1J|^!YgVZ{ME@5w*ZXDw literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/common_password_hide.png b/src/res/drawable-xhdpi/common_password_hide.png new file mode 100644 index 0000000000000000000000000000000000000000..18eb3bcacf59f9713fe3e394274d857a4290fc1e GIT binary patch literal 9660 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%0D%NSBw5(4x@z=i>UU|go>u>dY*sJl*8W7Y> z(bnW2;=_hz3mt)faLsmB>F+tG1lqH?b zK&@y=gBol66#=KL2=75hAJZ3q!4suWq>HeRQ~Q0|W#}-J*U+;@5B8T$0j9}vyWNIc zCb#sBdsIZ&uhl8vyNWB49ofab-|YIgIY2@M5s7P*@3Fz?8WbHFS(N%Kn?M{7EbgHp z7Q>@Gqd^Y67I^;P28zqaTh}XV%4Q-bc8ThgnPxOJ{+lY z3{EMP;l`^&=|pT+|cAkQ5Cm=24Mdc*qHW7hGc7PFl(I~6oJ3?+f`t+ zWea~!xISIuoG}y_#h9hk`>a)5OAA4kH&HkEFu;To`p5G$h4)d5h0dR@H9j$Rp54am zS)L`+KSRlfIbgnSg&96O1VcN-R7#Z8JxOfv{DIBJ%|pz0w!V4HC=CbboX5~kIj=t6 z@fgY0VPDhm(1*d0wTqchprVCGOo~-15Y^XJo^%nc019|1cqMbCMStGar}0AuJlx&o zofYYtWHs~?w|W~jL-Rv0bMQsx&P<2!jQOBrNyRC@Av~XT6%`c+mctTWPvq+8ZZ^R& zf(GazRIfAwRgJz*&QcA^E=iGU?|7pJM1@7T`|a+G@Z35J9zb_@XqT-Xu8$`(JQ%!Z zt4en?5K>U!4)ypGPdsE&M+9bRoeWx#qyeXt5hpcyWJ=7T;vZX#8K$AaZF1OX8CscL zN|*RURn9mg6?`=Roja#^7oHYKA116r;vsgCdO^H@LD*J~ zm$93hscMYz7jwXEjmg_0BQeJC;dZC5t@$5l4z6X#X_}}=$&zeDUj3N znrQ)typ`Rc&P$kFy$RFuxKe3lWySZb9jMwe`kg;AW*`suX%X(3#F+RF?cRv$Ca3YVAb2`$zEJrl{2O-ATxxR@^ZpbT zYeqE`LYt$0)ESw3TO~nh`tyw<{zbjU{^co2eGBq``JSX%ig3!D>TD)aq6J^VN>2SR zjV#Z2`HSu$V28I0h;(H$|FcOX%+*F_8by=8ojqfhh9JE56*mhCR@DQ#>yAZ(`gwQW z+bXhJlhyuQFF&JM2qW|RF{Xi}`cA3I1+=hmx9Wb#@~w*|&!-AWaBb zIKI`%RbpN>PX-ab0TzIUn~X!E#f;y)PTI3h-?n>upRm2Qtqd0|&?tIwePQFWv*KYi zAH|4@kajLiP&YmSEp^h#4}(Zy?QVktXgLI z%pqaF^vo-H`I+;F7GY%bJ?1}8{p`@FdU9elHS~NU=%*NLZ$r7+yEi>8Hqa>Z-r8{; zuC{Xi%;(0vqoeQN+FZ7BhVLkaOnm$yv|8$d=;U^s2}Qst8mzOTB$^e}2d@G3{k08P zut|R;Y?|x3v0(7jnQn;a%yK7Dvq0H^FXDAb(jKS~`Z$>S^Jw#?2d^`FiYNG4`sur)1sk@UB1|141s3Uu9>W?hH%M#p3ZH zO_q%GHqf^M#|#I@?hdzYl~Z+P279hSMijHMwpN zRu#AUoRikBS(J3IN0A&|QK3Vf|iha0$>I}s^ zL02%QtL6)m$BXHVk6~^1$HJ);ia%O3y5XMO-ZS)|*7n7n8_uY85W*9&JCa>+r8OW{ z^8j$Z0>k%V@4_((*g8mc_F3Y$MczspvOYM=eBNia>tLBA$z3!O?>9i2P&FrNupA-# zrWJ_jWbVc6NZW*@_6`+4M;g0S3P9&et!Jy#*jiD{0jo*E0LPsB*4^UA@Ps27_vdWVpqY>9HSv*-Je- zvLxTHmH-k4%yk$-&IFM08)g>OYeg04d@%4+;K@QldPyIU5fq2Ps*>lSNvC z98pUpfGUfjl=N46CXi(-|{0Lpt+1}L*7p3FW9U~ub5vP{al-q;ml{c z^dpaZ=?Ce(sHhXxnGbbuO|%5|Dy(xm&9XZuBj7QKc&r*l)5NL)Ie`it2TY+tLzXc` zRP{PVVcfPilJ2RaqbjO(6%i7@Y>4{%@E!Ojq1m)5VU(1VoJ36-sJ0AFdgO2_+L{h)v%^33DnorBwf-d0Fe|1EqRvY(DrF+pmVYb>>{F{ z2Z=sX#^;fnQ}rs;#{1ERQ7(N|BltVWTODERO)&6Rl%1VDi_~KhKq}HtXu-}f=p3Z{ zew7Wnt!&r|3->%(W~N_@AZGRI9ZuJ9urQ}ScBr_KfPWp9uJ;-sC@U|=mGN9Bd`HD2 z%S#lCPAF=wpJJ5&DpMy=x?-|6Uj?6_uR-xv+0F{R)u&nOyw0gFPvwZDJJU$CwY3}4 zlc7ld2tE706o{9gztp%utxkS5=$w%LP8vL_SHXV_0n zZ&h%#zHeQSpjTr(L38tX!zFjUEoih*tX?&|H#FU&g0q%=411Ss_H^pEeVaxtt6YNXF4hGOpxb7D{tDf&`>v- zD1Prm^bdb#XcW&>QKUyo;SVO_7`3dQ7J8iJlk2jH-Uy`@RuQ7q!A+ zH#zx?05NTr$at{3XaPbZe$p)d;R9*)Ekm)VHF0M3tc6@b3i)(L% zeE?R_UlO|RL+!Vc=#&tEE&*NDyF=u6z20&n3iQx5a5Zz7N`-7NI8Wo#S2dpi>0T}I z%Y{!nCVKmqdxlra1meP;45w;8p@AkACsp@`5XqSu!Ds>!Ik(QXE!i}UTKar|_4*ad~ zYl_Af34fuO%Jpn;cx0@!}MoMi=U(h91Hyitct!U`vmtQ!MIp9i>OoK!-cL#E6a6Yojr~`cX_f%u=(j~3+%)7@uCH;By~{o*DS%(7Q(X&93^44G zyeL?7CZJ&;G<$u#QqpYRL4{vC#?^I5r&rug-D&uUCpBmH?=E^IL*VW(r(3xefOIqT ziUx-5F=@7GRb8~)G(XX9^do2f^^VQ{l2vA;y)*!f9mI9qiqF5G~#;NIU3++il%|5o#%&6kJO0z{EKp$5>KqOmbOOd@J@5 z7)0*w;W4}Y@bE<*Qlga{{fFHir}BDE9)O-=pi3{c6}E+l)ARXaH_UjHh?nMCyO3-D zCK{_EPpavJ2zeo-lwfOB$4K*nd}L&#wSX$!O5wdkJH)_X>95Pc-?kEALQDkE80C){ z;kiz)KU_0D#MT`7TIP&2;s$~_VgCXwFjVej`r*`5)<49L%GXmn2{cH4q%CE&`1rL& zq1@fiC0Vo>k;D>bN=CfGAM>Aw&p55NHbBYLWL0WBvXLhpfGCrEo zwYrml`<`)hSi~Qi4ZJL$54D7!NLcPU>m7Q42wxqR{295$!69c)NrHTQLZY zhThQa6n^~EoYv7x!mWJkA=n}P?-Sma5DN`|({}7|AlIXPP0MZj={jOH%5cLg=ZRt& z!?TZpelEw7+!;PhoUaBzK<7;#HhL|eDL^ov6rzA1&IOw@-6!H{Wzkl5D?iM$ZgiWp z@qSAcTc2wGAOdhcm7_~+o0*)fT06`V_Q%Br;h{*zw1|p|6G=7ypx98GvmHpFUz~jq z3P4s20j2V9_Zy7Xrm>rnPV?JI=rU3LKB%NtVPLpFSZ;88F<+>%IH)^tP11rn6atvf z;z!KISdo)MNXF3qAGizGCUtFKsy>f!rhlG6h@Z3E;Q74`(81DUs zs-9`#ql5dj1b{%mD^eQiend&JnC)S(`Aunpxy&lRA^r65ak1?JeEiTBgoyH=gS_R zp9-3K-DhO-&qxxvZ-dJsSl~&bZaY|+qHbT~hVb41iOvW&@^e^~kc!FyUu`Y$aWh2( z^^TpL^cuQ1$*tQUlrPX?EwIgJ^$+k_-Sv_i`S91N0?&ar|@BwYZ3AWglu76 zy?|T2<@<{wdqAycw5Y@_P$L|Pz1!2M85ZtcX56VcS+K{snXk3ks;8Y=BL!&Pym0pgNM3xF9Q$0W;2d_^CAC_?R zbP3eAW*zJdPf&d{@pTjNI*TxAbLmnxKcIeWomf-dDlRs3t9=OMb$Rsa^jGjaGv)rm zHGx2+$72i9D^!cvRV2H|X&zDs#%1^lj8>Yu}1q#?S1A2=$&m6=@YK@A|*b2}9eKLU)g0>3hMib=8T;E-VHK4NartkLl~4lF^*Q zd|d2@XU3ld0^X5k_y{iE^kN?z@BdhB74y6(pQ<@JXUhhG#Zu+yo(B$(+R#32zM1XC zlEBcgsMensQ`dT+g=mpnOSJ0(bBNe9Zc(hyxM0Kl=D2A}o_XxPA|lhkN3y*VtV_9_71wGeT~!h5GKou*n5aB88ePs!1>dh-#*1 zXLa};m;clgTy#M~D3TxxWKr^{!_BcFw^ewX;aV))emnZDC_!zsq&;hHjJ`_ zs?T=GHIoJ;z2&!5@mRb*XvSlvQNVXoKvNedLv3v5@rPi#?F{;nuNun|E3)$yZDI6y>}Cbn9ui z2E)WHA=UwxZ+h@MNJ#oGO=AbSq4-^Qs{~Z=Q43gFM!=0UGxx_<%N73=E;>z1eI!bLw;9KnFLz zx^bR$R{KY#T0=At9#N;XH2>NWL+2swh@|t{r1O6x|6kTve*tu6GrvVMA9s80$^yvC Ls6fi3OoRR(UF=Az literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/common_password_show.png b/src/res/drawable-xhdpi/common_password_show.png new file mode 100644 index 0000000000000000000000000000000000000000..553120d21e5fb063c8c585752cad63c57148ab00 GIT binary patch literal 11598 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 LqC~BjanSz&1rlpz literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/config_help_button.png b/src/res/drawable-xhdpi/config_help_button.png new file mode 100644 index 0000000000000000000000000000000000000000..37d38403c296e84d2e0d06d97b4016b573391970 GIT binary patch literal 2283 zcmZ{lc{tQ-8^?c2V;OryV;Lq(h#BjQ31c+2vSjj7)?qA-b*zm+!z4?|a*pDqla!@Y zMjByk<0w+EEYqtHiDMa5BN4`Ort{zX$NOB@{d}J9{aoMY`_Fw{PwrV)2T5^=H~;{W zPL4RdfX2T{1|-;B86MvS5Dvq-U;*H10eC0ykU$H?;~i{)`nM`vflwzp;#~lMsto|? znEzPhK_}It29*xZ|CmM&UO=f7h9Q489v^HUwcHV zQr5-$3ZS$5uTOJ-GvtOxnnpFpvR65^hh=3|Q9x2#zv$9(2ilV5yk&>>0d#dKcxe^( z*q4cJclV5Q`+GNZ+A4*($`JBipER!mv%P-b;mYjHkFuMkIcra!W_)|kIcR8b2x_HQ zU5sZ@KxrK z=~gZ-8yi#Y{g-21OFd-0GHZ#IlE9E-|OvcB$t0f?0n#1V;T8HGa{UW{?Y z7ab|nrAnN9Fp{vq`;6$UdeKRUo)q^vm!*8$k`y4*9CIaG(&WqWS|J_Y;uGe(DNJ8M z_GZ?F3mbnVCYqJ@?d}IGn$7 z-Hmm93b3XWoVwSZHqjDtJ+>z|=i+PmMc)oc-y_eA!*Y4c9QzPYdHEkE_lxB7HSb83Xe54 zA3wSC63pCWZFU8^k1vCnGjs`9J%wZ(7TJUy8WYe1|up6$TFa z9?V-9WJxtEqrD!B8dkKRcrUM0tuZuut!v_FJ^g^6!=>iV$?4zIOS)6AMX)Av<+DHC zDxSwswVjpDU&hmuxmmH_tDYsTdjDIYwe_;xkMV-DRgP9^OOFX^gS7p6@KkI3(3U>F zYJTwjmlXb}Ew`v@y8uTwv5_}KRM-%{(CwOp|;Y1U~6)*82SWb?-!Iu?z$ zy`TCdCUz$+D{(pXoVc8a`{&}bgzv$-o3jp)607ze57^2i6kw`F_R#PfAz5*^jPqw+L&TI?Z5B#zW!?8{W3R6_5INfN zIN?!>+l|c#(eOMl=JM_cV_s%J1JJE1Y`e6qb7_UW^AcjCNLri=6SOci7O#huiAZ@) zdYG0`;!S2I8GQI+k42$qkOm>T@P*x-uYdHZOAQ3`T54iXYYlp-2_t!`sT_RvW z9RsoyFcR~LiQS-bIF$v>_R>)ECvO=3E;`59N9ykkLH=Twug&*Fw4BUaGH6Gh8L74a9C-Qf|xuBg!J0u z>7)8^t|Am6wgmd$nu8x$ literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/device_none.png b/src/res/drawable-xhdpi/device_none.png new file mode 100644 index 0000000000000000000000000000000000000000..278221e2d8cf80ebf40da700fe6ca5ff6c1f4bc6 GIT binary patch literal 11149 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 literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/feedbacksupport_unselected.png b/src/res/drawable-xhdpi/feedbacksupport_unselected.png new file mode 100644 index 0000000000000000000000000000000000000000..55b3d80d530a9e321d8bcdba2f3f10dce716dca8 GIT binary patch literal 1207 zcmeAS@N?(olHy`uVBq!ia0vp^8Xzpd1|;v~rRV`EmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG z?d}4kf#9d}?s_1_S>O>_45U54*zIJt9RmZigr|#RNXEUlv+eyq1&ADbuX)O0jstts z5sAecoJ)?qPcZn!>G8#RN5gIj1C_ipeE%YSelW0=8ya5ZnxwJeg#w@L`ww3h3DoK? z{KE7ta^4p+-RFNSa`WHsRed;N#>|(^R5+EZZ}&d8>Xj_}cPS|;8SyOtv{`<}K{n}!1_$20KfF4$%%#8ogAZHbne(fk zB?{iSBg15G)wKQgIfmc9Mtw1Sh3C$#diIsGZ|2PH+a8=Axb_C4*R8Uf<_gN8Qr;dWowrDMX+M9+qfbU!f!FP|C$Mndx_PjT`(1VA-Um~> zPKq6}^*463vpI15!QH@>S*AY@HF4(U^1f@@yez<@PiZEDFy~dp-nkwV7JMxgPOw>L zHSc4{a;EUGkanYaT`oQiMJzX_rfy6)cyPf_k-Y5}UzNrG3f{ezw{FsYUEu|D))b~j z>O_2ay_$1FT)6D{8=WkitFHStY~Q}>v7~>fmfC@$$Wo2RD~oQjXs9oVjTGY+i_!YZ zqju;1;lqhnKlW}bk=?grMX7$HhFEC3*{7s~P2H|1&&me8_5ReFoXN?Mz17cMN_ovy zt!;h%q3u?)v_w=aZhktvWYYcndw;!Lf4)Zw0OJZ`4oH?^|&Z{YJ1I@ClkA4lGc~XU`qB5}e(5!j$1>YZQdwk#@zmY(L zyxgJt_d^%I>U;cv;obMu&r$_5G+553JlOS)#~{|db?IfJzQm`V&GQ$@FPPO<7iy#T zJanVEShKrQ!ORc-^DR%9t6BC%>YctQ`159S@O;ZZ%u?qKj_$U8`5u^AR7+eVN>UO_ zQmvAUQh^kMk%6JPuAz~xp-G6Lft87om9dewfrXWU!HVSN0w@}C^HVa@DsgMLX(zu1 zsG$R7LvdNURZ?Pcs%~jfCPP|gPO6o@zJ5l2ZmND_N^WMJer9rho^D!xUWtB5ZULAV zUs#l0Qese6U}%z`npc!5pYN6_Au4-YZ>S_w&TDYjXTBbP0l+XkK$@TWm literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/icon.png b/src/res/drawable-xhdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc3667929791e5f5785f466b2530d21c606e902 GIT binary patch literal 5517 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 Y^s_D|gxBc_9R5dYsB5fKsf~^K4?p=_mjD0& literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/info_edit.png b/src/res/drawable-xhdpi/info_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..9ad867b10b430e25d78a2681265a3150b498eab2 GIT binary patch literal 1026 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU0wmSG7d!(}Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4_quxb`@MI+ikK|FJM(@`*)#La#?1d?1BF;UuaaH4Hk$loDaYI3)_ReCV z2G3(ZT-jV@7!oGjE?dK^!T))d&c2II>m$szE(!Lxt~?X0ZKuk5O1GqFs>1W58{WP+ zUD?*%9wWYAxWTAB@!KVxd1`0!gl&BS_4ZiFKw%Z&J&A-YdHCdI~h+WaU za5Oe}>U@D*nWh(uPUL81h;FQ1yQA1<;auxwOB=(qQnoQJkvZgSHub5+JD&3|o=lUv zeL>!E(F4N-v%p_lgTH+0kj|>PoO7h3DURu3XwieLN>}siA+e{gC4Fm(P;I!*A!anM zVfC{9=P^O00rgQVJ;50)#*rmYR#lwlo)z*tQfE>oi};Cx2Ym((^66Ja+wY%AILN_P zXw7o|!uiav{mFiJSQ2ZK>lcM;mDO99PMUm9avImtJLY{KY$u#P=A8$$_i%&0Ue0P? zzwgIGe<~f5(s(A}IC*2D?X5iSJn_4R!fd^QhUsS%w|r;|+9&a7PfbeHX1SE9FQYYo zui&hYvFA76ct(Srb)^_*oz0SN(PTbB?T}zM=TmYf0d8A2+*-UT`qibmv()YeO>dhs zYhB>ZxdPTF#V>mnS92J;?~909ZFsjTsWVAICDyY@&&lDVm3VcpQrd~f?82MuIM>bN ztec>o*0VJ%e|Cx7UO_QmvAUQh^kMk%6JPu7R1Zp=F4nxs{=%m9e?DfrXWULHDh- f%TYAs=BH$)RpQq0t6fwYsDZ)L)z4*}Q$iB}gcO>$ literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/info_edit_cancel.png b/src/res/drawable-xhdpi/info_edit_cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a1e90aad221a8eaf1b2071b897cbef7a4597ed GIT binary patch literal 1297 zcmV+s1@8KZP)t45UujCXs<#}kZ^*S69jLNdNza;#GD|`8lm_T@;c55a83YhrX@CZP7rc}zzIlJ zwuJ18-l!W5X2vr;Kj5z=FKoAF>ecV-s%ENb8DriO(R&f;Fms29@ExDzx*?()5xHjO zYa;rgwZ?Ci7gu=#glFah5$Ri@e~HKx!dgL}JRU%?mznp7=$+j=5|PU)ph^KT#z2UV zMARdqOCq{ZN?mlj-9J8xnM@|z^ZEP(5#e({MB^X`zU}Yt!&+X;3y6L3S0Xxu@I*AI zqQ#`7)-?wf)VWgXvyWm51Bs#tT03LrA4Jrz3&5({Eg-nsdm=gt!w?F~U4?)cW6od& z5$P3uaPFIPHb8OAJSL)Zt@Tmf^VR~fu5?aBuVM10tdJ$7wGJ$Dr<6Ke=W3Zi0Ae1}@kJb|)i6HAdcTD7&-NwvyTGDw0#Ky&MpR||v^1ARlqn9%zRWv z5ylt<`xmYC4m%SmrCyh%A!Wc+1p&+3B6)|901%)8Ew4mHe8AKJ!nv@eE+dYjXoMfr z%6A) z?D{ky@&dAn|8c4nk)K;zTiqw^AZHa3c@>5sCQ=)_q9}sG|E4zRAhk_rn7TgOK*v{G zt~afedYjoYwW-*R*f!3^oJ*zkrnANhV-b0`Zm{C3$*TL^;0d$&LSqH@LVK1+yi}qt zRRJXA0TsE;Y9g*3z0K$I+>uvZf@VFZ=m;=(7&@EH(AULL_3*jVvW*F3s9U8}uhcL! zsUb_1anqsj+`Fo!+(3tjz8C4a6`HfVY=*hFh+xwDxhd;dD|}_Z-F?EO5m9C?XdCrIfn#d2vE9xLpL{ zQNO+iK`?6kQq8L0TQ`6Jn6JFSJuD)cwpy*5<#L&N!>841b(YH|*!G^i*M+N5V<@AF zbxTg?IC-gYg$G4 literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/launch.png b/src/res/drawable-xhdpi/launch.png new file mode 100644 index 0000000000000000000000000000000000000000..c3cb074e4703e12448d2f9249fff938883ea2ecb GIT binary patch literal 57394 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Ƭ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 sm+v1)4!pC|pS!`z^;0na!+P=fMjze&igI^V!Z literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/page_back_button.png b/src/res/drawable-xhdpi/page_back_button.png new file mode 100644 index 0000000000000000000000000000000000000000..3da2151d7333d54b14b1fe433ed250c650e66c6a GIT binary patch literal 1587 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 literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/qrcode_scan_frame.png b/src/res/drawable-xhdpi/qrcode_scan_frame.png new file mode 100644 index 0000000000000000000000000000000000000000..de6cfbf7a30d5947329adbd5fcd4fd6605de461f GIT binary patch literal 2879 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4mO}jWo=(60|Pgkr;B4qMcmuFyL(evrCKjm zudZ0)z_5qug~YA*Y{C;+QWzt*oIUJnq0(^QgmVJZs&%UZdmGc1%$&Gm(XS6@<02&H zRDaw5?V?!R-26D(-S&HL*2nGn`>=fe{+r=d(u_>?TMwLF{aoK~`S0`pUfus2zrWlp zB7f5D-5h`ZbI904gvZZYpI2X(bME%-*Z1%JeKC7_|6jTN{tX8nbN%^uT3tRq{{Fu2 zJMt~(zI(rJ-W@m2r)L7cFs!Y5U_ALkRW^L-BK2g7^Q>_dV!yL7@68RB-S|J z*gJ)x(VK$c(Ad*(@KlJZ1|t*OX>*4L2e$(WsjGyhFfcYhl~!<2 zP)^uj6w2w<&~We*uYke?U^8dtDi&3T0|`IbI0Q}rE%FI%5>iOmP{Yi^kpgTh|w{K2D!6|9k2GPrvo={rj-{{QU>N_jEBdx(n>6{QBqU%aZ>$mH&LH q|LfWORc-6u?gRfP9uRE)%D?+&r160{`!4_+#tfdWelF{r5}E)A*wAYL literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/qrcode_scan_line.png b/src/res/drawable-xhdpi/qrcode_scan_line.png new file mode 100644 index 0000000000000000000000000000000000000000..0749422bc0697bdcdb42767ae0797cf139549469 GIT binary patch literal 481 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 XpTjG?iDzi8-2zE26vEYg^u+%F;COB1 literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/thumb.png b/src/res/drawable-xhdpi/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..0db9afa55133ef47bbd63999bbe746feff90c1e8 GIT binary patch literal 1768 zcmaJ?Yfuwc6pm0Rh|KuF@G7#dC{iF#5+D#z2#)|k3=~2|G$b3cKz8G1mGJ0DK^{sK zd8uFnJ}5{n3RK1i;wu!Pf+L7luvAbPYoS1?f~f6ugM$50y0g3Y+&ka*opaAQckbS> z&;ZlLR*Oj_k|{rsCnU!8y3fdv_u?%($Q&$CVr^H90w%lFX!_SUi>P?(VMBU@)8sgtICI!NqE4M73s4fd{E1 z7_7u$6ajRK;y83C&IO4`-)%vmoR>vZ@6$vijH(tZsdNfWx1~9tK=A)ig<>A9!iCU> zc>hya6_KKZs6t4E?!+WS;bd!cu9O^K3=-og7J;Hkb6E_Nqd2OPqe{RxoDHmxf)Od2 zta6ye3j`cKqQb?91mg3!AfZ5kVJXL*?!%O08n67lXAKS;(--pNZb$K^VLXlKNw)0+`)02VOW9-v#yFbEON%!ds9_ zC4!;q3j41@&n*$%qci8*mYB>pK7aav;dyp0j+{>~$U#1)&(a+n=1 zwsrD5@}-3b~Zz|wgry!QT|!JW7T12X7BCh;w3%1a|2cT{hwIcI2KJs4tc3Q(SpJG zwUHO18PSKP`rO)*ej+`8EozC~-79YEmz78k{BBY&tPSZ+XtEa;SjB0dTqSikd|pQh z<{}fX?4^#^u#2PL9N4s0V|973c4gQx?_4{Lwdc?PS(%phhTV1U+g~y!_DmyQrzZm_ zhpns4pV<_hdQ;?IF=3dMU}%zkgWEA^XxOx5->&Ara=H_#%)B&4U~Nl6>w`oV`Ff*A zR%EVr87*$K$tr()VV`tEVZXuM64BLY-rDVzcb~r~GdLLix|{?nS20b1?_KnT9#ZlK z8LW4%tiJy|tLw2wqd{e>C5Nh`lN?HeD!cSfNedTQpKDF0>EI<9FVnp$*@W3!nsHC< zc_rvp$bj69mSGU`W0N`qryuQV+aH^MokW(sKDx0d5-b$aIa!_cO&(b!oAUDVOZ?JS z>ywQiqqL0SO_OE@iQaHJ3_FB8`i|8yG-!;{Xtyf%S>4mWe{G~&{^Fu86Rym>1Y3c{ zk!LcQY^+*XyC+sTk!gQ+f;V z?A(@4yEv_W>}X%jbFJnnm_l1uT~jk202Z1LeC?K(eI&2z$!%>#CV7KpW2MLAF(g|% zbo0gXts^(`)us(gizR6fg2M*%BKwA0`Su0*n|pR#edHZf@KgvawV0kskFSe7Ef|?B z4Xp`p5GAq97PkbgD;^PHd^aS{!|38~W??z4B>~wUoj2IyU(U?T+$}CHuDKjL{%d=C z`{wfxzj!c=nNCdcYei0EHk<9$Z6~U^S+*r6COzQrl|QE@0`5l%1*V}U$FN--SO^cSzb*(!d(M-V-E8=Feo`(pTw% e(?gpU5f|67<++azouKIM9==~F?~Kp(%zpr#6t&U- literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/txt_delete_btn.png b/src/res/drawable-xhdpi/txt_delete_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..7e4821dab3d424fcb540b351735f932bfa77317e GIT binary patch literal 823 zcmV-71IYY|P)QUnwJVR}q8G8E-5{(bq;3shW1o0chJV8in9SA=`;>ry(0k`%{ps^bY z(@Sh-6^Y2Q&>aF~lAF;`-0j_`-CNz>4?@n?>-CO^=s0{VL_Ca7MMOhH93$e;_xY_0Hu^1Quf|kHang;3&3#S z{n|pduKKdihGFbS`*8s%rR)H}$5m(B()dNF13*3@eBWp9Wwvs;4E)^R-^0_>lWO>j z{)2-9uq+EkqY=zzGo@|l#c=>ArMv`yGnLiJ$;o2KU@(BmWTG+&`s?+2@M7Hf$UMS8npU>Yh z-~}Rn)&UBX>Q6$($Lb`JYVEZF)55*3=i<=+KVT6d=G#_HwHMO*x1A&aF#0DxGdusG-tD7~ z_m-5BFVcU?jf|G(gh<-l+}yx)I#n&j{SzTXrSNi#OEms~YqY=RmTtjXtyY6$?BU@- zyB3T><}dE?t% z_QgGdbR4ITi0`)+$CQbQ=(^EpywZY}ibtO3b&7&yIMXy++Tu~c;r=FsSSpMv1x(g! zh={$p(d_1IMa0%x0%qjNP`BaB{idXmwqY0-8m(K{j{E<%Q^?&tj*;x|J&-G~{@tE~V4002ovPDHLkV1mct BoQnVe literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/user_login_logo.png b/src/res/drawable-xhdpi/user_login_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e49b86be6a2d6b0a6cbba9a5a9f6c9b8c6e9d225 GIT binary patch literal 5433 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 IUfUV{KXCTgi2wiq literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/user_login_qq.png b/src/res/drawable-xhdpi/user_login_qq.png new file mode 100644 index 0000000000000000000000000000000000000000..0b3b4d8ef639c9b164c0b8e2284024364c17c03a GIT binary patch literal 10849 zcmV-nDxTGeP)Ic?_b%$+$!fB{-* zpapN1v80N(@nMnzfyhuSa@K0{6hkPP5H0NntX`Jk1BB_F^>0ILD4b*)0O z5E-2S!$9QEf+hg|&t(|b$w#Al&m91k16TwgS9NNBM!+x-X#+|tLq7l`0o)1S`hh6~ zuoS?%0QO50J8)YY1|n|k>jL-(fDr&1iR+^4RzCrl58!hECA#L+%gh-D;(h?a0Zaz) zGytoY$4U+Ie**X?fd2qsY7p>soQ8o^KZ2x}Cjk5lKz&~yWD)%T;#wi;(|}4EFbw4C z>Cg$l`vB-OkbqVYdXc9UpHB2!OX;zodaYKk@)P1z=$yE1^Pm!$8V4 zaXo+)0O+>cfN~8ia~)&Ty-L7>VIV*XfY|_O1u@`C4V(e+Ab@~0A2tvD-iV*s0KpLf?Hj_Qh_+`a%5f%U`U`H2M3~oTmxV`0QxjQng-}%aS#Bz zv~IrJI?xP+oC?V|iB=E;hA|Y?~1$P(9)BsXOlh-%aT z9sAx5;5&cQk-r)U#c#ajZ-b?Cc?tlu18`F3d`e=^9}Of40A>0JmZS-zF%Jz;q+%C; zx^4G212F-hK?<~34jz-67mo1&-sFYM+j#uVKq%OUq5w66{{8!7)Va;0zv}h5A4jn4KgPWG&;o;b|YZuzKrJam;_~C~iaOKA^A$a-am$__pwr<@jdgZ9fC~fzK4I3tle;J)V z@bwsfe=rbob(kn)@FaH`KYl!$HEWh^o!RYnTz~!b`1RLcCDX3xFlNjcHfPQp**p-Q z{{8#2HEY%=!XZ)s2Y{9Uj*D!syJlJ_Nll?CuH%#zN!=nNBXRcZS9&z?PH zp{QH8E>502iHL{@S^Xd>JB_V1UT9{0r;U&Qq3)4A~Q~ngE?g^A$h?wtdw= zsB{@6Ue+X`^yJBt*|cfXxaz81yLRm0!Gof4zVgZ|?1dLz5ZzwP+!--q1Y59R0au)E z=u(Xmie>jH&`LSHl|om?GkGJe3E!$!t62a3{YB}DTubQIn(jU5d;9k7@zz^!p+}D% zSD;TxNn!83_ns)6)RDGCUAuM_-Cm4t-h1yomXeaf6{j1zbooN1BhHKAO)qVQPruKm9b`dFP!P`8s|2w9}!HVB5BBtVfR?9&u9J zsHiBGlao_pTQcC)t5-V>lfG9#bab?HJWIC=6UYudD_DE%iUCbH9~PhZuR z4C0w*o&nvhxC1f{+U8YW!Ki&nNeK%H2@%BuM`b_kN{r1BrFy8eR*q6h5&-4fvcZb6PPZLS3pH+piWoBlwI(6!Z(tlD?5=%=<`(ImfdaPK9NEo`G zq3s<_elkK@&FERRYL#>ARRPr*NKjCaR?dqRY*73<`ORIHJP=;!AZmcTz*kKqDGh%| zt@+8w$Y61Cac*@b)j&?2I>nNbl0@mhUcGwk{Q2|FwpCqKrc9aQb|s;0*xPTv?R*EJ z&&rUUoy}rmVnp%4S?5o>s(5im%O9OLlp|LPa-H@{LV&}E4?CR<-GNjC*}HcyI&~5k z85|N4f}$b{)PvI)DuSP?o{ULVEJYo*YSl_=Hy-WjrAeMc8V~9caQKpeyaYhgu(%36 zQgGD0_qs15BE|`kf}1K{s6YGcGd%W~csH`&e)|m+i$dEbS_x=NHDJI12}6B#QQDCyZ}pH<|(FNTJjHk6vF<}-1H$a!_=s&HORRfC82H-}Zk z?-uoqH{OV!exfjI_dvhy_uo%R&##7d?b=;&f!Mu!cWmEIWlF@s0EFrP;GD5#jgSs>UQIN-@_v2t$tM-*Z2tWDY}BYxvT@MS>~+^s3NZOFd-iNL zVZsF2JjkbfRnJ`jx^cwE9hDxG(538zR1qB68f31v+3{NuG z`1gD6xd-2V`>pK$v}(}%3?;SG0qFic#1{<2>+c_xCsMCoy|8K1CYVg*buSH)larmv z-ju?mNt4)&88al09c5W0_jbzbr6VB6Q{9$LkgQ}cDAw!mA5~=@H*TCW@2(V>F=Gbk zsFoMJ_S$QB?z!hgqa)|Y-o1N+VnB2Tbap*OXFUCn9laX}dGBf#G%aP21`Qg7IdkTC zOanw&49TD<{U~o3IB*~qFJ26*)qUhKZ43MK>4UViG~O)mz_-d(F_#A}?l|;rAmkP; zf5XjPT~{KEkB0@l zH}$l&@&TYFuvCwH>U{-S4B&A+D$d}Es|IcaK-u|q2YNRUaum8U1WtDaASlRq{Rs2w37#`Q_Y5ED*ql&kz=HW>>;RvvJf3@0DR z%4eYePdmqO>O8}-bcSMGo(om0SgLfYtgeKF@siS1`DjU@CaoK0$Mf_ z(5jKi`AJVwymXfntpv&~WXQ~AxR?W+y~uF%HwO;?#<26K16lgJ7NNTKWm@S*EFC=? z$Q%G;#0sKDyF1&PaCavYZoA%uwvF{`2y$fq`Gfeavw_fSWVl)iST!jKeQq$Th2HP*J~XowtAC`TwW@(G-QM+VAe6&Zl|2s~ z!JbA&mvQGfzd7PoC7KE*|7DHs@p44<`)1S(VJHF zY9J9*LPHB>_3327ypcg@7^_!RXrYDbX}q$`hN(+6D+Wb@aqbf!dqEX?ofYJEkfoJA z!mPlkd(9X>z{159L@U14qC=O5L*FSwYPzbs+^XzTiD)Vntt-&0fz+r%Q#nPCwv;*+YPZ*`fsl)d{vsBt84X%lZf|FDdH~ReNza$SL54TNTys@Jw^jY3oy(4~b5-CCN^^*X`% zJtSB?HUE~u@I$HtyHXuacXbV%3e{2_xw@> z3tC+Sv}kBT^M(TAqNJ<-#Geiv|C1sE8TOrWV8>Ah&ih2QaZzKi4nQAKEj4T;eU!9g zj;dkm?o@-P_}A1ak717rt9}@4_VT#%%shq+`nm9LSPI~8dJ|F420}UdTkB0>20yB4 z;5`5-s$rLjSeFJeF*^FT2gAd+{mJfG$=mdWD8M zpQNBGlV-l3lhgjC?Cb-2Qk3pikTDSvb)Jcdxe#tL)yUf=yB%aO+g;BYn`R!TdKx?3 z^Fq_Vqt%LALqePneGhh%C2w6};f^608M>;St~&#n6C1ng;fRR-Qbzxr&4w+-#rUP9 z1p7-$V5~4ww8yV)xFDc|)ryY6!MHgj1UFf&2$N8%F57NrEz;9N0hI9LN*N}-8HnYV z1`Uc5f`Sx9F%>!-I9yta{iUVYM^8x!P8+L?vYAq)H$}9y4i0u2MEl@iw6|K()MA0) zE|01R4p!vnFHE^~X_$znnl#asfxHwQ{pP4zwVqK!@_dH_$IHraqO8pMS@Ha4vq9Gm z7-}d(0?trDK(nAAG!F`LeztIZPqbKIR%i^>v2muXtmvjc{|uABqN+`GWgu(o)ywZ3 z5~5lrlbSS1tIb)P4X4Y>aNcgm?>3wBp;f2Qk5A9yOeWMZo1ITx*Arthp@Hjr&9Pab2)q0dVH zNB_=e%=v%xTyki;F3|~5l*xohK|myZnoNi{n-S+SfI24AU*BB@;Pu&80|UPl7ysGk z!UYO>@H*(mKt8Ec=k(oSVToSX2uB8rD;W$K4H;0W>nW-Dq~d&4{?951sCekqhrUy0 z=l^{d1k^H_5MeSQN)Qlj*0)Eo9F?xj%e(o>tSqmmBGrX~JQ^O}_O;m912ho~Ff>3K z*jiY)=i!Wu&feCBE@tGradF!o3J>q@ZDknr^`n6zhl6d%&aV59yu3_ra^-ac=>!BV zNk}M;HJiN~Na4*jpACI(pXMYtkLrMIuf zeDYrn>@F%wA8_$vBX3FQRReiHE^hCD@bD|VcDdV1&)K=T|eUNeyO@$vZ`tX9qat^#dx`HQ@td zjs09}VGVk|tATwbC7E}hKVL^{3A|z;AH~I`_6-kjp|!9EJs;KpW9&cq`L~SE%G#x+ z6q*}I46%}D`Nl8WI=Uo6ciNm10mDUDA87rvN)>Y6mBm}*~!a$#iRnoyI7t_Gt z3mTwY0+gv{U16a!3C9I{wdt9c0~n~4JX#yb#{fLueNf0JrHSbl5`tSoLeS6)VV_zJ zKp@j$jNxEuDYm+Dp8Zr(0uc$EC@C7%kIB|TcUl?NiVm)n zGZcbqfW9fO2oAZ7B30cKv0VWCsJ2SAGLXgqs0N+t5Fa0pbLY-E={Pbo zVf*!0*iuu=Kj}Gs94IPMoezH{K!#v$+7y-+EnsQh9F}IyoS&u!4Un3eik2-k%Rl`Q zfZ=NESt|p18Nd{^g(3XiyLV^Xwr#6XuF|brkv)WVdj?de0U;_1rucZ6>({^XvtdJ+ z6BA)>RC8#C&1OT8b|;Vp0O|ptPt`yR10fnz(z$_ZQdB}bc<^AhXwf3WK&nx;sb0PE zNgp2%`tJO!{O^PWz^W|5wLyah?A*C?TFfhwkX8^{NmK(Z1nB|bzp6=41@W|L)7a$6 zlXYVtmbPsHn+>e65Ui-E{1NePL|YjI2ScD=WUICOGbjiG{a^)T zynXw2+;Yn;HFhuEy45fcxylvM?}Zm$z`y?WFA*)dHF*QTbKJ01L8P{UJOY4 zPoHLqiHXJvqM638Bs6#KTsC&>SheR>Wug}V)K|-aQEfrK25_&IW0jkm%OWEq4Fl0q z>6K`G`st@`x40^?)l04STr~|O+T~iJ=@mEm_qYRNi>1;Ob)j9iZXN5>r;nQRsyYEw zyAx4UkP!erP{jOh58%-Pw^IAEd%KT;2Yk|dct?d9e1!zn>HCM zh$ls<`1gW>0u~Vwq1L=|$2mFRarf3xOOSa0QdAs=YEk#?+n23fyVfuetrcI1p51O| z7K=r#dF4s6wg3)!Y9!_FY6M}kS$-n+%OPNic-vxpieHKh7g+p(2<+wkdl&udGqM?r)Dtj zLDU}>3R=5xfjmIG0(S!Vju&O#20~Tm^8k1yE8OVOquJcKbBz^**X)pqr%|IuEImD) z_uLZ8%_{(26x-NSJKjQ&8|`*aMAiDcVIXR0RvO;MjT^HwXU_1RTVk1@i!jQ+#szo_ zF$us7E}Y3gVi<@FrK!-RS+iy=EiH}r+!D(vrPhiBP%O5CyLP;V*ueV~L5h%ufk@Go zdTm>_Y{^nnQ+dxVDGc`nKv{GY18*U608nyauYh47UQzp1MBB7!!ww%l%zJK05suq^ z2u~rJ0yrT>3f^r;jvR^k^XI!oYn)>7*80`>+O=zkg9i_)PpD=J%K$vgg8`lf@+g4M zcrYaw$Izie*~cG$Y@A}rRUoH+I@n@S4z?s7;_x((*#IbKs@LF=M;>8Imo7C7#A_o^ zPB<|!k)1tzmgn4(BT)>G1lK%;pv#%tn@)~(AjGBSA1 zEjgUrR#T}BDad#VaTx%G*?J9n_wLQsuU~H%h}TA-oN#1hB+Jjw=Q+3JNHiLNd$$S^ zSa}H%51>3Dt{1^m+EHT7cu7}(fV}9Me4vUVC<~6UBsEs^2x+_6IeR&Bo5`g>jRi&JY z=pP*&%`RWQEJ`L;P~gn=?nqCE{f|FTcI+5z2M@x2=8OnR;+q7TfgCw=@J3600gAE%tu)FWRTj{*|H;?TRj|D)fAQj`k z7C>KxlYvqMk&zWD!E^lhan`I^GhT8jVI?5@E?BUDjTkXPiT){MmTIA&1W-qz659hf zpah2!K`PUw2ttY^lndk{e~s(h`Z$1QauIFWvW4~R*^`%Ca@h#jep9AQVbi8fQ=;!PL0-h8f_3|(f3UO3Yl9!f1S_&)Rc>puzDrMZbacuVN**xTu z%R)f+>)5d)+qZ9@68%$55g7(S3jkEGQ!davnkct3^;0591zn{=bONxqk`Q+Qpx}F1 z(5qK3wt4er9&*W|AIO~?4hO7OE2tEk0*I(mR*j+qr_01gwP}XQ?Cb2tV@RD;J|?ctbP0TO6Js00B)+HP?`t(0Z^eFsjvn> zf2o}+w^t%e1s-}4S}B8xvjCdY<#siFsbm|KZj%MS|Nc8mNJ!uzn=JZ)+G)|EMQrHM zp-S{l(WsNF(O(AuzsUGOr>$De)s#dGloDYo(9_+;A`!HzHmSVVtok?FH@+$Zr?boI z)vIyeeVXRYmdmPN^&2~OEauLgt3)Qc`K~Fa!Rr8?m57{zQrb!Eb47C=20|%Dr8jw2`1#@+XpgWk7Uz zOrr4sW=UXrm+KnhO_T{e4K_N8X+{M~iG zCYvuF1|lVsB2D_%0Elrnl2fDc6|kM1_a?&EyQ zKxpZtfU0dGlt4}H0r0KJwpTS;ZQ8`{y6Y|_bLl|s*7XZy8*0oBiwQYzE$Lh zQ{i?XQGdYapMTCCe)wS}11FhgAa)o$craVMc(GhP(|akMUde%m04UXHVhx?;tV~y+ zk}FhYBy`#LYYhz2i50zfC`kiJxQT{jNNy@f000UcNkl)W?tEL4RIbJriv?6vGA4#rV*}LCz_Mk_l&;d(x%q(=%QC%)(>n=;OjHI+9;fI< zl!t*3L*%zl{`(a`KKPVKu1KteZrV{Q(?0>o3KOJEi_yn8j=+&RV%(vCN~}fcxmA5 z*|SJWN`l>9lk1d6O0*^SYA$Dw9CGr-5<`ba8*)*h=tDXbkPI6)Ze(}fd8aS^AV`)` z%MPPPjbiiX&zGyuqcY<=v=q@vORj*LGwLEp7m{=_DH(3K;Rfv4L$65&DAmBJQ>UD( zhXSBjAF(b+3dkt$>T3o<7en+eBCAN~ym|9jN=k~a$*g>oIb-PFy*svVmtBhTYXJQ? zv!oh2Uz{uyNF^%}pAyQYrKN$&6dNE<151`HVNX2qgxq;UFD!KLA^X5Z9@p}F$rV&S zMddx|Lh=}Z1UaaZlatws6)SvEZaLy|?Q`kUCFij&`MAjhsv$$+5k3RHI#KBSTz0Ye z<;$1j!3W7d&HyPINKQ`1%9V1`4>+k%rbIeuQQ~$ag(p2>JzwrXH|A8Bv#3b6=MW`apoD-v2fl0|q-;fXNv2Mn%3gZuC12Nps*|p?v=kjW zba1Y?GJ(9Y>BZb9!5=1vl$iLd2I-q`zCoWpy!_>Sat^pM6{bQ;|nnGRsu&g`5W6 z1=C4Js&xl{F%Yw>1e~WB~QY04Jg;Zj2Sc7jEI#p#VPu5!GZ-CHcU}z2|1*_ z(x$w9Oc0^*Ia`o zOO}9Ky!{Ev%F5`Z3a`HUs-lWePv2+8%)#b7K`^Zc9IJ!FOIHcKAv*_<-gN922EtaO zL8&8TBp4nS1YBEL$+?9L$*-2-`y=EIBp=3&8|R!*{*bBh(4j+k{PD*@tA|_&wg4ZF z4#K0i(FyyNz`#~PV9SGRm3}4k^eyMas+ zrgcE6Y+n^`>e(j^q;yrta4Q0eE4t# z2UA@aeZ%R~r!jr{bZ2>H1xXg1Lf+oarFTWM ztqgv^4&e;}g6x#`7qc10eo%(5b}QR*RjeqqRiWD8db@?El%Q+YtZ^E}`t|D-8%A_E z@Y)ayhTb8owrcsrVXO=S<^`3NyetfKX5-X7_=JJ5uTZy4uzm^%R3e%SeEYKQkATKYE3(h{BO!#1Q5b8#Anl20%O<@0L zNiL!IbX@}{iPe*_Y*ok|j5+hGa!;^(IiKP66*kQO){dg;YVFDtt9|?Spp=|_`}PIJ zov0aeLNz%yY}kOWzy8{p0#rebj;o|?Qcu9lAr=hia`lV2Ox0BB#@-FSzl7?`=oWNs zAf+pV9tX@+icM9>%w>3Mb-AGwa1IEi7yGVVyP`#l7HHC>i8EbJ)22oA!A3jsWCzcQCrepYsy^iELO0t~P9Q%&-}$K^NrHH0D3?+&Fs{ED z@kVX~rYBno%pIcc(h=?{zk;*yTW}O$Gv;cDc5WfX8~6F!**e8rSo5pP{}GjIov0V^ zO7$#t1^P9R6+sQ7#}>KWWHA8C54WTH3zU2s9$EXP6Py9pOsftcyTGio)Zjb zFEXTGVo1*{e|~p;zpP+;M(+*{0aU)!ddCn76gz!m|* z>Y%XV&-Lv6t7`+Ptl-iWL0w=nw*^=W#y}UML zWe8vw7}#0C#7yBou^VCOC@B^xgS?g2x*W z=CBtti%=L0p%5r3gc(IbUtAWWaIM;~wFm<$p5U;uQWho%EDVB0fiqP#+%qsH*z<$z rrd$M-vYL|st6t`00000NkvXXu0mjfKif~^ literal 0 HcmV?d00001 diff --git a/src/res/drawable-xhdpi/user_login_wechat.png b/src/res/drawable-xhdpi/user_login_wechat.png new file mode 100644 index 0000000000000000000000000000000000000000..f09cbf0dec88364357f8ea708a03bf5b6389458b GIT binary patch literal 8048 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 Y^s_D|gxBc_9R5dYsB5fKsf~^K4?p=_mjD0& literal 0 HcmV?d00001 diff --git a/src/res/drawable-xxhdpi/launch.png b/src/res/drawable-xxhdpi/launch.png new file mode 100644 index 0000000000000000000000000000000000000000..80e88e743f7db73e213f5fc70b6459b3f23f9683 GIT binary patch literal 93508 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ʚ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

X%_HW3~OzIXTlyf*+H5SGXPw1qK=Bl9B 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 literal 0 HcmV?d00001 diff --git a/src/res/drawable/alert_bottom_left_shape.xml b/src/res/drawable/alert_bottom_left_shape.xml new file mode 100644 index 0000000..bbefd18 --- /dev/null +++ b/src/res/drawable/alert_bottom_left_shape.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/res/drawable/alert_bottom_left_shape_gray.xml b/src/res/drawable/alert_bottom_left_shape_gray.xml new file mode 100644 index 0000000..a23656b --- /dev/null +++ b/src/res/drawable/alert_bottom_left_shape_gray.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/res/drawable/alert_bottom_right_shape.xml b/src/res/drawable/alert_bottom_right_shape.xml new file mode 100644 index 0000000..423417b --- /dev/null +++ b/src/res/drawable/alert_bottom_right_shape.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/res/drawable/alert_bottom_right_shape_gray.xml b/src/res/drawable/alert_bottom_right_shape_gray.xml new file mode 100644 index 0000000..ffa8ccc --- /dev/null +++ b/src/res/drawable/alert_bottom_right_shape_gray.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/res/drawable/alert_bottom_shape.xml b/src/res/drawable/alert_bottom_shape.xml new file mode 100644 index 0000000..23bf7da --- /dev/null +++ b/src/res/drawable/alert_bottom_shape.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/src/res/drawable/alert_shape.xml b/src/res/drawable/alert_shape.xml new file mode 100644 index 0000000..1835354 --- /dev/null +++ b/src/res/drawable/alert_shape.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/alert_top_shape.xml b/src/res/drawable/alert_top_shape.xml new file mode 100644 index 0000000..8751978 --- /dev/null +++ b/src/res/drawable/alert_top_shape.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/alert_top_shape_gray.xml b/src/res/drawable/alert_top_shape_gray.xml new file mode 100644 index 0000000..2ed4c02 --- /dev/null +++ b/src/res/drawable/alert_top_shape_gray.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/border_input_box.xml b/src/res/drawable/border_input_box.xml new file mode 100644 index 0000000..ce6f458 --- /dev/null +++ b/src/res/drawable/border_input_box.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/src/res/drawable/border_layer_list.xml b/src/res/drawable/border_layer_list.xml new file mode 100644 index 0000000..75970f7 --- /dev/null +++ b/src/res/drawable/border_layer_list.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/btn_next_shape_gray.xml b/src/res/drawable/btn_next_shape_gray.xml new file mode 100644 index 0000000..674f838 --- /dev/null +++ b/src/res/drawable/btn_next_shape_gray.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/res/drawable/checkbox_hook_selector.xml b/src/res/drawable/checkbox_hook_selector.xml new file mode 100644 index 0000000..2f43081 --- /dev/null +++ b/src/res/drawable/checkbox_hook_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/checkbox_laws_selector.xml b/src/res/drawable/checkbox_laws_selector.xml new file mode 100644 index 0000000..061b8b4 --- /dev/null +++ b/src/res/drawable/checkbox_laws_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/common_page_back_button.xml b/src/res/drawable/common_page_back_button.xml new file mode 100644 index 0000000..edcf940 --- /dev/null +++ b/src/res/drawable/common_page_back_button.xml @@ -0,0 +1,4 @@ + + + diff --git a/src/res/drawable/common_qrcode_button.xml b/src/res/drawable/common_qrcode_button.xml new file mode 100644 index 0000000..01d1478 --- /dev/null +++ b/src/res/drawable/common_qrcode_button.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/res/drawable/common_setting_more.xml b/src/res/drawable/common_setting_more.xml new file mode 100644 index 0000000..e55da18 --- /dev/null +++ b/src/res/drawable/common_setting_more.xml @@ -0,0 +1,4 @@ + + + diff --git a/src/res/drawable/devicelist_item_selector.xml b/src/res/drawable/devicelist_item_selector.xml new file mode 100644 index 0000000..a57286d --- /dev/null +++ b/src/res/drawable/devicelist_item_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/res/drawable/deviceonboarding_add.xml b/src/res/drawable/deviceonboarding_add.xml new file mode 100644 index 0000000..6f2f2be --- /dev/null +++ b/src/res/drawable/deviceonboarding_add.xml @@ -0,0 +1,4 @@ + + + diff --git a/src/res/drawable/gray_thumb.xml b/src/res/drawable/gray_thumb.xml new file mode 100644 index 0000000..1f0a893 --- /dev/null +++ b/src/res/drawable/gray_thumb.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/gray_track.xml b/src/res/drawable/gray_track.xml new file mode 100644 index 0000000..187810c --- /dev/null +++ b/src/res/drawable/gray_track.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/green_thumb.xml b/src/res/drawable/green_thumb.xml new file mode 100644 index 0000000..6553a07 --- /dev/null +++ b/src/res/drawable/green_thumb.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/green_track.xml b/src/res/drawable/green_track.xml new file mode 100644 index 0000000..f0d37fe --- /dev/null +++ b/src/res/drawable/green_track.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/ic_list_divider.xml b/src/res/drawable/ic_list_divider.xml new file mode 100644 index 0000000..8ebba91 --- /dev/null +++ b/src/res/drawable/ic_list_divider.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/img_bg_shape.xml b/src/res/drawable/img_bg_shape.xml new file mode 100644 index 0000000..076dc54 --- /dev/null +++ b/src/res/drawable/img_bg_shape.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/res/drawable/img_bg_shape_white.xml b/src/res/drawable/img_bg_shape_white.xml new file mode 100644 index 0000000..170a204 --- /dev/null +++ b/src/res/drawable/img_bg_shape_white.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/src/res/drawable/key_number_bg.xml b/src/res/drawable/key_number_bg.xml new file mode 100644 index 0000000..9bb831b --- /dev/null +++ b/src/res/drawable/key_number_bg.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/keyboard_number.xml b/src/res/drawable/keyboard_number.xml new file mode 100644 index 0000000..bf12ad0 --- /dev/null +++ b/src/res/drawable/keyboard_number.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/res/drawable/keyboard_number_pressed.xml b/src/res/drawable/keyboard_number_pressed.xml new file mode 100644 index 0000000..7db75d5 --- /dev/null +++ b/src/res/drawable/keyboard_number_pressed.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/res/drawable/redoval.xml b/src/res/drawable/redoval.xml new file mode 100644 index 0000000..b6a8537 --- /dev/null +++ b/src/res/drawable/redoval.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/round_dot.xml b/src/res/drawable/round_dot.xml new file mode 100644 index 0000000..40b7be2 --- /dev/null +++ b/src/res/drawable/round_dot.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/res/drawable/shape_button.xml b/src/res/drawable/shape_button.xml new file mode 100644 index 0000000..8e1ca15 --- /dev/null +++ b/src/res/drawable/shape_button.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/shape_button2.xml b/src/res/drawable/shape_button2.xml new file mode 100644 index 0000000..2994bb8 --- /dev/null +++ b/src/res/drawable/shape_button2.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/tabbar_messages.xml b/src/res/drawable/tabbar_messages.xml new file mode 100644 index 0000000..cdf76a6 --- /dev/null +++ b/src/res/drawable/tabbar_messages.xml @@ -0,0 +1,12 @@ + + + + diff --git a/src/res/drawable/tabbar_mydevice.xml b/src/res/drawable/tabbar_mydevice.xml new file mode 100644 index 0000000..80d35a5 --- /dev/null +++ b/src/res/drawable/tabbar_mydevice.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/src/res/drawable/tabbar_personal.xml b/src/res/drawable/tabbar_personal.xml new file mode 100644 index 0000000..679c169 --- /dev/null +++ b/src/res/drawable/tabbar_personal.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/res/drawable/thumb.xml b/src/res/drawable/thumb.xml new file mode 100644 index 0000000..57fa830 --- /dev/null +++ b/src/res/drawable/thumb.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/res/drawable/track.xml b/src/res/drawable/track.xml new file mode 100644 index 0000000..da1b10f --- /dev/null +++ b/src/res/drawable/track.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/res/layout/.DS_Store b/src/res/layout/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..12d268ecd0ee31a7b5837f5a78fd97e01e83adc0 GIT binary patch literal 14340 zcmeHNO^+Kz5Un9bS_vdVfXzY(aYQ8G0^x!paj~Ls;LL^F;I((dD)!Fe4>rqbF9?1D zKLP#;KP7iA+~B?H8Beuc)Aj}lDN2vkZhJiay82ar)pLtT@o+i*T;#rp>>)9~{yN@% z5$Q8G7k_8kxUS(&f%F9uK3^AE$cg-jw2+I9r#ElBf?F)#L;6sLGK$KV@>nXFONsP7 zex1pYjPY%ZoOO(lmomYpIm&%1Ph~2TuP4>$a8ext5#|&>BR%^^FWhNM5iwtxfy_W= zATy8|csUv1+KX%NwUFoc%s^%!Gq7TS^Ftqr`Jm1(L#|T?-nfP5@7%)ch0oY{>%D%R z59<6fl=xc24vG(Y5AB*fqST|g(A7rU4`P^VcL>O`|(b08ceb+^W1`2D8A*rs@rUyJsJ_BZw&&N3zX z3R^Spumz=i2c|vuRvN4w3(efZIg6M-L3?dJudBG7ZI0@>y{f0d4qERadUmNEEa972 zANG+kZgxUmXrE`_*b$jysrRel<_0w6Fw=y2oQM^8K7^%Rb0bDlgmD1g7C@Q8ibn0W zOz+_B2=C5TyqMqgdX8}xq3=8BQ?!{DZ?lwsvFv#*Z~M6A!1c3w<8R{)&$bpX*-nn) zp2fNgFAmZ3D$GKhsX3F3@O^~)!PifaU%=Cq`kMbraP>ICPQkU7|3gGI+*&=~`kf}Sm+xc-G6R``%s^(qXJ8+<4>tBz>;JMhyA*eI<60~qo3;3(t$6V+ zguAdgULpQ(S3kcttkzL&j7H*}VY{Xdb&cjK?qV?-iLl;FVvVuWv6lOoSnDIq&ytvN z>^j1plDkO8nd?5F3Nb^3+w5xm+Oa2yYX9U)wO82DGg9HMeuVm#_`X1^E7aPdPpJ2Q zGv4=lQ?s`n!5YS^OWjksE#PiUEM7m+0`f)Wh`Lb;WNJQh)oW(3+QnC&Tl|zt)$I=- zo9tU`ZzQx_{8wMIr`g(4XK3PI}RR2HLIf1>Oamr5p zpW`dSe<$Hj>V4hHBxcVDDK+xrIo=;V=+6<}yGhGJ+?kB*)JvAjRL`PcsKfF!S%~r) zHPy9N{q)TE>0ZKG&gZ9?kxJx&)5(?mW$Q_?67)$%lAIG0Dv#0Wlc(pRnB9x9bNtVh zCddC+it?2i$P8o#G6OFN1Fr@<@ALfMSKa6TUy#;hGcyC3f#+eM=so)8(L{V z@T^@Q={uz6!n67~-t;IQay^QNFFcC(pm~ltejC*JWyrNC?rTxx|JxzJ9RKI|pYbvO PS>?HzR{eR&;{SgEQ)|l_ literal 0 HcmV?d00001 diff --git a/src/res/layout/activity_device_item.xml b/src/res/layout/activity_device_item.xml new file mode 100644 index 0000000..b606847 --- /dev/null +++ b/src/res/layout/activity_device_item.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/layout/activity_device_shared_message_list.xml b/src/res/layout/activity_device_shared_message_list.xml new file mode 100644 index 0000000..33aece4 --- /dev/null +++ b/src/res/layout/activity_device_shared_message_list.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/res/layout/activity_gos_about.xml b/src/res/layout/activity_gos_about.xml new file mode 100644 index 0000000..62497e6 --- /dev/null +++ b/src/res/layout/activity_gos_about.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/layout/activity_gos_addshared.xml b/src/res/layout/activity_gos_addshared.xml new file mode 100644 index 0000000..90a93a7 --- /dev/null +++ b/src/res/layout/activity_gos_addshared.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/res/layout/activity_gos_airlink_choose_device_workwifi.xml b/src/res/layout/activity_gos_airlink_choose_device_workwifi.xml new file mode 100644 index 0000000..7facd31 --- /dev/null +++ b/src/res/layout/activity_gos_airlink_choose_device_workwifi.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +