+
+
\ No newline at end of file
diff --git b/assets/packet8583.xml a/assets/packet8583.xml
new file mode 100644
index 0000000..c5c5bdc
--- /dev/null
+++ a/assets/packet8583.xml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/external_libs/bw_odm_20160526.jar a/external_libs/bw_odm_20160526.jar
new file mode 100644
index 0000000..865029f
--- /dev/null
+++ a/external_libs/bw_odm_20160526.jar
diff --git b/external_libs/classes_2.1.11_20160907.jar a/external_libs/classes_2.1.11_20160907.jar
new file mode 100644
index 0000000..3021d0b
--- /dev/null
+++ a/external_libs/classes_2.1.11_20160907.jar
diff --git b/ic_launcher-web.png a/ic_launcher-web.png
new file mode 100644
index 0000000..a18cbb4
--- /dev/null
+++ a/ic_launcher-web.png
diff --git b/libs/android-support-v4.jar a/libs/android-support-v4.jar
new file mode 100644
index 0000000..428bdbc
--- /dev/null
+++ a/libs/android-support-v4.jar
diff --git b/libs/arm64-v8a/libserial_IdCard.so a/libs/arm64-v8a/libserial_IdCard.so
new file mode 100644
index 0000000..e2257a1
--- /dev/null
+++ a/libs/arm64-v8a/libserial_IdCard.so
diff --git b/libs/armeabi/libEZTLIB.so a/libs/armeabi/libEZTLIB.so
new file mode 100644
index 0000000..3c59df3
--- /dev/null
+++ a/libs/armeabi/libEZTLIB.so
diff --git b/libs/armeabi/libfctrlgp.so a/libs/armeabi/libfctrlgp.so
new file mode 100644
index 0000000..118adcc
--- /dev/null
+++ a/libs/armeabi/libfctrlgp.so
diff --git b/libs/armeabi/libiconv.so a/libs/armeabi/libiconv.so
new file mode 100644
index 0000000..429d22e
--- /dev/null
+++ a/libs/armeabi/libiconv.so
diff --git b/libs/armeabi/libidcread.so a/libs/armeabi/libidcread.so
new file mode 100644
index 0000000..61146d8
--- /dev/null
+++ a/libs/armeabi/libidcread.so
diff --git b/libs/armeabi/libpwmV2.so a/libs/armeabi/libpwmV2.so
new file mode 100644
index 0000000..5dfd4d3
--- /dev/null
+++ a/libs/armeabi/libpwmV2.so
diff --git b/libs/armeabi/libserial_IdCard.so a/libs/armeabi/libserial_IdCard.so
new file mode 100644
index 0000000..f65651d
--- /dev/null
+++ a/libs/armeabi/libserial_IdCard.so
diff --git b/libs/armeabi/libserial_port.so a/libs/armeabi/libserial_port.so
new file mode 100644
index 0000000..2b54f5b
--- /dev/null
+++ a/libs/armeabi/libserial_port.so
diff --git b/libs/armeabi/libserial_portHandset.so a/libs/armeabi/libserial_portHandset.so
new file mode 100644
index 0000000..016e782
--- /dev/null
+++ a/libs/armeabi/libserial_portHandset.so
diff --git b/libs/armeabi/libserial_port_newhandset.so a/libs/armeabi/libserial_port_newhandset.so
new file mode 100644
index 0000000..b2d1f9d
--- /dev/null
+++ a/libs/armeabi/libserial_port_newhandset.so
diff --git b/libs/armeabi/libzbarjni.so a/libs/armeabi/libzbarjni.so
new file mode 100644
index 0000000..526a98d
--- /dev/null
+++ a/libs/armeabi/libzbarjni.so
diff --git b/libs/bcprov-jdk16-1.45.jar a/libs/bcprov-jdk16-1.45.jar
new file mode 100644
index 0000000..38685d5
--- /dev/null
+++ a/libs/bcprov-jdk16-1.45.jar
diff --git b/libs/bw_pos_sdk2.0.18.jar a/libs/bw_pos_sdk2.0.18.jar
new file mode 100644
index 0000000..498b9ca
--- /dev/null
+++ a/libs/bw_pos_sdk2.0.18.jar
diff --git b/libs/dom4j-1.6.1.jar a/libs/dom4j-1.6.1.jar
new file mode 100644
index 0000000..c8c4dbb
--- /dev/null
+++ a/libs/dom4j-1.6.1.jar
diff --git b/libs/fastjson-1.2.3.jar a/libs/fastjson-1.2.3.jar
new file mode 100644
index 0000000..3ad28cd
--- /dev/null
+++ a/libs/fastjson-1.2.3.jar
diff --git b/libs/gson-2.6.2.jar a/libs/gson-2.6.2.jar
new file mode 100644
index 0000000..9d78626
--- /dev/null
+++ a/libs/gson-2.6.2.jar
diff --git b/libs/mips/libserial_IdCard.so a/libs/mips/libserial_IdCard.so
new file mode 100644
index 0000000..8d90475
--- /dev/null
+++ a/libs/mips/libserial_IdCard.so
diff --git b/libs/mips64/libserial_IdCard.so a/libs/mips64/libserial_IdCard.so
new file mode 100644
index 0000000..502ecc7
--- /dev/null
+++ a/libs/mips64/libserial_IdCard.so
diff --git b/libs/sunjce_provider.jar a/libs/sunjce_provider.jar
new file mode 100644
index 0000000..1203ff2
--- /dev/null
+++ a/libs/sunjce_provider.jar
diff --git b/libs/x86/libserial_IdCard.so a/libs/x86/libserial_IdCard.so
new file mode 100644
index 0000000..6e6a807
--- /dev/null
+++ a/libs/x86/libserial_IdCard.so
diff --git b/libs/x86/libserial_port.so a/libs/x86/libserial_port.so
new file mode 100644
index 0000000..4f1f03e
--- /dev/null
+++ a/libs/x86/libserial_port.so
diff --git b/libs/zbar.jar a/libs/zbar.jar
new file mode 100644
index 0000000..7d50b95
--- /dev/null
+++ a/libs/zbar.jar
diff --git b/libs/zxing.jar a/libs/zxing.jar
new file mode 100644
index 0000000..29fa881
--- /dev/null
+++ a/libs/zxing.jar
diff --git b/res/color/date_picker_selector.xml a/res/color/date_picker_selector.xml
new file mode 100644
index 0000000..c0527c3
--- /dev/null
+++ a/res/color/date_picker_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/color/date_picker_year_selector.xml a/res/color/date_picker_year_selector.xml
new file mode 100644
index 0000000..7dab2aa
--- /dev/null
+++ a/res/color/date_picker_year_selector.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git b/res/color/done_text_color.xml a/res/color/done_text_color.xml
new file mode 100644
index 0000000..549a209
--- /dev/null
+++ a/res/color/done_text_color.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git b/res/color/mr_calendar_text_selector.xml a/res/color/mr_calendar_text_selector.xml
new file mode 100644
index 0000000..9abdfea
--- /dev/null
+++ a/res/color/mr_calendar_text_selector.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/color/num_textcolor_selector.xml a/res/color/num_textcolor_selector.xml
new file mode 100644
index 0000000..8bd32d7
--- /dev/null
+++ a/res/color/num_textcolor_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable-hdpi/backgrouds.png a/res/drawable-hdpi/backgrouds.png
new file mode 100644
index 0000000..28ad784
--- /dev/null
+++ a/res/drawable-hdpi/backgrouds.png
diff --git b/res/drawable-hdpi/btn_num.9.png a/res/drawable-hdpi/btn_num.9.png
new file mode 100644
index 0000000..f15a221
--- /dev/null
+++ a/res/drawable-hdpi/btn_num.9.png
diff --git b/res/drawable-hdpi/checkbox_off.png a/res/drawable-hdpi/checkbox_off.png
new file mode 100644
index 0000000..e2c0e78
--- /dev/null
+++ a/res/drawable-hdpi/checkbox_off.png
diff --git b/res/drawable-hdpi/checkbox_on.png a/res/drawable-hdpi/checkbox_on.png
new file mode 100644
index 0000000..5e3520d
--- /dev/null
+++ a/res/drawable-hdpi/checkbox_on.png
diff --git b/res/drawable-hdpi/circle.png a/res/drawable-hdpi/circle.png
new file mode 100644
index 0000000..9bb6755
--- /dev/null
+++ a/res/drawable-hdpi/circle.png
diff --git b/res/drawable-hdpi/circle_selector.png a/res/drawable-hdpi/circle_selector.png
new file mode 100644
index 0000000..afff1f4
--- /dev/null
+++ a/res/drawable-hdpi/circle_selector.png
diff --git b/res/drawable-hdpi/count_colorful.png a/res/drawable-hdpi/count_colorful.png
new file mode 100644
index 0000000..8713920
--- /dev/null
+++ a/res/drawable-hdpi/count_colorful.png
diff --git b/res/drawable-hdpi/count_gray.png a/res/drawable-hdpi/count_gray.png
new file mode 100644
index 0000000..96d5849
--- /dev/null
+++ a/res/drawable-hdpi/count_gray.png
diff --git b/res/drawable-hdpi/dapiao.9.png a/res/drawable-hdpi/dapiao.9.png
new file mode 100644
index 0000000..7cd85aa
--- /dev/null
+++ a/res/drawable-hdpi/dapiao.9.png
diff --git b/res/drawable-hdpi/ico_choose.png a/res/drawable-hdpi/ico_choose.png
new file mode 100644
index 0000000..c88f133
--- /dev/null
+++ a/res/drawable-hdpi/ico_choose.png
diff --git b/res/drawable-hdpi/ico_choose_checked.png a/res/drawable-hdpi/ico_choose_checked.png
new file mode 100644
index 0000000..6b5c503
--- /dev/null
+++ a/res/drawable-hdpi/ico_choose_checked.png
diff --git b/res/drawable-hdpi/id2.jpg a/res/drawable-hdpi/id2.jpg
new file mode 100644
index 0000000..429069b
--- /dev/null
+++ a/res/drawable-hdpi/id2.jpg
diff --git b/res/drawable-hdpi/id_blue.png a/res/drawable-hdpi/id_blue.png
new file mode 100644
index 0000000..8011f06
--- /dev/null
+++ a/res/drawable-hdpi/id_blue.png
diff --git b/res/drawable-hdpi/id_red.png a/res/drawable-hdpi/id_red.png
new file mode 100644
index 0000000..d679cec
--- /dev/null
+++ a/res/drawable-hdpi/id_red.png
diff --git b/res/drawable-hdpi/logo_cyt.png a/res/drawable-hdpi/logo_cyt.png
new file mode 100644
index 0000000..01e73f0
--- /dev/null
+++ a/res/drawable-hdpi/logo_cyt.png
diff --git b/res/drawable-hdpi/logo_llt.png a/res/drawable-hdpi/logo_llt.png
new file mode 100644
index 0000000..6e029be
--- /dev/null
+++ a/res/drawable-hdpi/logo_llt.png
diff --git b/res/drawable-hdpi/logo_qne.png a/res/drawable-hdpi/logo_qne.png
new file mode 100644
index 0000000..edd7cbf
--- /dev/null
+++ a/res/drawable-hdpi/logo_qne.png
diff --git b/res/drawable-hdpi/logo_qne_launcher.png a/res/drawable-hdpi/logo_qne_launcher.png
new file mode 100644
index 0000000..9cc4500
--- /dev/null
+++ a/res/drawable-hdpi/logo_qne_launcher.png
diff --git b/res/drawable-hdpi/main_cyt.jpg a/res/drawable-hdpi/main_cyt.jpg
new file mode 100644
index 0000000..7ad89d5
--- /dev/null
+++ a/res/drawable-hdpi/main_cyt.jpg
diff --git b/res/drawable-hdpi/main_cyt_pad.png a/res/drawable-hdpi/main_cyt_pad.png
new file mode 100644
index 0000000..0dc6190
--- /dev/null
+++ a/res/drawable-hdpi/main_cyt_pad.png
diff --git b/res/drawable-hdpi/main_emc.jpg a/res/drawable-hdpi/main_emc.jpg
new file mode 100644
index 0000000..e5b4ebc
--- /dev/null
+++ a/res/drawable-hdpi/main_emc.jpg
diff --git b/res/drawable-hdpi/main_emc_pad.png a/res/drawable-hdpi/main_emc_pad.png
new file mode 100644
index 0000000..5cea6d4
--- /dev/null
+++ a/res/drawable-hdpi/main_emc_pad.png
diff --git b/res/drawable-hdpi/main_lly.jpg a/res/drawable-hdpi/main_lly.jpg
new file mode 100644
index 0000000..0f42b39
--- /dev/null
+++ a/res/drawable-hdpi/main_lly.jpg
diff --git b/res/drawable-hdpi/main_lly_pad.png a/res/drawable-hdpi/main_lly_pad.png
new file mode 100644
index 0000000..9eeb3f8
--- /dev/null
+++ a/res/drawable-hdpi/main_lly_pad.png
diff --git b/res/drawable-hdpi/main_qne.jpg a/res/drawable-hdpi/main_qne.jpg
new file mode 100644
index 0000000..2d69c08
--- /dev/null
+++ a/res/drawable-hdpi/main_qne.jpg
diff --git b/res/drawable-hdpi/main_qnr_pad.png a/res/drawable-hdpi/main_qnr_pad.png
new file mode 100644
index 0000000..a145b61
--- /dev/null
+++ a/res/drawable-hdpi/main_qnr_pad.png
diff --git b/res/drawable-hdpi/no_data.png a/res/drawable-hdpi/no_data.png
new file mode 100644
index 0000000..f2e42d9
--- /dev/null
+++ a/res/drawable-hdpi/no_data.png
diff --git b/res/drawable-hdpi/num_blue.png a/res/drawable-hdpi/num_blue.png
new file mode 100644
index 0000000..0a71c9b
--- /dev/null
+++ a/res/drawable-hdpi/num_blue.png
diff --git b/res/drawable-hdpi/num_red.png a/res/drawable-hdpi/num_red.png
new file mode 100644
index 0000000..4077062
--- /dev/null
+++ a/res/drawable-hdpi/num_red.png
diff --git b/res/drawable-hdpi/pos.png a/res/drawable-hdpi/pos.png
new file mode 100644
index 0000000..ec5610b
--- /dev/null
+++ a/res/drawable-hdpi/pos.png
diff --git b/res/drawable-hdpi/printer_blue.png a/res/drawable-hdpi/printer_blue.png
new file mode 100644
index 0000000..98a9dd3
--- /dev/null
+++ a/res/drawable-hdpi/printer_blue.png
diff --git b/res/drawable-hdpi/printer_red.png a/res/drawable-hdpi/printer_red.png
new file mode 100644
index 0000000..0edab68
--- /dev/null
+++ a/res/drawable-hdpi/printer_red.png
diff --git b/res/drawable-hdpi/qr_code_bg.9.png a/res/drawable-hdpi/qr_code_bg.9.png
new file mode 100644
index 0000000..dc6316d
--- /dev/null
+++ a/res/drawable-hdpi/qr_code_bg.9.png
diff --git b/res/drawable-hdpi/scan_line.png a/res/drawable-hdpi/scan_line.png
new file mode 100644
index 0000000..531e83d
--- /dev/null
+++ a/res/drawable-hdpi/scan_line.png
diff --git b/res/drawable-hdpi/scanning_blue.png a/res/drawable-hdpi/scanning_blue.png
new file mode 100644
index 0000000..62ec140
--- /dev/null
+++ a/res/drawable-hdpi/scanning_blue.png
diff --git b/res/drawable-hdpi/scanning_red.png a/res/drawable-hdpi/scanning_red.png
new file mode 100644
index 0000000..3828d23
--- /dev/null
+++ a/res/drawable-hdpi/scanning_red.png
diff --git b/res/drawable-hdpi/set_colorful.png a/res/drawable-hdpi/set_colorful.png
new file mode 100644
index 0000000..6325650
--- /dev/null
+++ a/res/drawable-hdpi/set_colorful.png
diff --git b/res/drawable-hdpi/set_gray.png a/res/drawable-hdpi/set_gray.png
new file mode 100644
index 0000000..963f5e1
--- /dev/null
+++ a/res/drawable-hdpi/set_gray.png
diff --git b/res/drawable-hdpi/shadow.png a/res/drawable-hdpi/shadow.png
new file mode 100644
index 0000000..6be3091
--- /dev/null
+++ a/res/drawable-hdpi/shadow.png
diff --git b/res/drawable-hdpi/switch_btn_off.png a/res/drawable-hdpi/switch_btn_off.png
new file mode 100644
index 0000000..546b929
--- /dev/null
+++ a/res/drawable-hdpi/switch_btn_off.png
diff --git b/res/drawable-hdpi/switch_btn_on.png a/res/drawable-hdpi/switch_btn_on.png
new file mode 100644
index 0000000..268ebb7
--- /dev/null
+++ a/res/drawable-hdpi/switch_btn_on.png
diff --git b/res/drawable-hdpi/tel_blue.png a/res/drawable-hdpi/tel_blue.png
new file mode 100644
index 0000000..8c3331b
--- /dev/null
+++ a/res/drawable-hdpi/tel_blue.png
diff --git b/res/drawable-hdpi/tel_red.png a/res/drawable-hdpi/tel_red.png
new file mode 100644
index 0000000..c38cf49
--- /dev/null
+++ a/res/drawable-hdpi/tel_red.png
diff --git b/res/drawable-hdpi/ticket_blue.png a/res/drawable-hdpi/ticket_blue.png
new file mode 100644
index 0000000..55138d8
--- /dev/null
+++ a/res/drawable-hdpi/ticket_blue.png
diff --git b/res/drawable-hdpi/ticket_red.png a/res/drawable-hdpi/ticket_red.png
new file mode 100644
index 0000000..74b5f11
--- /dev/null
+++ a/res/drawable-hdpi/ticket_red.png
diff --git b/res/drawable-hdpi/top_arrow.png a/res/drawable-hdpi/top_arrow.png
new file mode 100644
index 0000000..6cf448e
--- /dev/null
+++ a/res/drawable-hdpi/top_arrow.png
diff --git b/res/drawable-hdpi/welcome_bg_cyt.jpg a/res/drawable-hdpi/welcome_bg_cyt.jpg
new file mode 100644
index 0000000..243e60a
--- /dev/null
+++ a/res/drawable-hdpi/welcome_bg_cyt.jpg
diff --git b/res/drawable-hdpi/welcome_bg_qne.jpg a/res/drawable-hdpi/welcome_bg_qne.jpg
new file mode 100644
index 0000000..1a1cc18
--- /dev/null
+++ a/res/drawable-hdpi/welcome_bg_qne.jpg
diff --git b/res/drawable-mdpi/welcome_bg_cyt.jpg a/res/drawable-mdpi/welcome_bg_cyt.jpg
new file mode 100644
index 0000000..4e44195
--- /dev/null
+++ a/res/drawable-mdpi/welcome_bg_cyt.jpg
diff --git b/res/drawable-mdpi/welcome_bg_qne.jpg a/res/drawable-mdpi/welcome_bg_qne.jpg
new file mode 100644
index 0000000..7c32d67
--- /dev/null
+++ a/res/drawable-mdpi/welcome_bg_qne.jpg
diff --git b/res/drawable-xhdpi/about_icon.png a/res/drawable-xhdpi/about_icon.png
new file mode 100644
index 0000000..7dd77d0
--- /dev/null
+++ a/res/drawable-xhdpi/about_icon.png
diff --git b/res/drawable-xhdpi/checkswitch_bottom.png a/res/drawable-xhdpi/checkswitch_bottom.png
new file mode 100644
index 0000000..8076a1e
--- /dev/null
+++ a/res/drawable-xhdpi/checkswitch_bottom.png
diff --git b/res/drawable-xhdpi/checkswitch_btn_pressed.png a/res/drawable-xhdpi/checkswitch_btn_pressed.png
new file mode 100644
index 0000000..2c3bdd8
--- /dev/null
+++ a/res/drawable-xhdpi/checkswitch_btn_pressed.png
diff --git b/res/drawable-xhdpi/checkswitch_btn_unpressed.png a/res/drawable-xhdpi/checkswitch_btn_unpressed.png
new file mode 100644
index 0000000..7ac5440
--- /dev/null
+++ a/res/drawable-xhdpi/checkswitch_btn_unpressed.png
diff --git b/res/drawable-xhdpi/checkswitch_frame.png a/res/drawable-xhdpi/checkswitch_frame.png
new file mode 100644
index 0000000..da7b567
--- /dev/null
+++ a/res/drawable-xhdpi/checkswitch_frame.png
diff --git b/res/drawable-xhdpi/checkswitch_mask.png a/res/drawable-xhdpi/checkswitch_mask.png
new file mode 100644
index 0000000..0f8dded
--- /dev/null
+++ a/res/drawable-xhdpi/checkswitch_mask.png
diff --git b/res/drawable-xhdpi/code_icon.png a/res/drawable-xhdpi/code_icon.png
new file mode 100644
index 0000000..61d6d11
--- /dev/null
+++ a/res/drawable-xhdpi/code_icon.png
diff --git b/res/drawable-xhdpi/day_icon.png a/res/drawable-xhdpi/day_icon.png
new file mode 100644
index 0000000..967d4e1
--- /dev/null
+++ a/res/drawable-xhdpi/day_icon.png
diff --git b/res/drawable-xhdpi/handset_code.png a/res/drawable-xhdpi/handset_code.png
new file mode 100644
index 0000000..d736c36
--- /dev/null
+++ a/res/drawable-xhdpi/handset_code.png
diff --git b/res/drawable-xhdpi/icon_bg02.9.png a/res/drawable-xhdpi/icon_bg02.9.png
new file mode 100644
index 0000000..29e7680
--- /dev/null
+++ a/res/drawable-xhdpi/icon_bg02.9.png
diff --git b/res/drawable-xhdpi/id_icon.png a/res/drawable-xhdpi/id_icon.png
new file mode 100644
index 0000000..f8e0e2f
--- /dev/null
+++ a/res/drawable-xhdpi/id_icon.png
diff --git b/res/drawable-xhdpi/month_icon.png a/res/drawable-xhdpi/month_icon.png
new file mode 100644
index 0000000..0a0c3b5
--- /dev/null
+++ a/res/drawable-xhdpi/month_icon.png
diff --git b/res/drawable-xhdpi/order_icon.png a/res/drawable-xhdpi/order_icon.png
new file mode 100644
index 0000000..321753a
--- /dev/null
+++ a/res/drawable-xhdpi/order_icon.png
diff --git b/res/drawable-xhdpi/qrcode_icon.png a/res/drawable-xhdpi/qrcode_icon.png
new file mode 100644
index 0000000..be46402
--- /dev/null
+++ a/res/drawable-xhdpi/qrcode_icon.png
diff --git b/res/drawable-xhdpi/query_icon.png a/res/drawable-xhdpi/query_icon.png
new file mode 100644
index 0000000..e057b7e
--- /dev/null
+++ a/res/drawable-xhdpi/query_icon.png
diff --git b/res/drawable-xhdpi/read_idcard.jpg a/res/drawable-xhdpi/read_idcard.jpg
new file mode 100644
index 0000000..74e7c06
--- /dev/null
+++ a/res/drawable-xhdpi/read_idcard.jpg
diff --git b/res/drawable-xhdpi/statistic_icon.png a/res/drawable-xhdpi/statistic_icon.png
new file mode 100644
index 0000000..127a8ff
--- /dev/null
+++ a/res/drawable-xhdpi/statistic_icon.png
diff --git b/res/drawable-xhdpi/switch_btn_slipper.png a/res/drawable-xhdpi/switch_btn_slipper.png
new file mode 100644
index 0000000..3690a79
--- /dev/null
+++ a/res/drawable-xhdpi/switch_btn_slipper.png
diff --git b/res/drawable/bg_button_cricleshape.xml a/res/drawable/bg_button_cricleshape.xml
new file mode 100644
index 0000000..12f42b7
--- /dev/null
+++ a/res/drawable/bg_button_cricleshape.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/bg_cricle_shape.xml a/res/drawable/bg_cricle_shape.xml
new file mode 100644
index 0000000..0f3ff18
--- /dev/null
+++ a/res/drawable/bg_cricle_shape.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/bg_list_item_cricleshape.xml a/res/drawable/bg_list_item_cricleshape.xml
new file mode 100644
index 0000000..2c4ea49
--- /dev/null
+++ a/res/drawable/bg_list_item_cricleshape.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_all_shape.xml a/res/drawable/btn_all_shape.xml
new file mode 100644
index 0000000..f6eb0b7
--- /dev/null
+++ a/res/drawable/btn_all_shape.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_blu_devices_selector.xml a/res/drawable/btn_blu_devices_selector.xml
new file mode 100644
index 0000000..082a353
--- /dev/null
+++ a/res/drawable/btn_blu_devices_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_collections_bg.xml a/res/drawable/btn_collections_bg.xml
new file mode 100644
index 0000000..cc75b04
--- /dev/null
+++ a/res/drawable/btn_collections_bg.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_part_shape.xml a/res/drawable/btn_part_shape.xml
new file mode 100644
index 0000000..2dda350
--- /dev/null
+++ a/res/drawable/btn_part_shape.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_scan_id_selector.xml a/res/drawable/btn_scan_id_selector.xml
new file mode 100644
index 0000000..c657379
--- /dev/null
+++ a/res/drawable/btn_scan_id_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_shape.xml a/res/drawable/btn_shape.xml
new file mode 100644
index 0000000..a0a5485
--- /dev/null
+++ a/res/drawable/btn_shape.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_tongji_selector.xml a/res/drawable/btn_tongji_selector.xml
new file mode 100644
index 0000000..2a9847d
--- /dev/null
+++ a/res/drawable/btn_tongji_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/btn_wheel.9.png a/res/drawable/btn_wheel.9.png
new file mode 100644
index 0000000..1b51cd4
--- /dev/null
+++ a/res/drawable/btn_wheel.9.png
diff --git b/res/drawable/check_selector.xml a/res/drawable/check_selector.xml
new file mode 100644
index 0000000..363caf1
--- /dev/null
+++ a/res/drawable/check_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/dialog_shape.xml a/res/drawable/dialog_shape.xml
new file mode 100644
index 0000000..bf925da
--- /dev/null
+++ a/res/drawable/dialog_shape.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/id_selector.xml a/res/drawable/id_selector.xml
new file mode 100644
index 0000000..5a301e5
--- /dev/null
+++ a/res/drawable/id_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/login_dialog_shape.xml a/res/drawable/login_dialog_shape.xml
new file mode 100644
index 0000000..255807c
--- /dev/null
+++ a/res/drawable/login_dialog_shape.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/drawable/main_btn_shape_bg.xml a/res/drawable/main_btn_shape_bg.xml
new file mode 100644
index 0000000..097824c
--- /dev/null
+++ a/res/drawable/main_btn_shape_bg.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/mm_title_back_btn.xml a/res/drawable/mm_title_back_btn.xml
new file mode 100644
index 0000000..a2d1086
--- /dev/null
+++ a/res/drawable/mm_title_back_btn.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/mm_title_back_focused.PNG a/res/drawable/mm_title_back_focused.PNG
new file mode 100644
index 0000000..e979613
--- /dev/null
+++ a/res/drawable/mm_title_back_focused.PNG
diff --git b/res/drawable/mm_title_back_normal.PNG a/res/drawable/mm_title_back_normal.PNG
new file mode 100644
index 0000000..f57da3d
--- /dev/null
+++ a/res/drawable/mm_title_back_normal.PNG
diff --git b/res/drawable/mm_title_back_pressed.PNG a/res/drawable/mm_title_back_pressed.PNG
new file mode 100644
index 0000000..8cb91f6
--- /dev/null
+++ a/res/drawable/mm_title_back_pressed.PNG
diff --git b/res/drawable/mmtitle_bg_alpha.PNG a/res/drawable/mmtitle_bg_alpha.PNG
new file mode 100644
index 0000000..99528cc
--- /dev/null
+++ a/res/drawable/mmtitle_bg_alpha.PNG
diff --git b/res/drawable/mr_calendar_bg_selector.xml a/res/drawable/mr_calendar_bg_selector.xml
new file mode 100644
index 0000000..0eba7e7
--- /dev/null
+++ a/res/drawable/mr_calendar_bg_selector.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/drawable/navigation_list_bg.xml a/res/drawable/navigation_list_bg.xml
new file mode 100644
index 0000000..6799d13
--- /dev/null
+++ a/res/drawable/navigation_list_bg.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
diff --git b/res/drawable/order_selector.xml a/res/drawable/order_selector.xml
new file mode 100644
index 0000000..710e6e2
--- /dev/null
+++ a/res/drawable/order_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/phone_selector.xml a/res/drawable/phone_selector.xml
new file mode 100644
index 0000000..091d65f
--- /dev/null
+++ a/res/drawable/phone_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/repaint_selector.xml a/res/drawable/repaint_selector.xml
new file mode 100644
index 0000000..2de35e6
--- /dev/null
+++ a/res/drawable/repaint_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/scan_selector.xml a/res/drawable/scan_selector.xml
new file mode 100644
index 0000000..f874892
--- /dev/null
+++ a/res/drawable/scan_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/set_choice_blue.png a/res/drawable/set_choice_blue.png
new file mode 100644
index 0000000..22e1f98
--- /dev/null
+++ a/res/drawable/set_choice_blue.png
diff --git b/res/drawable/set_choice_gray.png a/res/drawable/set_choice_gray.png
new file mode 100644
index 0000000..ebc4a26
--- /dev/null
+++ a/res/drawable/set_choice_gray.png
diff --git b/res/drawable/set_selector.xml a/res/drawable/set_selector.xml
new file mode 100644
index 0000000..e450cb3
--- /dev/null
+++ a/res/drawable/set_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/statistic_selector.xml a/res/drawable/statistic_selector.xml
new file mode 100644
index 0000000..5728804
--- /dev/null
+++ a/res/drawable/statistic_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/switch_btn.xml a/res/drawable/switch_btn.xml
new file mode 100644
index 0000000..ba5fb5d
--- /dev/null
+++ a/res/drawable/switch_btn.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/textstyle.xml a/res/drawable/textstyle.xml
new file mode 100644
index 0000000..f2af35f
--- /dev/null
+++ a/res/drawable/textstyle.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/drawable/toast_img.9.png a/res/drawable/toast_img.9.png
new file mode 100644
index 0000000..0827e4c
--- /dev/null
+++ a/res/drawable/toast_img.9.png
diff --git b/res/drawable/wheel_bg_hor.xml a/res/drawable/wheel_bg_hor.xml
new file mode 100644
index 0000000..a19c201
--- /dev/null
+++ a/res/drawable/wheel_bg_hor.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/wheel_bg_ver.xml a/res/drawable/wheel_bg_ver.xml
new file mode 100644
index 0000000..44c42b6
--- /dev/null
+++ a/res/drawable/wheel_bg_ver.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/drawable/wheel_val.xml a/res/drawable/wheel_val.xml
new file mode 100644
index 0000000..f93e4b2
--- /dev/null
+++ a/res/drawable/wheel_val.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git b/res/drawable/xuxian_shape.xml a/res/drawable/xuxian_shape.xml
new file mode 100644
index 0000000..418d797
--- /dev/null
+++ a/res/drawable/xuxian_shape.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-land/app_grid_item.xml a/res/layout-land/app_grid_item.xml
new file mode 100644
index 0000000..06e3482
--- /dev/null
+++ a/res/layout-land/app_grid_item.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-land/app_idcard_temple.xml a/res/layout-land/app_idcard_temple.xml
new file mode 100644
index 0000000..1967056
--- /dev/null
+++ a/res/layout-land/app_idcard_temple.xml
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-land/app_input_orid.xml a/res/layout-land/app_input_orid.xml
new file mode 100644
index 0000000..d14dc3b
--- /dev/null
+++ a/res/layout-land/app_input_orid.xml
@@ -0,0 +1,316 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-land/app_welcome.xml a/res/layout-land/app_welcome.xml
new file mode 100644
index 0000000..7c8ca04
--- /dev/null
+++ a/res/layout-land/app_welcome.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git b/res/layout-land/date_picker_dialog.xml a/res/layout-land/date_picker_dialog.xml
new file mode 100644
index 0000000..865e92c
--- /dev/null
+++ a/res/layout-land/date_picker_dialog.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-land/small_select_grid_item.xml a/res/layout-land/small_select_grid_item.xml
new file mode 100644
index 0000000..1395028
--- /dev/null
+++ a/res/layout-land/small_select_grid_item.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-land/time_picker_dialog.xml a/res/layout-land/time_picker_dialog.xml
new file mode 100644
index 0000000..d24cfc0
--- /dev/null
+++ a/res/layout-land/time_picker_dialog.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout-sw360dp/app_top_title.xml a/res/layout-sw360dp/app_top_title.xml
new file mode 100644
index 0000000..441f209
--- /dev/null
+++ a/res/layout-sw360dp/app_top_title.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-sw360dp/statistics_day_activity.xml a/res/layout-sw360dp/statistics_day_activity.xml
new file mode 100644
index 0000000..ff75664
--- /dev/null
+++ a/res/layout-sw360dp/statistics_day_activity.xml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout-sw360dp/statistics_mon_activity.xml a/res/layout-sw360dp/statistics_mon_activity.xml
new file mode 100644
index 0000000..3921c1b
--- /dev/null
+++ a/res/layout-sw360dp/statistics_mon_activity.xml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/activity_about.xml a/res/layout/activity_about.xml
new file mode 100644
index 0000000..89eda3f
--- /dev/null
+++ a/res/layout/activity_about.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/activity_capture.xml a/res/layout/activity_capture.xml
new file mode 100644
index 0000000..e86b429
--- /dev/null
+++ a/res/layout/activity_capture.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/activity_capture2.xml a/res/layout/activity_capture2.xml
new file mode 100644
index 0000000..4407e38
--- /dev/null
+++ a/res/layout/activity_capture2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/activity_newhandle_scaner.xml a/res/layout/activity_newhandle_scaner.xml
new file mode 100644
index 0000000..a98a225
--- /dev/null
+++ a/res/layout/activity_newhandle_scaner.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/activity_title.xml a/res/layout/activity_title.xml
new file mode 100644
index 0000000..87f054d
--- /dev/null
+++ a/res/layout/activity_title.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/activity_zbar.xml a/res/layout/activity_zbar.xml
new file mode 100644
index 0000000..fdb11d2
--- /dev/null
+++ a/res/layout/activity_zbar.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_dialog_list.xml a/res/layout/app_dialog_list.xml
new file mode 100644
index 0000000..58d819d
--- /dev/null
+++ a/res/layout/app_dialog_list.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_grid_item.xml a/res/layout/app_grid_item.xml
new file mode 100644
index 0000000..c2aadaa
--- /dev/null
+++ a/res/layout/app_grid_item.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_idcard_temple.xml a/res/layout/app_idcard_temple.xml
new file mode 100644
index 0000000..1a47f2a
--- /dev/null
+++ a/res/layout/app_idcard_temple.xml
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_input_idcard.xml a/res/layout/app_input_idcard.xml
new file mode 100644
index 0000000..c94f307
--- /dev/null
+++ a/res/layout/app_input_idcard.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_input_orid.xml a/res/layout/app_input_orid.xml
new file mode 100644
index 0000000..2f4323d
--- /dev/null
+++ a/res/layout/app_input_orid.xml
@@ -0,0 +1,312 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_line_downitem.xml a/res/layout/app_line_downitem.xml
new file mode 100644
index 0000000..3f5a029
--- /dev/null
+++ a/res/layout/app_line_downitem.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_list_template.xml a/res/layout/app_list_template.xml
new file mode 100644
index 0000000..38aab83
--- /dev/null
+++ a/res/layout/app_list_template.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_main.xml a/res/layout/app_main.xml
new file mode 100644
index 0000000..ad69c24
--- /dev/null
+++ a/res/layout/app_main.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_ord_scanner.xml a/res/layout/app_ord_scanner.xml
new file mode 100644
index 0000000..b33c51b
--- /dev/null
+++ a/res/layout/app_ord_scanner.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_order_list.xml a/res/layout/app_order_list.xml
new file mode 100644
index 0000000..ae0bec4
--- /dev/null
+++ a/res/layout/app_order_list.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_orderlist_item.xml a/res/layout/app_orderlist_item.xml
new file mode 100644
index 0000000..e478b51
--- /dev/null
+++ a/res/layout/app_orderlist_item.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_reprint.xml a/res/layout/app_reprint.xml
new file mode 100644
index 0000000..4b9d484
--- /dev/null
+++ a/res/layout/app_reprint.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_result.xml a/res/layout/app_result.xml
new file mode 100644
index 0000000..1c90001
--- /dev/null
+++ a/res/layout/app_result.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_scan_handset.xml a/res/layout/app_scan_handset.xml
new file mode 100644
index 0000000..36219c9
--- /dev/null
+++ a/res/layout/app_scan_handset.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/app_selection_action.xml a/res/layout/app_selection_action.xml
new file mode 100644
index 0000000..49f46d7
--- /dev/null
+++ a/res/layout/app_selection_action.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_settings.xml a/res/layout/app_settings.xml
new file mode 100644
index 0000000..b67f48d
--- /dev/null
+++ a/res/layout/app_settings.xml
@@ -0,0 +1,450 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_top_title.xml a/res/layout/app_top_title.xml
new file mode 100644
index 0000000..fd9008f
--- /dev/null
+++ a/res/layout/app_top_title.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_top_title_old.xml a/res/layout/app_top_title_old.xml
new file mode 100644
index 0000000..2eba628
--- /dev/null
+++ a/res/layout/app_top_title_old.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_update_notice.xml a/res/layout/app_update_notice.xml
new file mode 100644
index 0000000..4f9be36
--- /dev/null
+++ a/res/layout/app_update_notice.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/app_update_progress.xml a/res/layout/app_update_progress.xml
new file mode 100644
index 0000000..21b721d
--- /dev/null
+++ a/res/layout/app_update_progress.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git b/res/layout/app_welcome.xml a/res/layout/app_welcome.xml
new file mode 100644
index 0000000..cfcf791
--- /dev/null
+++ a/res/layout/app_welcome.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git b/res/layout/child_list_item.xml a/res/layout/child_list_item.xml
new file mode 100644
index 0000000..7fc7e0b
--- /dev/null
+++ a/res/layout/child_list_item.xml
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/child_list_item_ldip.xml a/res/layout/child_list_item_ldip.xml
new file mode 100644
index 0000000..e76cf4d
--- /dev/null
+++ a/res/layout/child_list_item_ldip.xml
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/console.xml a/res/layout/console.xml
new file mode 100644
index 0000000..41c79e1
--- /dev/null
+++ a/res/layout/console.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git b/res/layout/consume_dialog.xml a/res/layout/consume_dialog.xml
new file mode 100644
index 0000000..5776fa5
--- /dev/null
+++ a/res/layout/consume_dialog.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/date_picker_dialog.xml a/res/layout/date_picker_dialog.xml
new file mode 100644
index 0000000..55aee7d
--- /dev/null
+++ a/res/layout/date_picker_dialog.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/date_picker_done_button.xml a/res/layout/date_picker_done_button.xml
new file mode 100644
index 0000000..acb7cd6
--- /dev/null
+++ a/res/layout/date_picker_done_button.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/date_picker_header_view.xml a/res/layout/date_picker_header_view.xml
new file mode 100644
index 0000000..17b2aba
--- /dev/null
+++ a/res/layout/date_picker_header_view.xml
@@ -0,0 +1,11 @@
+
+
diff --git b/res/layout/date_picker_selected_date.xml a/res/layout/date_picker_selected_date.xml
new file mode 100644
index 0000000..484d377
--- /dev/null
+++ a/res/layout/date_picker_selected_date.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/date_picker_view_animator.xml a/res/layout/date_picker_view_animator.xml
new file mode 100644
index 0000000..33113ad
--- /dev/null
+++ a/res/layout/date_picker_view_animator.xml
@@ -0,0 +1,7 @@
+
+
diff --git b/res/layout/device_list.xml a/res/layout/device_list.xml
new file mode 100644
index 0000000..a183636
--- /dev/null
+++ a/res/layout/device_list.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/device_name.xml a/res/layout/device_name.xml
new file mode 100644
index 0000000..322431f
--- /dev/null
+++ a/res/layout/device_name.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git b/res/layout/dialog_order_consumed.xml a/res/layout/dialog_order_consumed.xml
new file mode 100644
index 0000000..acd5dcb
--- /dev/null
+++ a/res/layout/dialog_order_consumed.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
diff --git b/res/layout/group_list_item.xml a/res/layout/group_list_item.xml
new file mode 100644
index 0000000..854a56d
--- /dev/null
+++ a/res/layout/group_list_item.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/group_list_item2.xml a/res/layout/group_list_item2.xml
new file mode 100644
index 0000000..48d5153
--- /dev/null
+++ a/res/layout/group_list_item2.xml
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/group_list_item2_ldip.xml a/res/layout/group_list_item2_ldip.xml
new file mode 100644
index 0000000..ec2d489
--- /dev/null
+++ a/res/layout/group_list_item2_ldip.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/group_list_item_ldip.xml a/res/layout/group_list_item_ldip.xml
new file mode 100644
index 0000000..7ccf3a2
--- /dev/null
+++ a/res/layout/group_list_item_ldip.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/id_order_list_activity.xml a/res/layout/id_order_list_activity.xml
new file mode 100644
index 0000000..bdf52db
--- /dev/null
+++ a/res/layout/id_order_list_activity.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/item_order_consumed.xml a/res/layout/item_order_consumed.xml
new file mode 100644
index 0000000..1235246
--- /dev/null
+++ a/res/layout/item_order_consumed.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/list_item.xml a/res/layout/list_item.xml
new file mode 100644
index 0000000..c125eda
--- /dev/null
+++ a/res/layout/list_item.xml
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/list_item2.xml a/res/layout/list_item2.xml
new file mode 100644
index 0000000..23aa964
--- /dev/null
+++ a/res/layout/list_item2.xml
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/listview_loding.xml a/res/layout/listview_loding.xml
new file mode 100644
index 0000000..1739803
--- /dev/null
+++ a/res/layout/listview_loding.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/login_dialog.xml a/res/layout/login_dialog.xml
new file mode 100644
index 0000000..ceada42
--- /dev/null
+++ a/res/layout/login_dialog.xml
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/main_grid_item.xml a/res/layout/main_grid_item.xml
new file mode 100644
index 0000000..bb85d3e
--- /dev/null
+++ a/res/layout/main_grid_item.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/mobel_tool.xml a/res/layout/mobel_tool.xml
new file mode 100644
index 0000000..5cca561
--- /dev/null
+++ a/res/layout/mobel_tool.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/mr_month.xml a/res/layout/mr_month.xml
new file mode 100644
index 0000000..5c8dc93
--- /dev/null
+++ a/res/layout/mr_month.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/mr_week.xml a/res/layout/mr_week.xml
new file mode 100644
index 0000000..b8b3e85
--- /dev/null
+++ a/res/layout/mr_week.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/navigation_pop_list.xml a/res/layout/navigation_pop_list.xml
new file mode 100644
index 0000000..6f38fc7
--- /dev/null
+++ a/res/layout/navigation_pop_list.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/read_idcard.xml a/res/layout/read_idcard.xml
new file mode 100644
index 0000000..888d353
--- /dev/null
+++ a/res/layout/read_idcard.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/search_type_item.xml a/res/layout/search_type_item.xml
new file mode 100644
index 0000000..a624904
--- /dev/null
+++ a/res/layout/search_type_item.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/select_date_time.xml a/res/layout/select_date_time.xml
new file mode 100644
index 0000000..cd2916f
--- /dev/null
+++ a/res/layout/select_date_time.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/serialidcardport.xml a/res/layout/serialidcardport.xml
new file mode 100644
index 0000000..39a0d35
--- /dev/null
+++ a/res/layout/serialidcardport.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/small_select_grid_item.xml a/res/layout/small_select_grid_item.xml
new file mode 100644
index 0000000..0803e8c
--- /dev/null
+++ a/res/layout/small_select_grid_item.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/statistic_day_item.xml a/res/layout/statistic_day_item.xml
new file mode 100644
index 0000000..56bdc20
--- /dev/null
+++ a/res/layout/statistic_day_item.xml
@@ -0,0 +1,70 @@
+
+
+
+
diff --git b/res/layout/statistic_day_item_item.xml a/res/layout/statistic_day_item_item.xml
new file mode 100644
index 0000000..5a34276
--- /dev/null
+++ a/res/layout/statistic_day_item_item.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/statistics_activity.xml a/res/layout/statistics_activity.xml
new file mode 100644
index 0000000..2561eb7
--- /dev/null
+++ a/res/layout/statistics_activity.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/statistics_day_activity.xml a/res/layout/statistics_day_activity.xml
new file mode 100644
index 0000000..001dc6f
--- /dev/null
+++ a/res/layout/statistics_day_activity.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/statistics_mon_activity.xml a/res/layout/statistics_mon_activity.xml
new file mode 100644
index 0000000..c7dfc12
--- /dev/null
+++ a/res/layout/statistics_mon_activity.xml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/layout/time_header_label.xml a/res/layout/time_header_label.xml
new file mode 100644
index 0000000..2392245
--- /dev/null
+++ a/res/layout/time_header_label.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/time_picker_dialog.xml a/res/layout/time_picker_dialog.xml
new file mode 100644
index 0000000..4b275b8
--- /dev/null
+++ a/res/layout/time_picker_dialog.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/layout/year_item.xml a/res/layout/year_item.xml
new file mode 100644
index 0000000..3cef21f
--- /dev/null
+++ a/res/layout/year_item.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git b/res/layout/year_label_text_view.xml a/res/layout/year_label_text_view.xml
new file mode 100644
index 0000000..a4b5417
--- /dev/null
+++ a/res/layout/year_label_text_view.xml
@@ -0,0 +1,9 @@
+
+
diff --git b/res/menu/main.xml a/res/menu/main.xml
new file mode 100644
index 0000000..4e7b289
--- /dev/null
+++ a/res/menu/main.xml
@@ -0,0 +1,3 @@
+
diff --git b/res/raw/bad.wav a/res/raw/bad.wav
new file mode 100644
index 0000000..b963d63
--- /dev/null
+++ a/res/raw/bad.wav
diff --git b/res/raw/beep.ogg a/res/raw/beep.ogg
new file mode 100644
index 0000000..1419947
--- /dev/null
+++ a/res/raw/beep.ogg
diff --git b/res/raw/huanyinguanglin.wav a/res/raw/huanyinguanglin.wav
new file mode 100644
index 0000000..fe8e53c
--- /dev/null
+++ a/res/raw/huanyinguanglin.wav
diff --git b/res/raw/qingchongxinyanpiao.wav a/res/raw/qingchongxinyanpiao.wav
new file mode 100644
index 0000000..b8a73ea
--- /dev/null
+++ a/res/raw/qingchongxinyanpiao.wav
diff --git b/res/raw/wuxiaopiao.wav a/res/raw/wuxiaopiao.wav
new file mode 100644
index 0000000..b963d63
--- /dev/null
+++ a/res/raw/wuxiaopiao.wav
diff --git b/res/values-480x320/dimens.xml a/res/values-480x320/dimens.xml
new file mode 100644
index 0000000..5c026b8
--- /dev/null
+++ a/res/values-480x320/dimens.xml
@@ -0,0 +1,8 @@
+
+
+ 145.0dip
+ 190.0dip
+ 16dp
+ 18dp
+ 20dp
+
diff --git b/res/values-land/dimens.xml a/res/values-land/dimens.xml
new file mode 100644
index 0000000..7158904
--- /dev/null
+++ a/res/values-land/dimens.xml
@@ -0,0 +1,24 @@
+
+
+
+ 200dip
+ 250dip
+
+ 30dp
+ 100dp
+ 30dp
+
diff --git b/res/values-large/settings.xml a/res/values-large/settings.xml
new file mode 100644
index 0000000..82ed112
--- /dev/null
+++ a/res/values-large/settings.xml
@@ -0,0 +1,4 @@
+
+
+ true
+
diff --git b/res/values-normal/dimens.xml a/res/values-normal/dimens.xml
new file mode 100644
index 0000000..ab399da
--- /dev/null
+++ a/res/values-normal/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 160dip
+ 210.0dip
+ 45dip
+
diff --git b/res/values-small/dimens.xml a/res/values-small/dimens.xml
new file mode 100644
index 0000000..6437d6d
--- /dev/null
+++ a/res/values-small/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 145.0dip
+ 190.0dip
+
diff --git b/res/values-sw400dp/dimens.xml a/res/values-sw400dp/dimens.xml
new file mode 100644
index 0000000..30e7ad2
--- /dev/null
+++ a/res/values-sw400dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 60dip
+ 320dip
+ 320.0dip
+
diff --git b/res/values-sw600dp-land/dimens.xml a/res/values-sw600dp-land/dimens.xml
new file mode 100644
index 0000000..c19dd8c
--- /dev/null
+++ a/res/values-sw600dp-land/dimens.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+ 45dp
+ 16sp
+ 64sp
+ 21sp
+ 7dip
+ 5dip
+ 96dip
+ 48dip
+ 315dip
+
+
\ No newline at end of file
diff --git b/res/values-sw600dp/dimens.xml a/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..e47b1f7
--- /dev/null
+++ a/res/values-sw600dp/dimens.xml
@@ -0,0 +1,8 @@
+
+
+
+ 320.0dip
+
diff --git b/res/values-sw720dp-land/dimens.xml a/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..61e3fa8
--- /dev/null
+++ a/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,9 @@
+
+
+
+ 128dp
+
+
diff --git b/res/values-v11/styles.xml a/res/values-v11/styles.xml
new file mode 100644
index 0000000..3c02242
--- /dev/null
+++ a/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git b/res/values-v14/styles.xml a/res/values-v14/styles.xml
new file mode 100644
index 0000000..a91fd03
--- /dev/null
+++ a/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git b/res/values/attrs.xml a/res/values/attrs.xml
new file mode 100644
index 0000000..e326de8
--- /dev/null
+++ a/res/values/attrs.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/values/baudrates.xml a/res/values/baudrates.xml
new file mode 100644
index 0000000..b86e4f9
--- /dev/null
+++ a/res/values/baudrates.xml
@@ -0,0 +1,69 @@
+
+
+
+
+ 50
+ 75
+ 110
+ 134
+ 150
+ 200
+ 300
+ 600
+ 1200
+ 1800
+ 2400
+ 4800
+ 9600
+ 19200
+ 38400
+ 57600
+ 115200
+ 230400
+ 460800
+ 500000
+ 576000
+ 921600
+ 1000000
+ 1152000
+ 1500000
+ 2000000
+ 2500000
+ 3000000
+ 3500000
+ 4000000
+
+
+ 50
+ 75
+ 110
+ 134
+ 150
+ 200
+ 300
+ 600
+ 1200
+ 1800
+ 2400
+ 4800
+ 9600
+ 19200
+ 38400
+ 57600
+ 115200
+ 230400
+ 460800
+ 500000
+ 576000
+ 921600
+ 1000000
+ 1152000
+ 1500000
+ 2000000
+ 2500000
+ 3000000
+ 3500000
+ 4000000
+
+
+
\ No newline at end of file
diff --git b/res/values/colors.xml a/res/values/colors.xml
new file mode 100644
index 0000000..2195ad9
--- /dev/null
+++ a/res/values/colors.xml
@@ -0,0 +1,65 @@
+
+
+
+ #095380
+ #5C8DAB
+ #FB5240
+ #1F1F1F
+
+
+ #b0000000
+ #60000000
+ #c0ffff00
+
+ #5862ff
+ #ffffff
+ #ff9900
+ #00000000
+
+
+ #5F9EA0
+ #31d3fc
+ #413fb4
+ #8C8DAB
+
+ #51b4e5
+
+
+ #fff2f2f2
+ #ffcccccc
+ #ff333333
+ #ffcccccc
+ #ff33b5e5
+ #ff0099cc
+ #ff999999
+ #ff999999
+ #fff2f2f2
+
+ #8c8c8c
+ #8c8c8c
+
+ #7F000000
+
+
+ #fff5f7f9
+ #ffffffff
+ #ffbababa
+ #ffd7d9db
+ #ff379bff
+ #ccffcc
+ #ff96caff
+ #40778088
+ #ff778088
+ #ffffffff
+ #7f778088
+ #ff77be3c
+ #ff77be3c
+ MMMM yyyy
+ EEE
+ Date must be between %1$s and %2$s.
+
+
+ #fe4400
+
+ #099fde
+
\ No newline at end of file
diff --git b/res/values/dimens.xml a/res/values/dimens.xml
new file mode 100644
index 0000000..8ed7c54
--- /dev/null
+++ a/res/values/dimens.xml
@@ -0,0 +1,51 @@
+
+
+
+ 16dp
+ 16dp
+
+ 14sp
+ 270dip
+ 30dip
+ 155dip
+ 270dip
+ 50dip
+ 10sp
+ 16dip
+ 45dip
+ 30dip
+ 75dip
+ 30dip
+ 14dip
+ 16sp
+ 16sp
+ 64dip
+ 22dip
+
+ 60sp
+ -30dp
+ 16sp
+ 6dip
+ 4dip
+ 96dip
+ 270dip
+ 48dip
+ 24dip
+
+ 0.82
+ 0.85
+ 0.16
+ 0.19
+ 0.81
+ 0.60
+ 0.83
+ 0.17
+ 0.14
+ 0.11
+
+ 45dip
+
+ 18dp
+ 18dp
+ 20dp
+
diff --git b/res/values/dimens_mr.xml a/res/values/dimens_mr.xml
new file mode 100644
index 0000000..c53a485
--- /dev/null
+++ a/res/values/dimens_mr.xml
@@ -0,0 +1,10 @@
+
+
+
+ 4dp
+ 16dp
+ 4dp
+ 18sp
+ 14sp
+
+
\ No newline at end of file
diff --git b/res/values/ids.xml a/res/values/ids.xml
new file mode 100644
index 0000000..decf333
--- /dev/null
+++ a/res/values/ids.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/values/strings.xml a/res/values/strings.xml
new file mode 100644
index 0000000..3de88f0
--- /dev/null
+++ a/res/values/strings.xml
@@ -0,0 +1,287 @@
+
+
+
+
+ 畅游通O2O移动终端
+ 请输入身份证号码
+
+ 正在加载
+ 点击重试
+ 订单编号:
+ 取票密码:
+ 请输入订单编号
+ 请输入取票密码
+ 正在处理....
+ 设 置
+
+
+
+ 订单查询范围:
+ 服务器地址:
+ 输入服务器地址
+ 机器编码:
+ 获取MAC地址
+ 常用设置:
+ 启动应用自动进入检票扫描
+ 扫描为有效票自动开始下一次扫描
+ 默认设置
+ 秒沒扫描到数据退出扫描
+ 保存设置
+ 系统密码:
+ 1234
+ "订单号:"
+ "数量:"
+ 状态:
+ 票种:
+ 剩余数量:
+ 游览日期:
+ 打 票
+ 连接打印机
+ 已匹配设备
+ 其它可用设备
+ 扫描设备
+ 没有匹配的设备
+ 扫描设备....
+ 选择连接的设备
+ 没有找到设备
+ 正在连接....
+ 已连接:
+ 没有连接
+ 蓝牙没有启动,退出程序
+ 将二维码放入框内, 即可自动扫描
+ 手持机的读头对准二维码,即可扫描
+
+
+ Please configure your serial port first.
+ You do not have read/write permission to the serial port.
+ The serial port can not be opened for an unknown reason.
+ 证件号:
+ 总数量:
+ "完成"
+ 取消
+ "小时转盘"
+ "分钟转盘"
+ "选择小时"
+ "选择分钟"
+ "按月份划分的日期网格"
+ "年份列表"
+ "选择月份和日期"
+ "选择年份"
+ "已选择"
+ "已删除"
+ --
+ :
+ sans-serif
+ sans-serif
+
+
+ 新版pos机
+ 新版手持pos机
+ 新版身份证pos机
+ 身份证pos机
+ 手持机
+ 小pos机
+ 普通pos机
+ 手机
+ 系统设置
+ 补打小票
+ 检票操作
+ 订单查询
+ 请输入密码
+ 确定
+ 密码错误 !
+ 取消
+ 请输入退出密码
+ 密码有误,无法退出
+ 温馨提示
+ 修改成功
+ ========当前连接地址============
+ 按下了back键 onBackPressed()
+ 月
+ 日
+ 年,
+ 年
+ 日期必须大于或者等于今天
+ 日期必须大于今天
+ 一
+ 二
+ 三
+ 四
+ 五
+ 六
+ 天
+ 星期
+ 检票—订单列表
+ 补票—订单列表
+ 查询—订单列表
+ 获取订单中..
+ 订单列表
+ 获取数据失败!
+ 签名不通过!
+ 蓝牙设备
+ 停止扫描
+ " 数量:"
+ 输入验证码
+ 确 定
+ 验证码不能为空
+ 订单号:
+ 输入身份证
+ 请输入取票密码
+ 身份证不合法
+ 输入订单号
+ 订单号不能为空
+ 密码不能为空
+ 显示结果
+ 输入手机号
+ 填写手机号!
+ 手机号不正确
+ 订单号不正确
+ 查看设置是否正确!
+ 二维码
+ 扫描失败
+ 扫二维码
+ 扫描结果
+ 扫描身份证
+ 努力加载中..
+ 认证二代身份证卡成功!
+ 认证二代身份证卡失败!
+ 读取身份证信息成功!
+ 读取身份证信息失败!
+ 请将二代身份证贴至手持机背部!
+ 身份证号码:
+ 获取身份证失败或者身份证无效
+ 选择操作
+ 手 机 号
+ 身份证
+ 验 证 码
+ 订 单 号
+ 统 计
+ 检票—扫描二维码
+ 补票—扫描二维码
+ 查询—扫描二维码
+ 检票—验证码
+ 补票—验证码
+ 查询—验证码
+ 验证码
+ 检票—身份证
+ 补票—身份证
+ 查询—身份证
+ 身份证
+ 检票—手机
+ 补票—手机
+ 查询—手机
+ 手机号
+ 检票—订单号
+ 补票—订单号
+ 查询—订单号
+ 订单号
+ 统计
+ 设置
+ 请输入密码,打开调试模式
+ 请进行初始化设置!!!
+ 打开wifi才能获取mac
+ 打印次数:
+ 填写服务地址
+ 填写企业标识
+ 填写企业密钥
+ 未解密成功===========
+ 企业通信标识===========
+ 给企业通信标识加密时产生错误,请重新输入!
+ 服务器地址不为空
+ 密码不为空
+ 企业编码不为空
+ 企业通信标识不为空
+ 按月统计
+ 按天统计
+ 不能选择今天之后的时间!
+ 开始时间不能大于结束时间!
+ 后者时间不能前于前者!
+ 两个日期距离不能超过31天!
+ 获取统计信息..
+ 无数据!
+ 获取统计信息失败!
+ 请选择开始时间!
+ 请选择结束时间!
+ 无数据可打印!
+ 统计时间:
+ 选择月份!
+ 扫描
+ 返回
+ 正在扫描.....
+ 系统密码
+ 标识:
+ 密钥:
+ "版本号 "
+ 调节模式 (不用时关闭):
+ 是否
+ 开
+ 关
+ 检票后打印小票:
+ 是
+ 否
+ 版本检测
+ 是否打票
+ 继续检票
+ 清除匹配设备
+ 消费时间:
+ 消费金额:
+ 流水号:
+ 打票
+ 部分检票
+ 1)必须打开蓝牙功能,才能连接打印机,才能打印小票。
+ 2)看“已匹配设备”列表,是否存在你已经匹配的设备,选择设备打印;如果匹配列表中不存在您需要的设备,则“扫描设备”,从中获取您需要的设备进行匹配。
+ 3)打印机的名称为“EZTPrinter。”
+ 4)打印不成功,则重试。
+ 跳至设备页
+ 点击扫描
+ 请将二代身份证放至感应区
+ 票 名:
+ 订单数量:
+ 人 数:
+ 开始时间:
+ 结束时间:
+ 查 询
+ 打 印
+ 年 份:
+ 月 份:
+ 蓝牙不能使用!
+ 次数
+ 目前不支持打印!
+ 选择补打
+ 至少选择一项!
+ 获取小票信息...
+ 准备打印....
+ 已支付
+ 已退订
+ 已消费
+ 未付款
+ 出票中
+ 检全票
+ 先验票再补打小票!
+ 剩余数量 :
+ 总数量 :
+ 补打加密:
+
+ false
+
+ 获取升级信息....
+ 已经是最新
+ 无法获取更新信息
+ 服务器地址错误
+ 升级失败
+ 系统提示
+ 软件版本更新
+ 正在下载新版本
+ 无法下载安装文件,请检查SD卡是否挂载
+ 天统计
+ 月统计
+ 统计
+ 删除
+ 清空
+ 已连上网络!
+ 年份:
+ 关于
+ \u3000\u3000移动检票系统包含:检票、补打小票功能两大模块。
+ \u3000\u3000检票和补打细分小模块包含:手机号、二维码、身份证、订单号。
+ \u3000\u3000移动终端包含多款机型,包含:手持机、带身份证pos、小pos等。
+
\ No newline at end of file
diff --git b/res/values/styles.xml a/res/values/styles.xml
new file mode 100644
index 0000000..69e163a
--- /dev/null
+++ a/res/values/styles.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git b/res/values/styles_mr.xml a/res/values/styles_mr.xml
new file mode 100644
index 0000000..65ebe9d
--- /dev/null
+++ a/res/values/styles_mr.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/values/wheel__attrs.xml a/res/values/wheel__attrs.xml
new file mode 100644
index 0000000..db64ba7
--- /dev/null
+++ a/res/values/wheel__attrs.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/res/xml/serial_port_preferences.xml a/res/xml/serial_port_preferences.xml
new file mode 100644
index 0000000..a82fb58
--- /dev/null
+++ a/res/xml/serial_port_preferences.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git b/run_emulator.sh a/run_emulator.sh
new file mode 100644
index 0000000..838d299
--- /dev/null
+++ a/run_emulator.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+{
+ adb wait-for-device
+ adb shell chmod 666 /dev/ttyS2
+} &
+emulator-arm -avd Android_1.5 -qemu -serial stdio
+
diff --git b/src/android_serialport_api/SerialPort.java a/src/android_serialport_api/SerialPort.java
new file mode 100644
index 0000000..fbb6924
--- /dev/null
+++ a/src/android_serialport_api/SerialPort.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2009 Cedric Priscal
+ *
+ * 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 android_serialport_api;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+import android.util.Log;
+
+public class SerialPort {
+
+ private static final String TAG = "SerialPort";
+
+ /*
+ * Do not remove or rename the field mFd: it is used by native method close();
+ */
+ private FileDescriptor mFd;
+ private FileInputStream mFileInputStream;
+ private FileOutputStream mFileOutputStream;
+
+ public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
+
+ /* Check access permission */
+ if (!device.canRead() || !device.canWrite()) {
+
+ try {
+ Log.e(TAG, "1============================");
+ // Missing read/write permission, trying to chmod the file
+ Process su;
+ su = Runtime.getRuntime().exec("/system/xbin/su");
+ //String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
+ //+ "exit\n";
+ String cmd = "chmod 666 " + device.getAbsolutePath();
+ Log.e(TAG, "cmd====================="+cmd);
+ Runtime.getRuntime().exec(cmd);
+ //su.getOutputStream().write(cmd.getBytes());
+ if (/*(su.waitFor() != 0) || */!device.canRead()
+ || !device.canWrite()) {
+ Log.e(TAG, "2=====================");
+ throw new SecurityException();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "3=================");
+ e.printStackTrace();
+ throw new SecurityException();
+ }
+
+ //do_exec("su root\n");
+ //Log.e(TAG, "=============cmd : "+device.getAbsolutePath());
+ //do_exec("chmod 755 " + device.getAbsolutePath() + "\n");
+ //do_exec("rm /sdcard/123");
+ //Runtime.getRuntime().exec("/system/xbin/su");
+ //Runtime.getRuntime().exec("chmod 755 /dev/ttyS1");
+
+ }
+
+ mFd = open(device.getAbsolutePath(), baudrate, flags);
+ if (mFd == null) {
+ Log.e(TAG, "native open returns null");
+ throw new IOException();
+ }
+ mFileInputStream = new FileInputStream(mFd);
+ mFileOutputStream = new FileOutputStream(mFd);
+ }
+
+ // Getters and setters
+ public InputStream getInputStream() {
+ return mFileInputStream;
+ }
+
+ public OutputStream getOutputStream() {
+ return mFileOutputStream;
+ }
+
+ String do_exec(String cmd) {
+ String s = "/n";
+ try {
+ Process p = Runtime.getRuntime().exec(cmd);
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(p.getInputStream()));
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ s += line + "/n";
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return cmd;
+ }
+
+ // JNI
+ private native static FileDescriptor open(String path, int baudrate, int flags);
+ public native void close();
+ static {
+ try {
+ System.loadLibrary("serial_port");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+
+
+ /*
+ * iD pos机
+ */
+ public SerialPort(String dev, int baudrate, int flags)
+ throws IOException
+ {
+ OpenSerialPort(new File(dev), baudrate, flags);
+ }
+
+ private void OpenSerialPort(File device, int baudrate, int flags) throws IOException {
+ this.mFd = open(device.getAbsolutePath(), baudrate, flags);
+ if (this.mFd == null) {
+ Log.e("SerialPort", "native open returns null");
+ throw new IOException();
+ }
+ this.mFileInputStream = new FileInputStream(this.mFd);
+ this.mFileOutputStream = new FileOutputStream(this.mFd);
+ }
+}
diff --git b/src/android_serialport_api/SerialPortFinderHandset.java a/src/android_serialport_api/SerialPortFinderHandset.java
new file mode 100644
index 0000000..479870f
--- /dev/null
+++ a/src/android_serialport_api/SerialPortFinderHandset.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2009 Cedric Priscal
+ *
+ * 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 android_serialport_api;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.util.Iterator;
+import java.util.Vector;
+
+import android.util.Log;
+
+public class SerialPortFinderHandset {
+
+ public class Driver {
+ public Driver(String name, String root) {
+ mDriverName = name;
+ mDeviceRoot = root;
+ }
+ private String mDriverName;
+ private String mDeviceRoot;
+ Vector mDevices = null;
+ public Vector getDevices() {
+ if (mDevices == null) {
+ mDevices = new Vector();
+ File dev = new File("/dev");
+ File[] files = dev.listFiles();
+ int i;
+ for (i=0; i mDrivers = null;
+
+ Vector getDrivers() throws IOException {
+ if (mDrivers == null) {
+ mDrivers = new Vector();
+ LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
+ String l;
+ while((l = r.readLine()) != null) {
+ // Issue 3:
+ // Since driver name may contain spaces, we do not extract driver name with split()
+ String drivername = l.substring(0, 0x15).trim();
+ String[] w = l.split(" +");
+ if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
+ Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]);
+ mDrivers.add(new Driver(drivername, w[w.length-4]));
+ }
+ }
+ r.close();
+ }
+ return mDrivers;
+ }
+
+ public String[] getAllDevices() {
+ Vector devices = new Vector();
+ // Parse each driver
+ Iterator itdriv;
+ try {
+ itdriv = getDrivers().iterator();
+ while(itdriv.hasNext()) {
+ Driver driver = itdriv.next();
+ Iterator itdev = driver.getDevices().iterator();
+ while(itdev.hasNext()) {
+ String device = itdev.next().getName();
+ String value = String.format("%s (%s)", device, driver.getName());
+ devices.add(value);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return devices.toArray(new String[devices.size()]);
+ }
+
+ public String[] getAllDevicesPath() {
+ Vector devices = new Vector();
+ // Parse each driver
+ Iterator itdriv;
+ try {
+ itdriv = getDrivers().iterator();
+ while(itdriv.hasNext()) {
+ Driver driver = itdriv.next();
+ Iterator itdev = driver.getDevices().iterator();
+ while(itdev.hasNext()) {
+ String device = itdev.next().getAbsolutePath();
+ devices.add(device);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return devices.toArray(new String[devices.size()]);
+ }
+}
diff --git b/src/android_serialport_api/SerialPortHandset.java a/src/android_serialport_api/SerialPortHandset.java
new file mode 100644
index 0000000..4fbd4c6
--- /dev/null
+++ a/src/android_serialport_api/SerialPortHandset.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2009 Cedric Priscal
+ *
+ * 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 android_serialport_api;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.util.Log;
+
+public class SerialPortHandset {
+
+ private static final String TAG = "SerialPort";
+
+ /*
+ * Do not remove or rename the field mFd: it is used by native method close();
+ */
+ private FileDescriptor mFd;
+ private FileInputStream mFileInputStream;
+ private FileOutputStream mFileOutputStream;
+
+ public SerialPortHandset(File device, int baudrate, int flags) throws SecurityException, IOException {
+
+ /* Check access permission */
+ if (!device.canRead() || !device.canWrite()) {
+ try {
+ /* Missing read/write permission, trying to chmod the file */
+ Process su;
+ su = Runtime.getRuntime().exec("/system/bin/su");
+ String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
+ + "exit\n";
+ su.getOutputStream().write(cmd.getBytes());
+ if ((su.waitFor() != 0) || !device.canRead()
+ || !device.canWrite()) {
+ throw new SecurityException();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new SecurityException();
+ }
+ }
+
+ mFd = open(device.getAbsolutePath(), baudrate, flags);
+ if (mFd == null) {
+ Log.e(TAG, "native open returns null");
+ throw new IOException();
+ }
+ mFileInputStream = new FileInputStream(mFd);
+ mFileOutputStream = new FileOutputStream(mFd);
+ }
+
+ // Getters and setters
+ public InputStream getInputStream() {
+ return mFileInputStream;
+ }
+
+ public OutputStream getOutputStream() {
+ return mFileOutputStream;
+ }
+
+ // JNI
+ private native static FileDescriptor open(String path, int baudrate, int flags);
+ public native void close();
+ static {
+ try {
+ System.loadLibrary("serial_portHandset");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git b/src/android_serialport_api/SerialPortNewHandleFinder.java a/src/android_serialport_api/SerialPortNewHandleFinder.java
new file mode 100644
index 0000000..533574a
--- /dev/null
+++ a/src/android_serialport_api/SerialPortNewHandleFinder.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2009 Cedric Priscal
+ *
+ * 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 android_serialport_api;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.util.Iterator;
+import java.util.Vector;
+
+import android.util.Log;
+
+public class SerialPortNewHandleFinder {
+
+ public class Driver {
+ public Driver(String name, String root) {
+ mDriverName = name;
+ mDeviceRoot = root;
+ }
+ private String mDriverName;
+ private String mDeviceRoot;
+ Vector mDevices = null;
+ public Vector getDevices() {
+ if (mDevices == null) {
+ mDevices = new Vector();
+ File dev = new File("/dev");
+ File[] files = dev.listFiles();
+ int i;
+ for (i=0; i mDrivers = null;
+
+ Vector getDrivers() throws IOException {
+ if (mDrivers == null) {
+ mDrivers = new Vector();
+ LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
+ String l;
+ while((l = r.readLine()) != null) {
+ // Issue 3:
+ // Since driver name may contain spaces, we do not extract driver name with split()
+ String drivername = l.substring(0, 0x15).trim();
+ String[] w = l.split(" +");
+ if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
+ Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]);
+ mDrivers.add(new Driver(drivername, w[w.length-4]));
+ }
+ }
+ r.close();
+ }
+ return mDrivers;
+ }
+
+ public String[] getAllDevices() {
+ Vector devices = new Vector();
+ // Parse each driver
+ Iterator itdriv;
+ try {
+ itdriv = getDrivers().iterator();
+ while(itdriv.hasNext()) {
+ Driver driver = itdriv.next();
+ Iterator itdev = driver.getDevices().iterator();
+ while(itdev.hasNext()) {
+ String device = itdev.next().getName();
+ String value = String.format("%s (%s)", device, driver.getName());
+ devices.add(value);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return devices.toArray(new String[devices.size()]);
+ }
+
+ public String[] getAllDevicesPath() {
+ Vector devices = new Vector();
+ // Parse each driver
+ Iterator itdriv;
+ try {
+ itdriv = getDrivers().iterator();
+ while(itdriv.hasNext()) {
+ Driver driver = itdriv.next();
+ Iterator itdev = driver.getDevices().iterator();
+ while(itdev.hasNext()) {
+ String device = itdev.next().getAbsolutePath();
+ devices.add(device);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return devices.toArray(new String[devices.size()]);
+ }
+}
diff --git b/src/android_serialport_api/SerialPortNewHandset.java a/src/android_serialport_api/SerialPortNewHandset.java
new file mode 100644
index 0000000..658bf88
--- /dev/null
+++ a/src/android_serialport_api/SerialPortNewHandset.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2009 Cedric Priscal
+ *
+ * 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 android_serialport_api;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.util.Log;
+
+public class SerialPortNewHandset {
+
+ private static final String TAG = "SerialPort";
+
+ /*
+ * Do not remove or rename the field mFd: it is used by native method close();
+ */
+ private FileDescriptor mFd;
+ private FileInputStream mFileInputStream;
+ private FileOutputStream mFileOutputStream;
+
+ public SerialPortNewHandset(File device, int baudrate, int flags) throws SecurityException, IOException {
+
+ /* Check access permission */
+ if (!device.canRead() || !device.canWrite()) {
+ try {
+ /* Missing read/write permission, trying to chmod the file */
+ Process su;
+ su = Runtime.getRuntime().exec("/system/bin/su");
+ String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
+ + "exit\n";
+ su.getOutputStream().write(cmd.getBytes());
+ if ((su.waitFor() != 0) || !device.canRead()
+ || !device.canWrite()) {
+ throw new SecurityException();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new SecurityException();
+ }
+ }
+
+ mFd = open(device.getAbsolutePath(), baudrate, flags);
+ if (mFd == null) {
+ Log.e(TAG, "native open returns null");
+ throw new IOException();
+ }
+ mFileInputStream = new FileInputStream(mFd);
+ mFileOutputStream = new FileOutputStream(mFd);
+ }
+
+ // Getters and setters
+ public InputStream getInputStream() {
+ return mFileInputStream;
+ }
+
+ public OutputStream getOutputStream() {
+ return mFileOutputStream;
+ }
+
+ // JNI
+ private native static FileDescriptor open(String path, int baudrate, int flags);
+ public native void close();
+ static {
+ try {
+ System.loadLibrary("serial_port_newhandset");
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git b/src/android_serialport_api/print_tool/BasewinRebPosPortTool.java a/src/android_serialport_api/print_tool/BasewinRebPosPortTool.java
new file mode 100644
index 0000000..763a809
--- /dev/null
+++ a/src/android_serialport_api/print_tool/BasewinRebPosPortTool.java
@@ -0,0 +1,372 @@
+package android_serialport_api.print_tool;
+
+import hdx.HdxUtil;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import com.basewin.aidl.OnPrinterListener;
+import com.basewin.services.DeviceInfoBinder;
+import com.basewin.services.PrinterBinder;
+import com.ectrip.cyt.config.BindService;
+import com.ectrip.cyt.config.MyApp;
+import com.ectrip.cyt.constant.DeviceType;
+import com.ectrip.cyt.constant.LogoType;
+import com.ectrip.cyt.constant.SelectAction;
+import com.ectrip.cyt.constant.constant;
+import com.ectrip.cyt.ui.PhomeScanerOrderActivity;
+import com.ectrip.cyt.utils.SharedPreferences2Obj;
+import com.ectrip.trips.check.R;
+
+/**
+ * 盛本的红色pos机
+ * @author Administrator
+ *
+ */
+public class BasewinRebPosPortTool {
+
+ private WakeLock lock;
+ private static final String TAG = "BasewinRebPosPortTool";
+ private Context context;
+ private final int ENABLE_BUTTON = 2;
+ private int printNum = 1;//打印次数
+ // 打印信息
+ private MyHandler handler;
+
+ private DeviceInfoBinder deviceInfo = null;
+ private PrinterBinder printer = null;
+
+ // 初始化
+ @SuppressWarnings("deprecation")
+ public void init(Context context, String contentStr) {
+ this.context = context;
+ if (handler == null) {
+ handler = new MyHandler();
+ }
+ if (deviceInfo == null) {
+ deviceInfo = BindService.getInstance().getDeviceInfo();
+ }
+ if (printer == null) {
+ printer = BindService.getInstance().getPrinter();
+ }
+ popUpDialog();
+ try {
+ if (!deviceInfo.isSupportPrint()) {
+ Toast.makeText(context, "不支持", Toast.LENGTH_LONG).show();
+ return;
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ Toast.makeText(context, "不支持", Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ PowerManager pm = (PowerManager) context
+ .getSystemService(Context.POWER_SERVICE);
+ lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+ new WriteThread(contentStr).start();
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ private class WriteThread extends Thread {
+ private String arr;
+
+ public WriteThread(String str) {
+ arr = str;
+ }
+
+ public void run() {
+ super.run();
+ lock.acquire();
+
+ JSONObject titelJson = null;
+ JSONObject SubtitleJson = null;
+ if (isStatistic != null && isStatistic.equals("1")) {
+ titelJson = getJsonObject(true, "统计信息\n");
+ } else {
+ titelJson = getJsonObject(true, "订单信息\n");
+ if (Select == SelectAction.Reprint.getValue()) {
+ SubtitleJson = getJsonObject(true, "(重打小票)\n");
+ try {
+ SubtitleJson.put("bold", "0");
+ SubtitleJson.put("size", "2");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if (arr.contains("\n\n\n\n\n")) {
+ arr = arr.replace("\n\n\n\n\n", "\n");
+ }
+ JSONObject contentJson = getJsonObject(false, arr);
+ JSONObject dateJson = null;
+ JSONObject signJson = null;
+
+ if (isStatistic != null && isStatistic.equals("1")) {
+
+ } else {
+ // 重打时间
+ if (Select == SelectAction.Query.getValue()) { // 打印时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ dateJson = getJsonObject(false,
+ "检票时间:" + df.format(new Date())+"\n\n\n");
+ } else if (Select == SelectAction.Reprint.getValue()) {// 重打时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ dateJson = getJsonObject(false,
+ " " + "\n\n");
+ }
+ signJson = getJsonObject(false, "\n" +
+ "\n取票人签名:\n\n");
+ }
+
+ JSONObject logoJson = null;
+ JSONObject urlJson = null;
+ if (constant.logoMark == LogoType.CYT.getValue()) {
+ logoJson = getJsonObject(false, "---畅游通—智慧旅游O2O平台---");
+ urlJson = getJsonObject(false,
+ "--------www.jingqu.cn---------\n\n");
+ } else if (constant.logoMark == LogoType.QNE.getValue()) {
+ logoJson = getJsonObject(false, "---欢迎使用去哪儿网O2O系统---");
+ urlJson = getJsonObject(false,
+ "--------www.qunar.com--------\n\n");
+ }
+
+ JSONObject blankJson = getJsonObject(false, " "+"\n\n\n\n\n");
+
+ JSONArray printTest = new JSONArray();
+
+
+ // 打印次数控制
+ for (int x = 0; x < printNum; x++) {
+
+ if (x == 1 && isStatistic.equals("1")) {
+ break;
+ }
+ if (titelJson != null) {
+ printTest.put(titelJson);
+ }
+ if (SubtitleJson !=null) {
+ printTest.put(SubtitleJson);
+ }
+ if (contentJson != null) {
+ printTest.put(contentJson);
+ }
+ if (dateJson != null) {
+ printTest.put(dateJson);
+
+ }
+ if (signJson != null) {
+ printTest.put(signJson);
+
+ }
+ if (logoJson != null) {
+ printTest.put(logoJson);
+
+ }
+ if (urlJson != null) {
+ printTest.put(urlJson);
+
+ }
+ if (blankJson!=null) {
+ printTest.put(blankJson);
+ }
+
+ }
+
+ JSONObject priJsonObject = new JSONObject();
+ try {
+ priJsonObject.put("spos", printTest);
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ try {
+ printer.printBottomFeedLine(2);
+ printer.print(priJsonObject.toString(), null,
+ printer_callback);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+ }
+
+
+ private final OnPrinterListener printer_callback = new OnPrinterListener() {
+
+ @Override
+ public void onStart() {
+ // 打印开始
+
+ }
+
+ @Override
+ public void onFinish() {
+ // 打印结束
+ close();
+ Boolean scanBack = SharedPreferences2Obj.getInstance(context).setName("config").getObject("scanBack", Boolean.class);
+ if (MyApp.getInstance().getCheckType()==0&&scanBack != null && scanBack) {
+ checkScan();
+ }
+
+ }
+
+ @Override
+ public void onError(int arg0, String arg1) {
+ // 打印出错
+
+ close();
+ Toast.makeText(context,"打印出错,请检查打印纸!",Toast.LENGTH_SHORT).show();
+ }
+ };
+
+ private void checkScan() {
+ if (MyApp.getInstance().getCheckType() == 0) {
+ Integer Select = SharedPreferences2Obj
+ .getInstance(context)
+ .setName("SelectAction").getObject("Select", Integer.class);
+ Intent intent = new Intent(context,
+ PhomeScanerOrderActivity.class);
+ if (Select != null) {
+ if (Select == SelectAction.Check.getValue()) {
+ intent.putExtra("titleName",
+ context.getString(R.string.check_scan_code));
+ } else if (Select == SelectAction.Reprint.getValue()) {
+ intent.putExtra("titleName",
+ context.getString(R.string.repriint_scan_code));
+ } else if (Select == SelectAction.Query.getValue()) {
+ intent.putExtra("titleName",
+ context.getString(R.string.query_scan_code));
+ }
+ } else {
+ intent.putExtra("titleName",
+ context.getString(R.string.scan_qr_code));
+ }
+ context.startActivity(intent);
+ Activity activity = (Activity) context;
+ activity.finish();
+ }
+ }
+
+ private JSONObject getJsonObject(Boolean isTitel, String content) {
+ JSONObject json1 = new JSONObject();
+ try {
+ json1.put("content-type", "txt");// 打印类型
+ json1.put("content", content);
+
+ json1.put("offset", "0");
+ json1.put("italic", "0");// “1”表示斜体, “0”表示正常
+ json1.put("height", "-1");
+ if (isTitel) {
+ json1.put("bold", "1");// 是否加粗
+ json1.put("size", "3");// 字体大小
+ json1.put("position", "center");// 对齐方式
+
+ } else {
+ json1.put("bold", "0");
+ json1.put("size", "2");
+ json1.put("position", "left");
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ return json1;
+ }
+
+ @SuppressLint("HandlerLeak")
+ private class MyHandler extends Handler {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case ENABLE_BUTTON:
+ try {
+ if (dialog != null) {
+ dialog.dismiss();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /************************ 关闭处理 **********************************/
+ public void close() {
+
+ if (deviceInfo != null) {
+ deviceInfo = null;
+ }
+ if (printer != null) {
+ printer = null;
+ }
+ if (dialog != null) {
+ dialog.dismiss();
+ }
+ }
+
+ /*************************** 弹框处理 ********************************/
+ private ProgressDialog dialog;
+ private String isStatistic;
+ private Integer type;
+ private int Select = 0;
+
+ private void popUpDialog() {
+ try {
+ isStatistic = SharedPreferences2Obj.getInstance(context)
+ .setName("SelectAction")
+ .getObject("isStatistic", String.class); // 非统计判断
+ type = SharedPreferences2Obj.getInstance(context)
+ .setName("MachineType").getObject("type", Integer.class);
+ Select = SharedPreferences2Obj.getInstance(context)
+ .setName("SelectAction").getObject("Select", Integer.class);
+ printNum = MyApp.getInstance().getPrintNum();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ if (dialog == null) {
+ // 显示ProgressDialog
+ dialog = new ProgressDialog(context);
+ dialog.setMessage("打印中...");
+ dialog.setCanceledOnTouchOutside(true);
+ dialog.setCancelable(false);
+ if (type == DeviceType.HANDSET.getValue()) {
+ dialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+ try {
+ dialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ dialog.setMessage("打印中...");
+ dialog.show();
+ }
+ }
+}
diff --git b/src/android_serialport_api/print_tool/MobilePrintTool.java a/src/android_serialport_api/print_tool/MobilePrintTool.java
new file mode 100644
index 0000000..489371a
--- /dev/null
+++ a/src/android_serialport_api/print_tool/MobilePrintTool.java
@@ -0,0 +1,650 @@
+package android_serialport_api.print_tool;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import com.ectrip.cyt.config.MyApp;
+import com.ectrip.cyt.constant.DeviceType;
+import com.ectrip.cyt.constant.LogoType;
+import com.ectrip.cyt.constant.SelectAction;
+import com.ectrip.cyt.constant.constant;
+import com.ectrip.cyt.shield_home.LockLayer.MToast;
+import com.ectrip.cyt.ui.DeviceListActivity;
+import com.ectrip.cyt.utils.LogUtil;
+import com.ectrip.cyt.utils.SharedPreferences2Obj;
+import com.ectrip.trips.check.R;
+import com.eztlib.BluetoothService;
+import com.eztlib.PrinterEscCmd;
+import com.eztlib.blu.PairUtil;
+
+/**
+ * @author jigo 手机、手持机打印
+ */
+public class MobilePrintTool extends Activity {
+ private String TAG = "MobilePrintTool";
+ private String info;
+ private PrinterEscCmd printer;// 蓝牙打印的类
+ private Integer type = null;// 设备类型
+ public BluetoothService mService = null;
+ // 请求的代码
+ public final int REQUEST_CONNECT_DEVICE = 15;
+ private final int REQUEST_ENABLE_BT = 16;
+ public final int PRINT_RESPONSE = 10;
+ private BluetoothAdapter mBluetoothAdapter = null;// 当地蓝牙适配器
+ private boolean isOpen = false;
+ private boolean isturn = false;
+ private boolean isprint = false;
+ private boolean isprint2 = false;
+ private String isStatistic = "0";
+ private MyHandler myHandler = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.mobel_tool);
+ initView();
+ try {
+ isStatistic = SharedPreferences2Obj
+ .getInstance(MobilePrintTool.this).setName("SelectAction")
+ .getObject("isStatistic", String.class); // 非统计判断
+ init(getIntent().getStringExtra("info"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ finish();
+ }
+ myHandler = new MyHandler();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (isprint) {
+ finish();
+ }
+ }
+
+ public void initView() {
+ findViewById(R.id.retryButton).setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ adapterCallback();
+ }
+ });
+ findViewById(R.id.topBack).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finish();
+ }
+ });
+ }
+
+ public void init(String info) {
+ this.info = info;
+ if (printer == null) {
+ printer = new PrinterEscCmd();
+ }
+ type = SharedPreferences2Obj.getInstance(MobilePrintTool.this)
+ .setName("MachineType").getObject("type", Integer.class);
+ if (initBlu()) {
+ initBS();
+ }
+ }
+
+ private boolean initBlu() { // 判断是否有蓝牙功能
+ // 得到本地的适配器
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (mBluetoothAdapter == null) {
+ if (type != null && type == DeviceType.HANDSET.getValue()) {
+ MToast.makeText(MobilePrintTool.this,
+ getString(R.string.bluetooth_not_available),
+ MToast.LENGTH_LONG).show();
+ finish();
+ } else {
+ Toast.makeText(MobilePrintTool.this,
+ R.string.bluetooth_not_available, Toast.LENGTH_LONG)
+ .show();
+ finish();
+ }
+ return false;
+ }
+ return true;
+ }
+
+ private void initBS() { // 初始化mService
+ if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
+ isOpen = false;
+ if (turnOnBluetooth()) {
+ openBluDevices();
+ } else {
+ Intent enableIntent = new Intent(
+ BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
+ }
+ if (type != null && type == DeviceType.HANDSET.getValue()) { // 手持机强制打开
+ adapterCallback();
+ }
+ } else {
+ isOpen = true;
+ if (mService == null) {
+ mService = new BluetoothService(MobilePrintTool.this, mHandler);
+ }
+ adapterCallback();
+ }
+ }
+
+ public void adapterCallback() { // 跳转到驱动页面
+ if (initBlu()) {
+ if (mBluetoothAdapter.isEnabled()) {
+ if (mService != null) {
+ if (mService.getState() == BluetoothService.STATE_NONE) {
+ mService.start();
+ }
+ } else {
+ mService = new BluetoothService(MobilePrintTool.this,
+ mHandler);
+ }
+ openBluDevices();
+ } else {
+ if (type != null && type == DeviceType.HANDSET.getValue()) {
+ // 先试着强制打开时,不行者弹框打开
+ if (turnOnBluetooth()) {
+ openBluDevices();
+ } else {
+ Intent enableIntent = new Intent(
+ BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
+ }
+ } else {
+ Intent enableIntent = new Intent(
+ BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
+ }
+ }
+ }
+ }
+
+ /**
+ * 强制开启当前 Android 设备的 Bluetooth
+ *
+ * @return true:强制打开 Bluetooth 成功 false:强制打开 Bluetooth 失败
+ */
+ public boolean turnOnBluetooth() {
+ if (mBluetoothAdapter != null) {
+ return mBluetoothAdapter.enable();
+ }
+ return false;
+ }
+
+ private void openBluDevices() {
+ // 打开连接蓝牙设备页面
+ if (!isturn && mBluetoothAdapter.isEnabled()) {
+ Intent intent = new Intent(MobilePrintTool.this,
+ DeviceListActivity.class);
+ startActivityForResult(intent, REQUEST_CONNECT_DEVICE);
+ isturn = true;
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case REQUEST_CONNECT_DEVICE:
+ // 当DeviceListActivity返回一个设备连接
+ if (resultCode == Activity.RESULT_OK) {
+ // 获取设备的MAC地址
+ String address = data.getExtras().getString(
+ DeviceListActivity.EXTRA_DEVICE_ADDRESS);
+ // 得到BLuetoothDevice对象
+ if (address == null) {
+ break;
+ }
+ LogUtil.i("address" + address);
+ // 获取设备进行连接
+ BluetoothDevice device = mBluetoothAdapter
+ .getRemoteDevice(address);
+ try {
+ if (type != null
+ && type == DeviceType.HANDSET.getValue()
+ && device.getBondState() != BluetoothDevice.BOND_BONDED) {
+ PairUtil.pair(address, constant.pair, device);
+ }
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ // 尝试连接到设备
+ if (device != null) {
+ try {
+ mService.connect(device);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ finish();
+ }
+ } else {
+ finish();
+ }
+ break;
+ case REQUEST_ENABLE_BT:
+ // 当请求激活蓝牙的回报
+ if (!isOpen) {
+ adapterCallback();
+ }
+ if (resultCode == Activity.RESULT_OK) {
+ // 蓝牙现在是启用的,因此,建立一个聊天会话
+ // 蓝牙开启成功,则继续初始化UI
+ if (mService == null) {
+ mService = new BluetoothService(MobilePrintTool.this,
+ mHandler);
+ }
+
+ // openBluDevices();
+ } else {
+ // 用户没有启用蓝牙或出错
+ LogUtil.d(TAG, "BT not enabled");
+ }
+ default:
+ break;
+ }
+
+ }
+
+ private void print(final String str) {
+ if (isprint && isprint2) {
+ isprint2 = false;
+ if (printer == null) {
+ printer = new PrinterEscCmd();
+ }
+ final int printNum = MyApp.getInstance().getPrintNum();
+ LogUtil.d(printNum + getString(R.string.times));
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ printThread(printNum, str);
+ }
+ }).start();
+ }
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ private void printThread(int printNum, List str) {
+ for (int x = 0; x < printNum; x++) {
+ if (x == 1 && isStatistic.equals("1")) {
+ if (dialog != null) {
+ dialog.dismiss();
+ }
+ return;
+ }
+ try {
+ if (isStatistic != null && isStatistic.equals("1")) {
+ printer.escPrintText(" 统计信息" + "\n");
+ } else {
+ printer.escPrintText(" 订单信息");
+ // 当时重打小票的时候,多打一段字符
+ int Select = SharedPreferences2Obj
+ .getInstance(MobilePrintTool.this)
+ .setName("SelectAction")
+ .getObject("Select", Integer.class);
+ if (Select == SelectAction.Reprint.getValue()) {
+ printer.escEnter();
+ printer.escPrintText(" (重打小票)");
+ }
+ }
+ printer.escEnter();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (str == null) {
+ return;
+ }
+ // 打印信息
+ try {
+ if (isStatistic != null && isStatistic.equals("1")) {
+ System.out.println(str);
+ try {
+ for (int i = 0; i < str.size(); i++) {
+ printer.escPrintText(str.get(i));// 订单信息
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ int Select = SharedPreferences2Obj
+ .getInstance(MobilePrintTool.this)
+ .setName("SelectAction")
+ .getObject("Select", Integer.class);
+ if (Select == SelectAction.Query.getValue()) { // 打印时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ printer.escPrintText("检票时间:" + df.format(new Date()));// new
+ printer.escEnter();
+ // Date()为获取当前系统时间
+ }else if (Select == SelectAction.Reprint.getValue()) {// 重打时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ //printer.escPrintText("重打时间:" + df.format(new Date()));// new
+ printer.escEnter();
+ // Date()为获取当前系统时间
+ }
+
+ for (int i = 0; i < str.size(); i++) {
+ printer.escPrintText(str.get(i));// 订单信息
+ }
+ printer.escEnter();
+ printer.escPrintText("取票人签名:" + "\n");
+ }
+
+ if (constant.logoMark == LogoType.CYT.getValue()) {
+ printer.escEnter();
+ printer.escPrintText("---畅游通—智慧旅游O2O平台---");
+ printer.escEnter();
+ printer.escPrintText("--------www.jingqu.cn---------");
+ } else if (constant.logoMark == LogoType.QNE.getValue()) {
+ printer.escEnter();
+ printer.escPrintText("---欢迎使用去哪儿网O2O系统---");
+ printer.escEnter();
+ printer.escPrintText("--------www.qunar.com--------");
+ }
+ printer.escEnter();
+ sleep(2000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // 信息完打印的空格行数
+ try {
+ printer.escEnter();
+ printer.escEnter();
+ printer.escEnter();
+ if ((x + 1) == printNum) {
+ myHandler.sendMessage(myHandler
+ .obtainMessage(FINISH_ACTIVITY));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @SuppressLint("SimpleDateFormat") private void printThread(int printNum, String str) {
+ for (int x = 0; x < printNum; x++) {
+ if (x == 1 && isStatistic.equals("1")) {
+ if (dialog != null) {
+ dialog.dismiss();
+ }
+ return;
+ }
+ try {
+ if (isStatistic != null && isStatistic.equals("1")) {
+ printer.escPrintText(" 统计信息" + "\n");
+ } else {
+ printer.escPrintText(" 订单信息");
+ // 当时重打小票的时候,多打一段字符
+ int Select = SharedPreferences2Obj
+ .getInstance(MobilePrintTool.this)
+ .setName("SelectAction")
+ .getObject("Select", Integer.class);
+ if (Select == 2) {
+ printer.escEnter();
+ printer.escPrintText(" (重打小票)");
+ }
+ }
+ printer.escEnter();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (str == null) {
+ return;
+ }
+ // 打印信息
+ try {
+ if (isStatistic != null && isStatistic.equals("1")) {
+ System.out.println(str);
+ try {
+ printer.escPrintText(str);// 订单信息
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ // 重打时间
+ int Select = SharedPreferences2Obj
+ .getInstance(MobilePrintTool.this)
+ .setName("SelectAction")
+ .getObject("Select", Integer.class);
+ if (Select == 2) {
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ printer.escPrintText("重打时间:" + df.format(new Date()));// new
+ printer.escEnter();
+ // Date()为获取当前系统时间
+ }
+
+ printer.escPrintText(str);// 订单信息
+ printer.escEnter();
+ printer.escPrintText("取票人签名:" + "\n");
+ }
+
+ if (constant.logoMark == LogoType.CYT.getValue()) {
+ printer.escEnter();
+ printer.escPrintText("---畅游通—智慧旅游O2O平台---");
+ printer.escEnter();
+ printer.escPrintText("--------www.jingqu.cn---------");
+ } else if (constant.logoMark == LogoType.QNE.getValue()) {
+ printer.escEnter();
+ printer.escPrintText("---欢迎使用去哪儿网O2O系统---");
+ printer.escEnter();
+ printer.escPrintText("--------www.qunar.com--------");
+ }
+ try {
+ printer.escEnter();
+ printer.escEnter();
+ printer.escEnter();
+ printer.escEnter();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ sleep(2000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if ((x + 1) == printNum) {
+ myHandler.sendMessage(myHandler
+ .obtainMessage(FINISH_ACTIVITY));
+ }
+ }
+ }
+ }
+
+ private final int FINISH_ACTIVITY = 10;
+
+ @SuppressLint("HandlerLeak") class MyHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what) {
+ case FINISH_ACTIVITY:
+ sleep(2000);
+ if (mService != null) {
+ mService.stop();
+ }
+ if (mBluetoothAdapter != null) {
+ mBluetoothAdapter.cancelDiscovery();
+ if (mBluetoothAdapter.isEnabled()) {
+ mBluetoothAdapter.disable();
+ }
+ }
+ Intent intent = new Intent();
+ setResult(2, intent);
+ finish();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ public void sleep(int ms) {
+
+ try {
+ java.lang.Thread.sleep(ms);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 蓝牙连接等待弹框
+ private ProgressDialog dialog = null;
+ // 连接的设备的名称
+ private String mConnectedDeviceName = null;
+ // 更新标题栏右边状态和读写状态的Handler
+ @SuppressLint("HandlerLeak")
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case BluetoothService.MESSAGE_STATE_CHANGE:
+ switch (msg.arg1) {
+ case BluetoothService.STATE_CONNECTED:
+ MyApp.getInstance().setBluConnection(true);
+ if (!isprint) {
+ isprint = true;
+ isprint2 = true;
+ }
+ print(info);
+ if (dialog != null) {
+ dialog.dismiss();
+ dialog = null;
+ }
+ break;
+ case BluetoothService.STATE_CONNECTING:
+ if (dialog == null) {
+ // 显示ProgressDialog
+ dialog = new ProgressDialog(MobilePrintTool.this);
+ dialog.setMessage("连接打印机中...");
+ dialog.setCanceledOnTouchOutside(true);
+ dialog.setCancelable(true);
+ if (type == DeviceType.HANDSET.getValue()) {
+ dialog.getWindow()
+ .setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+ try {
+ dialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ dialog.setMessage("连接打印机中...");
+ }
+ break;
+ case BluetoothService.STATE_NONE:
+ break;
+ case BluetoothService.STATE_LISTEN:
+ // MyApp.getInstance().setBluConnection(false);
+ if (dialog != null) {
+ dialog.dismiss();
+ dialog = null;
+ }
+ break;
+ case BluetoothService.STATE_FAILL:
+ if (dialog != null) {
+ dialog.dismiss();
+ dialog = null;
+ }
+ finish();
+ break;
+ }
+ break;
+ case BluetoothService.STATE_FAILL:
+ if (dialog != null) {
+ dialog.dismiss();
+ dialog = null;
+ }
+ finish();
+ break;
+ case BluetoothService.MESSAGE_WRITE:
+ break;
+ case BluetoothService.MESSAGE_READ:
+ break;
+ case BluetoothService.MESSAGE_DEVICE_NAME:
+ // 保存连接设备的名字
+ mConnectedDeviceName = msg.getData().getString(
+ BluetoothService.DEVICE_NAME);
+ if (type != null && type == DeviceType.HANDSET.getValue()) {
+ MToast.makeText(MobilePrintTool.this,
+ "连接到" + mConnectedDeviceName, MToast.LENGTH_SHORT)
+ .show();
+ } else {
+ Toast.makeText(MobilePrintTool.this,
+ "连接到" + mConnectedDeviceName, Toast.LENGTH_SHORT)
+ .show();
+ }
+ if (!isprint) {
+ isprint = true;
+ isprint2 = true;
+ }
+ print(info);
+ break;
+ case BluetoothService.MESSAGE_TOAST:
+ if (!msg.getData().getBoolean("sucess", false)) {
+ finish();
+ return;
+ }
+ if (Thread.currentThread() != Looper.getMainLooper()
+ .getThread()) {
+ Looper.prepare();
+ }
+ String info = msg.getData().getString(BluetoothService.TOAST);
+ if (info != null && !info.equals("")) {
+ if (type != null && type == DeviceType.HANDSET.getValue()) {
+ MToast.makeText(
+ MobilePrintTool.this,
+ msg.getData().getString(BluetoothService.TOAST),
+ MToast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(
+ MobilePrintTool.this,
+ msg.getData().getString(BluetoothService.TOAST),
+ Toast.LENGTH_LONG).show();
+ }
+ if (Thread.currentThread() != Looper.getMainLooper()
+ .getThread()) {
+ Looper.loop();
+ }
+ }
+ break;
+ }
+ }
+ };
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mBluetoothAdapter != null) {
+ mBluetoothAdapter.cancelDiscovery();
+ if (mBluetoothAdapter.isEnabled()) {
+ mBluetoothAdapter.disable();
+ }
+ }
+ }
+}
diff --git b/src/android_serialport_api/print_tool/SerialIDPortTool.java a/src/android_serialport_api/print_tool/SerialIDPortTool.java
new file mode 100644
index 0000000..65d9a83
--- /dev/null
+++ a/src/android_serialport_api/print_tool/SerialIDPortTool.java
@@ -0,0 +1,438 @@
+package android_serialport_api.print_tool;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.view.WindowManager;
+
+import com.ectrip.cyt.callback.CloseCallback;
+import com.ectrip.cyt.config.MyApp;
+import com.ectrip.cyt.constant.DeviceType;
+import com.ectrip.cyt.constant.LogoType;
+import com.ectrip.cyt.constant.SelectAction;
+import com.ectrip.cyt.constant.constant;
+import com.ectrip.cyt.ui.ScanerOrderActivity;
+import com.ectrip.cyt.utils.LogUtil;
+import com.ectrip.cyt.utils.SharedPreferences2Obj;
+import com.ectrip.trips.check.R;
+import com.hdx.lib.printer.SerialPrinter;
+import com.hdx.lib.serial.SerialParam;
+import com.hdx.lib.serial.SerialPortOperaion;
+import com.hdx.lib.serial.SerialPortOperaion.SerialReadData;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidParameterException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import android_serialport_api.SerialPort;
+import hdx.HdxUtil;
+
+public class SerialIDPortTool implements CloseCallback {
+ private String TAG = "SerialIDPortTool";
+ private Context mcontext;
+ private MyIdPosHandler idPosHandler;
+ private WakeLock lock;
+ private final int PRINTIT = 1;
+ private final int CLOSE = 2;
+ protected SerialPort mSerialPort = null;
+ protected OutputStream mOutputStream;
+ public SerialPrinter mSerialPrinter = null;
+ private InputStream mInputStream;
+ private ProgressDialog dialog;
+ private Integer type;
+ private int printNum = 1;
+ private int Select = 0;
+ private String isStatistic = "0";
+ private String printinfo;
+ private SerialDataHandler serialDataHandler;
+
+ @SuppressLint("Wakelock")
+ public void init(Context mContext, String printInfo) {
+ this.printinfo = printInfo;
+ this.mcontext = mContext;
+ if (idPosHandler == null) {
+ idPosHandler = new MyIdPosHandler();
+ }
+ if (serialDataHandler == null) {
+ serialDataHandler = new SerialDataHandler();
+ }
+ popUpDialog();
+ new Thread(new Runnable() {
+ @SuppressWarnings("deprecation")
+ @Override
+ public void run() {
+ try {
+ try {
+ if (mSerialPort == null) {
+ mSerialPort = getSerialPort();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (mSerialPrinter == null) {
+ mSerialPrinter = SerialPrinter.GetSerialPrinter();
+ }
+ if (mSerialPort != null) {
+ mOutputStream = mSerialPort.getOutputStream();
+ mInputStream = mSerialPort.getInputStream();
+ } else {
+
+ }
+ HdxUtil.SwitchSerialFunction(HdxUtil.SERIAL_FUNCTION_PRINTER);
+ sleep(500);
+ try {
+ mSerialPrinter.OpenPrinter(new SerialParam(115200,
+ "/dev/ttyS1", 0), serialDataHandler,
+ SerialIDPortTool.this);
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+
+ PowerManager pm = (PowerManager) mcontext
+ .getSystemService(Context.POWER_SERVICE);
+ lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+ lock.acquire();
+ try {
+ HdxUtil.SetPrinterPower(1);
+ try {
+ sleep(200);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ List info = new ArrayList();
+ if (printinfo != null) {
+ String[] str = printinfo.split("\n");
+ for (int i = 0; i < str.length; i++) {
+ info.add(str[i]);
+ }
+ }
+ try {
+ HdxUtil.SetPrinterPower(1);
+ sleep(200);
+ sendCharacterDemo(info);
+ sleep(500);
+ //打印完成发送消息关闭dialog。
+ idPosHandler.sendMessage(idPosHandler.obtainMessage(CLOSE, 1,
+ 0, null));
+ mSerialPrinter.printString("printClose", 1);
+ } catch (Exception e) {
+ close();
+ e.printStackTrace();
+ }
+ } finally {
+ try {
+ lock.release();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ HdxUtil.SetPrinterPower(0);
+ }
+
+ } catch (SecurityException e) {
+ close();
+ // DisplayError(R.string.error_security);
+ } catch (InvalidParameterException e) {
+ close();
+ // DisplayError(R.string.error_configuration);
+ } catch (Exception e) {
+ close();
+ // TODO: handle exception
+ }
+ }
+ }).start();
+ }
+
+ private void popUpDialog() {
+ try {
+ isStatistic = SharedPreferences2Obj.getInstance(mcontext)
+ .setName("SelectAction")
+ .getObject("isStatistic", String.class); // 非统计判断
+ type = SharedPreferences2Obj.getInstance(mcontext)
+ .setName("MachineType").getObject("type", Integer.class);
+ Select = SharedPreferences2Obj.getInstance(mcontext)
+ .setName("SelectAction").getObject("Select", Integer.class);
+ printNum = MyApp.getInstance().getPrintNum();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ if (dialog == null) {
+ // 显示ProgressDialog
+ dialog = new ProgressDialog(mcontext);
+ dialog.setMessage("打印中...");
+ dialog.setCanceledOnTouchOutside(true);
+ dialog.setCancelable(false);
+ if (type == DeviceType.HANDSET.getValue()) {
+ dialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+ try {
+ dialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ dialog.setMessage("打印中...");
+ dialog.show();
+ }
+ }
+
+ public SerialPort getSerialPort() throws SecurityException, IOException,
+ InvalidParameterException {
+ if (mSerialPort == null) {
+ String path = "/dev/ttyS1";
+ int baudrate = 115200;
+
+ if ((path.length() == 0) || (baudrate == -1)) {
+ path = "/dev/ttyS1";
+ baudrate = 115200;
+ }
+ mSerialPort = new SerialPort(new File(path), baudrate, 0);
+ }
+ return mSerialPort;
+ }
+
+ @SuppressLint("HandlerLeak")
+ private class MyIdPosHandler extends Handler {
+ public MyIdPosHandler() {
+ }
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case CLOSE:
+ if (dialog != null) {
+ dialog.dismiss();
+ }
+
+ Boolean scanBack = SharedPreferences2Obj.getInstance(mcontext).setName("config").getObject("scanBack", Boolean.class);
+ if (MyApp.getInstance().getCheckType()==0&&scanBack != null && scanBack) {
+ checkScan();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private void checkScan() {
+ if (MyApp.getInstance().getCheckType() == 0) {
+ Integer Select = SharedPreferences2Obj
+ .getInstance(mcontext)
+ .setName("SelectAction").getObject("Select", Integer.class);
+ Intent intent = new Intent(mcontext,
+ ScanerOrderActivity.class);
+ if (Select != null) {
+ if (Select == SelectAction.Check.getValue()) {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.check_scan_code));
+ } else if (Select == SelectAction.Reprint.getValue()) {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.repriint_scan_code));
+ } else if (Select == SelectAction.Query.getValue()) {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.query_scan_code));
+ }
+ } else {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.scan_qr_code));
+ }
+ mcontext.startActivity(intent);
+ Activity activity = (Activity) mcontext;
+ activity.finish();
+ }
+ }
+
+ @SuppressLint("HandlerLeak")
+ private class SerialDataHandler extends Handler {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SerialPortOperaion.SERIAL_RECEIVED_DATA_MSG:
+ SerialReadData data = (SerialReadData) msg.obj;
+ StringBuilder sb = new StringBuilder();
+ for (int x = 0; x < data.size; x++)
+ sb.append(String.format("%02x", data.data[x]));
+ LogUtil.d(TAG, "data =" + sb);
+ }
+ }
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ private void sendCharacterDemo(List arr) {
+
+ LogUtil.e(TAG, "#########sendCharacterDemo##########");
+
+ for (int x = 0; x < printNum; x++) {
+ if (x == 1 && isStatistic.equals("1")) {
+ close();
+ return;
+ }
+
+ try {
+ if (isStatistic != null && isStatistic.equals("1")) {
+ mSerialPrinter.enlargeFontSize(2, 2);//
+ mSerialPrinter.printString(" 统计信息", x);
+ sleep(100);
+ } else {
+ mSerialPrinter.enlargeFontSize(2, 2);//
+ mSerialPrinter.printString(" 订单信息", x);
+ sleep(100);
+ // 当时重打小票的时候,多打一段字符
+
+ if (Select == SelectAction.Reprint.getValue()) {
+ mSerialPrinter.enlargeFontSize(1, 1);
+ mSerialPrinter.printString(" (重打小票)", x);
+ sleep(100);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ mSerialPrinter.setLineSpace(5); // 间隔
+ sleep(100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (arr == null) {
+ return;
+ }
+ // 打印信息
+ try {
+ mSerialPrinter.enlargeFontSize(1, 1);
+ for (int i = 0; i < arr.size(); i++) {
+ mSerialPrinter.printString(arr.get(i), x);
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+ }
+ if (isStatistic != null && isStatistic.equals("1")) {
+
+ } else {
+ if (Select == SelectAction.Query.getValue()) { // 打印时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ mSerialPrinter.printString(
+ "检票时间:" + df.format(new Date()), x);// new
+ sleep(100);
+ // Date()为获取当前系统时间
+ mSerialPrinter.sendLineFeed();
+ } else if(Select == SelectAction.Reprint.getValue()) {// 重打时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ mSerialPrinter.printString(
+ "重打时间:" + df.format(new Date()), x);// new
+ sleep(100);
+ // Date()为获取当前系统时间
+ mSerialPrinter.sendLineFeed();
+ }
+ mSerialPrinter.setLineSpace(10);
+ mSerialPrinter.sendLineFeed();
+ mSerialPrinter.printString("取票人签名:", x);
+ sleep(100);
+ mSerialPrinter.setLineSpace(10);
+ }
+
+ mSerialPrinter.sendLineFeed();
+
+ if (constant.logoMark == LogoType.CYT.getValue()) {
+ mSerialPrinter.printString("---畅游通—智慧旅游O2O平台---", x);
+ sleep(100);
+ mSerialPrinter.sendLineFeed();
+ mSerialPrinter.printString(
+ "--------www.jingqu.cn---------", x);
+ } else if (constant.logoMark == LogoType.QNE.getValue()) {
+ mSerialPrinter.printString("---欢迎使用去哪儿网O2O系统---", x);
+ sleep(100);
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+ mSerialPrinter.printString("--------www.qunar.com--------",
+ x);
+ sleep(100);
+ }
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // 信息完打印的空格行数
+ try {
+ mSerialPrinter.setLineSpace(30); //
+ sleep(100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ mSerialPrinter.walkPaper(60);//
+ sleep(100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ //sleep(1500);
+ LogUtil.e(TAG, "print end");
+ }
+
+ public void sleep(int ms) {
+
+ try {
+ Thread.sleep(ms);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void close() {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ if (mSerialPrinter != null) {
+ try {
+ mSerialPrinter.ClosePrinter();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (mSerialPort != null) {
+ try {
+ mSerialPort.close();
+ mSerialPort = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ try {
+ if (mOutputStream != null) {
+ mOutputStream.close();
+ }
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
+ } catch (IOException e) {
+ } catch (Exception e) {
+ }
+ idPosHandler.sendMessage(idPosHandler.obtainMessage(CLOSE, 1,
+ 0, null));
+ }
+ }).start();
+ }
+
+ @Override
+ public void closeback() {
+ close();
+ }
+
+}
diff --git b/src/android_serialport_api/print_tool/SerialNewHandlePortTool.java a/src/android_serialport_api/print_tool/SerialNewHandlePortTool.java
new file mode 100644
index 0000000..be2ae49
--- /dev/null
+++ a/src/android_serialport_api/print_tool/SerialNewHandlePortTool.java
@@ -0,0 +1,384 @@
+package android_serialport_api.print_tool;
+
+import hdx.HdxUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidParameterException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import android.annotation.SuppressLint;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.view.WindowManager;
+import android.widget.Toast;
+import android_serialport_api.SerialPort;
+
+import com.ectrip.cyt.config.MyApp;
+import com.ectrip.cyt.constant.DeviceType;
+import com.ectrip.cyt.constant.LogoType;
+import com.ectrip.cyt.constant.constant;
+import com.ectrip.cyt.utils.LogUtil;
+import com.ectrip.cyt.utils.SharedPreferences2Obj;
+
+/**
+ * @author jigo
+ * 新版手持pos机
+ */
+public class SerialNewHandlePortTool {
+ private WakeLock lock;
+ private static final String TAG = "SerialNewPortTool";
+
+ private Context context;
+
+ private final int ENABLE_BUTTON = 2;
+
+ private SerialPort mSerialPort = null;
+ protected OutputStream mOutputStream;
+ private InputStream mInputStream;
+ protected ReadThread mReadThread;
+ private int n = 0;
+ private int printer_status = 0;
+
+ private MyHandler handler;
+
+ private int printNum=1;
+
+ @SuppressWarnings("deprecation")
+ public void init(Context context,String contentStr) {
+ this.context=context;
+ if(handler==null){
+ handler = new MyHandler();
+ }
+ popUpDialog();
+ try {
+ HdxUtil.SwitchSerialFunction(HdxUtil.SERIAL_FUNCTION_PRINTER);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ Toast.makeText(context, "不支持", Toast.LENGTH_LONG).show();
+ return;
+ }
+ PowerManager pm = (PowerManager) context
+ .getSystemService(Context.POWER_SERVICE);
+ lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+
+ new WriteThread(contentStr).start();
+ }
+
+ @SuppressLint("SimpleDateFormat") private class WriteThread extends Thread {
+ private String arr;
+
+ public WriteThread(String str) {
+ arr = str;
+ }
+
+ public void run() {
+ super.run();
+ try {
+ mSerialPort =getSerialPort();
+ mOutputStream = mSerialPort.getOutputStream();
+ mInputStream = mSerialPort.getInputStream();
+
+ /* Create a receiving thread */
+ mReadThread = new ReadThread();
+ mReadThread.start();
+ } catch (SecurityException e) {
+ // DisplayError(R.string.error_security);
+ } catch (IOException e) {
+ // DisplayError(R.string.error_unknown);
+ } catch (InvalidParameterException e) {
+ // DisplayError(R.string.error_configuration);
+ }
+ HdxUtil.SetPrinterPower(1);
+ lock.acquire();
+ try {
+ try {
+ sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ sendCommand(0x1B, 0x23, 0x23, 0x53, 0x4C, 0x41, 0x4E, 0x0f); // china
+ sendCommand(0x1B,0x32);//设置行间距
+// for(int i=0;i<2;i++){
+// sendCharacterDemo(arr);
+// sendCommand(0x0a);
+// sendCommand(0x1d, 0x56, 0x30);
+// try {
+// sleep(4000);
+// } catch (InterruptedException e) {
+// e.printStackTrace();
+// }
+// }
+
+ for (int x = 0; x < printNum; x++) {
+
+ if(x==1&&isStatistic.equals("1")){
+ break;
+ }
+
+ try {
+ if(isStatistic!=null&&isStatistic.equals("1")){
+ sendCharacterDemo(" 统计信息"+"\n");
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ }else{
+ sendCharacterDemo(" 订单信息"+"\n");
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ // 当时重打小票的时候,多打一段字符
+
+ if (Select== 2) {
+ sendCharacterDemo(" (重打小票)");
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ sendCommand(0x1b, 0x33, 0x14, 0x0a); // 间隔
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ sendCharacterDemo(arr);
+ sendCommand(0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ try {
+ sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ if(isStatistic!=null&&isStatistic.equals("1")){
+
+ }else{
+ // 重打时间
+// if (Select== 2) {
+// SimpleDateFormat df = new SimpleDateFormat(
+// "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+// sendCharacterDemo("重打时间:" + df.format(new Date()));
+// sendCommand(0x1b, 0x33, 0x14, 0x0a);
+// }
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCharacterDemo("取票人签名:");
+ }
+
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ if (constant.logoMark == LogoType.CYT.getValue()) {
+ sendCharacterDemo("---畅游通—智慧旅游O2O平台---");
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCharacterDemo("--------www.jingqu.cn---------");
+ } else if (constant.logoMark ==LogoType.QNE.getValue()) {
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+
+ sendCharacterDemo("---欢迎使用去哪儿网O2O系统---");
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCharacterDemo("--------www.qunar.com--------");
+ }
+ sendCharacterDemo("\n");
+ sendCharacterDemo("\n");
+ sendCharacterDemo("\n");
+ sendCharacterDemo("\n");
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ try {
+ sleep(2500);
+ if (isStatistic.equals("1")){
+ sleep(1500);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ } finally {
+ lock.release();
+ //HdxUtil.SetPrinterPower(0);
+ }
+
+ handler.sendMessage(handler
+ .obtainMessage(ENABLE_BUTTON, 1, 0, null));
+ }
+ }
+
+ private void sendCharacterDemo(String arr) {
+ synchronized (MyApp.getInstance()) {
+ try {
+ mOutputStream.write(arr.getBytes("GBK"));
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @SuppressLint("HandlerLeak")
+ private class MyHandler extends Handler {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case ENABLE_BUTTON:
+ close();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ class ReadThread extends Thread {
+
+ @Override
+ public void run() {
+ super.run();
+ while(!isInterrupted()) {
+ int size;
+ try {
+ byte[] buffer = new byte[64];
+
+ if (mInputStream == null) return;
+ size = mInputStream.read(buffer);
+ if (size > 0) {
+ onDataReceived(buffer, size,n);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+ }
+ }
+ }
+
+ protected void onDataReceived(final byte[] buffer, final int size,
+ final int n) {
+ printer_status = buffer[0];
+ LogUtil.e(TAG, "onDataReceived= " + printer_status);
+ }
+
+ private void sendCommand(int... command) {
+ try {
+ for (int i = 0; i < command.length; i++) {
+ mOutputStream.write(command[i]);
+ // Log.e(TAG,"command["+i+"] = "+Integer.toHexString(command[i]));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ // / sleep(1);
+ }
+
+ public void sleep(int ms) {
+
+ try {
+ java.lang.Thread.sleep(ms);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public SerialPort getSerialPort() throws SecurityException, IOException,
+ InvalidParameterException {
+ if (mSerialPort == null) {
+ /* Read serial port parameters */
+ String path = "/dev/ttyS1";
+ ;// sp.getString("DEVICE", "");
+ int baudrate = 115200;// Integer.decode(sp.getString("BAUDRATE",
+ // "-1"));
+
+ /* Check parameters */
+ if ((path.length() == 0) || (baudrate == -1)) {
+ // throw new InvalidParameterException();
+ /* use default value. Nirvana 0710 */
+ path = "/dev/ttyS1";
+ baudrate = 115200;
+ }
+
+ /* Open the serial port */
+ mSerialPort = new SerialPort(new File(path), baudrate, 0);
+ }
+ return mSerialPort;
+ }
+
+ public void closeSerialPort() {
+ if (mSerialPort != null) {
+ mSerialPort.close();
+ mSerialPort = null;
+ }
+ }
+
+ public void close(){
+ try {
+ if (mReadThread != null)
+ mReadThread.interrupt();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ try {
+ mSerialPort = null;
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ try
+ {
+ mOutputStream.close();
+ mInputStream.close();
+ } catch (IOException e) {
+ }catch (Exception e) {
+ }
+ if(dialog!=null){
+ dialog.dismiss();
+ }
+ }
+
+ private ProgressDialog dialog;
+ private String isStatistic;
+ private Integer type;
+ private int Select = 0;
+ private void popUpDialog(){
+ try {
+ isStatistic=SharedPreferences2Obj.getInstance(context).
+ setName("SelectAction").getObject("isStatistic",String.class); //非统计判断
+ type=SharedPreferences2Obj.getInstance(context).
+ setName("MachineType").getObject("type", Integer.class);
+ Select=SharedPreferences2Obj.getInstance(context).
+ setName("SelectAction").getObject("Select",Integer.class);
+ printNum = MyApp.getInstance().getPrintNum();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ if (dialog == null) {
+ // 显示ProgressDialog
+ dialog = new ProgressDialog(context);
+ dialog.setMessage("打印中...");
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.setCancelable(false);
+ if (type==DeviceType.HANDSET.getValue()) {
+ dialog.getWindow()
+ .setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+ try {
+ dialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }else{
+ dialog.setMessage("打印中...");
+ dialog.show();
+ }
+ }
+}
diff --git b/src/android_serialport_api/print_tool/SerialNewPortTool.java a/src/android_serialport_api/print_tool/SerialNewPortTool.java
new file mode 100644
index 0000000..ff45add
--- /dev/null
+++ a/src/android_serialport_api/print_tool/SerialNewPortTool.java
@@ -0,0 +1,534 @@
+package android_serialport_api.print_tool;
+
+import hdx.HdxUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidParameterException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import android_serialport_api.SerialPort;
+
+import com.ectrip.cyt.config.MyApp;
+import com.ectrip.cyt.constant.DeviceType;
+import com.ectrip.cyt.constant.LogoType;
+import com.ectrip.cyt.constant.SelectAction;
+import com.ectrip.cyt.constant.constant;
+import com.ectrip.cyt.ui.PhomeScanerOrderActivity;
+import com.ectrip.cyt.utils.LogUtil;
+import com.ectrip.cyt.utils.SharedPreferences2Obj;
+import com.ectrip.trips.check.R;
+
+/**
+ * @author jigo 新款pos机
+ */
+public class SerialNewPortTool {
+ private WakeLock lock;
+ private static final String TAG = "SerialNewPortTool";
+
+ private Context context;
+
+ private final int ENABLE_BUTTON = 2;
+
+ private SerialPort mSerialPort = null;
+ protected OutputStream mOutputStream;
+ private InputStream mInputStream;
+ protected ReadThread mReadThread;
+ private int n = 0;
+ private int printer_status = 0;
+
+ private MyHandler handler;
+
+ private int printNum = 1;
+ // 打印信息
+ private ConcurrentLinkedQueue queue;
+
+ // 初始化
+ @SuppressWarnings("deprecation")
+ public void init(Context context, String contentStr) {
+ this.context = context;
+ if (queue == null) {
+ queue = new ConcurrentLinkedQueue();
+ }
+ if (handler == null) {
+ handler = new MyHandler();
+ }
+ popUpDialog();
+ try {
+ HdxUtil.SwitchSerialFunction(HdxUtil.SERIAL_FUNCTION_PRINTER);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ Toast.makeText(context, "不支持", Toast.LENGTH_LONG).show();
+ return;
+ }
+ PowerManager pm = (PowerManager) context
+ .getSystemService(Context.POWER_SERVICE);
+ lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+
+ new WriteThread(contentStr).start();
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ private class WriteThread extends Thread {
+ private String arr;
+
+ public WriteThread(String str) {
+ arr = str;
+ }
+
+ public void run() {
+ super.run();
+ try {
+ mSerialPort = getSerialPort();
+ mOutputStream = mSerialPort.getOutputStream();
+ mInputStream = mSerialPort.getInputStream();
+
+ /* Create a receiving thread */
+ mReadThread = new ReadThread();
+ mReadThread.start();
+ } catch (SecurityException e) {
+ // DisplayError(R.string.error_security);
+ } catch (IOException e) {
+ // DisplayError(R.string.error_unknown);
+ } catch (InvalidParameterException e) {
+ // DisplayError(R.string.error_configuration);
+ }
+ HdxUtil.SetPrinterPower(1);
+ lock.acquire();
+ try {
+ try {
+ sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ sendCommand(0x1B, 0x23, 0x23, 0x53, 0x4C, 0x41, 0x4E, 0x0f); // china
+
+
+ for (int x = 0; x < printNum; x++) {
+
+ if (x == 1 && isStatistic.equals("1")) {
+ break;
+ }
+
+ try {
+ sendCommand(0x1D, 0x21, 0x11); //double height
+ if (isStatistic != null && isStatistic.equals("1")) {
+ mOutputStream.write(" 统计信息\n".getBytes("cp936"));
+ sendCommand(0x1D, 0x21, 0x00); //cancel double height
+ sendCommand(0x1B, 0x32); //设置行间距
+ // queue.offer(" 统计信息\n");
+ } else {
+ mOutputStream.write(" 订单信息\n".getBytes("cp936"));
+ sendCommand(0x1D, 0x21, 0x00); //cancel double height
+ sendCommand(0x1B, 0x32); //设置行间距
+ // queue.offer(" 订单信息\n");
+ if (Select == SelectAction.Reprint.getValue()) {
+ mOutputStream.write("\n (重打小票)\n\n".getBytes("cp936"));
+ //queue.offer(" (重打小票)\n\n");
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // queue.offer(arr);
+ try {
+ String [] arrs =arr.split("\n");
+ for (int i=0;i 0) {
+ onDataReceived(buffer, size, n);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+ }
+ }
+ }
+
+ protected void onDataReceived(final byte[] buffer, final int size,
+ final int n) {
+ printer_status = buffer[0];
+ LogUtil.e(TAG, "onDataReceived= " + printer_status);
+ }
+
+ private void sendCommand(int... command) {
+ try {
+ for (int i = 0; i < command.length; i++) {
+ mOutputStream.write(command[i]);
+ // Log.e(TAG,"command["+i+"] = "+Integer.toHexString(command[i]));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void sleep(int ms) {
+
+ try {
+ java.lang.Thread.sleep(ms);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public SerialPort getSerialPort() throws SecurityException, IOException,
+ InvalidParameterException {
+ if (mSerialPort == null) {
+ /* Read serial port parameters */
+ // SharedPreferences sp = context.getSharedPreferences(
+ // "android_serialport_api.sample_preferences",0);
+ String path = "/dev/ttyS3";
+ ;// sp.getString("DEVICE", "");
+ int baudrate = 115200;// Integer.decode(sp.getString("BAUDRATE",
+ // "-1"));
+
+ /* Check parameters */
+ if ((path.length() == 0) || (baudrate == -1)) {
+ // throw new InvalidParameterException();
+ /* use default value. Nirvana 0710 */
+ path = "/dev/ttyS2";
+ baudrate = 115200;
+ }
+
+ /* Open the serial port */
+ mSerialPort = new SerialPort(new File(path), baudrate, 0);
+ }
+ return mSerialPort;
+ }
+
+ public void closeSerialPort() {
+ if (mSerialPort != null) {
+ mSerialPort.close();
+ mSerialPort = null;
+ }
+ }
+
+ /************************
+ * 关闭处理
+ **********************************/
+ public void close() {
+ try {
+ if (mReadThread != null)
+ mReadThread.interrupt();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ try {
+ mSerialPort = null;
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ try {
+ mOutputStream.close();
+ mInputStream.close();
+ } catch (IOException e) {
+ } catch (Exception e) {
+ }
+ if (dialog != null) {
+ dialog.dismiss();
+ }
+ HdxUtil.SetPrinterPower(0);
+ }
+
+ /***************************
+ * 打印状态
+ ***********************************/
+ byte[] Status_Buffer = new byte[300];
+ boolean Status_Start_Falg = false;
+ int Status_Buffer_Index = 0;
+ Time time = new Time();
+ int TimeSecond;
+ private final byte HDX_ST_WORK = (byte) (1 << 5);// 1 打印机在工作状态
+
+ void setStatus_Buffer_Index(int v) {
+ Status_Buffer_Index = v;
+ }
+
+ int getStatus_Buffer_Index() {
+ return Status_Buffer_Index;
+
+ }
+
+ boolean TimeIsOver(int second) {
+
+ time.setToNow();
+ int t = time.second;
+ if (t < TimeSecond) {
+ t += 60;
+ }
+
+ if (t - TimeSecond > second) {
+ return true;
+ }
+ return false;
+ }
+
+ byte Get_Printer_Status() {
+ Status_Buffer[0] = 0;
+ Status_Buffer[1] = 0;
+ Status_Start_Falg = true;
+ setStatus_Buffer_Index(0);
+ sendCommand(0x1b, 0x76);
+ LogUtil.i(TAG, "Get_Printer_Status->0x1b,0x76");
+ Time_Check_Start();
+ while (true) {
+ if (getStatus_Buffer_Index() > 0) {
+ Status_Start_Falg = false;
+ LogUtil.e(TAG, "Get_Printer_Status :" + Status_Buffer[0]);
+ return Status_Buffer[0];
+ }
+ if (TimeIsOver(5)) {
+ Status_Start_Falg = false;
+ LogUtil.e(TAG, "Get_Printer_Status->TIME OVER:"
+ + Status_Buffer[0]);
+ return (byte) 0xff;
+ }
+ sleep(50);
+ }
+ }
+
+ void Time_Check_Start() {
+ time.setToNow();
+ TimeSecond = time.second;
+ }
+
+ AtomicBoolean isStop = new AtomicBoolean();
+
+ void Wait_Printer_Ready(final ConcurrentLinkedQueue queue) {
+
+ new AsyncTask() {
+ @Override
+ protected Object doInBackground(Object[] objects) {
+
+ while (!isStop.get()) {
+ if (!queue.isEmpty()) {
+ try {
+ mOutputStream.write(queue.poll().getBytes("gbk"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ } else {
+
+ isStop.set(true);
+ sleep(500);
+
+ }
+
+ sleep(40);
+ }
+ if (MyApp.getInstance().getCheckType() == 0) {
+ sleep(1000);
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Object o) {
+ super.onPostExecute(o);
+ handler.sendMessage(handler.obtainMessage(
+ ENABLE_BUTTON, 1, 0, null));
+
+
+ }
+ }.execute();
+
+ }
+
+
+ private void checkScan() {
+ if (MyApp.getInstance().getCheckType() == 0) {
+ Integer Select = SharedPreferences2Obj
+ .getInstance(context)
+ .setName("SelectAction").getObject("Select", Integer.class);
+ Intent intent = new Intent(context,
+ PhomeScanerOrderActivity.class);
+ if (Select != null) {
+ if (Select == SelectAction.Check.getValue()) {
+ intent.putExtra("titleName",
+ context.getString(R.string.check_scan_code));
+ } else if (Select == SelectAction.Reprint.getValue()) {
+ intent.putExtra("titleName",
+ context.getString(R.string.repriint_scan_code));
+ } else if (Select == SelectAction.Query.getValue()) {
+ intent.putExtra("titleName",
+ context.getString(R.string.query_scan_code));
+ }
+ } else {
+ intent.putExtra("titleName",
+ context.getString(R.string.scan_qr_code));
+ }
+ context.startActivity(intent);
+ Activity activity = (Activity) context;
+ activity.finish();
+ }
+ }
+
+ /***************************
+ * 弹框处理
+ ********************************/
+ private ProgressDialog dialog;
+ private String isStatistic;
+ private Integer type;
+ private int Select = 0;
+
+ private void popUpDialog() {
+ try {
+ isStatistic = SharedPreferences2Obj.getInstance(context)
+ .setName("SelectAction")
+ .getObject("isStatistic", String.class); // 非统计判断
+ type = SharedPreferences2Obj.getInstance(context)
+ .setName("MachineType").getObject("type", Integer.class);
+ Select = SharedPreferences2Obj.getInstance(context)
+ .setName("SelectAction").getObject("Select", Integer.class);
+ printNum = MyApp.getInstance().getPrintNum();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ if (dialog == null) {
+ // 显示ProgressDialog
+ dialog = new ProgressDialog(context);
+ dialog.setMessage("打印中...");
+ dialog.setCanceledOnTouchOutside(true);
+ dialog.setCancelable(false);
+ if (type == DeviceType.HANDSET.getValue()) {
+ dialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+ try {
+ dialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ dialog.setMessage("打印中...");
+ dialog.show();
+ }
+ }
+}
diff --git b/src/android_serialport_api/print_tool/SerialPortTool.java a/src/android_serialport_api/print_tool/SerialPortTool.java
new file mode 100644
index 0000000..4e56550
--- /dev/null
+++ a/src/android_serialport_api/print_tool/SerialPortTool.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2009 Cedric Priscal
+ *
+ * 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 android_serialport_api.print_tool;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidParameterException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Handler;
+import android.os.Message;
+import android.view.WindowManager;
+import android_serialport_api.SerialPort;
+
+import com.ectrip.cyt.callback.CloseCallback;
+import com.ectrip.cyt.config.MyApp;
+import com.ectrip.cyt.constant.DeviceType;
+import com.ectrip.cyt.constant.LogoType;
+import com.ectrip.cyt.constant.SelectAction;
+import com.ectrip.cyt.constant.constant;
+import com.ectrip.cyt.utils.LogUtil;
+import com.ectrip.cyt.utils.SharedPreferences2Obj;
+import com.hdx.lib.printer.SerialPrinter;
+import com.hdx.lib.serial.SerialParam;
+import com.hdx.lib.serial.SerialPortOperaion;
+import com.hdx.lib.serial.SerialPortOperaion.SerialReadData;
+
+/**
+ * @author jigo pos机打印工具类
+ */
+public class SerialPortTool implements CloseCallback{
+
+ private Context mContext;
+ protected SerialPort mSerialPort=null;
+ protected OutputStream mOutputStream;
+ private InputStream mInputStream;
+ protected ReadThread mReadThread;
+ private static final String TAG = "SerialPortTool";
+ public SerialPrinter mSerialPrinter = null;
+ private int n = 0;
+ private ProgressDialog dialog;
+ private Integer type;
+ private int printNum=1;
+ private int Select = 0;
+ private String isStatistic;
+ private String printinfo;
+ private MyHandler handler;
+ private final int CLOSE=5;
+ private SerialDataHandler serialDataHandler;
+
+ @SuppressLint("SimpleDateFormat") public void init(Context mContext, String printInfo) {
+ this.mContext = mContext;
+ this.printinfo = printInfo;
+ this.serialDataHandler=new SerialDataHandler();
+ if(handler==null){
+ handler=new MyHandler();
+ }
+ popUpDialog();
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ if (mSerialPort == null) {
+ mSerialPort = getSerialPort();
+ }
+ if (mSerialPrinter == null) {
+ mSerialPrinter = SerialPrinter.GetSerialPrinter();
+ }
+ try {
+ mSerialPrinter.OpenPrinter(new SerialParam(115200,
+ "/dev/ttyS2", 0),serialDataHandler,SerialPortTool.this);
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ if (mSerialPort != null) {
+ mOutputStream = mSerialPort.getOutputStream();
+ mInputStream = mSerialPort.getInputStream();
+ sleep(200);
+ mReadThread = new ReadThread();
+ mReadThread.start();
+ } else {
+
+ }
+
+ LogUtil.e(TAG, "print end");
+
+ for (int x = 0; x < printNum; x++) {
+
+ if(x==1&&isStatistic.equals("1")){
+ close();
+ return;
+ }
+
+ try {
+ if(isStatistic!=null&&isStatistic.equals("1")){
+ sendString(" 统计信息"+"\n",x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ }else{
+ sendString(" 订单信息"+"\n",x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ // 当时重打小票的时候,多打一段字符
+
+ if (Select==SelectAction.Reprint.getValue()) {
+ sendString(" (重打小票)",x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ mSerialPrinter.setLineSpace(5); // 间隔
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ sendString(printinfo,x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+
+ if(isStatistic!=null&&isStatistic.equals("1")){
+
+ }else{
+ if(Select== SelectAction.Query.getValue()){ //打印时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ sendString("检票时间:" + df.format(new Date()),x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ }else if (Select==SelectAction.Reprint.getValue()) {// 重打时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ //sendString("重打时间:" + df.format(new Date()),x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ }
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendString("取票人签名:",x);
+ }
+
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ if (constant.logoMark == LogoType.CYT.getValue()) {
+ sendString("---畅游通—智慧旅游O2O平台---",x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendString("--------www.jingqu.cn---------",x);
+ } else if (constant.logoMark == LogoType.QNE.getValue()) {
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+
+ sendString("---欢迎使用去哪儿网O2O系统---",x);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendString("--------www.qunar.com--------",x);
+
+ }
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendCommand(0x1b, 0x33, 0x14, 0x0a);
+ sendString("",x);
+
+ }
+ sleep(1000);
+ mSerialPrinter.printString("printClose",1);
+ LogUtil.e(TAG, "print end");
+
+ } catch (SecurityException e) {
+ close();
+ // DisplayError(R.string.error_security);
+ } catch (IOException e) {
+ close();
+ // DisplayError(R.string.error_unknown);
+ } catch (InvalidParameterException e) {
+ close();
+ // DisplayError(R.string.error_configuration);
+ }catch (Exception e) {
+ close();
+ }
+ }
+ }).start();
+ }
+
+ @SuppressLint("HandlerLeak")
+ private class SerialDataHandler extends Handler {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SerialPortOperaion.SERIAL_RECEIVED_DATA_MSG:
+ SerialReadData data = (SerialReadData) msg.obj;
+ StringBuilder sb = new StringBuilder();
+ for (int x = 0; x < data.size; x++)
+ sb.append(String.format("%02x", data.data[x]));
+ LogUtil.d(TAG, "data =" + sb);
+ }
+ }
+ }
+
+ private void popUpDialog(){
+ try {
+ isStatistic=SharedPreferences2Obj.getInstance(mContext).
+ setName("SelectAction").getObject("isStatistic",String.class); //非统计判断
+ type=SharedPreferences2Obj.getInstance(mContext).
+ setName("MachineType").getObject("type", Integer.class);
+ Select=SharedPreferences2Obj.getInstance(mContext).
+ setName("SelectAction").getObject("Select",Integer.class);
+ printNum = MyApp.getInstance().getPrintNum();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ if (dialog == null) {
+ // 显示ProgressDialog
+ dialog = new ProgressDialog(mContext);
+ dialog.setMessage("打印中...");
+ dialog.setCanceledOnTouchOutside(true);
+ dialog.setCancelable(false);
+ if (type==DeviceType.HANDSET.getValue()) {
+ dialog.getWindow()
+ .setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+ try {
+ dialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }else{
+ dialog.setMessage("打印中...");
+ dialog.show();
+ }
+ }
+
+ public SerialPort getSerialPort() throws SecurityException, IOException,
+ InvalidParameterException {
+ if (mSerialPort == null) {
+ /* Read serial port parameters */
+// SharedPreferences sp = mContext.getSharedPreferences(
+// "android_serialport_api.sample_preferences",0);
+ String path = "/dev/ttyS2";
+ ;// sp.getString("DEVICE", "");
+ int baudrate = 115200;// Integer.decode(sp.getString("BAUDRATE",
+ // "-1"));
+
+ /* Check parameters */
+ if ((path.length() == 0) || (baudrate == -1)) {
+ // throw new InvalidParameterException();
+ /* use default value. Nirvana 0710 */
+ path = "/dev/ttyS2";
+ baudrate = 115200;
+ }
+
+ /* Open the serial port */
+ mSerialPort = new SerialPort(new File(path), baudrate, 0);
+ // (new File(path), baudrate, 0);
+ }
+ return mSerialPort;
+ }
+
+ class ReadThread extends Thread {
+ @Override
+ public void run() {
+ super.run();
+ while (!isInterrupted()) {
+ try {
+ sleep(500);
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ sendCommand(0x1d, 0x4f, 0x01, 0x0a, 0x1b, 0x21, 0x00);
+ int size;
+ LogUtil.e(TAG, "=============while(!isInterrupted())==========");
+ try {
+ byte[] buffer = new byte[64];
+ LogUtil.e(TAG, "1.=============ReadThread");
+ if (mInputStream == null)
+ return;
+ LogUtil.e(TAG, "2.=============ReadThread");
+ LogUtil.i(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
+ buffer.toString());
+ size = mInputStream.read(buffer);
+
+ LogUtil.e(TAG, "3.==============ReadThread,size : " + size);
+
+ if (size > 0) {
+ String tString = new String(buffer, 0, size);
+
+ LogUtil.e(TAG, "4.==============ReadThread,size : "
+ + size);
+ LogUtil.e(TAG, "5.==============ReadThread,buffer : "
+ + tString);
+ for (int i = 0; i < tString.length(); i++) {
+ LogUtil.e(
+ TAG,
+ "6. ===" + i + " : "
+ + (tString.charAt(i)));
+ LogUtil.e(TAG, "7.(int)===" + i + " : "
+ + (int) (tString.charAt(i)));
+ }
+ LogUtil.e(TAG, "111==============n : " + n);
+ n = ((n > 4) ? 0 : n);
+ // onDataReceived(buffer, size, n);
+ n++;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void DisplayError(int resourceId) {
+ AlertDialog.Builder b = new AlertDialog.Builder(mContext);
+ b.setTitle("Error");
+ b.setMessage(resourceId);
+ b.setPositiveButton("OK", new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ b.show();
+ }
+
+ public void print(String printInfo) {
+
+ }
+
+ private void sendCommand(int... command) {
+ synchronized ( SerialPrinter.GetSerialPrinter()) {
+ try {
+ if (mOutputStream != null) {
+ for (int i = 0; i < command.length; i++) {
+ mOutputStream.write(command[i]);
+ LogUtil.e(TAG,
+ "command[" + i + "] = "
+ + Integer.toHexString(command[i]));
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sleep(60);
+ }
+ }
+
+ private void sendString(String tString, int num) {
+ synchronized (SerialPrinter.GetSerialPrinter()) {
+ String string = null;
+ string = UnicodeToGBK(tString);
+ if ("printClose".equals(string)) {
+ closeback();
+ }else{
+ try {
+ for (int i = 0; i < string.length(); i++) {
+ LogUtil.e(
+ TAG,
+ "sendString," + i + " = "
+ + Integer.toHexString(string.charAt(i)));
+ if (mOutputStream != null) {
+ mOutputStream.write(string.charAt(i));
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ sleep(50);
+ }
+ }
+ }
+
+ public static String UnicodeToGBK(String s) {
+ try {
+ String newstring = null;
+ newstring = new String(s.getBytes("GBK"), "ISO-8859-1");
+ return newstring;
+ } catch (UnsupportedEncodingException e) {
+ return s;
+ }
+ }
+
+ public void sleep(int ms) {
+
+ try {
+ java.lang.Thread.sleep(ms);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @SuppressLint("HandlerLeak")
+ class MyHandler extends Handler{
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what) {
+ case CLOSE:
+ if(dialog!=null&&dialog.isShowing()){
+ try {
+ dialog.dismiss();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ public void close() {
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ if (mReadThread != null)
+ mReadThread.interrupt();
+ if (mSerialPrinter != null) {
+ try {
+ mSerialPrinter.ClosePrinter();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (mSerialPort != null) {
+ try {
+ mSerialPort.close();
+ mSerialPort = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ try {
+ if (mOutputStream != null) {
+ mOutputStream.close();
+ }
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
+ } catch (IOException e) {
+ }
+ handler.sendMessage(handler.obtainMessage(CLOSE));
+ }
+ }).start();
+ }
+
+ @Override
+ public void closeback() {
+ close();
+ }
+}
diff --git b/src/android_serialport_api/print_tool/SerialSmallPortTool.java a/src/android_serialport_api/print_tool/SerialSmallPortTool.java
new file mode 100644
index 0000000..d6cf1d0
--- /dev/null
+++ a/src/android_serialport_api/print_tool/SerialSmallPortTool.java
@@ -0,0 +1,460 @@
+package android_serialport_api.print_tool;
+
+import hdx.pwm.PWMControl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidParameterException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.view.WindowManager;
+import android_serialport_api.SerialPort;
+
+import com.ectrip.cyt.callback.CloseCallback;
+import com.ectrip.cyt.config.MyApp;
+import com.ectrip.cyt.constant.DeviceType;
+import com.ectrip.cyt.constant.LogoType;
+import com.ectrip.cyt.constant.SelectAction;
+import com.ectrip.cyt.constant.constant;
+import com.ectrip.cyt.ui.ScanerOrderActivity;
+import com.ectrip.cyt.utils.LogUtil;
+import com.ectrip.cyt.utils.SharedPreferences2Obj;
+import com.ectrip.trips.check.R;
+import com.hdx.lib.printer.SerialPrinter;
+import com.hdx.lib.serial.SerialParam;
+import com.hdx.lib.serial.SerialPortOperaion;
+import com.hdx.lib.serial.SerialPortOperaion.SerialReadData;
+
+public class SerialSmallPortTool implements CloseCallback{
+ private String TAG = "SerialSmallPortTool";
+ private Context mcontext;
+ private boolean stop = false;
+ private final int ENABLE_BUTTON = 2;
+ private final int CLOSEDismiss = 3;
+ protected SerialPort mSerialPort = null;
+ protected OutputStream mOutputStream;
+ public SerialPrinter mSerialPrinter = null;
+ private InputStream mInputStream;
+ private WakeLock lock;
+ private ProgressDialog dialog;
+ private Integer type;
+ private int printNum=1;
+ private int Select = 0;
+ private String isStatistic="0";
+ private PowerManager pm;
+ private String printinfo;
+ private SerialDataHandler serialDataHandler;
+
+ @SuppressLint("Wakelock") public void init(Context mContext,String printInfo) {
+ this.printinfo=printInfo;
+ this.mcontext = mContext;
+ serialDataHandler=new SerialDataHandler();
+ smollPosHandler = new MySmollPosHandler();
+ popUpDialog();
+ new Thread(new Runnable() {
+ @SuppressWarnings("deprecation")
+ @Override
+ public void run() {
+ try {
+ try {
+ if (mSerialPort == null) {
+ mSerialPort = getSerialPort();
+ }
+ if (mSerialPrinter == null) {
+ mSerialPrinter = SerialPrinter.GetSerialPrinter();
+ }
+ try {
+ mSerialPrinter.OpenPrinter(new SerialParam(115200,
+ "/dev/ttyS2", 0),serialDataHandler,SerialSmallPortTool.this);
+ } catch (Exception e) {
+ try {
+ mSerialPrinter.OpenPrinter(new SerialParam(115200,
+ "/dev/ttyS2", 0),serialDataHandler,SerialSmallPortTool.this);
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ e.printStackTrace();
+ System.out.println(e+"");
+ }
+ if (pm == null) {
+ pm = (PowerManager) mcontext
+ .getSystemService(Context.POWER_SERVICE);
+ }
+ if (lock == null) {
+ lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK,
+ TAG);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (mSerialPort != null) {
+ mOutputStream = mSerialPort.getOutputStream();
+ mInputStream = mSerialPort.getInputStream();
+ }
+ lock.acquire();
+
+ try {
+ PWMControl.PrinterEnable(1);
+ sleep(400);
+ for (int x = 0; x < printNum; x++) {
+ if(x==1&&isStatistic.equals("1")){
+ //close();
+ //return;
+ break;
+ }
+ sendSmollCharacterDemo(printinfo,x);
+ //sleep(1500);
+ }
+ mSerialPrinter.printString("printClose",1);
+ }catch(Exception e){
+ close();
+ }
+ } catch (SecurityException e) {
+ close();
+ // DisplayError(R.string.error_security);
+ } catch (InvalidParameterException e) {
+ close();
+ // DisplayError(R.string.error_configuration);
+ } catch (Exception e) {
+ close();
+ // TODO: handle exception
+ }
+ }
+ }).start();
+ }
+
+ public void sleep(int ms) {
+
+ try {
+ java.lang.Thread.sleep(ms);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void popUpDialog(){
+ try {
+ isStatistic=SharedPreferences2Obj.getInstance(mcontext).
+ setName("SelectAction").getObject("isStatistic",String.class); //非统计判断
+ if(type==null){
+ type=SharedPreferences2Obj.getInstance(mcontext).
+ setName("MachineType").getObject("type", Integer.class);
+ }
+ if(Select==0){
+ Select = SharedPreferences2Obj.getInstance(mcontext).
+ setName("SelectAction").getObject("Select",Integer.class);
+ }
+ printNum= MyApp.getInstance().getPrintNum();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ if (dialog == null) {
+ // 显示ProgressDialog
+ dialog = new ProgressDialog(mcontext);
+ dialog.setMessage("打印中...");
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.setCancelable(false);
+ if (type==DeviceType.HANDSET.getValue()) {
+ dialog.getWindow()
+ .setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+ try {
+ dialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }else{
+ dialog.setMessage("打印中...");
+ dialog.show();
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public SerialPort getSerialPort() throws SecurityException, IOException,
+ InvalidParameterException {
+ if (mSerialPort == null) {
+// SharedPreferences sp = mContext.getSharedPreferences(
+// "android_serialport_api.sample_preferences", 0);
+ String path = "/dev/ttyS2";
+ int baudrate = 115200;
+
+ if ((path.length() == 0) || (baudrate == -1)) {
+ path = "/dev/ttyS2";
+ baudrate = 115200;
+ }
+ mSerialPort = new SerialPort(new File(path), baudrate, 0);
+ }
+ return mSerialPort;
+ }
+
+ // 小pos机打印
+ private MySmollPosHandler smollPosHandler;
+
+
+ @SuppressLint("HandlerLeak")
+ private class SerialDataHandler extends Handler {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SerialPortOperaion.SERIAL_RECEIVED_DATA_MSG:
+ SerialReadData data = (SerialReadData) msg.obj;
+ StringBuilder sb = new StringBuilder();
+ for (int x = 0; x < data.size; x++)
+ sb.append(String.format("%02x", data.data[x]));
+ LogUtil.d(TAG, "data =" + sb);
+ }
+ }
+ }
+
+ @SuppressLint("HandlerLeak")
+ private class MySmollPosHandler extends Handler {
+
+
+ public MySmollPosHandler() {
+ }
+
+ public void handleMessage(Message msg) {
+ if (stop == true)
+ return;
+ switch (msg.what) {
+ case ENABLE_BUTTON:
+ close();
+ case CLOSEDismiss:
+ if(dialog!=null&&dialog.isShowing()){
+ try {
+ dialog.dismiss();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ Boolean scanBack = SharedPreferences2Obj.getInstance(mcontext).setName("config").getObject("scanBack", Boolean.class);
+ if (MyApp.getInstance().getCheckType()==0&&scanBack != null && scanBack) {
+ checkScan();
+ }
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+
+ private void checkScan() {
+ if (MyApp.getInstance().getCheckType() == 0) {
+ Integer Select = SharedPreferences2Obj
+ .getInstance(mcontext)
+ .setName("SelectAction").getObject("Select", Integer.class);
+ Intent intent = new Intent(mcontext,
+ ScanerOrderActivity.class);
+ if (Select != null) {
+ if (Select == SelectAction.Check.getValue()) {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.check_scan_code));
+ } else if (Select == SelectAction.Reprint.getValue()) {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.repriint_scan_code));
+ } else if (Select == SelectAction.Query.getValue()) {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.query_scan_code));
+ }
+ } else {
+ intent.putExtra("titleName",
+ mcontext.getString(R.string.scan_qr_code));
+ }
+ mcontext.startActivity(intent);
+ Activity activity = (Activity) mcontext;
+ activity.finish();
+ }
+ }
+
+ // 小pos机打印
+ @SuppressLint("SimpleDateFormat") private void sendSmollCharacterDemo(String arr,int x) {
+ try {
+ if(isStatistic!=null&&isStatistic.equals("1")){
+ mSerialPrinter.enlargeFontSize(2, 2);//
+ mSerialPrinter.printString(" 统计信息",x);
+ sleep(100);
+ }else{
+ mSerialPrinter.enlargeFontSize(2, 2);//
+ mSerialPrinter.printString(" 订单信息",x);
+ sleep(100);
+ // 当时重打小票的时候,多打一段字符
+ if (Select== SelectAction.Reprint.getValue()) {
+ mSerialPrinter.enlargeFontSize(1, 1);
+ mSerialPrinter.printString(" (重打小票)",x);
+ sleep(100);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ mSerialPrinter.setLineSpace(5); // 间隔
+ sleep(100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (arr == null) {
+ return;
+ }
+ // 打印信息
+ try {
+ mSerialPrinter.enlargeFontSize(1, 1);
+// for (int i = 0; i < arr.size(); i++) {
+ mSerialPrinter.printString(arr,x);
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+// }
+ if(isStatistic!=null&&isStatistic.equals("1")){
+
+ }else{
+ if(Select== SelectAction.Query.getValue()){ //打印时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ mSerialPrinter.printString("检票时间:" + df.format(new Date()),x);// new
+ // Date()为获取当前系统时间
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+ }else if (Select== SelectAction.Reprint.getValue()) {// 重打时间
+ SimpleDateFormat df = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");// 设置日期格式
+ mSerialPrinter.printString("重打时间:" + df.format(new Date()),x);// new
+ // Date()为获取当前系统时间
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+ }
+ mSerialPrinter.setLineSpace(10);
+ mSerialPrinter.sendLineFeed();
+ mSerialPrinter.printString("取票人签名:",x);
+ mSerialPrinter.setLineSpace(10);
+ sleep(100);
+ }
+
+ mSerialPrinter.sendLineFeed();
+
+ if (constant.logoMark == LogoType.CYT.getValue()) {
+ mSerialPrinter.printString("---畅游通—智慧旅游O2O平台---",x);
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+ mSerialPrinter
+ .printString("--------www.jingqu.cn---------",x);
+ sleep(100);
+ } else if (constant.logoMark == LogoType.QNE.getValue()) {
+ mSerialPrinter.printString("---欢迎使用去哪儿网O2O系统---",x);
+ mSerialPrinter.sendLineFeed();
+ sleep(100);
+ mSerialPrinter.printString("--------www.qunar.com--------",x);
+ sleep(100);
+ }
+ mSerialPrinter.sendLineFeed();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // 信息完打印的空格行数
+ try {
+ mSerialPrinter.sendLineFeed();
+ mSerialPrinter.sendLineFeed();
+ mSerialPrinter.sendLineFeed();
+ mSerialPrinter.setLineSpace(30); //
+ sleep(100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ mSerialPrinter.walkPaper(60);//
+ sleep(100);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+// smollPosHandler.sendMessage(smollPosHandler.obtainMessage(
+// ENABLE_BUTTON, 1, 0, null));
+ LogUtil.e(TAG, "print end");
+ }
+
+
+ public void close() {
+
+
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ if (mSerialPrinter != null) {
+ try {
+ mSerialPrinter.ClosePrinter();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (mSerialPort != null) {
+ try {
+ mSerialPort.close();
+ mSerialPort = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ try {
+ if (mOutputStream != null) {
+ try {
+ mOutputStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
+ } catch (IOException e) {
+ }catch (Exception e) {
+ }
+
+
+ smollPosHandler.sendMessage(smollPosHandler.obtainMessage(
+ CLOSEDismiss, 1, 0, null));
+ if (isStatistic.equals("1")){
+ sleep(3500);
+ PWMControl.PrinterEnable(0);
+ }else {
+ if (printNum==2){
+ sleep(4000);
+ PWMControl.PrinterEnable(0);
+ }else if (printNum==3){
+ sleep(6000);
+ PWMControl.PrinterEnable(0);
+ }else if (printNum==1){
+ sleep(2000);
+ PWMControl.PrinterEnable(0);
+ }
+ }
+ }
+ }).start();
+ }
+
+ @Override
+ public void closeback() {
+ close();
+ }
+}
diff --git b/src/android_serialport_pos_id_api/SerialIdCardPort.java a/src/android_serialport_pos_id_api/SerialIdCardPort.java
new file mode 100644
index 0000000..22bc706
--- /dev/null
+++ a/src/android_serialport_pos_id_api/SerialIdCardPort.java
@@ -0,0 +1,335 @@
+/*
+ *
+ * Copyright 2009 Cedric Priscal
+ *
+ * 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 android_serialport_pos_id_api;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import com.synjones.sdt.IDCard;
+
+//import android.util.Log;
+
+//SerialIDPort
+public class SerialIdCardPort{
+
+ //private static final String TAG = "SerialPort";
+
+ /*
+ * Do not remove or rename the field mFd: it is used by native method close();
+ */
+ private FileDescriptor mFd;
+ private FileInputStream mFileInputStream;
+ private FileOutputStream mFileOutputStream;
+ private final long Tresponse = 1000;
+ private IDCard idcard = new IDCard();
+ private byte[] basemsg = null;
+ public SerialIdCardPort(File device, int baudrate, int flags) throws SecurityException, IOException {
+
+ /* Check access permission */
+ if (!device.canRead() || !device.canWrite()) {
+ try {
+ /* Missing read/write permission, trying to chmod the file */
+ Process su;
+ su = Runtime.getRuntime().exec("/system/bin/su");
+ String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
+ + "exit\n";
+ su.getOutputStream().write(cmd.getBytes());
+ if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
+ throw new SecurityException();
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ throw new SecurityException();
+ }
+ }
+
+ mFd = open(device.getAbsolutePath(), baudrate, flags);
+ if (mFd == null) {
+ //Log.e(TAG, "native open returns null");
+ throw new IOException();
+ }
+
+ mFileInputStream = new FileInputStream(mFd);
+ mFileOutputStream = new FileOutputStream(mFd);
+ }
+
+ // Getters and setters
+ public FileInputStream getInputStream() {
+ return mFileInputStream;
+ }
+
+ public OutputStream getOutputStream() {
+ return mFileOutputStream;
+ }
+
+ private byte xorchk(byte[] b, int offset, int length) {
+ byte chk = 0;
+ int i;
+ for (i = 0; i < length; i++) {
+ chk ^= b[offset + i];
+ }
+ return chk;
+ }
+
+ private byte[] commandReader(byte[] cmd, long timeout) {
+ byte[] recv = new byte[7], recvl = null;
+ long TickCount;
+ int recvlen = 0;
+
+ try {
+ //Log.i("串口调试", "Enter commandReader");
+ mFileOutputStream.write(cmd);
+ TickCount = System.currentTimeMillis();
+ while (mFileInputStream.available()<7 && (System.currentTimeMillis()-TickCount)0)
+ mFileInputStream.read();
+ return null;
+ }
+ //Log.i("串口调试", "available="+mFileInputStream.available());
+ if (mFileInputStream.read(recv) != recv.length
+ || recv[0] != (byte)0xAA
+ || recv[1] != (byte)0xAA
+ || recv[2] != (byte)0xAA
+ || recv[3] != (byte)0x96
+ || recv[4] != (byte)0x69) {
+ while (mFileInputStream.available()>0)
+ mFileInputStream.read();
+ return null;
+ }
+
+ recvlen = recv[5] * 256 + recv[6];
+ //Log.i("串口调试", "bytes are availabled! recvlen="+recvlen);
+ while (mFileInputStream.available()0)
+ mFileInputStream.read();
+ return null;
+ }
+ recvl = new byte[recv.length+recvlen];
+ System.arraycopy(recv, 0, recvl, 0, recv.length);
+ if (mFileInputStream.read(recvl, recv.length, recvlen) != recvlen) {
+ while (mFileInputStream.available()>0)
+ mFileInputStream.read();
+ return null;
+ }
+
+ /*
+ if (recvlen <64) {
+ String dbgmsg = "cmd=" + Integer.toHexString(cmd[7]) + " " + Integer.toHexString(cmd[8]) + ",";
+ for (int i=0;i0)
+ mFileInputStream.read();
+
+ if (xorchk(recvl, 5, recvl.length-5)!=0)
+ return null;
+ } catch (IOException ioe) {
+ recvl = null;
+ } catch (NullPointerException npe) {
+ recvl = null;
+ } catch (InterruptedException ie) {
+ recvl = null;
+ }
+
+ return recvl;
+ }
+
+ public byte resetSAM() {
+ byte Status = 0;
+ byte[] cmd = {(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,(byte)0x69,(byte)0x00,(byte)0x03,(byte)0x10,(byte)0xFF,(byte)0xEC};
+ byte[] recvl = commandReader(cmd, Tresponse);
+ if (recvl == null)
+ Status = 1;
+ else if (recvl[7] != 0x00 || recvl[8] != 0x00 || recvl[9] != 0x90)
+ Status = 2;
+ return Status;
+ }
+
+ public byte setMaxRFByte(byte max) {
+ byte Status = 0;
+ byte[] cmd = {(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,(byte)0x69,(byte)0x00,(byte)0x04,(byte)0x61,(byte)0xFF,(byte)0x50,(byte)0xCA};
+ cmd[9] = max;
+ byte[] recvl = commandReader(cmd, Tresponse);
+ if (recvl == null)
+ Status = 1;
+ else if (recvl[7] != 0x00 || recvl[8] != 0x00 || recvl[9] != 0x90)
+ Status = 2;
+ return Status;
+ }
+
+ public byte getSAMStatus() {
+ byte Status = 0;
+ byte[] cmd = {(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,(byte)0x69,(byte)0x00,(byte)0x03,(byte)0x11,(byte)0xFF,(byte)0xED};
+ byte[] recvl = commandReader(cmd, Tresponse);
+ if (recvl == null)
+ Status = 1;
+ else if (recvl[7] != 0x00 || recvl[8] != 0x00 || recvl[9] != 0x90)
+ Status = 2;
+ return Status;
+ }
+
+ public byte getSAMID(byte[] samid) {
+ byte Status = 0;
+ byte[] cmd = {(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,(byte)0x69,(byte)0x00,(byte)0x03,(byte)0x12,(byte)0xFF,(byte)0xFE};
+ byte[] recvl = commandReader(cmd, Tresponse);
+ if (recvl == null)
+ Status = 1;
+ else if (recvl[7] != 0x00 || recvl[8] != 0x00 || recvl[9] != 0x90)
+ Status = 2;
+ else if (recvl.length < 27)
+ Status = 3;
+ else {
+ samid = new byte[16];
+ System.arraycopy(recvl, 10, samid, 0, samid.length);
+ }
+ return Status;
+ }
+
+ public byte startFindIDCard() {
+ byte Status = 0;
+ byte[] cmd = {(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,(byte)0x69,(byte)0x00,(byte)0x03,(byte)0x20,(byte)0x01,(byte)0x22};
+ byte[] recvl = commandReader(cmd, Tresponse);
+ if (recvl == null)
+ Status = 1;
+ else if (recvl[7] != 0x00 || recvl[8] != 0x00 || (recvl[9] != (byte)0x9F && recvl[9] != (byte)0x80)) {
+ Status = 2;
+ IDCard.SW1 = recvl[7];
+ IDCard.SW2 = recvl[8];
+ IDCard.SW3 = recvl[9];
+ }
+ //Log.i("串口调试", "startFindCard="+Status);
+ return Status;
+ }
+
+ public byte selectIDCard() {
+ byte Status = 0;
+ byte[] cmd = {(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,(byte)0x69,(byte)0x00,(byte)0x03,(byte)0x20,(byte)0x02,(byte)0x21};
+ byte[] recvl = commandReader(cmd, Tresponse);
+ if (recvl == null)
+ Status = 1;
+ else if (recvl[7] != 0x00 || recvl[8] != 0x00 || (recvl[9] != (byte)0x90 && recvl[9] != (byte)0x81)) {
+ Status = 2;
+ IDCard.SW1 = recvl[7];
+ IDCard.SW2 = recvl[8];
+ IDCard.SW3 = recvl[9];
+ }
+ //Log.i("串口调试", "selectIDCard="+Status);
+ return Status;
+ }
+
+ public byte readBaseMsg() {
+ byte Status = 0;
+ byte[] cmd = {(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,(byte)0x69,(byte)0x00,(byte)0x03,(byte)0x30,(byte)0x01,(byte)0x32};
+ byte[] recvl = commandReader(cmd, Tresponse*10);
+ if (recvl == null)
+ Status = 1;
+ else if (recvl[7] != 0x00 || recvl[8] != 0x00 || recvl[9] != (byte)0x90) {
+ Status = 2;
+ IDCard.SW1 = recvl[7];
+ IDCard.SW2 = recvl[8];
+ IDCard.SW3 = recvl[9];
+ }
+ else if (recvl.length < 1295)
+ Status = 3;
+ else {
+ basemsg = new byte[4+256+1024];
+ System.arraycopy(recvl, 10, basemsg, 0, basemsg.length);
+ //Log.i("串口调试", "basemsg="+basemsg.length);
+ }
+ //Log.i("串口调试", "readBaseMsg="+Status+" recvl="+(recvl==null?0:recvl.length));
+
+ return Status;
+ }
+
+ public IDCard getIDCard() {
+ short textlen, wltlen;
+ String dbgmsg = "";
+ if (startFindIDCard() == 0x00 && selectIDCard()==0x00 && readBaseMsg()==0) {
+ try {
+ textlen = (short) (basemsg[0] * 256 + basemsg[1]);
+ wltlen = (short) (basemsg[2] * 256 + basemsg[3]);
+ byte[] name = new byte[30];
+ System.arraycopy(basemsg, 4, name, 0, name.length);
+ idcard.setName(new String(name, "UTF-16LE").trim());
+ byte[] sex = new byte[2];
+ System.arraycopy(basemsg, 34, sex, 0, sex.length);
+ idcard.setSex(new String(sex, "UTF-16LE"));
+ if (idcard.getSex().equalsIgnoreCase("1"))
+ idcard.setSex("男");
+ else
+ idcard.setSex("女");
+ byte[] nation = new byte[4];
+ System.arraycopy(basemsg, 36, nation, 0, nation.length);
+ idcard.setNation(idcard.getNationName(new String(nation, "UTF-16LE")));
+ byte[] birthday = new byte[16];
+ System.arraycopy(basemsg, 40, birthday, 0, birthday.length);
+ idcard.setBirthday(new String(birthday, "UTF-16LE"));
+ byte[] address = new byte[70];
+ System.arraycopy(basemsg, 56, address, 0, address.length);
+ idcard.setAddress(new String(address, "UTF-16LE").trim());
+ byte[] idcardno = new byte[36];
+ System.arraycopy(basemsg, 126, idcardno, 0, idcardno.length);
+ idcard.setIDCardNo(new String(idcardno, "UTF-16LE"));
+ byte[] grantdept = new byte[30];
+ System.arraycopy(basemsg, 162, grantdept, 0, grantdept.length);
+ idcard.setGrantDept(new String(grantdept, "UTF-16LE").trim());
+ byte[] userlifebegin = new byte[16];
+ System.arraycopy(basemsg, 192, userlifebegin, 0, userlifebegin.length);
+ idcard.setUserLifeBegin(new String(userlifebegin, "UTF-16LE"));
+ byte[] userlifeend = new byte[16];
+ System.arraycopy(basemsg, 208, userlifeend, 0, userlifeend.length);
+ idcard.setUserLifeEnd(new String(userlifeend, "UTF-16LE").trim());
+ byte[] wlt = new byte[1024];
+ System.arraycopy(basemsg, textlen+4, wlt, 0, wlt.length);
+ idcard.setWlt(wlt);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ } else {
+ return null;
+ }
+ return idcard;
+ }
+
+ // JNI
+ private native static FileDescriptor open(String path, int baudrate, int flags);
+ public native void close();
+ public native int readCard();
+ public native int getField(int fieldId);
+
+
+ static {//serial_idcard_port
+ System.loadLibrary("serial_IdCard");
+ }
+}
diff --git b/src/antistatic/spinnerwheel/AbstractWheel.java a/src/antistatic/spinnerwheel/AbstractWheel.java
new file mode 100644
index 0000000..e66a821
--- /dev/null
+++ a/src/antistatic/spinnerwheel/AbstractWheel.java
@@ -0,0 +1,884 @@
+/*
+ * android-spinnerwheel
+ * https://github.com/ai212983/android-spinnerwheel
+ *
+ * based on
+ *
+ * Android Wheel Control.
+ * https://code.google.com/p/android-wheel/
+ *
+ * Copyright 2011 Yuri Kanivets
+ *
+ * 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 antistatic.spinnerwheel;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
+
+import com.ectrip.cyt.spinnerwheel.adapters.WheelViewAdapter;
+import com.ectrip.trips.check.R;
+
+/**
+ * Abstract spinner spinnerwheel view.
+ * This class should be subclassed.
+ *
+ * @author Yuri Kanivets
+ * @author Dimitri Fedorov
+ */
+public abstract class AbstractWheel extends View {
+
+ private static int itemID = -1;
+
+ @SuppressWarnings("unused")
+ private final String LOG_TAG = AbstractWheel.class.getName() + " #" + (++itemID);
+
+ //----------------------------------
+ // Default properties values
+ //----------------------------------
+
+ /** Default count of visible items */
+ private static final int DEF_VISIBLE_ITEMS = 4;
+ private static final boolean DEF_IS_CYCLIC = false;
+
+ //----------------------------------
+ // Class properties
+ //----------------------------------
+
+ protected int mCurrentItemIdx = 0;
+
+ // Count of visible items
+ protected int mVisibleItems;
+ // Should all items be visible
+ protected boolean mIsAllVisible;
+
+ protected boolean mIsCyclic;
+
+ // Scrolling
+ protected WheelScroller mScroller;
+ protected boolean mIsScrollingPerformed;
+ protected int mScrollingOffset;
+
+ // Items layout
+ protected LinearLayout mItemsLayout;
+
+ // The number of first item in layout
+ protected int mFirstItemIdx;
+
+ // View adapter
+ protected WheelViewAdapter mViewAdapter;
+
+ protected int mLayoutHeight;
+ protected int mLayoutWidth;
+
+ // Recycle
+ private WheelRecycler mRecycler = new WheelRecycler(this);
+
+ // Listeners
+ private List changingListeners = new LinkedList();
+ private List scrollingListeners = new LinkedList();
+ private List clickingListeners = new LinkedList();
+
+ //XXX: I don't like listeners the way as they are now. -df
+
+ // Adapter listener
+ private DataSetObserver mDataObserver;
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Create a new AbstractWheel instance
+ *
+ * @param context the application environment.
+ * @param attrs a collection of attributes.
+ * @param defStyle The default style to apply to this view.
+ */
+ public AbstractWheel(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+ initAttributes(attrs, defStyle);
+ initData(context);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Initiating data and assets at start up
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Initiates data and parameters from styles
+ *
+ * @param attrs a collection of attributes.
+ * @param defStyle The default style to apply to this view.
+ */
+ protected void initAttributes(AttributeSet attrs, int defStyle) {
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.AbstractWheelView, defStyle, 0);
+ mVisibleItems = a.getInt(R.styleable.AbstractWheelView_visibleItems, DEF_VISIBLE_ITEMS);
+ mIsAllVisible = a.getBoolean(R.styleable.AbstractWheelView_isAllVisible, false);
+ mIsCyclic = a.getBoolean(R.styleable.AbstractWheelView_isCyclic, DEF_IS_CYCLIC);
+
+ a.recycle();
+ }
+
+ /**
+ * Initiates data
+ *
+ * @param context the context
+ */
+ protected void initData(Context context) {
+
+ mDataObserver = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ invalidateItemsLayout(false);
+ }
+
+ @Override
+ public void onInvalidated() {
+ invalidateItemsLayout(true);
+ }
+ };
+
+ // creating new scroller
+ mScroller = createScroller(new WheelScroller.ScrollingListener() {
+
+ public void onStarted() {
+ mIsScrollingPerformed = true;
+ notifyScrollingListenersAboutStart();
+ onScrollStarted();
+ }
+
+ public void onTouch() {
+ onScrollTouched();
+ }
+
+ public void onTouchUp() {
+ if (!mIsScrollingPerformed)
+ onScrollTouchedUp(); // if scrolling IS performed, whe should use onFinished instead
+ }
+
+ public void onScroll(int distance) {
+ doScroll(distance);
+
+ int dimension = getBaseDimension();
+ if (mScrollingOffset > dimension) {
+ mScrollingOffset = dimension;
+ mScroller.stopScrolling();
+ } else if (mScrollingOffset < - dimension) {
+ mScrollingOffset = - dimension;
+ mScroller.stopScrolling();
+ }
+ }
+
+ public void onFinished() {
+ if (mIsScrollingPerformed) {
+ notifyScrollingListenersAboutEnd();
+ mIsScrollingPerformed = false;
+ onScrollFinished();
+ }
+
+ mScrollingOffset = 0;
+ invalidate();
+ }
+
+ public void onJustify() {
+ if (Math.abs(mScrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) {
+ mScroller.scroll(mScrollingOffset, 0);
+ }
+ }
+ });
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ //begin boilerplate code that allows parent classes to save state
+ Parcelable superState = super.onSaveInstanceState();
+ SavedState ss = new SavedState(superState);
+ //end
+
+ ss.currentItem = this.getCurrentItem();
+
+ return ss;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ //begin boilerplate code so parent classes can restore state
+ if(!(state instanceof SavedState)) {
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ final SavedState ss = (SavedState)state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ //end
+
+ mCurrentItemIdx = ss.currentItem;
+
+ // dirty hack to re-draw child items correctly
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ invalidateItemsLayout(false);
+ }
+ }, 100);
+ }
+
+ static class SavedState extends BaseSavedState {
+ int currentItem;
+
+ SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ this.currentItem = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ out.writeInt(this.currentItem);
+ }
+
+ //required field that makes Parcelables from a Parcel
+ public static final Parcelable.Creator CREATOR =
+ new Parcelable.Creator() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+ abstract protected void recreateAssets(int width, int height);
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Scroller operations
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates scroller appropriate for specific wheel implementation.
+ *
+ * @param scrollingListener listener to be passed to the scroller
+ * @return Initialized scroller to be used
+ */
+ abstract protected WheelScroller createScroller(WheelScroller.ScrollingListener scrollingListener);
+
+ /* These methods are not abstract, as we may want to override only some of them */
+ protected void onScrollStarted() {}
+ protected void onScrollTouched() {}
+ protected void onScrollTouchedUp() {}
+ protected void onScrollFinished() {}
+
+ /**
+ * Stops scrolling
+ */
+ public void stopScrolling() {
+ mScroller.stopScrolling();
+ }
+
+ /**
+ * Set the the specified scrolling interpolator
+ * @param interpolator the interpolator
+ */
+ public void setInterpolator(Interpolator interpolator) {
+ mScroller.setInterpolator(interpolator);
+ }
+
+ /**
+ * Scroll the spinnerwheel
+ * @param itemsToScroll items to scroll
+ * @param time scrolling duration
+ */
+ public void scroll(int itemsToScroll, int time) {
+ int distance = itemsToScroll * getItemDimension() - mScrollingOffset;
+ onScrollTouched(); // we have to emulate touch when scrolling spinnerwheel programmatically to light up stuff
+ mScroller.scroll(distance, time);
+ }
+
+ /**
+ * Scrolls the spinnerwheel
+ * @param delta the scrolling value
+ */
+ private void doScroll(int delta) {
+ mScrollingOffset += delta;
+
+ int itemDimension = getItemDimension();
+ int count = mScrollingOffset / itemDimension;
+
+ int pos = mCurrentItemIdx - count;
+ int itemCount = mViewAdapter.getItemsCount();
+
+ int fixPos = mScrollingOffset % itemDimension;
+ if (Math.abs(fixPos) <= itemDimension / 2) {
+ fixPos = 0;
+ }
+ if (mIsCyclic && itemCount > 0) {
+ if (fixPos > 0) {
+ pos--;
+ count++;
+ } else if (fixPos < 0) {
+ pos++;
+ count--;
+ }
+ // fix position by rotating
+ while (pos < 0) {
+ pos += itemCount;
+ }
+ pos %= itemCount;
+ } else {
+ if (pos < 0) {
+ count = mCurrentItemIdx;
+ pos = 0;
+ } else if (pos >= itemCount) {
+ count = mCurrentItemIdx - itemCount + 1;
+ pos = itemCount - 1;
+ } else if (pos > 0 && fixPos > 0) {
+ pos--;
+ count++;
+ } else if (pos < itemCount - 1 && fixPos < 0) {
+ pos++;
+ count--;
+ }
+ }
+
+ int offset = mScrollingOffset;
+ if (pos != mCurrentItemIdx) {
+ setCurrentItem(pos, false);
+ } else {
+ invalidate();
+ }
+
+ // update offset
+ int baseDimension = getBaseDimension();
+ mScrollingOffset = offset - count * itemDimension;
+ if (mScrollingOffset > baseDimension) {
+ mScrollingOffset = mScrollingOffset % baseDimension + baseDimension;
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Base measurements
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns base dimension of the spinnerwheel 鈥� width for horizontal spinnerwheel, height for vertical
+ *
+ * @return width or height of the spinnerwheel
+ */
+ abstract protected int getBaseDimension();
+
+ /**
+ * Returns base dimension of base item 鈥� width for horizontal spinnerwheel, height for vertical
+ *
+ * @return width or height of base item
+ */
+ abstract protected int getItemDimension();
+
+ /**
+ * Processes MotionEvent and returns relevant position 鈥� x for horizontal spinnerwheel, y for vertical
+ *
+ * @param event MotionEvent to be processed
+ * @return relevant position of the MotionEvent
+ */
+ abstract protected float getMotionEventPosition(MotionEvent event);
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Layout creation and measurement operations
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates item layouts if necessary
+ */
+ abstract protected void createItemsLayout();
+
+ /**
+ * Sets layout width and height
+ */
+ abstract protected void doItemsLayout();
+
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ if (changed) {
+ int w = r - l;
+ int h = b - t;
+ doItemsLayout();
+ if (mLayoutWidth != w || mLayoutHeight != h) {
+ recreateAssets(getMeasuredWidth(), getMeasuredHeight());
+ }
+ mLayoutWidth = w;
+ mLayoutHeight = h;
+ }
+ }
+
+ /**
+ * Invalidates items layout
+ *
+ * @param clearCaches if true then cached views will be cleared
+ */
+ public void invalidateItemsLayout(boolean clearCaches) {
+ if (clearCaches) {
+ mRecycler.clearAll();
+ if (mItemsLayout != null) {
+ mItemsLayout.removeAllViews();
+ }
+ mScrollingOffset = 0;
+ } else if (mItemsLayout != null) {
+ // cache all items
+ mRecycler.recycleItems(mItemsLayout, mFirstItemIdx, new ItemsRange());
+ }
+ invalidate();
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Getters and setters
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Gets count of visible items
+ *
+ * @return the count of visible items
+ */
+ public int getVisibleItems() {
+ return mVisibleItems;
+ }
+
+ /**
+ * Sets the desired count of visible items.
+ * Actual amount of visible items depends on spinnerwheel layout parameters.
+ * To apply changes and rebuild view call measure().
+ *
+ * @param count the desired count for visible items
+ */
+ public void setVisibleItems(int count) {
+ mVisibleItems = count;
+ }
+
+ /**
+ * Sets all items to have no dim and makes them visible
+ * @param isAllVisible
+ */
+ public void setAllItemsVisible(boolean isAllVisible){
+ mIsAllVisible = isAllVisible;
+ invalidateItemsLayout(false);
+ }
+
+ /**
+ * Gets view adapter
+ * @return the view adapter
+ */
+ public WheelViewAdapter getViewAdapter() {
+ return mViewAdapter;
+ }
+
+
+ /**
+ * Sets view adapter. Usually new adapters contain different views, so
+ * it needs to rebuild view by calling measure().
+ *
+ * @param viewAdapter the view adapter
+ */
+ public void setViewAdapter(WheelViewAdapter viewAdapter) {
+ if (this.mViewAdapter != null) {
+ this.mViewAdapter.unregisterDataSetObserver(mDataObserver);
+ }
+ this.mViewAdapter = viewAdapter;
+ if (this.mViewAdapter != null) {
+ this.mViewAdapter.registerDataSetObserver(mDataObserver);
+ }
+ invalidateItemsLayout(true);
+ }
+
+ /**
+ * Gets current value
+ *
+ * @return the current value
+ */
+ public int getCurrentItem() {
+ return mCurrentItemIdx;
+ }
+
+ /**
+ * Sets the current item. Does nothing when index is wrong.
+ *
+ * @param index the item index
+ * @param animated the animation flag
+ */
+ public void setCurrentItem(int index, boolean animated) {
+ if (mViewAdapter == null || mViewAdapter.getItemsCount() == 0) {
+ return; // throw?
+ }
+
+ int itemCount = mViewAdapter.getItemsCount();
+ if (index < 0 || index >= itemCount) {
+ if (mIsCyclic) {
+ while (index < 0) {
+ index += itemCount;
+ }
+ index %= itemCount;
+ } else{
+ return; // throw?
+ }
+ }
+ if (index != mCurrentItemIdx) {
+ if (animated) {
+ int itemsToScroll = index - mCurrentItemIdx;
+ if (mIsCyclic) {
+ int scroll = itemCount + Math.min(index, mCurrentItemIdx) - Math.max(index, mCurrentItemIdx);
+ if (scroll < Math.abs(itemsToScroll)) {
+ itemsToScroll = itemsToScroll < 0 ? scroll : -scroll;
+ }
+ }
+ scroll(itemsToScroll, 0);
+ } else {
+ mScrollingOffset = 0;
+ final int old = mCurrentItemIdx;
+ mCurrentItemIdx = index;
+ notifyChangingListeners(old, mCurrentItemIdx);
+ invalidate();
+ }
+ }
+ }
+
+ /**
+ * Sets the current item w/o animation. Does nothing when index is wrong.
+ *
+ * @param index the item index
+ */
+ public void setCurrentItem(int index) {
+ setCurrentItem(index, false);
+ }
+
+ /**
+ * Tests if spinnerwheel is cyclic. That means before the 1st item there is shown the last one
+ * @return true if spinnerwheel is cyclic
+ */
+ public boolean isCyclic() {
+ return mIsCyclic;
+ }
+
+ /**
+ * Set spinnerwheel cyclic flag
+ * @param isCyclic the flag to set
+ */
+ public void setCyclic(boolean isCyclic) {
+ this.mIsCyclic = isCyclic;
+ invalidateItemsLayout(false);
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Listener operations
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Adds spinnerwheel changing listener
+ * @param listener the listener
+ */
+ public void addChangingListener(OnWheelChangedListener listener) {
+ changingListeners.add(listener);
+ }
+
+ /**
+ * Removes spinnerwheel changing listener
+ * @param listener the listener
+ */
+ public void removeChangingListener(OnWheelChangedListener listener) {
+ changingListeners.remove(listener);
+ }
+
+ /**
+ * Notifies changing listeners
+ * @param oldValue the old spinnerwheel value
+ * @param newValue the new spinnerwheel value
+ */
+ protected void notifyChangingListeners(int oldValue, int newValue) {
+ for (OnWheelChangedListener listener : changingListeners) {
+ listener.onChanged(this, oldValue, newValue);
+ }
+ }
+
+ /**
+ * Adds spinnerwheel scrolling listener
+ * @param listener the listener
+ */
+ public void addScrollingListener(OnWheelScrollListener listener) {
+ scrollingListeners.add(listener);
+ }
+
+ /**
+ * Removes spinnerwheel scrolling listener
+ * @param listener the listener
+ */
+ public void removeScrollingListener(OnWheelScrollListener listener) {
+ scrollingListeners.remove(listener);
+ }
+
+ /**
+ * Notifies listeners about starting scrolling
+ */
+ protected void notifyScrollingListenersAboutStart() {
+ for (OnWheelScrollListener listener : scrollingListeners) {
+ listener.onScrollingStarted(this);
+ }
+ }
+
+ /**
+ * Notifies listeners about ending scrolling
+ */
+ protected void notifyScrollingListenersAboutEnd() {
+ for (OnWheelScrollListener listener : scrollingListeners) {
+ listener.onScrollingFinished(this);
+ }
+ }
+
+ /**
+ * Adds spinnerwheel clicking listener
+ * @param listener the listener
+ */
+ public void addClickingListener(OnWheelClickedListener listener) {
+ clickingListeners.add(listener);
+ }
+
+ /**
+ * Removes spinnerwheel clicking listener
+ * @param listener the listener
+ */
+ public void removeClickingListener(OnWheelClickedListener listener) {
+ clickingListeners.remove(listener);
+ }
+
+ /**
+ * Notifies listeners about clicking
+ * @param item clicked item
+ */
+ protected void notifyClickListenersAboutClick(int item) {
+ for (OnWheelClickedListener listener : clickingListeners) {
+ listener.onItemClicked(this, item);
+ }
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Rebuilding items
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Rebuilds spinnerwheel items if necessary. Caches all unused items.
+ *
+ * @return true if items are rebuilt
+ */
+ protected boolean rebuildItems() {
+ boolean updated;
+ ItemsRange range = getItemsRange();
+
+ if (mItemsLayout != null) {
+ int first = mRecycler.recycleItems(mItemsLayout, mFirstItemIdx, range);
+ updated = mFirstItemIdx != first;
+ mFirstItemIdx = first;
+ } else {
+ createItemsLayout();
+ updated = true;
+ }
+
+ if (!updated) {
+ updated = mFirstItemIdx != range.getFirst() || mItemsLayout.getChildCount() != range.getCount();
+ }
+
+ if (mFirstItemIdx > range.getFirst() && mFirstItemIdx <= range.getLast()) {
+ for (int i = mFirstItemIdx - 1; i >= range.getFirst(); i--) {
+ if (!addItemView(i, true)) {
+ break;
+ }
+ mFirstItemIdx = i;
+ }
+ } else {
+ mFirstItemIdx = range.getFirst();
+ }
+
+ int first = mFirstItemIdx;
+ for (int i = mItemsLayout.getChildCount(); i < range.getCount(); i++) {
+ if (!addItemView(mFirstItemIdx + i, false) && mItemsLayout.getChildCount() == 0) {
+ first++;
+ }
+ }
+ mFirstItemIdx = first;
+
+ return updated;
+ }
+
+ //----------------------------------
+ // ItemsRange operations
+ //----------------------------------
+
+ /**
+ * Calculates range for spinnerwheel items
+ * @return the items range
+ */
+ private ItemsRange getItemsRange() {
+ if (mIsAllVisible) {
+ int baseDimension = getBaseDimension();
+ int itemDimension = getItemDimension();
+ if (itemDimension != 0)
+ mVisibleItems = baseDimension / itemDimension + 1;
+ }
+
+ int start = mCurrentItemIdx - mVisibleItems / 2;
+ int end = start + mVisibleItems - (mVisibleItems % 2 == 0 ? 0 : 1);
+ if (mScrollingOffset != 0) {
+ if (mScrollingOffset > 0) {
+ start--;
+ } else {
+ end++;
+ }
+ }
+ if (!isCyclic()) {
+ if (start < 0)
+ start = 0;
+ if (end > mViewAdapter.getItemsCount())
+ end = mViewAdapter.getItemsCount();
+ }
+ return new ItemsRange(start, end - start + 1);
+ }
+
+ /**
+ * Checks whether item index is valid
+ * @param index the item index
+ * @return true if item index is not out of bounds or the spinnerwheel is cyclic
+ */
+ protected boolean isValidItemIndex(int index) {
+ return (mViewAdapter != null) && (mViewAdapter.getItemsCount() > 0) &&
+ (mIsCyclic || (index >= 0 && index < mViewAdapter.getItemsCount()));
+ }
+
+ //----------------------------------
+ // Operations with item view
+ //----------------------------------
+
+ /**
+ * Adds view for item to items layout
+ * @param index the item index
+ * @param first the flag indicates if view should be first
+ * @return true if corresponding item exists and is added
+ */
+ private boolean addItemView(int index, boolean first) {
+ View view = getItemView(index);
+ if (view != null) {
+ if (first) {
+ mItemsLayout.addView(view, 0);
+ } else {
+ mItemsLayout.addView(view);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns view for specified item
+ * @param index the item index
+ * @return item view or empty view if index is out of bounds
+ */
+ private View getItemView(int index) {
+ if (mViewAdapter == null || mViewAdapter.getItemsCount() == 0) {
+ return null;
+ }
+ int count = mViewAdapter.getItemsCount();
+ if (!isValidItemIndex(index)) {
+ return mViewAdapter.getEmptyItem( mRecycler.getEmptyItem(), mItemsLayout);
+ } else {
+ while (index < 0) {
+ index = count + index;
+ }
+ }
+ index %= count;
+ return mViewAdapter.getItem(index, mRecycler.getItem(), mItemsLayout);
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Intercepting and processing touch event
+ //
+ //--------------------------------------------------------------------------
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (!isEnabled() || getViewAdapter() == null) {
+ return true;
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ if (getParent() != null) {
+ getParent().requestDisallowInterceptTouchEvent(true);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ if (!mIsScrollingPerformed) {
+ int distance = (int) getMotionEventPosition(event) - getBaseDimension() / 2;
+ if (distance > 0) {
+ distance += getItemDimension() / 2;
+ } else {
+ distance -= getItemDimension() / 2;
+ }
+ int items = distance / getItemDimension();
+ if (items != 0 && isValidItemIndex(mCurrentItemIdx + items)) {
+ notifyClickListenersAboutClick(mCurrentItemIdx + items);
+ }
+ }
+ break;
+ }
+ return mScroller.onTouchEvent(event);
+ }
+
+}
diff --git b/src/antistatic/spinnerwheel/AbstractWheelView.java a/src/antistatic/spinnerwheel/AbstractWheelView.java
new file mode 100644
index 0000000..e4b4b9e
--- /dev/null
+++ a/src/antistatic/spinnerwheel/AbstractWheelView.java
@@ -0,0 +1,305 @@
+/*
+ * android-spinnerwheel
+ * https://github.com/ai212983/android-spinnerwheel
+ *
+ * based on
+ *
+ * Android Wheel Control.
+ * https://code.google.com/p/android-wheel/
+ *
+ * Copyright 2011 Yuri Kanivets
+ *
+ * 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 antistatic.spinnerwheel;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+
+import com.ectrip.trips.check.R;
+
+
+/**
+ * Abstract spinner spinnerwheel view.
+ * This class should be subclassed.
+ *
+ * @author Yuri Kanivets
+ * @author Dimitri Fedorov
+ */
+public abstract class AbstractWheelView extends AbstractWheel {
+
+ private static int itemID = -1;
+
+ @SuppressWarnings("unused")
+ private final String LOG_TAG = AbstractWheelView.class.getName() + " #" + (++itemID);
+
+ //----------------------------------
+ // Default properties values
+ //----------------------------------
+
+ protected static final int DEF_ITEMS_DIMMED_ALPHA = 50; // 60 in ICS
+
+ protected static final int DEF_SELECTION_DIVIDER_ACTIVE_ALPHA = 70;
+
+ protected static final int DEF_SELECTION_DIVIDER_DIMMED_ALPHA = 70;
+
+ protected static final int DEF_ITEM_OFFSET_PERCENT = 10;
+
+ protected static final int DEF_ITEM_PADDING = 10;
+
+ protected static final int DEF_SELECTION_DIVIDER_SIZE = 2;
+
+ //----------------------------------
+ // Class properties
+ //----------------------------------
+
+ // configurable properties
+
+ /** The alpha of the selector spinnerwheel when it is dimmed. */
+ protected int mItemsDimmedAlpha;
+
+ /** The alpha of separators spinnerwheel when they are shown. */
+ protected int mSelectionDividerActiveAlpha;
+
+ /** The alpha of separators when they are is dimmed. */
+ protected int mSelectionDividerDimmedAlpha;
+
+ /** Top and bottom items offset */
+ protected int mItemOffsetPercent;
+
+ /** Left and right padding value */
+ protected int mItemsPadding;
+
+ /** Divider for showing item to be selected while scrolling */
+ protected Drawable mSelectionDivider;
+
+ // the rest
+
+ /**
+ * The {@link android.graphics.Paint} for drawing the selector.
+ */
+ protected Paint mSelectorWheelPaint;
+
+ /**
+ * The {@link android.graphics.Paint} for drawing the separators.
+ */
+ protected Paint mSeparatorsPaint;
+
+ /**
+ * {@link com.nineoldandroids.animation.Animator} for dimming the selector spinnerwheel.
+ */
+ protected Animator mDimSelectorWheelAnimator;
+
+ /**
+ * {@link com.nineoldandroids.animation.Animator} for dimming the selector spinnerwheel.
+ */
+ protected Animator mDimSeparatorsAnimator;
+
+ /**
+ * The property for setting the selector paint.
+ */
+ protected static final String PROPERTY_SELECTOR_PAINT_COEFF = "selectorPaintCoeff";
+
+ /**
+ * The property for setting the separators paint.
+ */
+ protected static final String PROPERTY_SEPARATORS_PAINT_ALPHA = "separatorsPaintAlpha";
+
+
+ protected Bitmap mSpinBitmap;
+ protected Bitmap mSeparatorsBitmap;
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ public AbstractWheelView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Initiating assets and setters for paints
+ //
+ //--------------------------------------------------------------------------
+
+ @Override
+ protected void initAttributes(AttributeSet attrs, int defStyle) {
+ super.initAttributes(attrs, defStyle);
+
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.AbstractWheelView, defStyle, 0);
+ mItemsDimmedAlpha = a.getInt(R.styleable.AbstractWheelView_itemsDimmedAlpha, DEF_ITEMS_DIMMED_ALPHA);
+ mSelectionDividerActiveAlpha = a.getInt(R.styleable.AbstractWheelView_selectionDividerActiveAlpha, DEF_SELECTION_DIVIDER_ACTIVE_ALPHA);
+ mSelectionDividerDimmedAlpha = a.getInt(R.styleable.AbstractWheelView_selectionDividerDimmedAlpha, DEF_SELECTION_DIVIDER_DIMMED_ALPHA);
+ mItemOffsetPercent = a.getInt(R.styleable.AbstractWheelView_itemOffsetPercent, DEF_ITEM_OFFSET_PERCENT);
+ mItemsPadding = a.getDimensionPixelSize(R.styleable.AbstractWheelView_itemsPadding, DEF_ITEM_PADDING);
+ mSelectionDivider = a.getDrawable(R.styleable.AbstractWheelView_selectionDivider);
+ a.recycle();
+ }
+
+ @Override
+ protected void initData(Context context) {
+ super.initData(context);
+
+ // creating animators
+ mDimSelectorWheelAnimator = ObjectAnimator.ofFloat(this, PROPERTY_SELECTOR_PAINT_COEFF, 1, 0);
+
+ mDimSeparatorsAnimator = ObjectAnimator.ofInt(this, PROPERTY_SEPARATORS_PAINT_ALPHA,
+ mSelectionDividerActiveAlpha, mSelectionDividerDimmedAlpha
+ );
+
+ // creating paints
+ mSeparatorsPaint = new Paint();
+ mSeparatorsPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
+ mSeparatorsPaint.setAlpha(mSelectionDividerDimmedAlpha);
+
+ mSelectorWheelPaint = new Paint();
+ mSelectorWheelPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
+ }
+
+ /**
+ * Recreates assets (like bitmaps) when layout size has been changed
+ *
+ * @param width New spinnerwheel width
+ * @param height New spinnerwheel height
+ */
+ @Override
+ protected void recreateAssets(int width, int height) {
+ mSpinBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ mSeparatorsBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ setSelectorPaintCoeff(0);
+ }
+
+ /**
+ * Sets the alpha of the {@link Paint} for drawing separators
+ * spinnerwheel.
+ * @param alpha alpha value from 0 to 255
+ */
+ @SuppressWarnings("unused") // Called via reflection
+ public void setSeparatorsPaintAlpha(int alpha) {
+ mSeparatorsPaint.setAlpha(alpha);
+ invalidate();
+ }
+
+ /**
+ * Sets the coeff of the {@link Paint} for drawing
+ * the selector spinnerwheel.
+ *
+ * @param coeff Coefficient from 0 (selector is passive) to 1 (selector is active)
+ */
+ abstract public void setSelectorPaintCoeff(float coeff);
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Processing scroller events
+ //
+ //--------------------------------------------------------------------------
+
+ @Override
+ protected void onScrollTouched() {
+ mDimSelectorWheelAnimator.cancel();
+ mDimSeparatorsAnimator.cancel();
+ setSelectorPaintCoeff(1);
+ setSeparatorsPaintAlpha(mSelectionDividerActiveAlpha);
+ }
+
+ @Override
+ protected void onScrollTouchedUp() {
+ super.onScrollTouchedUp();
+ fadeSelectorWheel(750);
+ lightSeparators(750);
+ }
+
+ @Override
+ protected void onScrollFinished() {
+ fadeSelectorWheel(500);
+ lightSeparators(500);
+ }
+
+ //----------------------------------
+ // Animating components
+ //----------------------------------
+
+ /**
+ * Fade the selector spinnerwheel via an animation.
+ *
+ * @param animationDuration The duration of the animation.
+ */
+ private void fadeSelectorWheel(long animationDuration) {
+ mDimSelectorWheelAnimator.setDuration(animationDuration);
+ mDimSelectorWheelAnimator.start();
+ }
+
+ /**
+ * Fade the selector spinnerwheel via an animation.
+ *
+ * @param animationDuration The duration of the animation.
+ */
+ private void lightSeparators(long animationDuration) {
+ mDimSeparatorsAnimator.setDuration(animationDuration);
+ mDimSeparatorsAnimator.start();
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Layout measuring
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Perform layout measurements
+ */
+ abstract protected void measureLayout();
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Drawing stuff
+ //
+ //--------------------------------------------------------------------------
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mViewAdapter != null && mViewAdapter.getItemsCount() > 0) {
+ if (rebuildItems()) {
+ measureLayout();
+ }
+ doItemsLayout();
+ drawItems(canvas);
+ }
+ }
+
+ /**
+ * Draws items on specified canvas
+ *
+ * @param canvas the canvas for drawing
+ */
+ abstract protected void drawItems(Canvas canvas);
+}
diff --git b/src/antistatic/spinnerwheel/ItemsRange.java a/src/antistatic/spinnerwheel/ItemsRange.java
new file mode 100644
index 0000000..2d48a1e
--- /dev/null
+++ a/src/antistatic/spinnerwheel/ItemsRange.java
@@ -0,0 +1,86 @@
+/*
+ * android-spinnerwheel
+ * https://github.com/ai212983/android-spinnerwheel
+ *
+ * based on
+ *
+ * Android Wheel Control.
+ * https://code.google.com/p/android-wheel/
+ *
+ * Copyright 2011 Yuri Kanivets
+ *
+ * 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 antistatic.spinnerwheel;
+
+ /**
+ * Range for visible items.
+ */
+ public class ItemsRange {
+ // First item number
+ private int first;
+
+ // Items count
+ private int count;
+
+ /**
+ * Default constructor. Creates an empty range
+ */
+ public ItemsRange() {
+ this(0, 0);
+ }
+
+ /**
+ * Constructor
+ * @param first the number of first item
+ * @param count the count of items
+ */
+ public ItemsRange(int first, int count) {
+ this.first = first;
+ this.count = count;
+ }
+
+ /**
+ * Gets number of first item
+ * @return the number of the first item
+ */
+ public int getFirst() {
+ return first;
+ }
+
+ /**
+ * Gets number of last item
+ * @return the number of last item
+ */
+ public int getLast() {
+ return getFirst() + getCount() - 1;
+ }
+
+ /**
+ * Get items count
+ * @return the count of items
+ */
+ public int getCount() {
+ return count;
+ }
+
+ /**
+ * Tests whether item is contained by range
+ * @param index the item number
+ * @return true if item is contained
+ */
+ public boolean contains(int index) {
+ return index >= getFirst() && index <= getLast();
+ }
+}
\ No newline at end of file
diff --git b/src/antistatic/spinnerwheel/OnWheelChangedListener.java a/src/antistatic/spinnerwheel/OnWheelChangedListener.java
new file mode 100644
index 0000000..cb8cd8b
--- /dev/null
+++ a/src/antistatic/spinnerwheel/OnWheelChangedListener.java
@@ -0,0 +1,41 @@
+/*
+ * android-spinnerwheel
+ * https://github.com/ai212983/android-spinnerwheel
+ *
+ * based on
+ *
+ * Android Wheel Control.
+ * https://code.google.com/p/android-wheel/
+ *
+ * Copyright 2011 Yuri Kanivets
+ *
+ * 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 antistatic.spinnerwheel;
+
+/**
+ * Wheel changed listener interface.
+ *
The onChanged() method is called whenever current spinnerwheel positions is changed:
+ *
New Wheel position is set
+ *
Wheel view is scrolled
+ */
+public interface OnWheelChangedListener {
+ /**
+ * Callback method to be invoked when current item changed
+ * @param wheel the spinnerwheel view whose state has changed
+ * @param oldValue the old value of current item
+ * @param newValue the new value of current item
+ */
+ void onChanged(AbstractWheel wheel, int oldValue, int newValue);
+}
diff --git b/src/antistatic/spinnerwheel/OnWheelClickedListener.java a/src/antistatic/spinnerwheel/OnWheelClickedListener.java
new file mode 100644
index 0000000..d7e5479
--- /dev/null
+++ a/src/antistatic/spinnerwheel/OnWheelClickedListener.java
@@ -0,0 +1,40 @@
+/*
+ * android-spinnerwheel
+ * https://github.com/ai212983/android-spinnerwheel
+ *
+ * based on
+ *
+ * Android Wheel Control.
+ * https://code.google.com/p/android-wheel/
+ *
+ * Copyright 2011 Yuri Kanivets
+ *
+ * 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 antistatic.spinnerwheel;
+
+/**
+ * Wheel clicked listener interface.
+ *
The onItemClicked() method is called whenever a spinnerwheel item is clicked
+ *