ソースを参照

1.完成Apex Drivers首页。
2.完成Apex Drivers Order Detail。
3.完成Apex Drivers Order Edit。

Pen Li 7 年 前
コミット
4c2045e9f6
83 ファイル変更8572 行追加38 行削除
  1. 26 10
      ApexDrivers/RAUtilsLibrary/RAUtilsLibrary.iml
  2. 2 1
      ApexDrivers/RAUtilsLibrary/build.gradle
  3. 28 7
      ApexDrivers/app/app.iml
  4. 3 3
      ApexDrivers/app/build.gradle
  5. BIN
      ApexDrivers/app/libs/core-2.3.0.jar
  6. 15 4
      ApexDrivers/app/src/main/AndroidManifest.xml
  7. 71 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/ApexDriverApplication.java
  8. 87 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/AmbientLightManager.java
  9. 131 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/BeepManager.java
  10. 888 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/CaptureActivity.java
  11. 170 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/CaptureActivityHandler.java
  12. 102 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeFormatManager.java
  13. 122 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeHandler.java
  14. 236 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeHintManager.java
  15. 105 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeThread.java
  16. 49 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/FinishListener.java
  17. 116 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/InactivityTimer.java
  18. 261 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/Intents.java
  19. 35 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/ViewfinderResultPointCallback.java
  20. 189 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/ViewfinderView.java
  21. 402 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/DetailActivity.java
  22. 386 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/DetailAdapter.java
  23. 93 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/DetailSectionModel.java
  24. 78 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailActionModel.java
  25. 9 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailActionSelectionModel.java
  26. 14 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailBaseModel.java
  27. 8 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailLocationModel.java
  28. 6 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailMultipleLineModel.java
  29. 8 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailSingleLineModel.java
  30. 56 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailSubActionModel.java
  31. 477 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Home/HomeFragment.java
  32. 355 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Login/LoginFragment.java
  33. 419 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Login/RetrievePasswordActivity.java
  34. 41 9
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/MainActivity.java
  35. 228 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Network/Network.java
  36. 14 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateBaseModel.java
  37. 8 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateInputModel.java
  38. 7 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateLabelModel.java
  39. 7 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateMultInputModel.java
  40. 13 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdatePhotoModel.java
  41. 213 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/UpdateActivity.java
  42. 327 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/UpdateAdapter.java
  43. 88 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/UpdateSectionModel.java
  44. 112 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/AutoFocusManager.java
  45. 306 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/CameraConfigurationManager.java
  46. 312 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/CameraManager.java
  47. 43 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/FrontLightMode.java
  48. 56 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/PreferencesActivity.java
  49. 73 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/PreferencesFragment.java
  50. 56 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/PreviewCallback.java
  51. 62 0
      ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/open/OpenCameraInterface.java
  52. 28 0
      ApexDrivers/app/src/main/res/drawable-v24/btn_bg.xml
  53. 24 0
      ApexDrivers/app/src/main/res/layout/actionbar_customtitle.xml
  54. 16 0
      ApexDrivers/app/src/main/res/layout/activity_detail.xml
  55. 4 4
      ApexDrivers/app/src/main/res/layout/activity_main.xml
  56. 96 0
      ApexDrivers/app/src/main/res/layout/activity_retrieve_password.xml
  57. 16 0
      ApexDrivers/app/src/main/res/layout/activity_update.xml
  58. 215 0
      ApexDrivers/app/src/main/res/layout/capture.xml
  59. 9 0
      ApexDrivers/app/src/main/res/layout/detail_action_cell.xml
  60. 56 0
      ApexDrivers/app/src/main/res/layout/detail_location_cell.xml
  61. 15 0
      ApexDrivers/app/src/main/res/layout/detail_mult_line_cell.xml
  62. 29 0
      ApexDrivers/app/src/main/res/layout/detail_single_line_cell.xml
  63. 17 0
      ApexDrivers/app/src/main/res/layout/fragment_home.xml
  64. 127 0
      ApexDrivers/app/src/main/res/layout/fragment_login.xml
  65. 103 0
      ApexDrivers/app/src/main/res/layout/home_order_cell.xml
  66. 18 0
      ApexDrivers/app/src/main/res/layout/pop_cell.xml
  67. 15 0
      ApexDrivers/app/src/main/res/layout/pop_list_view.xml
  68. 32 0
      ApexDrivers/app/src/main/res/layout/section_header.xml
  69. 30 0
      ApexDrivers/app/src/main/res/layout/update_label_cell.xml
  70. 29 0
      ApexDrivers/app/src/main/res/layout/update_multinput_cell.xml
  71. 27 0
      ApexDrivers/app/src/main/res/layout/update_photo_cell.xml
  72. 48 0
      ApexDrivers/app/src/main/res/layout/update_scanner_input_cell.xml
  73. BIN
      ApexDrivers/app/src/main/res/raw/beep.ogg
  74. 239 0
      ApexDrivers/app/src/main/res/raw/fake_order_detail.json
  75. 92 0
      ApexDrivers/app/src/main/res/raw/fake_order_edit.json
  76. 95 0
      ApexDrivers/app/src/main/res/raw/fake_order_list.json
  77. 47 0
      ApexDrivers/app/src/main/res/values/arrays.xml
  78. 15 0
      ApexDrivers/app/src/main/res/values/colors.xml
  79. 3 0
      ApexDrivers/app/src/main/res/values/dimens.xml
  80. 25 0
      ApexDrivers/app/src/main/res/values/ids.xml
  81. 64 0
      ApexDrivers/app/src/main/res/values/strings.xml
  82. 15 0
      ApexDrivers/app/src/main/res/values/styles.xml
  83. 110 0
      ApexDrivers/app/src/main/res/xml/preferences.xml

+ 26 - 10
ApexDrivers/RAUtilsLibrary/RAUtilsLibrary.iml

@@ -71,13 +71,6 @@
       <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
@@ -85,23 +78,46 @@
       <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/attr" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/intermediate-jars" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged-aidl" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/packagedAssets" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged_res" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/public_res" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
       <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
       <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
     </content>
     <orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="Gradle: __local_aars__:/Users/ray/Documents/code_ERPSuiteAndroid/ApexDrivers/RAUtilsLibrary/libs/core-2.3.0.jar:unspecified@jar" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:runner-1.0.2" level="project" />
+    <orderEntry type="library" name="Gradle: __local_aars__:/Users/macmini1/android project/ApexDrivers/RAUtilsLibrary/libs/bcprov-jdk15on-157.jar:unspecified@jar" level="project" />
     <orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.0@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-27.1.1" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-compat-27.1.1" level="project" />
     <orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel-1.1.0" level="project" />
+    <orderEntry type="library" name="Gradle: __local_aars__:/Users/macmini1/android project/ApexDrivers/RAUtilsLibrary/libs/httpmime-4.1.1.jar:unspecified@jar" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-27.1.1" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-core-ui-27.1.1" level="project" />
-    <orderEntry type="library" name="Gradle: __local_aars__:/Users/ray/Documents/code_ERPSuiteAndroid/ApexDrivers/RAUtilsLibrary/libs/bcprov-jdk15on-157.jar:unspecified@jar" level="project" />
-    <orderEntry type="library" name="Gradle: __local_aars__:/Users/ray/Documents/code_ERPSuiteAndroid/ApexDrivers/RAUtilsLibrary/libs/httpmime-4.1.1.jar:unspecified@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-core-utils-27.1.1" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-core-3.0.2" level="project" />

+ 2 - 1
ApexDrivers/RAUtilsLibrary/build.gradle

@@ -42,11 +42,12 @@ android {
 }
 
 dependencies {
-    implementation fileTree(dir: 'libs', include: ['*.jar'])
     implementation 'com.android.support:appcompat-v7:27.1.1'
     testImplementation 'junit:junit:4.12'
     androidTestImplementation 'com.android.support.test:runner:1.0.2'
     androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+    implementation files('libs/bcprov-jdk15on-157.jar')
+    implementation files('libs/httpmime-4.1.1.jar')
 }
 
 

+ 28 - 7
ApexDrivers/app/app.iml

@@ -70,13 +70,6 @@
       <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
@@ -84,22 +77,49 @@
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/splits-support" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
       <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
       <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
     </content>
     <orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Gradle: com.android.support:transition-27.1.1" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:support-v4-27.1.1" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:runner-1.0.2" level="project" />
     <orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.0@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-27.1.1" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-compat-27.1.1" level="project" />
     <orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel-1.1.0" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7-27.1.1" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-27.1.1" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:support-media-compat-27.1.1" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-core-ui-27.1.1" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:support-core-utils-27.1.1" level="project" />
+    <orderEntry type="library" name="Gradle: __local_aars__:/Users/macmini1/android project/ApexDrivers/app/libs/core-2.3.0.jar:unspecified@jar" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-core-3.0.2" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
@@ -107,6 +127,7 @@
     <orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
     <orderEntry type="library" name="Gradle: android.arch.core:runtime-1.1.0" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.android.support:design-27.1.1" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:monitor-1.0.2" level="project" />
     <orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-27.1.1" level="project" />
     <orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-idling-resource-3.0.2" level="project" />

+ 3 - 3
ApexDrivers/app/build.gradle

@@ -19,12 +19,12 @@ android {
 }
 
 dependencies {
-
-    api project(":RAUtilsLibrary")
-    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    api project(':RAUtilsLibrary')
     implementation 'com.android.support:appcompat-v7:27.1.1'
     implementation 'com.android.support.constraint:constraint-layout:1.1.2'
+    implementation 'com.android.support:design:27.1.1'
     testImplementation 'junit:junit:4.12'
     androidTestImplementation 'com.android.support.test:runner:1.0.2'
     androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+    implementation files('libs/core-2.3.0.jar')
 }

BIN
ApexDrivers/app/libs/core-2.3.0.jar


+ 15 - 4
ApexDrivers/app/src/main/AndroidManifest.xml

@@ -1,21 +1,32 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.usai.redant.apexdrivers">
+          package="com.usai.redant.apexdrivers">
+
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.VIBRATE" />
 
     <application
+        android:name=".ApexDriverApplication"
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
-        <activity android:name=".MainActivity">
+        <activity
+            android:name=".MainActivity"
+            android:launchMode="singleTask">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.MAIN"/>
 
-                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".Detail.DetailActivity">
+        </activity>
+        <activity android:name=".Update.UpdateActivity">
+        </activity>
     </application>
 
 </manifest>

+ 71 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/ApexDriverApplication.java

@@ -0,0 +1,71 @@
+package com.usai.redant.apexdrivers;
+
+import android.app.Application;
+import android.content.SharedPreferences;
+
+import com.usai.redant.rautils.Utils.AESUtil;
+
+public class ApexDriverApplication extends Application {
+
+    public final static String secretKey = "usai";
+    public final static String preferencesKey = "Apex";
+    private static ApexDriverApplication mApp;
+
+    public String user;
+    public String password;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mApp = this;
+
+        user = savedUser();
+        password = savedPassword();
+    }
+
+    public boolean isLogin() {
+        return user != null && user.length() > 0 && password != null && password.length() > 0;
+    }
+
+    public void login(String user,String password) {
+        this.user = user;
+        this.password = password;
+
+        SharedPreferences pref = ApexDriverApplication.sharedApplication().getSharedPreferences(ApexDriverApplication.preferencesKey, 0);
+        SharedPreferences.Editor editor = pref.edit();
+        try {
+
+            editor.putString("user", AESUtil.encrypt(ApexDriverApplication.secretKey, user));
+            editor.putString("password", AESUtil.encrypt(ApexDriverApplication.secretKey, password));
+
+        } catch (Exception e) {
+            editor.putString("user", null);
+            editor.putString("password", null);
+            e.printStackTrace();
+        }
+        editor.commit();
+    }
+
+    public String savedUser() {
+        SharedPreferences pref = getSharedPreferences(ApexDriverApplication.preferencesKey, 0);
+        String user = pref.getString("user", null);
+        if (user != null) {
+            user = AESUtil.decrypt(ApexDriverApplication.secretKey, user);
+        }
+        return user;
+    }
+
+    public String savedPassword() {
+        SharedPreferences pref = getSharedPreferences(ApexDriverApplication.preferencesKey, 0);
+        String p = pref.getString("password", null);
+        if (p != null) {
+            p = AESUtil.decrypt(ApexDriverApplication.secretKey, p);
+        }
+        return p;
+    }
+
+    public static ApexDriverApplication sharedApplication() {
+        return mApp;
+    }
+}

+ 87 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/AmbientLightManager.java

@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.preference.PreferenceManager;
+
+import com.usai.redant.apexdrivers.camera.CameraManager;
+import com.usai.redant.apexdrivers.camera.FrontLightMode;
+
+/**
+ * Detects ambient light and switches on the front light when very dark, and off again when sufficiently light.
+ *
+ * @author Sean Owen
+ * @author Nikolaus Huber
+ */
+final class AmbientLightManager implements SensorEventListener {
+
+  private static final float TOO_DARK_LUX = 45.0f;
+  private static final float BRIGHT_ENOUGH_LUX = 450.0f;
+
+  private final Context context;
+  private CameraManager cameraManager;
+  private Sensor lightSensor;
+
+  AmbientLightManager(Context context) {
+    this.context = context;
+  }
+
+  void start(CameraManager cameraManager) {
+    this.cameraManager = cameraManager;
+    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
+    if (FrontLightMode.readPref(sharedPrefs) == FrontLightMode.AUTO) {
+      SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+      lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+      if (lightSensor != null) {
+        sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
+      }
+    }
+  }
+
+  void stop() {
+    if (lightSensor != null) {
+      SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+      sensorManager.unregisterListener(this);
+      cameraManager = null;
+      lightSensor = null;
+    }
+  }
+
+  @Override
+  public void onSensorChanged(SensorEvent sensorEvent) {
+    float ambientLightLux = sensorEvent.values[0];
+    if (cameraManager != null) {
+      if (ambientLightLux <= TOO_DARK_LUX) {
+        cameraManager.setTorch(true);
+      } else if (ambientLightLux >= BRIGHT_ENOUGH_LUX) {
+        cameraManager.setTorch(false);
+      }
+    }
+  }
+
+  @Override
+  public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    // do nothing
+  }
+
+}

+ 131 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/BeepManager.java

@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.os.Vibrator;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.apexdrivers.camera.PreferencesActivity;
+
+import java.io.IOException;
+
+/**
+ * Manages beeps and vibrations for {@link CaptureActivity}.
+ */
+final class BeepManager implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
+
+  private static final String TAG = BeepManager.class.getSimpleName();
+
+  private static final float BEEP_VOLUME = 0.10f;
+  private static final long VIBRATE_DURATION = 200L;
+
+  private final Activity activity;
+  private MediaPlayer mediaPlayer;
+  private boolean playBeep;
+  private boolean vibrate;
+
+  BeepManager(Activity activity) {
+    this.activity = activity;
+    this.mediaPlayer = null;
+    updatePrefs();
+  }
+
+  synchronized void updatePrefs() {
+    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
+    playBeep = shouldBeep(prefs, activity);
+    vibrate = prefs.getBoolean(PreferencesActivity.KEY_VIBRATE, false);
+    if (playBeep && mediaPlayer == null) {
+      // The volume on STREAM_SYSTEM is not adjustable, and users found it too loud,
+      // so we now play on the music stream.
+      activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
+      mediaPlayer = buildMediaPlayer(activity);
+    }
+  }
+
+  synchronized void playBeepSoundAndVibrate() {
+	  Log.i(TAG,"playBeep=========>"+playBeep);
+	  Log.i(TAG,"mediaPlayer=========>"+mediaPlayer==null?"null":"ok");
+	  Log.i(TAG,"vibrate=========>"+vibrate);
+    if (playBeep && mediaPlayer != null) {
+      mediaPlayer.start();
+    }
+    if (vibrate) {
+      Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
+      vibrator.vibrate(VIBRATE_DURATION);
+    }
+  }
+
+  private static boolean shouldBeep(SharedPreferences prefs, Context activity) {
+    boolean shouldPlayBeep = prefs.getBoolean(PreferencesActivity.KEY_PLAY_BEEP, true);
+    if (shouldPlayBeep) {
+      // See if sound settings overrides this
+      AudioManager audioService = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
+      if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
+        shouldPlayBeep = false;
+      }
+    }
+    return shouldPlayBeep;
+  }
+
+  private MediaPlayer buildMediaPlayer(Context activity) {
+    MediaPlayer mediaPlayer = new MediaPlayer();
+    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+    mediaPlayer.setOnCompletionListener(this);
+    mediaPlayer.setOnErrorListener(this);
+
+    AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.beep);
+    try {
+      mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
+      file.close();
+      mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
+      mediaPlayer.prepare();
+    } catch (IOException ioe) {
+      Log.w(TAG, ioe);
+      mediaPlayer = null;
+    }
+    return mediaPlayer;
+  }
+
+  @Override
+  public void onCompletion(MediaPlayer mp) {
+    // When the beep has finished playing, rewind to queue up another one.      
+    mp.seekTo(0);
+  }
+
+  @Override
+  public synchronized boolean onError(MediaPlayer mp, int what, int extra) {
+    if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
+      // we are finished, so put up an appropriate error toast if required and finish
+      activity.finish();
+    } else {
+      // possibly media player error, so release and recreate
+      mp.release();
+      mediaPlayer = null;
+      updatePrefs();
+    }
+    return true;
+  }
+
+}

+ 888 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/CaptureActivity.java

@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.Result;
+import com.google.zxing.ResultPoint;
+import com.google.zxing.client.result.ResultParser;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.apexdrivers.camera.CameraManager;
+import com.usai.redant.rautils.Utils.dbgUtil;
+
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+//import android.content.SharedPreferences;
+
+/**
+ * This activity opens the camera and does the actual scanning on a background
+ * thread. It draws a viewfinder to help the user place the barcode correctly,
+ * shows feedback as the image processing is happening, and then overlays the
+ * results when a scan is successful.
+ * 
+ * @author dswitkin@google.com (Daniel Switkin)
+ * @author Sean Owen
+ */
+public final class CaptureActivity extends Activity implements
+		SurfaceHolder.Callback
+{
+
+	private static final String TAG	= CaptureActivity.class
+													.getSimpleName();
+
+	// private static final long DEFAULT_INTENT_RESULT_DURATION_MS = 1500L;
+	// private static final long BULK_MODE_SCAN_DELAY_MS = 1000L;
+
+	// private static final String[] ZXING_URLS = {
+	// "http://zxing.appspot.com/scan", "zxing://scan/" };
+
+	// public static final int HISTORY_REQUEST_CODE = 0x0000bacc;
+
+	// private static final Collection<ResultMetadataType>
+	// DISPLAYABLE_METADATA_TYPES =
+	// EnumSet.of(ResultMetadataType.ISSUE_NUMBER,
+	// ResultMetadataType.SUGGESTED_PRICE,
+	// ResultMetadataType.ERROR_CORRECTION_LEVEL,
+	// ResultMetadataType.POSSIBLE_COUNTRY);
+
+	private CameraManager				cameraManager;
+	private CaptureActivityHandler		handler;
+	private Result						savedResultToShow;
+	private ViewfinderView				viewfinderView;
+	private TextView statusView;
+	// private View resultView;
+	private Result						lastResult;
+	private boolean						hasSurface;
+	// private boolean copyToClipboard;
+	// private IntentSource source;
+	// private String sourceUrl;
+	// private ScanFromWebPageManager scanFromWebPageManager;
+	private Collection<BarcodeFormat> decodeFormats;
+	private Map<DecodeHintType, ?> decodeHints;
+	private String characterSet;
+	// private HistoryManager historyManager;
+	private InactivityTimer				inactivityTimer;
+	private BeepManager					beepManager;
+	private AmbientLightManager			ambientLightManager;
+
+
+
+	ViewfinderView getViewfinderView()
+	{
+		return viewfinderView;
+	}
+
+	public Handler getHandler()
+	{
+		return handler;
+	}
+
+	CameraManager getCameraManager()
+	{
+		return cameraManager;
+	}
+
+	Button swith_button;
+
+	@Override
+	public void onCreate(Bundle icicle)
+	{
+		dbgUtil.Logd(TAG, "==============>CaptureActivity created!");
+
+		super.onCreate(icicle);
+
+		Window window = getWindow();
+		window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+		setContentView(R.layout.capture);
+
+		swith_button = (Button) findViewById(R.id.btn_switch);
+		swith_button.setTag("false");
+		swith_button.setBackgroundColor(getResources().getColor(
+				R.color.message_fail));
+		swith_button.setOnClickListener(new OnClickListener()
+		{
+
+			@Override
+			public void onClick(View v)
+			{
+
+				// inactivityTimer.onPause();
+
+				if (Boolean.parseBoolean(v.getTag().toString()) == false)
+				{
+					// inactivityTimer.onResume();
+					v.setTag("true");
+					v.setBackgroundColor(getResources().getColor(
+							R.color.message_success));
+				}
+				else
+				{
+
+					// inactivityTimer.onPause();
+					v.setTag("false");
+					v.setBackgroundColor(getResources().getColor(
+							R.color.message_fail));
+				}
+
+			}
+		});
+
+		// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+		hasSurface = false;
+		// historyManager = new HistoryManager(this);
+		// historyManager.trimHistory();
+		inactivityTimer = new InactivityTimer(this);
+		beepManager = new BeepManager(this);
+		ambientLightManager = new AmbientLightManager(this);
+
+		// PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
+
+
+		Log.d(TAG, "finish oncreate");
+	}
+	
+	@Override
+	protected void onResume()
+	{
+		super.onResume();
+
+		// CameraManager must be initialized here, not in onCreate(). This is
+		// necessary because we don't
+		// want to open the camera driver and measure the screen size if we're
+		// going to show the help on
+		// first launch. That led to bugs where the scanning rectangle was the
+		// wrong size and partially
+		// off screen.
+		cameraManager = new CameraManager(getApplication());
+
+		viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
+		viewfinderView.setCameraManager(cameraManager);
+
+		// resultView = findViewById(R.id.result_view);
+		statusView = (TextView) findViewById(R.id.status_view);
+
+		handler = null;
+		lastResult = null;
+
+		resetStatusView();
+
+		SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
+		SurfaceHolder surfaceHolder = surfaceView.getHolder();
+		if (hasSurface)
+		{
+			// The activity was paused but not stopped, so the surface still
+			// exists. Therefore
+			// surfaceCreated() won't be called, so init the camera here.
+			initCamera(surfaceHolder);
+		}
+		else
+		{
+			// Install the callback and wait for surfaceCreated() to init the
+			// camera.
+			surfaceHolder.addCallback(this);
+		}
+
+		beepManager.updatePrefs();
+		ambientLightManager.start(cameraManager);
+
+		inactivityTimer.onResume();
+
+		Intent intent = getIntent();
+
+		// SharedPreferences prefs =
+		// PreferenceManager.getDefaultSharedPreferences(this);
+		// copyToClipboard =
+		// prefs.getBoolean(PreferencesActivity.KEY_COPY_TO_CLIPBOARD, true)
+		// && (intent == null ||
+		// intent.getBooleanExtra(Intents.Scan.SAVE_HISTORY, true));
+
+		// source = IntentSource.NONE;
+		decodeFormats = null;
+		characterSet = null;
+
+		if (intent != null)
+		{
+
+			String action = intent.getAction();
+			// String dataString = intent.getDataString();
+
+			if (Intents.Scan.ACTION.equals(action))
+			{
+
+				// Scan the formats the intent requested, and return the result
+				// to the calling activity.
+				// source = IntentSource.NATIVE_APP_INTENT;
+				decodeFormats = DecodeFormatManager.parseDecodeFormats(intent);
+				decodeHints = DecodeHintManager.parseDecodeHints(intent);
+
+				if (intent.hasExtra(Intents.Scan.WIDTH)
+						&& intent.hasExtra(Intents.Scan.HEIGHT))
+				{
+					int width = intent.getIntExtra(Intents.Scan.WIDTH, 0);
+					int height = intent.getIntExtra(Intents.Scan.HEIGHT, 0);
+					if (width > 0 && height > 0)
+					{
+						cameraManager.setManualFramingRect(width, height);
+					}
+				}
+
+				String customPromptMessage = intent
+						.getStringExtra(Intents.Scan.PROMPT_MESSAGE);
+				if (customPromptMessage != null)
+				{
+					statusView.setText(customPromptMessage);
+				}
+
+			}
+			// else if (dataString != null &&
+			// dataString.contains("http://www.google") &&
+			// dataString.contains("/m/products/scan")) {
+			//
+			// // Scan only products and send the result to mobile Product
+			// Search.
+			// // source = IntentSource.PRODUCT_SEARCH_LINK;
+			// sourceUrl = dataString;
+			// decodeFormats = DecodeFormatManager.PRODUCT_FORMATS;
+			//
+			// }
+			// else if (isZXingURL(dataString)) {
+			//
+			// // Scan formats requested in query string (all formats if none
+			// specified).
+			// // If a return URL is specified, send the results there.
+			// Otherwise, handle it ourselves.
+			// source = IntentSource.ZXING_LINK;
+			// sourceUrl = dataString;
+			// Uri inputUri = Uri.parse(dataString);
+			// scanFromWebPageManager = new ScanFromWebPageManager(inputUri);
+			// decodeFormats = DecodeFormatManager.parseDecodeFormats(inputUri);
+			// // Allow a sub-set of the hints to be specified by the caller.
+			// decodeHints = DecodeHintManager.parseDecodeHints(inputUri);
+			//
+			// }
+
+			characterSet = intent.getStringExtra(Intents.Scan.CHARACTER_SET);
+
+		}
+	}
+
+	// private static boolean isZXingURL(String dataString) {
+	// if (dataString == null) {
+	// return false;
+	// }
+	// for (String url : ZXING_URLS) {
+	// if (dataString.startsWith(url)) {
+	// return true;
+	// }
+	// }
+	// return false;
+	// }
+
+	@Override
+	protected void onPause()
+	{
+		if (handler != null)
+		{
+			handler.quitSynchronously();
+			handler = null;
+		}
+		inactivityTimer.onPause();
+		ambientLightManager.stop();
+		cameraManager.closeDriver();
+		if (!hasSurface)
+		{
+			SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
+			SurfaceHolder surfaceHolder = surfaceView.getHolder();
+			surfaceHolder.removeCallback(this);
+		}
+		super.onPause();
+	}
+
+	@Override
+	protected void onDestroy()
+	{
+		inactivityTimer.shutdown();
+		super.onDestroy();
+	}
+
+	@Override
+	public boolean onKeyDown(int keyCode, KeyEvent event)
+	{
+		switch (keyCode)
+		{
+		// case KeyEvent.KEYCODE_BACK:
+		// if (source == IntentSource.NATIVE_APP_INTENT) {
+		// setResult(RESULT_CANCELED);
+		// finish();
+		// return true;
+		// }
+		// if ((source == IntentSource.NONE || source ==
+		// IntentSource.ZXING_LINK) && lastResult != null) {
+		// restartPreviewAfterDelay(0L);
+		// return true;
+		// }
+		// break;
+			case KeyEvent.KEYCODE_FOCUS:
+			case KeyEvent.KEYCODE_CAMERA:
+				// Handle these events so they don't launch the Camera app
+				return true;
+				// Use volume up/down to turn on light
+			case KeyEvent.KEYCODE_VOLUME_DOWN:
+				cameraManager.setTorch(false);
+				return true;
+			case KeyEvent.KEYCODE_VOLUME_UP:
+				cameraManager.setTorch(true);
+				return true;
+		}
+		return super.onKeyDown(keyCode, event);
+	}
+
+//	@Override
+//	public boolean onCreateOptionsMenu(Menu menu)
+//	{
+//		MenuInflater menuInflater = getMenuInflater();
+//		menuInflater.inflate(R.menu.capture, menu);
+//		return super.onCreateOptionsMenu(menu);
+//	}
+//
+//	@Override
+//	public boolean onOptionsItemSelected(MenuItem item)
+//	{
+//		Intent intent = new Intent(Intent.ACTION_VIEW);
+//		intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+//		switch (item.getItemId())
+//		{
+//		// case R.id.menu_share:
+//		// intent.setClassName(this, ShareActivity.class.getName());
+//		// startActivity(intent);
+//		// break;
+//		// case R.id.menu_history:
+//		// intent.setClassName(this, HistoryActivity.class.getName());
+//		// startActivityForResult(intent, HISTORY_REQUEST_CODE);
+//		// break;
+//			case R.id.menu_settings:
+//				intent.setClassName(this, PreferencesActivity.class.getName());
+//				startActivity(intent);
+//				break;
+//			// case R.id.menu_help:
+//			// intent.setClassName(this, HelpActivity.class.getName());
+//			// startActivity(intent);
+//			// break;
+//			default:
+//				return super.onOptionsItemSelected(item);
+//		}
+//		return true;
+//	}
+
+	// @Override
+	// public void onActivityResult(int requestCode, int resultCode, Intent
+	// intent) {
+	// if (resultCode == RESULT_OK) {
+	// // if (requestCode == HISTORY_REQUEST_CODE)
+	// // {
+	// // int itemNumber = intent.getIntExtra(Intents.History.ITEM_NUMBER, -1);
+	// // if (itemNumber >= 0) {
+	// // HistoryItem historyItem = historyManager.buildHistoryItem(itemNumber);
+	// // decodeOrStoreSavedBitmap(null, historyItem.getResult());
+	// // }
+	// // }
+	// }
+	// }
+
+	private void decodeOrStoreSavedBitmap(Bitmap bitmap, Result result)
+	{
+		// Bitmap isn't used yet -- will be used soon
+		if (handler == null)
+		{
+			savedResultToShow = result;
+		}
+		else
+		{
+			if (result != null)
+			{
+				savedResultToShow = result;
+			}
+			if (savedResultToShow != null)
+			{
+				Message message = Message.obtain(handler,
+						R.id.decode_succeeded, savedResultToShow);
+				handler.sendMessage(message);
+			}
+			savedResultToShow = null;
+		}
+	}
+
+	@Override
+	public void surfaceCreated(SurfaceHolder holder)
+	{
+		if (holder == null)
+		{
+			Log.d(TAG,
+					"*** WARNING *** surfaceCreated() gave us a null surface!");
+		}
+		if (!hasSurface)
+		{
+			hasSurface = true;
+			initCamera(holder);
+		}
+	}
+
+	@Override
+	public void surfaceDestroyed(SurfaceHolder holder)
+	{
+		hasSurface = false;
+	}
+
+	@Override
+	public void surfaceChanged(SurfaceHolder holder, int format, int width,
+                               int height)
+	{
+
+	}
+
+	/**
+	 * A valid barcode has been found, so give an indication of success and show
+	 * the results.
+	 * 
+	 * @param rawResult
+	 *            The contents of the barcode.
+	 * @param scaleFactor
+	 *            amount by which thumbnail was scaled
+	 * @param barcode
+	 *            A greyscale bitmap of the camera data which was decoded.
+	 */
+	public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor)
+	{
+		String tag = swith_button.getTag().toString();
+		if (Boolean.parseBoolean(tag) == false)
+		{
+			restartPreviewAfterDelay(0L);
+			return;
+		}
+		inactivityTimer.onActivity();
+		lastResult = rawResult;
+		TextView debugTextView = (TextView) findViewById(R.id.textView1);
+		debugTextView.setText(rawResult.getText());
+		// ResultHandler resultHandler =
+		// ResultHandlerFactory.makeResultHandler(this, rawResult);
+		Log.i(TAG, "RESULT=========>" + rawResult.getText().toString());
+		// ParsedResult result = parseResult(rawResult);
+		Log.i(TAG, "HANDLER========>"
+				+ ResultParser.parseResult(rawResult).getType().toString());
+		boolean fromLiveScan = barcode != null;
+		if (fromLiveScan)
+		{
+			// historyManager.addHistoryItem(rawResult, resultHandler);
+			// Then not from history, so beep/vibrate and we have an image to
+			// draw on
+			beepManager.playBeepSoundAndVibrate();
+			// drawResultPoints(barcode, scaleFactor, rawResult);
+		}
+
+		Intent result = new Intent();
+		result.putExtra("pid", rawResult.getText());
+		setResult(Activity.RESULT_OK, result);
+		finish();
+		// restartPreviewAfterDelay(1000l);
+		// finish();
+		//
+		// switch (source) {
+		// case NATIVE_APP_INTENT:
+		// case PRODUCT_SEARCH_LINK:
+		// handleDecodeExternally(rawResult, resultHandler, barcode);
+		// break;
+		// case ZXING_LINK:
+		// if (scanFromWebPageManager == null ||
+		// !scanFromWebPageManager.isScanFromWebPage()) {
+		// handleDecodeInternally(rawResult, resultHandler, barcode);
+		// } else {
+		// handleDecodeExternally(rawResult, resultHandler, barcode);
+		// }
+		// break;
+		// case NONE:
+		// SharedPreferences prefs =
+		// PreferenceManager.getDefaultSharedPreferences(this);
+		// if (fromLiveScan &&
+		// prefs.getBoolean(PreferencesActivity.KEY_BULK_MODE, false)) {
+		// Toast.makeText(getApplicationContext(),
+		// getResources().getString(R.string.msg_bulk_mode_scanned) + " (" +
+		// rawResult.getText() + ')',
+		// Toast.LENGTH_SHORT).show();
+		// // Wait a moment or else it will scan the same barcode continuously
+		// about 3 times
+		// restartPreviewAfterDelay(BULK_MODE_SCAN_DELAY_MS);
+		// } else {
+		// handleDecodeInternally(rawResult, resultHandler, barcode);
+		// }
+		// break;
+		// }
+	}
+
+	/**
+	 * Superimpose a line for 1D or dots for 2D to highlight the key features of
+	 * the barcode.
+	 * 
+	 * @param barcode
+	 *            A bitmap of the captured image.
+	 * @param scaleFactor
+	 *            amount by which thumbnail was scaled
+	 * @param rawResult
+	 *            The decoded results which contains the points to draw.
+	 */
+	// private void drawResultPoints(Bitmap barcode, float scaleFactor,
+	// Result rawResult)
+	// {
+	// ResultPoint[] points = rawResult.getResultPoints();
+	// if (points != null && points.length > 0)
+	// {
+	// Canvas canvas = new Canvas(barcode);
+	// Paint paint = new Paint();
+	// paint.setColor(getResources().getColor(R.color.result_points));
+	// if (points.length == 2)
+	// {
+	// paint.setStrokeWidth(4.0f);
+	// drawLine(canvas, paint, points[0], points[1], scaleFactor);
+	// }
+	// else if (points.length == 4
+	// && (rawResult.getBarcodeFormat() == BarcodeFormat.UPC_A || rawResult
+	// .getBarcodeFormat() == BarcodeFormat.EAN_13))
+	// {
+	// // Hacky special case -- draw two lines, for the barcode and
+	// // metadata
+	// drawLine(canvas, paint, points[0], points[1], scaleFactor);
+	// drawLine(canvas, paint, points[2], points[3], scaleFactor);
+	// }
+	// else
+	// {
+	// paint.setStrokeWidth(10.0f);
+	// for (ResultPoint point : points)
+	// {
+	// if (point != null)
+	// {
+	// canvas.drawPoint(scaleFactor * point.getX(),
+	// scaleFactor * point.getY(), paint);
+	// }
+	// }
+	// }
+	// }
+	// }
+
+	private static void drawLine(Canvas canvas, Paint paint, ResultPoint a,
+                                 ResultPoint b, float scaleFactor)
+	{
+		if (a != null && b != null)
+		{
+			canvas.drawLine(scaleFactor * a.getX(), scaleFactor * a.getY(),
+					scaleFactor * b.getX(), scaleFactor * b.getY(), paint);
+		}
+	}
+
+	// Put up our own UI for how to handle the decoded contents.
+	// private void handleDecodeInternally(Result rawResult, ResultHandler
+	// resultHandler, Bitmap barcode) {
+	// statusView.setVisibility(View.GONE);
+	// viewfinderView.setVisibility(View.GONE);
+	// // resultView.setVisibility(View.VISIBLE);
+	// Log.i(TAG, "RESULT=========>"+rawResult.getText().toString());
+	// Log.i(TAG, "HANDLER========>"+resultHandler.getType().toString());
+
+	// ImageView barcodeImageView = (ImageView)
+	// findViewById(R.id.barcode_image_view);
+	// if (barcode == null) {
+	// barcodeImageView.setImageBitmap(BitmapFactory.decodeResource(getResources(),
+	// R.drawable.ic_launcher));
+	// } else {
+	// barcodeImageView.setImageBitmap(barcode);
+	// }
+	//
+	// TextView formatTextView = (TextView) findViewById(R.id.format_text_view);
+	// formatTextView.setText(rawResult.getBarcodeFormat().toString());
+	//
+	// TextView typeTextView = (TextView) findViewById(R.id.type_text_view);
+	// typeTextView.setText(resultHandler.getType().toString());
+	//
+	// DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT,
+	// DateFormat.SHORT);
+	// TextView timeTextView = (TextView) findViewById(R.id.time_text_view);
+	// timeTextView.setText(formatter.format(new
+	// Date(rawResult.getTimestamp())));
+	//
+	//
+	// TextView metaTextView = (TextView) findViewById(R.id.meta_text_view);
+	// View metaTextViewLabel = findViewById(R.id.meta_text_view_label);
+	// metaTextView.setVisibility(View.GONE);
+	// metaTextViewLabel.setVisibility(View.GONE);
+	// Map<ResultMetadataType,Object> metadata = rawResult.getResultMetadata();
+	// if (metadata != null) {
+	// StringBuilder metadataText = new StringBuilder(20);
+	// for (Map.Entry<ResultMetadataType,Object> entry : metadata.entrySet()) {
+	// if (DISPLAYABLE_METADATA_TYPES.contains(entry.getKey())) {
+	// metadataText.append(entry.getValue()).append('\n');
+	// }
+	// }
+	// if (metadataText.length() > 0) {
+	// metadataText.setLength(metadataText.length() - 1);
+	// metaTextView.setText(metadataText);
+	// metaTextView.setVisibility(View.VISIBLE);
+	// metaTextViewLabel.setVisibility(View.VISIBLE);
+	// }
+	// }
+	//
+	// TextView contentsTextView = (TextView)
+	// findViewById(R.id.contents_text_view);
+	// CharSequence displayContents = resultHandler.getDisplayContents();
+	// contentsTextView.setText(displayContents);
+	// // Crudely scale betweeen 22 and 32 -- bigger font for shorter text
+	// int scaledSize = Math.max(22, 32 - displayContents.length() / 4);
+	// contentsTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, scaledSize);
+	//
+	// TextView supplementTextView = (TextView)
+	// findViewById(R.id.contents_supplement_text_view);
+	// supplementTextView.setText("");
+	// supplementTextView.setOnClickListener(null);
+	// // if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
+	// // PreferencesActivity.KEY_SUPPLEMENTAL, true)) {
+	// // SupplementalInfoRetriever.maybeInvokeRetrieval(supplementTextView,
+	// // resultHandler.getResult(),
+	// // historyManager,
+	// // this);
+	// // }
+	//
+	// int buttonCount = resultHandler.getButtonCount();
+	// ViewGroup buttonView = (ViewGroup) findViewById(R.id.result_button_view);
+	// buttonView.requestFocus();
+	// for (int x = 0; x < ResultHandler.MAX_BUTTON_COUNT; x++) {
+	// TextView button = (TextView) buttonView.getChildAt(x);
+	// if (x < buttonCount) {
+	// button.setVisibility(View.VISIBLE);
+	// button.setText(resultHandler.getButtonText(x));
+	// button.setOnClickListener(new ResultButtonListener(resultHandler, x));
+	// } else {
+	// button.setVisibility(View.GONE);
+	// }
+	// }
+	//
+	// if (copyToClipboard && !resultHandler.areContentsSecure()) {
+	// ClipboardInterface.setText(displayContents, this);
+	// }
+	// }
+
+	// // Briefly show the contents of the barcode, then handle the result
+	// outside Barcode Scanner.
+	// private void handleDecodeExternally(Result rawResult, ResultHandler
+	// resultHandler, Bitmap barcode) {
+	//
+	// if (barcode != null) {
+	// viewfinderView.drawResultBitmap(barcode);
+	// }
+	//
+	// long resultDurationMS;
+	// if (getIntent() == null) {
+	// resultDurationMS = DEFAULT_INTENT_RESULT_DURATION_MS;
+	// } else {
+	// resultDurationMS =
+	// getIntent().getLongExtra(Intents.Scan.RESULT_DISPLAY_DURATION_MS,
+	// DEFAULT_INTENT_RESULT_DURATION_MS);
+	// }
+	//
+	// if (resultDurationMS > 0) {
+	// String rawResultString = String.valueOf(rawResult);
+	// if (rawResultString.length() > 32) {
+	// rawResultString = rawResultString.substring(0, 32) + " ...";
+	// }
+	// statusView.setText(getString(resultHandler.getDisplayTitle()) + " : " +
+	// rawResultString);
+	// }
+	//
+	// if (copyToClipboard && !resultHandler.areContentsSecure()) {
+	// CharSequence text = resultHandler.getDisplayContents();
+	// ClipboardInterface.setText(text, this);
+	// }
+	//
+	// if (source == IntentSource.NATIVE_APP_INTENT) {
+	//
+	// // Hand back whatever action they requested - this can be changed to
+	// Intents.Scan.ACTION when
+	// // the deprecated intent is retired.
+	// Intent intent = new Intent(getIntent().getAction());
+	// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+	// intent.putExtra(Intents.Scan.RESULT, rawResult.toString());
+	// intent.putExtra(Intents.Scan.RESULT_FORMAT,
+	// rawResult.getBarcodeFormat().toString());
+	// byte[] rawBytes = rawResult.getRawBytes();
+	// if (rawBytes != null && rawBytes.length > 0) {
+	// intent.putExtra(Intents.Scan.RESULT_BYTES, rawBytes);
+	// }
+	// Map<ResultMetadataType,?> metadata = rawResult.getResultMetadata();
+	// if (metadata != null) {
+	// if (metadata.containsKey(ResultMetadataType.UPC_EAN_EXTENSION)) {
+	// intent.putExtra(Intents.Scan.RESULT_UPC_EAN_EXTENSION,
+	// metadata.get(ResultMetadataType.UPC_EAN_EXTENSION).toString());
+	// }
+	// Number orientation = (Number)
+	// metadata.get(ResultMetadataType.ORIENTATION);
+	// if (orientation != null) {
+	// intent.putExtra(Intents.Scan.RESULT_ORIENTATION, orientation.intValue());
+	// }
+	// String ecLevel = (String)
+	// metadata.get(ResultMetadataType.ERROR_CORRECTION_LEVEL);
+	// if (ecLevel != null) {
+	// intent.putExtra(Intents.Scan.RESULT_ERROR_CORRECTION_LEVEL, ecLevel);
+	// }
+	// @SuppressWarnings("unchecked")
+	// Iterable<byte[]> byteSegments = (Iterable<byte[]>)
+	// metadata.get(ResultMetadataType.BYTE_SEGMENTS);
+	// if (byteSegments != null) {
+	// int i = 0;
+	// for (byte[] byteSegment : byteSegments) {
+	// intent.putExtra(Intents.Scan.RESULT_BYTE_SEGMENTS_PREFIX + i,
+	// byteSegment);
+	// i++;
+	// }
+	// }
+	// }
+	// sendReplyMessage(R.id.return_scan_result, intent, resultDurationMS);
+	//
+	// } else if (source == IntentSource.PRODUCT_SEARCH_LINK) {
+	//
+	// // Reformulate the URL which triggered us into a query, so that the
+	// request goes to the same
+	// // TLD as the scan URL.
+	// int end = sourceUrl.lastIndexOf("/scan");
+	// String replyURL = sourceUrl.substring(0, end) + "?q=" +
+	// resultHandler.getDisplayContents() + "&source=zxing";
+	// sendReplyMessage(R.id.launch_product_query, replyURL, resultDurationMS);
+	//
+	// } else if (source == IntentSource.ZXING_LINK) {
+	//
+	// if (scanFromWebPageManager != null &&
+	// scanFromWebPageManager.isScanFromWebPage()) {
+	// String replyURL = scanFromWebPageManager.buildReplyURL(rawResult,
+	// resultHandler);
+	// sendReplyMessage(R.id.launch_product_query, replyURL, resultDurationMS);
+	// }
+	//
+	// }
+	// }
+
+	// private void sendReplyMessage(int id, Object arg, long delayMS) {
+	// if (handler != null) {
+	// Message message = Message.obtain(handler, id, arg);
+	// if (delayMS > 0L) {
+	// handler.sendMessageDelayed(message, delayMS);
+	// } else {
+	// handler.sendMessage(message);
+	// }
+	// }
+	// }
+
+	private void initCamera(SurfaceHolder surfaceHolder)
+	{
+		if (surfaceHolder == null)
+		{
+			throw new IllegalStateException("No SurfaceHolder provided");
+		}
+		if (cameraManager.isOpen())
+		{
+			Log.w(TAG,
+					"initCamera() while already open -- late SurfaceView callback?");
+			return;
+		}
+		try
+		{
+			cameraManager.openDriver(surfaceHolder);
+			// Creating the handler starts the preview, which can also throw a
+			// RuntimeException.
+			if (handler == null)
+			{
+				handler = new CaptureActivityHandler(this, decodeFormats,
+						decodeHints, characterSet, cameraManager);
+			}
+			decodeOrStoreSavedBitmap(null, null);
+		}
+		catch (IOException ioe)
+		{
+			Log.w(TAG, ioe);
+			displayFrameworkBugMessageAndExit();
+		}
+		catch (RuntimeException e)
+		{
+			// Barcode Scanner has seen crashes in the wild of this variety:
+			// java.?lang.?RuntimeException: Fail to connect to camera service
+			Log.w(TAG, "Unexpected error initializing camera", e);
+			displayFrameworkBugMessageAndExit();
+		}
+	}
+
+	private void displayFrameworkBugMessageAndExit()
+	{
+		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		builder.setTitle(getString(R.string.app_name));
+		builder.setMessage(getString(R.string.msg_camera_framework_bug));
+		builder.setPositiveButton(R.string.button_ok, new FinishListener(this));
+		builder.setOnCancelListener(new FinishListener(this));
+		builder.show();
+	}
+
+	public void restartPreviewAfterDelay(long delayMS)
+	{
+		if (handler != null)
+		{
+			handler.sendEmptyMessageDelayed(R.id.decode_failed, delayMS);
+		}
+		resetStatusView();
+	}
+
+	private void resetStatusView()
+	{
+		// resultView.setVisibility(View.GONE);
+		statusView.setText(R.string.msg_default_status);
+		statusView.setVisibility(View.VISIBLE);
+		viewfinderView.setVisibility(View.VISIBLE);
+		lastResult = null;
+	}
+
+	public void drawViewfinder()
+	{
+		viewfinderView.drawViewfinder();
+	}
+}

+ 170 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/CaptureActivityHandler.java

@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.Browser;
+import android.util.Log;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.Result;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.apexdrivers.camera.CameraManager;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * This class handles all the messaging which comprises the state machine for capture.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class CaptureActivityHandler extends Handler {
+
+  private static final String TAG = CaptureActivityHandler.class.getSimpleName();
+
+  private final CaptureActivity activity;
+  private final DecodeThread decodeThread;
+  private State state;
+  private final CameraManager cameraManager;
+
+  private enum State {
+    PREVIEW,
+    SUCCESS,
+    DONE
+  }
+
+  CaptureActivityHandler(CaptureActivity activity,
+                         Collection<BarcodeFormat> decodeFormats,
+                         Map<DecodeHintType,?> baseHints,
+                         String characterSet,
+                         CameraManager cameraManager) {
+    this.activity = activity;
+    decodeThread = new DecodeThread(activity, decodeFormats, baseHints, characterSet,
+        new ViewfinderResultPointCallback(activity.getViewfinderView()));
+    decodeThread.start();
+    state = State.SUCCESS;
+
+    // Start ourselves capturing previews and decoding.
+    this.cameraManager = cameraManager;
+    cameraManager.startPreview();
+    restartPreviewAndDecode();
+  }
+
+  @Override
+  public void handleMessage(Message message) {
+    switch (message.what) {
+      case R.id.restart_preview:
+        Log.d(TAG, "Got restart preview message");
+        restartPreviewAndDecode();
+        break;
+      case R.id.decode_succeeded:
+        Log.d(TAG, "Got decode succeeded message");
+        state = State.SUCCESS;
+        Bundle bundle = message.getData();
+        Bitmap barcode = null;
+        float scaleFactor = 1.0f;
+        if (bundle != null) {
+          byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
+          if (compressedBitmap != null) {
+            barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
+            // Mutable copy:
+            barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
+          }
+          scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR);          
+        }
+        activity.handleDecode((Result) message.obj, barcode, scaleFactor);
+        break;
+      case R.id.decode_failed:
+        // We're decoding as fast as possible, so when one decode fails, start another.
+        state = State.PREVIEW;
+        cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
+        break;
+      case R.id.return_scan_result:
+        Log.d(TAG, "Got return scan result message");
+        activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
+        activity.finish();
+        break;
+      case R.id.launch_product_query:
+        Log.d(TAG, "Got product query message");
+        String url = (String) message.obj;
+
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+        intent.setData(Uri.parse(url));
+
+        ResolveInfo resolveInfo =
+            activity.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        String browserPackageName = null;
+        if (resolveInfo != null && resolveInfo.activityInfo != null) {
+          browserPackageName = resolveInfo.activityInfo.packageName;
+          Log.d(TAG, "Using browser in package " + browserPackageName);
+        }
+
+        // Needed for default Android browser / Chrome only apparently
+        if ("com.android.browser".equals(browserPackageName) || "com.android.chrome".equals(browserPackageName)) {
+          intent.setPackage(browserPackageName);
+          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+          intent.putExtra(Browser.EXTRA_APPLICATION_ID, browserPackageName);
+        }
+
+        try {
+          activity.startActivity(intent);
+        } catch (ActivityNotFoundException ignored) {
+          Log.w(TAG, "Can't find anything to handle VIEW of URI " + url);
+        }
+        break;
+    }
+  }
+
+  public void quitSynchronously() {
+    state = State.DONE;
+    cameraManager.stopPreview();
+    Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
+    quit.sendToTarget();
+    try {
+      // Wait at most half a second; should be enough time, and onPause() will timeout quickly
+      decodeThread.join(500L);
+    } catch (InterruptedException e) {
+      // continue
+    }
+
+    // Be absolutely sure we don't send any queued up messages
+    removeMessages(R.id.decode_succeeded);
+    removeMessages(R.id.decode_failed);
+  }
+
+  private void restartPreviewAndDecode() {
+    if (state == State.SUCCESS) {
+      state = State.PREVIEW;
+      cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
+      activity.drawViewfinder();
+    }
+  }
+
+}

+ 102 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeFormatManager.java

@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.content.Intent;
+import android.net.Uri;
+
+import com.google.zxing.BarcodeFormat;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.regex.Pattern;
+
+final class DecodeFormatManager {
+
+  private static final Pattern COMMA_PATTERN = Pattern.compile(",");
+
+  static final Collection<BarcodeFormat> PRODUCT_FORMATS;
+  static final Collection<BarcodeFormat> ONE_D_FORMATS;
+  static final Collection<BarcodeFormat> QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
+  static final Collection<BarcodeFormat> DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX);
+  static {
+    PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A,
+                                 BarcodeFormat.UPC_E,
+                                 BarcodeFormat.EAN_13,
+                                 BarcodeFormat.EAN_8,
+                                 BarcodeFormat.RSS_14,
+                                 BarcodeFormat.RSS_EXPANDED);
+    ONE_D_FORMATS = EnumSet.of(BarcodeFormat.CODE_39,
+                               BarcodeFormat.CODE_93,
+                               BarcodeFormat.CODE_128,
+                               BarcodeFormat.ITF,
+                               BarcodeFormat.CODABAR);
+    ONE_D_FORMATS.addAll(PRODUCT_FORMATS);
+  }
+
+  private DecodeFormatManager() {}
+
+  static Collection<BarcodeFormat> parseDecodeFormats(Intent intent) {
+    Iterable<String> scanFormats = null;
+    CharSequence scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);
+    if (scanFormatsString != null) {
+      scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
+    }
+    return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
+  }
+
+  static Collection<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
+    List<String> formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);
+    if (formats != null && formats.size() == 1 && formats.get(0) != null){
+      formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
+    }
+    return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
+  }
+
+  private static Collection<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats,
+                                                              String decodeMode) {
+    if (scanFormats != null) {
+      Collection<BarcodeFormat> formats = EnumSet.noneOf(BarcodeFormat.class);
+      try {
+        for (String format : scanFormats) {
+          formats.add(BarcodeFormat.valueOf(format));
+        }
+        return formats;
+      } catch (IllegalArgumentException iae) {
+        // ignore it then
+      }
+    }
+    if (decodeMode != null) {
+      if (Intents.Scan.PRODUCT_MODE.equals(decodeMode)) {
+        return PRODUCT_FORMATS;
+      }
+      if (Intents.Scan.QR_CODE_MODE.equals(decodeMode)) {
+        return QR_CODE_FORMATS;
+      }
+      if (Intents.Scan.DATA_MATRIX_MODE.equals(decodeMode)) {
+        return DATA_MATRIX_FORMATS;
+      }
+      if (Intents.Scan.ONE_D_MODE.equals(decodeMode)) {
+        return ONE_D_FORMATS;
+      }
+    }
+    return null;
+  }
+
+}

+ 122 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeHandler.java

@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.PlanarYUVLuminanceSource;
+import com.google.zxing.ReaderException;
+import com.google.zxing.Result;
+import com.google.zxing.common.HybridBinarizer;
+import com.usai.redant.apexdrivers.R;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Map;
+
+final class DecodeHandler extends Handler {
+
+  private static final String TAG = DecodeHandler.class.getSimpleName();
+
+  private final CaptureActivity activity;
+  private final MultiFormatReader multiFormatReader;
+  private boolean running = true;
+
+  DecodeHandler(CaptureActivity activity, Map<DecodeHintType,Object> hints) {
+    multiFormatReader = new MultiFormatReader();
+    multiFormatReader.setHints(hints);
+    this.activity = activity;
+  }
+
+  @Override
+  public void handleMessage(Message message) {
+    if (!running) {
+      return;
+    }
+    switch (message.what) {
+      case R.id.decode:
+        decode((byte[]) message.obj, message.arg1, message.arg2);
+        break;
+      case R.id.quit:
+        running = false;
+        Looper.myLooper().quit();
+        break;
+    }
+  }
+
+  /**
+   * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
+   * reuse the same reader objects from one decode to the next.
+   *
+   * @param data   The YUV preview frame.
+   * @param width  The width of the preview frame.
+   * @param height The height of the preview frame.
+   */
+  private void decode(byte[] data, int width, int height) {
+    long start = System.currentTimeMillis();
+    Result rawResult = null;
+    PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
+    if (source != null) {
+      BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+      try {
+        rawResult = multiFormatReader.decodeWithState(bitmap);
+      } catch (ReaderException re) {
+        // continue
+      } finally {
+        multiFormatReader.reset();
+      }
+    }
+
+    Handler handler = activity.getHandler();
+    if (rawResult != null) {
+      // Don't log the barcode contents for security.
+      long end = System.currentTimeMillis();
+      Log.d(TAG, "Found barcode in " + (end - start) + " ms");
+      if (handler != null) {
+        Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
+        Bundle bundle = new Bundle();
+        bundleThumbnail(source, bundle);        
+        message.setData(bundle);
+        message.sendToTarget();
+      }
+    } else {
+      if (handler != null) {
+        Message message = Message.obtain(handler, R.id.decode_failed);
+        message.sendToTarget();
+      }
+    }
+  }
+
+  private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {
+    int[] pixels = source.renderThumbnail();
+    int width = source.getThumbnailWidth();
+    int height = source.getThumbnailHeight();
+    Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888);
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
+    bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray());
+    bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());
+  }
+
+}

+ 236 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeHintManager.java

@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.google.zxing.DecodeHintType;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * @author Lachezar Dobrev
+ */
+final class DecodeHintManager {
+  
+  private static final String TAG = DecodeHintManager.class.getSimpleName();
+
+  // This pattern is used in decoding integer arrays.
+  private static final Pattern COMMA = Pattern.compile(",");
+
+  private DecodeHintManager() {}
+
+  /**
+   * <p>Split a query string into a list of name-value pairs.</p>
+   * 
+   * <p>This is an alternative to the {@link Uri#getQueryParameterNames()} and
+   * {@link Uri#getQueryParameters(String)}, which are quirky and not suitable
+   * for exist-only Uri parameters.</p>
+   * 
+   * <p>This method ignores multiple parameters with the same name and returns the
+   * first one only. This is technically incorrect, but should be acceptable due
+   * to the method of processing Hints: no multiple values for a hint.</p>
+   * 
+   * @param query query to split
+   * @return name-value pairs
+   */
+  private static Map<String,String> splitQuery(String query) {
+    Map<String,String> map = new HashMap<String,String>();
+    int pos = 0;
+    while (pos < query.length()) {
+      if (query.charAt(pos) == '&') {
+        // Skip consecutive ampersand separators.
+        pos ++;
+        continue;
+      }
+      int amp = query.indexOf('&', pos);
+      int equ = query.indexOf('=', pos);
+      if (amp < 0) {
+        // This is the last element in the query, no more ampersand elements.
+        String name;
+        String text;
+        if (equ < 0) {
+          // No equal sign
+          name = query.substring(pos);
+          name = name.replace('+', ' '); // Preemptively decode +
+          name = Uri.decode(name);
+          text = "";
+        } else {
+          // Split name and text.
+          name = query.substring(pos, equ);
+          name = name.replace('+', ' '); // Preemptively decode +
+          name = Uri.decode(name);
+          text = query.substring(equ + 1);
+          text = text.replace('+', ' '); // Preemptively decode +
+          text = Uri.decode(text);
+        }
+        if (!map.containsKey(name)) {
+          map.put(name, text);
+        }
+        break;
+      }
+      if (equ < 0 || equ > amp) {
+        // No equal sign until the &: this is a simple parameter with no value.
+        String name = query.substring(pos, amp);
+        name = name.replace('+', ' '); // Preemptively decode +
+        name = Uri.decode(name);
+        if (!map.containsKey(name)) {
+          map.put(name, "");
+        }
+        pos = amp + 1;
+        continue;
+      }
+      String name = query.substring(pos, equ);
+      name = name.replace('+', ' '); // Preemptively decode +
+      name = Uri.decode(name);
+      String text = query.substring(equ+1, amp);
+      text = text.replace('+', ' '); // Preemptively decode +
+      text = Uri.decode(text);
+      if (!map.containsKey(name)) {
+        map.put(name, text);
+      }
+      pos = amp + 1;
+    }
+    return map;
+  }
+
+  static Map<DecodeHintType,?> parseDecodeHints(Uri inputUri) {
+    String query = inputUri.getEncodedQuery();
+    if (query == null || query.isEmpty()) {
+      return null;
+    }
+
+    // Extract parameters
+    Map<String, String> parameters = splitQuery(query);
+
+    Map<DecodeHintType, Object> hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
+
+    for (DecodeHintType hintType: DecodeHintType.values()) {
+
+      if (hintType == DecodeHintType.CHARACTER_SET ||
+          hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
+          hintType == DecodeHintType.POSSIBLE_FORMATS) {
+        continue; // This hint is specified in another way
+      }
+
+      String parameterName = hintType.name();
+      String parameterText = parameters.get(parameterName);
+      if (parameterText == null) {
+        continue;
+      }
+      if (hintType.getValueType().equals(Object.class)) {
+        // This is an unspecified type of hint content. Use the value as is.
+        // TODO: Can we make a different assumption on this?
+        hints.put(hintType, parameterText);
+        continue;
+      }
+      if (hintType.getValueType().equals(Void.class)) {
+        // Void hints are just flags: use the constant specified by DecodeHintType
+        hints.put(hintType, Boolean.TRUE);
+        continue;
+      }
+      if (hintType.getValueType().equals(String.class)) {
+        // A string hint: use the decoded value.
+        hints.put(hintType, parameterText);
+        continue;
+      }
+      if (hintType.getValueType().equals(Boolean.class)) {
+        // A boolean hint: a few values for false, everything else is true.
+        // An empty parameter is simply a flag-style parameter, assuming true
+        if (parameterText.isEmpty()) {
+          hints.put(hintType, Boolean.TRUE);
+        } else if ("0".equals(parameterText) || 
+                   "false".equalsIgnoreCase(parameterText) || 
+                   "no".equalsIgnoreCase(parameterText)) {
+          hints.put(hintType, Boolean.FALSE);
+        } else {
+          hints.put(hintType, Boolean.TRUE);
+        }
+
+        continue;
+      }
+      if (hintType.getValueType().equals(int[].class)) {
+        // An integer array. Used to specify valid lengths.
+        // Strip a trailing comma as in Java style array initialisers.
+        if (!parameterText.isEmpty() && parameterText.charAt(parameterText.length() - 1) == ',') {
+          parameterText = parameterText.substring(0, parameterText.length() - 1);
+        }
+        String[] values = COMMA.split(parameterText);
+        int[] array = new int[values.length];
+        for (int i = 0; i < values.length; i++) {
+          try {
+            array[i] = Integer.parseInt(values[i]);
+          } catch (NumberFormatException ignored) {
+            Log.w(TAG, "Skipping array of integers hint " + hintType + " due to invalid numeric value: '" + values[i] + '\'');
+            array = null;
+            break;
+          }
+        }
+        if (array != null) {
+          hints.put(hintType, array);
+        }
+        continue;
+      } 
+      Log.w(TAG, "Unsupported hint type '" + hintType + "' of type " + hintType.getValueType());
+    }
+
+    Log.i(TAG, "Hints from the URI: " + hints);
+    return hints;
+  }
+
+  static Map<DecodeHintType, Object> parseDecodeHints(Intent intent) {
+    Bundle extras = intent.getExtras();
+    if (extras == null || extras.isEmpty()) {
+      return null;
+    }
+    Map<DecodeHintType,Object> hints = new EnumMap<DecodeHintType,Object>(DecodeHintType.class);
+
+    for (DecodeHintType hintType: DecodeHintType.values()) {
+
+      if (hintType == DecodeHintType.CHARACTER_SET ||
+          hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
+          hintType == DecodeHintType.POSSIBLE_FORMATS) {
+        continue; // This hint is specified in another way
+      }
+
+      String hintName = hintType.name();
+      if (extras.containsKey(hintName)) {
+        if (hintType.getValueType().equals(Void.class)) {
+          // Void hints are just flags: use the constant specified by the DecodeHintType
+          hints.put(hintType, Boolean.TRUE);
+        } else {
+          Object hintData = extras.get(hintName);
+          if (hintType.getValueType().isInstance(hintData)) {
+            hints.put(hintType, hintData);
+          } else {
+            Log.w(TAG, "Ignoring hint " + hintType + " because it is not assignable from " + hintData);
+          }
+        }
+      }
+    }
+
+    Log.i(TAG, "Hints from the Intent: " + hints);
+    return hints;
+  }
+
+}

+ 105 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/DecodeThread.java

@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.content.SharedPreferences;
+import android.os.Handler;
+import android.os.Looper;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.ResultPointCallback;
+import com.usai.redant.apexdrivers.camera.PreferencesActivity;
+
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * This thread does all the heavy lifting of decoding the images.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+final class DecodeThread extends Thread {
+
+  public static final String BARCODE_BITMAP = "barcode_bitmap";
+  public static final String BARCODE_SCALED_FACTOR = "barcode_scaled_factor";
+
+  private final CaptureActivity activity;
+  private final Map<DecodeHintType,Object> hints;
+  private Handler handler;
+  private final CountDownLatch handlerInitLatch;
+
+  DecodeThread(CaptureActivity activity,
+               Collection<BarcodeFormat> decodeFormats,
+               Map<DecodeHintType,?> baseHints,
+               String characterSet,
+               ResultPointCallback resultPointCallback) {
+
+    this.activity = activity;
+    handlerInitLatch = new CountDownLatch(1);
+
+    hints = new EnumMap<DecodeHintType,Object>(DecodeHintType.class);
+    if (baseHints != null) {
+      hints.putAll(baseHints);
+    }
+
+    // The prefs can't change while the thread is running, so pick them up once here.
+    if (decodeFormats == null || decodeFormats.isEmpty()) {
+      SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
+      decodeFormats = EnumSet.noneOf(BarcodeFormat.class);
+      if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D, false)) {
+        decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
+      }
+      if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, false)) {
+        decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
+      }
+      if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX, false)) {
+        decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
+      }
+    }
+    hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
+
+    if (characterSet != null) {
+      hints.put(DecodeHintType.CHARACTER_SET, characterSet);
+    }
+    hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
+    Log.i("DecodeThread", "Hints: " + hints);
+  }
+
+  Handler getHandler() {
+    try {
+      handlerInitLatch.await();
+    } catch (InterruptedException ie) {
+      // continue?
+    }
+    return handler;
+  }
+
+  @Override
+  public void run() {
+    Looper.prepare();
+    handler = new DecodeHandler(activity, hints);
+    handlerInitLatch.countDown();
+    Looper.loop();
+  }
+
+}

+ 49 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/FinishListener.java

@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+
+/**
+ * Simple listener used to exit the app in a few cases.
+ *
+ * @author Sean Owen
+ */
+public final class FinishListener implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+
+  private final Activity activityToFinish;
+
+  public FinishListener(Activity activityToFinish) {
+    this.activityToFinish = activityToFinish;
+  }
+
+  @Override
+  public void onCancel(DialogInterface dialogInterface) {
+    run();
+  }
+
+  @Override
+  public void onClick(DialogInterface dialogInterface, int i) {
+    run();
+  }
+
+  private void run() {
+    activityToFinish.finish();
+  }
+
+}

+ 116 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/InactivityTimer.java

@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.BatteryManager;
+import android.util.Log;
+
+/**
+ * Finishes an activity after a period of inactivity if the device is on battery power.
+ */
+final class InactivityTimer {
+
+  private static final String TAG = InactivityTimer.class.getSimpleName();
+
+  private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L;
+
+  private final Activity activity;
+  private final BroadcastReceiver powerStatusReceiver;
+  private boolean registered;
+  private AsyncTask<?,?,?> inactivityTask;
+
+  InactivityTimer(Activity activity) {
+    this.activity = activity;
+    powerStatusReceiver = new PowerStatusReceiver();
+    registered = false;
+    onActivity();
+  }
+
+  synchronized void onActivity() {
+    cancel();
+    inactivityTask = new InactivityAsyncTask();
+    inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+  }
+
+  public synchronized void onPause() {
+    cancel();
+    if (registered) {
+      activity.unregisterReceiver(powerStatusReceiver);
+      registered = false;
+    } else {
+      Log.w(TAG, "PowerStatusReceiver was never registered?");
+    }
+  }
+
+  public synchronized void onResume() {
+    if (registered) {
+      Log.w(TAG, "PowerStatusReceiver was already registered?");
+    } else {
+      activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+      registered = true;
+    }
+    onActivity();
+  }
+
+  private synchronized void cancel() {
+    AsyncTask<?,?,?> task = inactivityTask;
+    if (task != null) {
+      task.cancel(true);
+      inactivityTask = null;
+    }
+  }
+
+  void shutdown() {
+    cancel();
+  }
+
+  private final class PowerStatusReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent){
+      if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+        // 0 indicates that we're on battery
+        boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0;
+        if (onBatteryNow) {
+          InactivityTimer.this.onActivity();
+        } else {
+          InactivityTimer.this.cancel();
+        }
+      }
+    }
+  }
+
+  private final class InactivityAsyncTask extends AsyncTask<Object,Object,Object> {
+    @Override
+    protected Object doInBackground(Object... objects) {
+      try {
+        Thread.sleep(INACTIVITY_DELAY_MS);
+        Log.i(TAG, "Finishing activity due to inactivity");
+        activity.finish();
+      } catch (InterruptedException e) {
+        // continue without killing
+      }
+      return null;
+    }
+  }
+
+}

+ 261 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/Intents.java

@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+/**
+ * This class provides the constants to use when sending an Intent to Barcode Scanner.
+ * These strings are effectively API and cannot be changed.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class Intents {
+  private Intents() {
+  }
+
+  public static final class Scan {
+    /**
+     * Send this intent to open the Barcodes app in scanning mode, find a barcode, and return
+     * the results.
+     */
+    public static final String ACTION = "com.google.zxing.client.android.SCAN";
+
+    /**
+     * By default, sending this will decode all barcodes that we understand. However it
+     * may be useful to limit scanning to certain formats. Use
+     * {@link android.content.Intent#putExtra(String, String)} with one of the values below.
+     *
+     * Setting this is effectively shorthand for setting explicit formats with {@link #FORMATS}.
+     * It is overridden by that setting.
+     */
+    public static final String MODE = "SCAN_MODE";
+
+    /**
+     * Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
+     * prices, reviews, etc. for products.
+     */
+    public static final String PRODUCT_MODE = "PRODUCT_MODE";
+
+    /**
+     * Decode only 1D barcodes.
+     */
+    public static final String ONE_D_MODE = "ONE_D_MODE";
+
+    /**
+     * Decode only QR codes.
+     */
+    public static final String QR_CODE_MODE = "QR_CODE_MODE";
+
+    /**
+     * Decode only Data Matrix codes.
+     */
+    public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";
+
+    /**
+     * Comma-separated list of formats to scan for. The values must match the names of
+     * {@link com.google.zxing.BarcodeFormat}s, e.g. {@link com.google.zxing.BarcodeFormat#EAN_13}.
+     * Example: "EAN_13,EAN_8,QR_CODE". This overrides {@link #MODE}.
+     */
+    public static final String FORMATS = "SCAN_FORMATS";
+
+    /**
+     * @see com.google.zxing.DecodeHintType#CHARACTER_SET
+     */
+    public static final String CHARACTER_SET = "CHARACTER_SET";
+
+    /**
+     * Optional parameters to specify the width and height of the scanning rectangle in pixels.
+     * The app will try to honor these, but will clamp them to the size of the preview frame.
+     * You should specify both or neither, and pass the size as an int.
+     */
+    public static final String WIDTH = "SCAN_WIDTH";
+    public static final String HEIGHT = "SCAN_HEIGHT";
+
+    /**
+     * Desired duration in milliseconds for which to pause after a successful scan before
+     * returning to the calling intent. Specified as a long, not an integer!
+     * For example: 1000L, not 1000.
+     */
+    public static final String RESULT_DISPLAY_DURATION_MS = "RESULT_DISPLAY_DURATION_MS";
+
+    /**
+     * Prompt to show on-screen when scanning by intent. Specified as a {@link String}.
+     */
+    public static final String PROMPT_MESSAGE = "PROMPT_MESSAGE";
+
+    /**
+     * If a barcode is found, Barcodes returns {@link android.app.Activity#RESULT_OK} to
+     * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}
+     * of the app which requested the scan via
+     * {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}
+     * The barcodes contents can be retrieved with
+     * {@link android.content.Intent#getStringExtra(String)}.
+     * If the user presses Back, the result code will be {@link android.app.Activity#RESULT_CANCELED}.
+     */
+    public static final String RESULT = "SCAN_RESULT";
+
+    /**
+     * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_FORMAT}
+     * to determine which barcode format was found.
+     * See {@link com.google.zxing.BarcodeFormat} for possible values.
+     */
+    public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";
+
+    /**
+     * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_UPC_EAN_EXTENSION}
+     * to return the content of any UPC extension barcode that was also found. Only applicable
+     * to {@link com.google.zxing.BarcodeFormat#UPC_A} and {@link com.google.zxing.BarcodeFormat#EAN_13}
+     * formats.
+     */
+    public static final String RESULT_UPC_EAN_EXTENSION = "SCAN_RESULT_UPC_EAN_EXTENSION";
+
+    /**
+     * Call {@link android.content.Intent#getByteArrayExtra(String)} with {@link #RESULT_BYTES}
+     * to get a {@code byte[]} of raw bytes in the barcode, if available.
+     */
+    public static final String RESULT_BYTES = "SCAN_RESULT_BYTES";
+
+    /**
+     * Key for the value of {@link com.google.zxing.ResultMetadataType#ORIENTATION}, if available.
+     * Call {@link android.content.Intent#getIntArrayExtra(String)} with {@link #RESULT_ORIENTATION}.
+     */
+    public static final String RESULT_ORIENTATION = "SCAN_RESULT_ORIENTATION";
+
+    /**
+     * Key for the value of {@link com.google.zxing.ResultMetadataType#ERROR_CORRECTION_LEVEL}, if available.
+     * Call {@link android.content.Intent#getStringExtra(String)} with {@link #RESULT_ERROR_CORRECTION_LEVEL}.
+     */
+    public static final String RESULT_ERROR_CORRECTION_LEVEL = "SCAN_RESULT_ERROR_CORRECTION_LEVEL";
+
+    /**
+     * Prefix for keys that map to the values of {@link com.google.zxing.ResultMetadataType#BYTE_SEGMENTS},
+     * if available. The actual values will be set under a series of keys formed by adding 0, 1, 2, ...
+     * to this prefix. So the first byte segment is under key "SCAN_RESULT_BYTE_SEGMENTS_0" for example.
+     * Call {@link android.content.Intent#getByteArrayExtra(String)} with these keys.
+     */
+    public static final String RESULT_BYTE_SEGMENTS_PREFIX = "SCAN_RESULT_BYTE_SEGMENTS_";
+
+    /**
+     * Setting this to false will not save scanned codes in the history. Specified as a {@code boolean}.
+     */
+    public static final String SAVE_HISTORY = "SAVE_HISTORY";
+
+    private Scan() {
+    }
+  }
+
+  public static final class History {
+
+    public static final String ITEM_NUMBER = "ITEM_NUMBER";
+
+    private History() {
+    }
+  }
+
+  public static final class Encode {
+    /**
+     * Send this intent to encode a piece of data as a QR code and display it full screen, so
+     * that another person can scan the barcode from your screen.
+     */
+    public static final String ACTION = "com.google.zxing.client.android.ENCODE";
+
+    /**
+     * The data to encode. Use {@link android.content.Intent#putExtra(String, String)} or
+     * {@link android.content.Intent#putExtra(String, android.os.Bundle)},
+     * depending on the type and format specified. Non-QR Code formats should
+     * just use a String here. For QR Code, see Contents for details.
+     */
+    public static final String DATA = "ENCODE_DATA";
+
+    /**
+     * The type of data being supplied if the format is QR Code. Use
+     * {@link android.content.Intent#putExtra(String, String)} with one of {@link Contents.Type}.
+     */
+    public static final String TYPE = "ENCODE_TYPE";
+
+    /**
+     * The barcode format to be displayed. If this isn't specified or is blank,
+     * it defaults to QR Code. Use {@link android.content.Intent#putExtra(String, String)}, where
+     * format is one of {@link com.google.zxing.BarcodeFormat}.
+     */
+    public static final String FORMAT = "ENCODE_FORMAT";
+
+    /**
+     * Normally the contents of the barcode are displayed to the user in a TextView. Setting this
+     * boolean to false will hide that TextView, showing only the encode barcode.
+     */
+    public static final String SHOW_CONTENTS = "ENCODE_SHOW_CONTENTS";
+
+    private Encode() {
+    }
+  }
+
+  public static final class SearchBookContents {
+    /**
+     * Use Google Book Search to search the contents of the book provided.
+     */
+    public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
+
+    /**
+     * The book to search, identified by ISBN number.
+     */
+    public static final String ISBN = "ISBN";
+
+    /**
+     * An optional field which is the text to search for.
+     */
+    public static final String QUERY = "QUERY";
+
+    private SearchBookContents() {
+    }
+  }
+
+  public static final class WifiConnect {
+    /**
+     * Internal intent used to trigger connection to a wi-fi network.
+     */
+    public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";
+
+    /**
+     * The network to connect to, all the configuration provided here.
+     */
+    public static final String SSID = "SSID";
+
+    /**
+     * The network to connect to, all the configuration provided here.
+     */
+    public static final String TYPE = "TYPE";
+
+    /**
+     * The network to connect to, all the configuration provided here.
+     */
+    public static final String PASSWORD = "PASSWORD";
+
+    private WifiConnect() {
+    }
+  }
+
+  public static final class Share {
+    /**
+     * Give the user a choice of items to encode as a barcode, then render it as a QR Code and
+     * display onscreen for a friend to scan with their phone.
+     */
+    public static final String ACTION = "com.google.zxing.client.android.SHARE";
+
+    private Share() {
+    }
+  }
+}

+ 35 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/ViewfinderResultPointCallback.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import com.google.zxing.ResultPoint;
+import com.google.zxing.ResultPointCallback;
+
+final class ViewfinderResultPointCallback implements ResultPointCallback {
+
+  private final ViewfinderView viewfinderView;
+
+  ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
+    this.viewfinderView = viewfinderView;
+  }
+
+  @Override
+  public void foundPossibleResultPoint(ResultPoint point) {
+    viewfinderView.addPossibleResultPoint(point);
+  }
+
+}

+ 189 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/CodeScanner/ViewfinderView.java

@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.CodeScanner;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.google.zxing.ResultPoint;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.apexdrivers.camera.CameraManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
+ * transparency outside it, as well as the laser scanner animation and result points.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class ViewfinderView extends View {
+
+  private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
+  private static final long ANIMATION_DELAY = 80L;
+  private static final int CURRENT_POINT_OPACITY = 0xA0;
+  private static final int MAX_RESULT_POINTS = 20;
+  private static final int POINT_SIZE = 6;
+
+  private CameraManager cameraManager;
+  private final Paint paint;
+  private Bitmap resultBitmap;
+  private final int maskColor;
+  private final int resultColor;
+  private final int laserColor;
+  private final int resultPointColor;
+  private int scannerAlpha;
+  private List<ResultPoint> possibleResultPoints;
+  private List<ResultPoint> lastPossibleResultPoints;
+
+  // This constructor is used when the class is built from an XML resource.
+  public ViewfinderView(Context context, AttributeSet attrs) {
+    super(context, attrs);
+
+    // Initialize these once for performance rather than calling them every time in onDraw().
+    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    Resources resources = getResources();
+    maskColor = resources.getColor(R.color.viewfinder_mask);
+    resultColor = resources.getColor(R.color.result_view);
+    laserColor = resources.getColor(R.color.viewfinder_laser);
+    resultPointColor = resources.getColor(R.color.possible_result_points);
+    scannerAlpha = 0;
+    possibleResultPoints = new ArrayList<ResultPoint>(5);
+    lastPossibleResultPoints = null;
+  }
+
+  public void setCameraManager(CameraManager cameraManager) {
+    this.cameraManager = cameraManager;
+  }
+
+  @Override
+  public void onDraw(Canvas canvas) {
+    if (cameraManager == null) {
+      return; // not ready yet, early draw before done configuring
+    }
+    Rect frame = cameraManager.getFramingRect();
+    Rect previewFrame = cameraManager.getFramingRectInPreview();
+    if (frame == null || previewFrame == null) {
+      return;
+    }
+    int width = canvas.getWidth();
+    int height = canvas.getHeight();
+
+    // Draw the exterior (i.e. outside the framing rect) darkened
+    paint.setColor(resultBitmap != null ? resultColor : maskColor);
+    canvas.drawRect(0, 0, width, frame.top, paint);
+    canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
+    canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
+    canvas.drawRect(0, frame.bottom + 1, width, height, paint);
+
+    if (resultBitmap != null) {
+      // Draw the opaque result bitmap over the scanning rectangle
+      paint.setAlpha(CURRENT_POINT_OPACITY);
+      canvas.drawBitmap(resultBitmap, null, frame, paint);
+    } else {
+
+      // Draw a red "laser scanner" line through the middle to show decoding is active
+      paint.setColor(laserColor);
+      paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
+      scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
+      int middle = frame.height() / 2 + frame.top;
+      canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
+      
+      float scaleX = frame.width() / (float) previewFrame.width();
+      float scaleY = frame.height() / (float) previewFrame.height();
+
+      List<ResultPoint> currentPossible = possibleResultPoints;
+      List<ResultPoint> currentLast = lastPossibleResultPoints;
+      int frameLeft = frame.left;
+      int frameTop = frame.top;
+      if (currentPossible.isEmpty()) {
+        lastPossibleResultPoints = null;
+      } else {
+        possibleResultPoints = new ArrayList<ResultPoint>(5);
+        lastPossibleResultPoints = currentPossible;
+        paint.setAlpha(CURRENT_POINT_OPACITY);
+        paint.setColor(resultPointColor);
+        synchronized (currentPossible) {
+          for (ResultPoint point : currentPossible) {
+            canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
+                              frameTop + (int) (point.getY() * scaleY),
+                              POINT_SIZE, paint);
+          }
+        }
+      }
+      if (currentLast != null) {
+        paint.setAlpha(CURRENT_POINT_OPACITY / 2);
+        paint.setColor(resultPointColor);
+        synchronized (currentLast) {
+          float radius = POINT_SIZE / 2.0f;
+          for (ResultPoint point : currentLast) {
+            canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
+                              frameTop + (int) (point.getY() * scaleY),
+                              radius, paint);
+          }
+        }
+      }
+
+      // Request another update at the animation interval, but only repaint the laser line,
+      // not the entire viewfinder mask.
+      postInvalidateDelayed(ANIMATION_DELAY,
+                            frame.left - POINT_SIZE,
+                            frame.top - POINT_SIZE,
+                            frame.right + POINT_SIZE,
+                            frame.bottom + POINT_SIZE);
+    }
+  }
+
+  public void drawViewfinder() {
+    Bitmap resultBitmap = this.resultBitmap;
+    this.resultBitmap = null;
+    if (resultBitmap != null) {
+      resultBitmap.recycle();
+    }
+    invalidate();
+  }
+
+  /**
+   * Draw a bitmap with the result points highlighted instead of the live scanning display.
+   *
+   * @param barcode An image of the decoded barcode.
+   */
+  public void drawResultBitmap(Bitmap barcode) {
+    resultBitmap = barcode;
+    invalidate();
+  }
+
+  public void addPossibleResultPoint(ResultPoint point) {
+    List<ResultPoint> points = possibleResultPoints;
+    synchronized (points) {
+      points.add(point);
+      int size = points.size();
+      if (size > MAX_RESULT_POINTS) {
+        // trim it
+        points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
+      }
+    }
+  }
+
+}

+ 402 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/DetailActivity.java

@@ -0,0 +1,402 @@
+package com.usai.redant.apexdrivers.Detail;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ExpandableListView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.PopupWindow;
+import android.widget.SimpleAdapter;
+import android.widget.TextView;
+
+import com.usai.redant.apexdrivers.Detail.Model.DetailActionSelectionModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailLocationModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailSubActionModel;
+import com.usai.redant.apexdrivers.Home.HomeFragment;
+import com.usai.redant.apexdrivers.MainActivity;
+import com.usai.redant.apexdrivers.Network.Network;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.apexdrivers.Update.UpdateActivity;
+import com.usai.redant.rautils.Utils.RAUtil;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.usai.redant.apexdrivers.Detail.Model.DetailSubActionModel.DetailActionSubType.DetailActionSubTypeEnum;
+import static com.usai.redant.rautils.Utils.Network.RESULT_TRUE;
+
+public class DetailActivity extends AppCompatActivity implements DetailAdapter.DetailActionDelegate {
+
+
+    private final static String IntentOrderIDKey = "orderID";
+    public static Intent build(Context context, String orderID) {
+
+        if (context == null) {
+            return null;
+        }
+
+        Intent intent = new Intent(context,DetailActivity.class);
+        if (orderID != null) {
+            intent.putExtra(IntentOrderIDKey,orderID);
+        }
+        return intent;
+    }
+
+    private String mOrderID;
+    private Context mCtx = this;
+    private DetailActivity self = this;
+    private ExpandableListView mListView;
+    private DetailAdapter mAdapter;
+    private ArrayList<DetailSectionModel> mSectionArray = new ArrayList<>();
+    private JSONObject mJson;
+
+    private DetailHandler mHandler;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_detail);
+
+        android.support.v7.app.ActionBar actionBar = getSupportActionBar();
+        if(actionBar != null){
+            actionBar.setHomeButtonEnabled(true);
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
+
+        mOrderID = getIntent().getStringExtra(IntentOrderIDKey);
+        mHandler = new DetailHandler(this);
+
+        mListView = findViewById(R.id.detail_list_view);
+        mAdapter = new DetailAdapter(mCtx,self,mSectionArray);
+
+        mListView.setAdapter(mAdapter);
+        mListView.setDivider(new ColorDrawable(Color.GRAY));
+        mListView.setDividerHeight(RAUtil.dp2px(mCtx,1));
+        mListView.setGroupIndicator(null);
+
+
+        loadData();
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                this.finish(); // back button
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /**
+     * Data
+     * */
+    private void loadData() {
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                JSONObject json = com.usai.redant.apexdrivers.Network.Network.requestOrderDetail(mCtx,mOrderID);
+
+                Message msg = new Message();
+                msg.what = DetailHandler.DetailActionReloadData;
+                msg.obj = json;
+                mHandler.sendMessage(msg);
+            }
+
+        }).start();
+    }
+
+    private void report(final String url, final Bundle params) {
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                JSONObject json = Network.report(url,params);
+
+                Message msg = new Message();
+                msg.what = DetailHandler.DetailActionRemote;
+                msg.obj = json;
+                mHandler.sendMessage(msg);
+
+            }
+        }).start();
+
+    }
+
+    private void handleEnumAction(View view,DetailSubActionModel actionModel) {
+
+        showWindow(view,actionModel.enums);
+    }
+
+    /**
+     * Detail Action
+     * */
+
+    @Override
+    public void performAction(View view,DetailSubActionModel actionModel) {
+
+        switch (actionModel.actionType) {
+            case DetailSubActionModel.DetailActionType.DetailActionTypeLocal: {
+
+                if (actionModel.actionSubType == DetailActionSubTypeEnum) {
+                    handleEnumAction(view,actionModel);
+                }
+
+            }
+            break;
+            case DetailSubActionModel.DetailActionType.DetailActionTypeRemote: {
+                report(actionModel.url,actionModel.params);
+            }
+            break;
+            default:
+                break;
+        }
+
+    }
+
+    @Override
+    public void navigationTo(DetailLocationModel locationModel) {
+
+    }
+
+
+    /**
+     * Handler
+     * */
+
+    private static final class DetailHandler extends Handler {
+
+        static final int DetailActionReloadData = 0;
+        static final int DetailActionRemote = 1;
+
+        WeakReference<DetailActivity> mWeakDetail;
+
+        public DetailHandler(DetailActivity activity) {
+            mWeakDetail = new WeakReference<>(activity);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+
+            DetailActivity activity = mWeakDetail.get();
+            switch (msg.what) {
+                case DetailActionReloadData: {
+
+                    JSONObject json = (JSONObject) msg.obj;
+
+                    if (json != null) {
+
+                        try {
+                            int restul = json.getInt("result");
+                            if (restul == RESULT_TRUE) {
+
+                                JSONArray sectionArr = json.optJSONArray("sections");
+                                if (sectionArr != null) {
+
+                                    activity.mJson = json;
+                                    activity.mSectionArray.clear();
+
+                                    for (int i = 0; i < sectionArr.length(); i++) {
+
+                                        JSONObject section = sectionArr.getJSONObject(i);
+                                        DetailSectionModel model = new DetailSectionModel();
+
+                                        model.title = section.optString("title");
+                                        model.setValues(section.optJSONArray("values"));
+
+                                        activity.mSectionArray.add(model);
+                                    }
+
+
+
+                                }
+
+                            } else {
+                                // error
+                            }
+
+                        } catch (JSONException e) {
+                            e.printStackTrace();
+                            // error
+                        }
+                    } else {
+                        // error
+                    }
+                    /**
+                     * 手动调用打开/关闭 Group,否则默认关闭
+                     * */
+                    if (activity.mSectionArray.size() > 0) {
+                        for (int i = 0; i < activity.mSectionArray.size(); i++) {
+                            activity.mListView.expandGroup(i);
+                        }
+                    }
+
+                    activity.mAdapter.notifyDataSetChanged();
+                }
+                break;
+                case DetailActionRemote: {
+
+                    JSONObject json = (JSONObject)msg.obj;
+                    if (json != null) {
+                        int result = json.optInt("result");
+                        if (result == RESULT_TRUE) {
+
+                            Intent intent = new Intent(activity, MainActivity.class);
+                            activity.startActivity(intent);
+                        } else {
+                            // error;
+                        }
+                    } else {
+                        // error
+                    }
+
+                }
+                break;
+                default:{
+
+                }
+                break;
+            }
+        }
+    }
+
+    /**
+     * Pop
+     * */
+    private PopupWindow popupWindow;
+    private ListView popListView;
+    private PopAdapter popAdapter;
+    private View popView;
+    private void showWindow(View parent, final ArrayList<DetailActionSelectionModel> models) {
+
+        LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        popView = layoutInflater.inflate(R.layout.pop_list_view, null);
+
+        popListView = (ListView) popView.findViewById(R.id.pop_list);
+
+        popAdapter = new PopAdapter(this, R.layout.pop_cell,models);
+        popListView.setAdapter(popAdapter);
+
+        // 创建一个PopuWidow对象
+        popupWindow = new PopupWindow(popView, RAUtil.dp2px(mCtx,250), RAUtil.dp2px(mCtx,300));
+
+        // 使其聚集
+        popupWindow.setFocusable(true);
+        // 设置允许在外点击消失
+        popupWindow.setOutsideTouchable(true);
+
+        popupWindow.update();
+
+        // 这个是为了点击“返回Back”也能使其消失,并且并不会影响你的背景
+        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.RED));
+        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+        // 显示的位置
+        int xPos = windowManager.getDefaultDisplay().getWidth() / 2 - popupWindow.getWidth() / 2;
+
+        popupWindow.showAsDropDown(parent, xPos, 0);
+//        popupWindow.showAsDropDown(parent);
+
+        popListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+            @Override
+            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
+
+
+                if (popupWindow != null) {
+                    popupWindow.dismiss();
+                }
+
+                DetailActionSelectionModel model = models.get(position);
+                Intent intent = UpdateActivity.build(mCtx,mOrderID,model.actionID,model.actionTitle);
+                mCtx.startActivity(intent);
+            }
+        });
+    }
+
+    private class PopAdapter extends ArrayAdapter<DetailActionSelectionModel> {
+
+        private Context ctx;
+        private int resId;
+        private ArrayList<DetailActionSelectionModel> selectionModels;
+
+        public PopAdapter(@NonNull Context context, int resource,ArrayList<DetailActionSelectionModel> selectionModels) {
+            super(context, resource);
+            ctx = context;
+            resId = resource;
+            this.selectionModels = selectionModels;
+        }
+
+        @Override
+        public int getCount() {
+
+            return selectionModels.size();
+        }
+
+        @NonNull
+        @Override
+        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+
+            PopHolder holder;
+            if (convertView == null) {
+
+                convertView = LayoutInflater.from(ctx).inflate(resId,null);
+                holder = new PopHolder(convertView);
+
+            } else {
+
+                holder = (PopHolder)convertView.getTag();
+            }
+
+            DetailActionSelectionModel model = selectionModels.get(position);
+            holder.bindPopModel(model);
+
+            return convertView;
+        }
+
+        private class PopHolder {
+
+            TextView titleTv;
+
+            PopHolder(View view) {
+
+                titleTv = view.findViewById(R.id.pop_title_tv);
+
+                view.setTag(this);
+            }
+
+            public void bindPopModel(DetailActionSelectionModel model) {
+                titleTv.setText(model.actionTitle);
+            }
+
+        }
+    }
+
+}

+ 386 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/DetailAdapter.java

@@ -0,0 +1,386 @@
+package com.usai.redant.apexdrivers.Detail;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.usai.redant.apexdrivers.Detail.Model.DetailActionModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailBaseModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailLocationModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailMultipleLineModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailSingleLineModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailSubActionModel;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.rautils.Utils.RAUtil;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+public class DetailAdapter extends BaseExpandableListAdapter {
+
+    private ArrayList<DetailSectionModel> mSections;
+    private Context mCtx;
+    private WeakReference<DetailActionDelegate> mDelegate;
+
+    DetailAdapter(Context ctx, DetailActionDelegate delegate, ArrayList<DetailSectionModel> sections) {
+        mCtx = ctx;
+        mSections = sections;
+        mDelegate = new WeakReference<>(delegate);
+    }
+
+    @Override
+    public int getGroupCount() {
+        if (mSections == null) {
+            return 0;
+        }
+        return mSections.size();
+    }
+
+    @Override
+    public int getChildrenCount(int groupPosition) {
+
+        DetailSectionModel sectionModel = mSections.get(groupPosition);
+
+        return sectionModel.itemCount();
+    }
+
+    @Override
+    public Object getGroup(int groupPosition) {
+        return mSections.get(groupPosition);
+    }
+
+    @Override
+    public Object getChild(int groupPosition, int childPosition) {
+        DetailSectionModel sectionModel = mSections.get(groupPosition);
+        return sectionModel.itemAtIndex(childPosition);
+    }
+
+    @Override
+    public long getGroupId(int groupPosition) {
+        return groupPosition;
+    }
+
+    @Override
+    public long getChildId(int groupPosition, int childPosition) {
+        return childPosition;
+    }
+
+    @Override
+    public int getChildTypeCount() {
+
+        return 4;
+    }
+
+    @Override
+    public int getChildType(int groupPosition, int childPosition) {
+
+        DetailSectionModel sectionModel = mSections.get(groupPosition);
+        DetailBaseModel model = sectionModel.itemAtIndex(childPosition);
+
+        return model.type;
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    @Override
+    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
+
+        if (mCtx == null) {
+            return null;
+        }
+
+        SectionHolder holder;
+        if (convertView == null) {
+
+            convertView = LayoutInflater.from(mCtx).inflate(R.layout.section_header,null);
+            holder = new SectionHolder(convertView);
+
+        } else {
+            holder = (SectionHolder) convertView.getTag();
+        }
+        DetailSectionModel sectionModel = mSections.get(groupPosition);
+        holder.bindSecionModel(sectionModel);
+
+
+        return convertView;
+    }
+
+    @Override
+    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
+        if (mCtx == null) {
+            return null;
+        }
+
+        DetailSectionModel sectionModel = mSections.get(groupPosition);
+        DetailBaseModel model = sectionModel.itemAtIndex(childPosition);
+
+        switch (getChildType(groupPosition,childPosition)) {
+            case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeSingleLine: {
+
+                SingleLineHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.detail_single_line_cell,null);
+                    holder = new SingleLineHolder(convertView);
+
+                } else {
+
+                    holder = (SingleLineHolder) convertView.getTag();
+                }
+
+                DetailSingleLineModel singleLineModel = (DetailSingleLineModel)model;
+
+                holder.bindSingleLineModel(singleLineModel);
+
+            }
+            break;
+            case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeMultipleLine: {
+
+                MultipleLineHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.detail_mult_line_cell,null);
+                    holder = new MultipleLineHolder(convertView);
+
+                } else {
+
+                    holder = (MultipleLineHolder)convertView.getTag();
+                }
+
+                DetailMultipleLineModel multipleLineModel = (DetailMultipleLineModel)model;
+
+                holder.bindMultLineModel(multipleLineModel);
+
+            }
+            break;
+            case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeAction: {
+
+                ActionHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.detail_action_cell,null);
+                    holder = new ActionHolder(convertView);
+
+                } else {
+
+                    holder = (ActionHolder) convertView.getTag();
+                }
+                DetailActionModel actionModel = (DetailActionModel)model;
+
+                holder.bindActionModel(actionModel);
+
+            }
+            break;
+            case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeLocation: {
+
+                LocationHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.detail_location_cell,null);
+                    holder = new LocationHolder(convertView);
+
+                } else {
+
+                    holder = (LocationHolder)convertView.getTag();
+                }
+                DetailLocationModel locationModel = (DetailLocationModel)model;
+
+                holder.bindLocationModel(locationModel);
+            }
+            break;
+            default:
+                break;
+        }
+
+
+        return convertView;
+    }
+
+    @Override
+    public boolean isChildSelectable(int groupPosition, int childPosition) {
+        return false;
+    }
+
+    private class SectionHolder {
+
+        TextView titleTv;
+        Button expandBtn;
+        SectionHolder(View view) {
+
+            titleTv = view.findViewById(R.id.header_title_tv);
+            expandBtn = view.findViewById(R.id.section_switch_btn);
+            expandBtn.setVisibility(View.GONE);
+
+            view.setTag(this);
+        }
+
+        public void bindSecionModel(DetailSectionModel model) {
+            titleTv.setText(model.title);
+        }
+    }
+
+    private class SingleLineHolder {
+
+        TextView titleTv;
+        TextView valueTv;
+
+        SingleLineHolder(View view) {
+
+            titleTv = view.findViewById(R.id.detail_title_tv);
+            valueTv = view.findViewById(R.id.detail_value_tv);
+
+            view.setTag(this);
+        }
+
+        public void bindSingleLineModel(DetailSingleLineModel model) {
+
+            titleTv.setText(model.title);
+            valueTv.setText(model.value);
+        }
+    }
+
+    private class MultipleLineHolder {
+
+        TextView valueTv;
+
+        MultipleLineHolder(View view) {
+
+            valueTv = view.findViewById(R.id.detail_multiple_tv);
+
+            view.setTag(this);
+        }
+
+        public void bindMultLineModel(DetailMultipleLineModel model) {
+            valueTv.setText(model.value);
+        }
+    }
+
+    private class ActionHolder {
+
+        LinearLayout linearLayout;
+
+        ActionHolder(View view) {
+
+            linearLayout = (LinearLayout) view;
+
+            view.setTag(this);
+        }
+
+        public void bindActionModel(DetailActionModel model) {
+
+            linearLayout.removeAllViews();
+
+            int actionCount = model.actionCount();
+            if (actionCount == 0) {
+                return;
+            }
+
+            int colCount = 2;
+            int rowCount = actionCount / colCount;
+            if (actionCount % colCount != 0) {
+                rowCount++;
+            }
+
+
+            for (int row = 0; row < rowCount; row++) {
+
+                LinearLayout ll = new LinearLayout(mCtx);
+                for (int col = 0; col < colCount; col++) {
+
+                    final int index = row * colCount + col;
+
+                    RelativeLayout container = new RelativeLayout(mCtx);
+                    LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT,1);
+                    ll.addView(container,layoutParams);
+
+                    Button btn = new Button(mCtx);
+                    RelativeLayout.LayoutParams btnLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+                    btnLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+
+                    int marginH = RAUtil.dp2px(mCtx,5);
+                    int marginT = RAUtil.dp2px(mCtx,2.5f);
+                    int marginB = RAUtil.dp2px(mCtx,2.5f);
+                    if (row == rowCount - 1) {
+                        marginB = RAUtil.dp2px(mCtx,5);
+                    } else if (row == 0) {
+                        marginT = RAUtil.dp2px(mCtx,5);
+                    }
+
+                    btnLayoutParams.setMargins(marginH,marginT,marginH,marginB);
+                    container.addView(btn,btnLayoutParams);
+
+                    final DetailSubActionModel subActionModel = model.actionModelForIndex(index);
+                    btn.setText(subActionModel.actionTitle);
+                    btn.setAllCaps(false);
+
+                    btn.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            if (mDelegate != null) {
+                                mDelegate.get().performAction(v,subActionModel);
+                            }
+                        }
+                    });
+
+                    if (index + 1 ==  actionCount) {
+                        break;
+                    }
+
+                }
+
+                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+                linearLayout.addView(ll,layoutParams);
+            }
+
+        }
+    }
+
+    private class LocationHolder {
+
+        TextView titleTv;
+        TextView locationTv;
+        Button navigationBtn;
+        WeakReference<DetailLocationModel> mWeakLocation;
+
+        LocationHolder(View view) {
+
+            titleTv = view.findViewById(R.id.detail_location_title_tv);
+            locationTv = view.findViewById(R.id.detail_location_value_tv);
+            navigationBtn = view.findViewById(R.id.detail_location_nav_btn);
+            navigationBtn.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (mWeakLocation != null && mDelegate != null) {
+                        DetailLocationModel model = mWeakLocation.get();
+                        mDelegate.get().navigationTo(model);
+                    }
+                }
+            });
+
+            view.setTag(this);
+        }
+
+        public void bindLocationModel(DetailLocationModel model) {
+
+            titleTv.setText(model.title);
+            locationTv.setText(model.location);
+
+            mWeakLocation = new WeakReference<>(model);
+        }
+    }
+
+    public interface DetailActionDelegate {
+
+        void performAction(View view,DetailSubActionModel actionModel);
+        void navigationTo(DetailLocationModel locationModel);
+    }
+}

+ 93 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/DetailSectionModel.java

@@ -0,0 +1,93 @@
+package com.usai.redant.apexdrivers.Detail;
+
+import com.usai.redant.apexdrivers.Detail.Model.DetailActionModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailBaseModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailLocationModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailMultipleLineModel;
+import com.usai.redant.apexdrivers.Detail.Model.DetailSingleLineModel;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+
+public class DetailSectionModel {
+
+    public ArrayList<DetailBaseModel> values = new ArrayList<>();
+    public String title;
+
+    public int itemCount() {
+        if (values == null) {
+            return 0;
+        }
+        return values.size();
+    }
+
+    public DetailBaseModel itemAtIndex(int index) {
+        if (values == null || index >= values.size()) {
+            return null;
+        }
+        return values.get(index);
+    }
+
+    public void setValues(JSONArray values) {
+        this.values.clear();
+        if (values == null) {
+            return;
+        } else {
+
+            for (int i = 0; i < values.length(); i++) {
+
+                JSONObject value = values.optJSONObject(i);
+                if (value != null) {
+                    int type = value.optInt("type",-1);
+                    switch (type) {
+                        case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeSingleLine: {
+                            DetailSingleLineModel model = new DetailSingleLineModel();
+
+                            model.title = value.optString("title");
+                            model.value = value.optString("value");
+                            model.type = type;
+
+                            this.values.add(model);
+                        }
+                        break;
+                        case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeMultipleLine: {
+                            DetailMultipleLineModel model = new DetailMultipleLineModel();
+
+                            model.value = value.optString("value");
+                            model.type = type;
+
+                            this.values.add(model);
+                        }
+                        break;
+                        case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeAction: {
+
+                            DetailActionModel model = new DetailActionModel();
+
+                            model.setActions(value.optJSONArray("actions"));
+                            model.type = type;
+
+                            this.values.add(model);
+                        }
+                        break;
+                        case DetailBaseModel.OrderDetailValueType.OderDetailValueTypeLocation: {
+
+                            DetailLocationModel model = new DetailLocationModel();
+
+                            model.title = value.optString("title");
+                            model.location = value.optString("location");
+                            model.type = type;
+
+                            this.values.add(model);
+                        }
+                        break;
+                        default:
+                            break;
+                    }
+                }
+            }
+        }
+    }
+
+}

+ 78 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailActionModel.java

@@ -0,0 +1,78 @@
+package com.usai.redant.apexdrivers.Detail.Model;
+
+import com.usai.redant.rautils.Utils.RAUtil;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+
+public class DetailActionModel extends DetailBaseModel{
+
+    public ArrayList<DetailSubActionModel> actions = new ArrayList<>();
+
+    public int actionCount() {
+        if (actions == null) {
+            return 0;
+        }
+        return actions.size();
+    }
+
+    public DetailSubActionModel actionModelForIndex(int index) {
+        if (actions == null || index >= actions.size()) {
+            return null;
+        }
+        return actions.get(index);
+    }
+
+    public void setActions(JSONArray actions) {
+
+        this.actions.clear();
+        if (actions == null) {
+
+            return;
+        } else  {
+
+            for (int i = 0; i < actions.length(); i++) {
+                JSONObject action = actions.optJSONObject(i);
+                if (action != null) {
+                    DetailSubActionModel subActionModel = new DetailSubActionModel();
+
+                    int type = action.optInt("actionType");
+                    int subType = action.optInt("actionSubType");
+
+                    subActionModel.actionType = type;
+                    subActionModel.actionSubType = subType;
+
+                    if (type == DetailSubActionModel.DetailActionType.DetailActionTypeLocal && subType == DetailSubActionModel.DetailActionSubType.DetailActionSubTypeEnum) {
+
+                        JSONArray enums = action.optJSONArray("enums");
+                        subActionModel.setEnums(enums);
+                    }
+
+                    if (type == DetailSubActionModel.DetailActionType.DetailActionTypeRemote) {
+
+                        String url = action.optString("url");
+                        subActionModel.url = url;
+
+                        JSONObject params = action.optJSONObject("params");
+                        if (params != null) {
+                            subActionModel.params = RAUtil.Json2Bundle(params);
+                        } else {
+                            subActionModel.params = null;
+                        }
+                    }
+
+                    String title = action.optString("actionTitle");
+                    subActionModel.actionTitle = title;
+
+                    this.actions.add(subActionModel);
+                }
+            }
+        }
+
+
+
+    }
+
+}

+ 9 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailActionSelectionModel.java

@@ -0,0 +1,9 @@
+package com.usai.redant.apexdrivers.Detail.Model;
+
+public class DetailActionSelectionModel {
+
+    public String actionTitle;
+    public String detailActionTitle;
+    public int actionID;
+
+}

+ 14 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailBaseModel.java

@@ -0,0 +1,14 @@
+package com.usai.redant.apexdrivers.Detail.Model;
+
+public class DetailBaseModel {
+
+    public static class OrderDetailValueType {
+        public static final int OderDetailValueTypeSingleLine = 0;
+        public static final int OderDetailValueTypeMultipleLine = 1;
+        public static final int OderDetailValueTypeAction = 2;
+        public static final int OderDetailValueTypeLocation = 3;
+    }
+
+    public int type;
+
+}

+ 8 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailLocationModel.java

@@ -0,0 +1,8 @@
+package com.usai.redant.apexdrivers.Detail.Model;
+
+public class DetailLocationModel extends DetailBaseModel {
+
+    public String title;
+    public String location;
+
+}

+ 6 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailMultipleLineModel.java

@@ -0,0 +1,6 @@
+package com.usai.redant.apexdrivers.Detail.Model;
+
+public class DetailMultipleLineModel extends DetailBaseModel {
+
+    public String value;
+}

+ 8 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailSingleLineModel.java

@@ -0,0 +1,8 @@
+package com.usai.redant.apexdrivers.Detail.Model;
+
+public class DetailSingleLineModel extends DetailBaseModel {
+
+    public String title;
+    public String value;
+
+}

+ 56 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Detail/Model/DetailSubActionModel.java

@@ -0,0 +1,56 @@
+package com.usai.redant.apexdrivers.Detail.Model;
+
+import android.os.Bundle;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+
+public class DetailSubActionModel {
+
+    public static class DetailActionType {
+        public static final int DetailActionTypeRemote = 0;
+        public static final int DetailActionTypeLocal = 1;
+    }
+
+    public static class DetailActionSubType {
+        public static final int DetailActionSubTypeEnum = 0;
+    }
+
+    public int actionType;
+    public int actionSubType;
+    public String actionTitle;
+
+    /**
+     * actionType == RADetailActionTypeLocal && actionSubType == RADetailActionSubTypeEnum
+     * */
+    public ArrayList<DetailActionSelectionModel> enums = new ArrayList();
+    public void setEnums(JSONArray enums) {
+
+        this.enums.clear();
+        if (enums == null) {
+            return;
+        }
+
+        for (int i = 0; i < enums.length(); i++) {
+            JSONObject enumObj = enums.optJSONObject(i);
+            if (enumObj != null) {
+                DetailActionSelectionModel model = new DetailActionSelectionModel();
+
+                model.actionID = enumObj.optInt("actionID");
+                model.actionTitle = enumObj.optString("actionTitle");
+                model.detailActionTitle = actionTitle;
+
+                this.enums.add(model);
+            }
+        }
+    }
+
+    /**
+     * actionType == RADetailActionTypeRemote
+     * */
+    public String url;
+    public Bundle params;
+
+}

+ 477 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Home/HomeFragment.java

@@ -0,0 +1,477 @@
+package com.usai.redant.apexdrivers.Home;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.Button;
+import android.widget.ExpandableListView;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+
+import com.usai.redant.apexdrivers.Detail.DetailActivity;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.rautils.Utils.Network;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+public class HomeFragment extends Fragment {
+
+
+    private Context mCtx;
+    private HomeFragment self = this;
+    private ExpandableListView mListView;
+    private HomeListAdapter mAdapter;
+    private ArrayList<HomeSectionModel> mSectionArray = new ArrayList<>();
+    private HomeHandler mHandler = new HomeHandler(this);
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+
+        /**
+         * 直接inflate并返回的,结果是看不到View
+         * */
+        View view = super.onCreateView(inflater,container,savedInstanceState);
+        if (view == null) {//
+            view = inflater.inflate(R.layout.fragment_home, container, false);
+        }
+        ViewGroup parent = (ViewGroup) view.getParent();
+        if (parent != null) {
+            parent.removeView(view);
+        }
+        return view;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        mListView = view.findViewById(R.id.home_list_view);
+
+        mAdapter = new HomeListAdapter();
+        mListView.setAdapter(mAdapter);
+        mListView.setGroupIndicator(null); // Section Header前面有一个小三角,移除。也可以设置自己的图片
+        mListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
+            @Override
+            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
+
+                HomeSectionModel sectionModel = mSectionArray.get(groupPosition);
+                HomeOrderModel orderModel = sectionModel.orderModelForIndex(childPosition);
+
+                Intent intent = DetailActivity.build(mCtx,orderModel.orderID);
+                mCtx.startActivity(intent);
+
+                return false;
+            }
+        });
+
+
+        loadData();
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mCtx = getActivity();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+    private void loadData() {
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                JSONObject json = com.usai.redant.apexdrivers.Network.Network.requestOrderList(mCtx);
+                if (json != null) {
+                    try {
+
+                        int restul = json.getInt("result");
+                        if (restul == Network.RESULT_TRUE) {
+
+                            JSONArray sectionArr = json.optJSONArray("sections");
+                            if (sectionArr != null) {
+
+                                mSectionArray.clear();
+
+                                for (int i = 0; i < sectionArr.length(); i++) {
+
+                                    JSONObject section = sectionArr.getJSONObject(i);
+                                    HomeSectionModel model = new HomeSectionModel();
+                                    model.section = i;
+
+                                    model.type = section.optInt("type");
+                                    model.title = section.optString("title");
+                                    model.setOrders(section.optJSONArray("orders"));
+
+                                    mSectionArray.add(model);
+                                }
+
+                                Message msg = new Message();
+                                msg.what = HomeHandler.HomeActionReloadData;
+                                mHandler.sendMessage(msg);
+
+                            }
+
+                        } else {
+
+                        }
+
+                    } catch (JSONException e) {
+                        e.printStackTrace();
+                    }
+                }
+
+            }
+
+        }).start();
+
+    }
+
+    private static final class HomeHandler extends Handler {
+
+        static final int HomeActionReloadData = 0;
+
+        WeakReference<HomeFragment> mWeakHome;
+
+        public HomeHandler(HomeFragment fragment) {
+            mWeakHome = new WeakReference<>(fragment);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+
+            HomeFragment fragment = mWeakHome.get();
+            switch (msg.what) {
+                case HomeActionReloadData: {
+
+                    /**
+                     * 手动调用打开/关闭 Group,否则默认关闭
+                     * */
+                    for (int i = 0; i < fragment.mSectionArray.size(); i++) {
+                        HomeSectionModel sectionModel = fragment.mSectionArray.get(i);
+                        if (sectionModel.expand) {
+                            fragment.mListView.expandGroup(i);
+                        } else {
+                            fragment.mListView.collapseGroup(i);
+                        }
+                    }
+
+                    fragment.mAdapter.notifyDataSetChanged();
+                }
+                break;
+                default:{
+
+                }
+                break;
+            }
+        }
+    }
+
+
+    private static int HOME_CELL_TYPE_SECTION_HEADER    = 0;
+    private static int HOME_CELL_TYPE_ORDER             = 1;
+
+    private class HomeListAdapter extends BaseExpandableListAdapter {
+
+        private class SectionHeaderHolder implements View.OnClickListener{
+
+            TextView titleTv;
+            Button expandBtn;
+            WeakReference<HomeSectionModel> weakSectionModel;
+
+            SectionHeaderHolder(View view) {
+
+                titleTv = view.findViewById(R.id.header_title_tv);
+                expandBtn = view.findViewById(R.id.section_switch_btn);
+                expandBtn.setOnClickListener(this);
+                view.setTag(this);
+            }
+
+            void setExpand(boolean expand) {
+                if (expand) {
+                    expandBtn.setText("Hide");
+                } else {
+                    expandBtn.setText("Show");
+                }
+            }
+
+            void hideExpandBtn(boolean hide) {
+                if (hide) {
+                    expandBtn.setVisibility(View.GONE);
+                } else {
+                    expandBtn.setVisibility(View.VISIBLE);
+                }
+            }
+
+            void bindSectionModel(HomeSectionModel model) {
+
+                titleTv.setText(model.title);
+                setExpand(model.expand);
+
+                weakSectionModel = new WeakReference<>(model);
+            }
+
+            @Override
+            public void onClick(View v) {
+                HomeSectionModel sectionModel = weakSectionModel.get();
+
+                sectionModel.expand = !sectionModel.expand;
+                setExpand(sectionModel.expand);
+
+                if (sectionModel.expand) {
+                    mListView.expandGroup(sectionModel.section);
+                } else {
+                    mListView.collapseGroup(sectionModel.section);
+                }
+            }
+        }
+
+        private class OrderCellHolder {
+
+            TextView titleTv, orderNoTv, containerNoTv, dateTv;
+            ImageView statusView;
+
+            OrderCellHolder(View view) {
+
+                titleTv = view.findViewById(R.id.title_tv);
+                orderNoTv = view.findViewById(R.id.order_no_tv);
+                containerNoTv = view.findViewById(R.id.container_no_tv);
+                dateTv = view.findViewById(R.id.date_tv);
+                statusView = view.findViewById(R.id.status_view);
+
+                view.setTag(this);
+            }
+
+            void bindOrderModel(HomeOrderModel model) {
+
+                titleTv.setText(model.title);
+                orderNoTv.setText(model.orderNo);
+                containerNoTv.setText(model.containerNo);
+                dateTv.setText(model.date);
+            }
+        }
+
+        @Override
+        public int getGroupCount() {
+            if (mSectionArray == null) {
+                return 0;
+            }
+            return mSectionArray.size();
+        }
+
+        @Override
+        public int getChildrenCount(int groupPosition) {
+
+            HomeSectionModel sectionModel = mSectionArray.get(groupPosition);
+
+            int childrenCount = sectionModel.orderCount();
+
+            return childrenCount;
+        }
+
+        @Override
+        public Object getGroup(int groupPosition) {
+            HomeSectionModel sectionModel = mSectionArray.get(groupPosition);
+            return sectionModel;
+        }
+
+        @Override
+        public Object getChild(int groupPosition, int childPosition) {
+
+            HomeSectionModel sectionModel = mSectionArray.get(groupPosition);
+            return sectionModel.orderModelForIndex(childPosition);
+        }
+
+        @Override
+        public int getChildType(int groupPosition, int childPosition) {
+            return 0;
+        }
+
+        @Override
+        public int getChildTypeCount() {
+            return 2;
+        }
+
+        @Override
+        public long getGroupId(int groupPosition) {
+            return groupPosition;
+        }
+
+        @Override
+        public long getChildId(int groupPosition, int childPosition) {
+            return childPosition;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        @Override
+        public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
+
+            View header;
+            SectionHeaderHolder holder;
+            if (convertView == null) {
+
+                header = LayoutInflater.from(mCtx).inflate(R.layout.section_header,null);
+                holder = new SectionHeaderHolder(header);
+
+            } else {
+                header = convertView;
+                holder = (SectionHeaderHolder)convertView.getTag();
+            }
+
+            HomeSectionModel sectionModel = mSectionArray.get(groupPosition);
+            holder.bindSectionModel(sectionModel);
+
+            return header;
+        }
+
+        @Override
+        public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
+
+
+            View header;
+            OrderCellHolder holder;
+            if (convertView == null) {
+
+                header = LayoutInflater.from(mCtx).inflate(R.layout.home_order_cell,null);
+                holder = new OrderCellHolder(header);
+
+            } else {
+
+                header = convertView;
+                holder = (OrderCellHolder)convertView.getTag();
+            }
+
+            HomeSectionModel sectionModel = mSectionArray.get(groupPosition);
+            HomeOrderModel orderModel = sectionModel.orderModelForIndex(childPosition);
+
+            holder.bindOrderModel(orderModel);
+
+            return header;
+        }
+
+        @Override
+        public boolean isChildSelectable(int groupPosition, int childPosition) {
+            return true;
+        }
+
+        @Override
+        public void onGroupExpanded(int groupPosition) {
+            super.onGroupExpanded(groupPosition);
+        }
+
+        @Override
+        public void onGroupCollapsed(int groupPosition) {
+            super.onGroupCollapsed(groupPosition);
+        }
+    }
+
+    private class HomeOrderModel {
+
+       static final int OrderStatusFinish = 0;
+       static final int OrderStatusProcessing = 1;
+       static final int OrderStatusNew = 2;
+
+       int status;
+       String title;
+       String orderNo;
+       String containerNo;
+       String date;
+       String orderID;
+
+    }
+
+    private class HomeSectionModel {
+
+        int type; // OrderStatus
+        ArrayList<HomeOrderModel> orders;
+        String title;
+        boolean expand = true;
+        int section;
+
+        int orderCount() {
+            if (orders == null || !expand) {
+                return 0;
+            }
+
+            return orders.size();
+        }
+
+        void setOrders(JSONArray orders) {
+            if (orders == null) {
+                this.orders = null;
+                return;
+            }
+            ArrayList<HomeOrderModel> orderArr = new ArrayList<>();
+            for (int i = 0; i < orders.length(); i++) {
+                JSONObject order = orders.optJSONObject(i);
+                if (order != null) {
+                    HomeOrderModel model = new HomeOrderModel();
+                    model.status = order.optInt("status",0);
+                    model.title = order.optString("title");
+                    model.orderNo = order.optString("orderNo");
+                    model.containerNo = order.optString("containerNo");
+                    model.date = order.optString("date");
+                    model.orderID = order.optString("orderID");
+
+                    orderArr.add(model);
+                }
+            }
+            this.orders = orderArr;
+        }
+
+        HomeOrderModel orderModelForIndex(int index) {
+            if (index >= orders.size()) {
+                return null;
+            }
+
+            return orders.get(index);
+        }
+
+        int orderModelIndexForID(String id) {
+
+            if (id == null) {
+                return 0;
+            }
+
+            for (int i = 0; i < orders.size(); i++) {
+
+                HomeOrderModel model = orders.get(i);
+                if(model.orderID != null && model.orderID.equals(id)) {
+                    return i;
+                }
+            }
+            return 0;
+        }
+
+    }
+}

+ 355 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Login/LoginFragment.java

@@ -0,0 +1,355 @@
+package com.usai.redant.apexdrivers.Login;
+
+//import android.app.Fragment;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.content.LocalBroadcastManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+
+import com.usai.redant.apexdrivers.ApexDriverApplication;
+import com.usai.redant.apexdrivers.Network.Network;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.rautils.Utils.AESUtil;
+
+
+/**
+ * Activity which displays a login screen to the user, offering registration as
+ * well.
+ */
+public class LoginFragment extends Fragment/* implements OnClickListener */
+{
+
+
+	public interface LoginCallBack{
+		public abstract void onLogin();
+//		public abstract void onLogout();
+	}
+	private LoginCallBack mCallBack;
+	private String m_sUser;
+	private String m_sPassword;
+	private EditText m_etName;
+	private EditText m_etPassword;
+	private UserLoginTask mAuthTask = null;
+	private TextView mLoginStatusMessageView;
+	private View mLoginFormView;
+	private View mLoginStatusView;
+
+	private CheckBox m_cbSave;
+
+	// SQLiteDatabase m_db;
+	public void setCallBack(LoginCallBack callBack) {
+		this.mCallBack = callBack;
+	}
+//
+//	@Override
+//	public void onSaveInstanceState(Bundle outState) {
+//		super.onSaveInstanceState(outState);
+//		outState.putSerializable("hashmap", mCallBack);
+//	}
+
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+
+		View view = inflater.inflate(R.layout.fragment_login, null);
+		TextView tv_ver = (TextView) view.findViewById(R.id.tv_ver);
+
+		try {
+			tv_ver.setText(getText(R.string.str_ver) + "2.20." + ApexDriverApplication.sharedApplication().getPackageManager().getPackageInfo("com.usai.redant.apexdrivers.Login", 0).versionName);
+		} catch (NameNotFoundException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		}
+
+		// // TODO Auto-generated catch block
+
+		m_etName = (EditText) view.findViewById(R.id.user);
+		// mUserView.setText(mUser);
+
+		m_etPassword = (EditText) view.findViewById(R.id.password);
+
+		m_cbSave = (CheckBox) view.findViewById(R.id.cb_save);
+
+		String u = ApexDriverApplication.sharedApplication().savedUser();
+		String p = ApexDriverApplication.sharedApplication().savedPassword();
+
+		if (u != null && p != null) {
+			try {
+				m_etName.setText(u);
+				m_etPassword.setText(p);
+				m_cbSave.setChecked(true);
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+
+		}
+
+		m_etPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+					@Override
+					public boolean onEditorAction(TextView textView, int id,
+							KeyEvent keyEvent) {
+						if (id == R.id.login || id == EditorInfo.IME_ACTION_DONE) {
+
+							InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+
+							inputMethodManager.hideSoftInputFromWindow(m_etPassword.getWindowToken(), 0);
+							attemptLogin();
+							return true;
+						}
+						return false;
+					}
+				});
+
+		mLoginFormView = view.findViewById(R.id.login_form);
+		mLoginStatusView = view.findViewById(R.id.login_status);
+		mLoginStatusMessageView = view.findViewById(R.id.login_status_message);
+
+		view.findViewById(R.id.sign_in_button).setOnClickListener(
+				new View.OnClickListener() {
+					@Override
+					public void onClick(View view) {
+						InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+
+						inputMethodManager.hideSoftInputFromWindow(m_etPassword.getWindowToken(), 0);
+						attemptLogin();
+						// showProgress(true);
+					}
+				});
+		
+		view.findViewById(R.id.tv_retrieve_pass).setOnClickListener(
+				new View.OnClickListener() {
+					@Override
+					public void onClick(View view) {
+						Intent intent = new Intent();
+						intent.setClass(getActivity(), RetrievePasswordActivity.class);
+						startActivity(intent);
+					}
+				});
+		return view;
+	}
+
+
+	public void attemptLogin() {
+
+		if (mAuthTask != null) {
+			return;
+		}
+
+		// Reset errors.
+		m_etName.setError(null);
+		m_etPassword.setError(null);
+
+		// Store values at the time of the login attempt.
+		m_sUser = m_etName.getText().toString().toLowerCase();
+		m_sPassword = m_etPassword.getText().toString();
+
+		boolean cancel = false;
+		View focusView = null;
+
+		// Check for a valid password.
+		if (TextUtils.isEmpty(m_sPassword)) {
+			m_etPassword.setError(getString(R.string.error_field_required));
+			focusView = m_etPassword;
+			cancel = true;
+		} /*else if (m_sPassword.length() < 4) {
+			m_etPassword.setError(getString(R.string.error_invalid_password));
+			focusView = m_etPassword;
+			cancel = true;
+		}*/
+
+		// Check for a valid user name.
+		if (TextUtils.isEmpty(m_sUser)) {
+			m_etName.setError(getString(R.string.error_field_required));
+			focusView = m_etName;
+			cancel = true;
+		}
+		// else if (!m_sName.contains("@")) {
+		// m_etName.setError(getString(R.string.error_invalid_email));
+		// focusView = m_etName;
+		// cancel = true;
+		// }
+
+		if (cancel) {
+			// There was an error; don't attempt login and focus the first
+			// form field with an error.
+			focusView.requestFocus();
+		} else {
+			// Show a progress spinner, and kick off a background task to
+			// perform the user login attempt.
+			mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
+			showProgress(true);
+			mAuthTask = new UserLoginTask();
+			mAuthTask.execute((Void) null);
+		}
+	}
+
+	//
+	// /**
+	// * Shows the progress UI and hides the login form.
+	// */
+	// @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
+	private void showProgress(final boolean show) {
+		// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
+		// for very easy animations. If available, use these APIs to fade-in
+		// the progress spinner.
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
+			int shortAnimTime = getResources().getInteger(
+					android.R.integer.config_shortAnimTime);
+
+			mLoginStatusView.setVisibility(View.VISIBLE);
+			mLoginStatusView.animate().setDuration(shortAnimTime)
+					.alpha(show ? 1 : 0)
+					.setListener(new AnimatorListenerAdapter() {
+						@Override
+						public void onAnimationEnd(Animator animation) {
+							mLoginStatusView.setVisibility(show ? View.VISIBLE
+									: View.INVISIBLE);
+						}
+					});
+
+			mLoginFormView.setVisibility(View.VISIBLE);
+			mLoginFormView.animate().setDuration(shortAnimTime)
+					.alpha(show ? 0 : 1)
+					.setListener(new AnimatorListenerAdapter() {
+						@Override
+						public void onAnimationEnd(Animator animation) {
+							mLoginFormView.setVisibility(show ? View.INVISIBLE
+									: View.VISIBLE);
+						}
+					});
+		} else {
+			// The ViewPropertyAnimator APIs are not available, so simply show
+			// and hide the relevant UI components.
+			mLoginStatusView
+					.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
+			mLoginFormView.setVisibility(show ? View.INVISIBLE : View.VISIBLE);
+		}
+	}
+
+	public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
+
+		int errorcode;
+
+		@Override
+		protected Boolean doInBackground(Void... params) {
+
+			errorcode = Network.login(m_sUser, m_sPassword);
+			if (errorcode == Network.RESULT_TRUE)
+				return true;
+			else {
+				return false;
+			}
+
+		}
+
+		@Override
+		protected void onPostExecute(final Boolean success) {
+			Log.d("onPostExecute", "entry");
+			mAuthTask = null;
+			showProgress(false);
+
+
+			if (success) {
+
+				ApexDriverApplication.sharedApplication().login(m_sUser.toLowerCase(),m_sPassword);
+
+				if(mCallBack!=null)
+					mCallBack.onLogin();
+
+
+//				{
+//					Intent intent = new Intent("Login");
+//					intent.putExtra("state", true);
+//					LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
+//				}
+
+			} else {
+				switch (errorcode) {
+				case Network.RESULT_NET_NOTAVAILABLE: {
+					Toast toast = Toast.makeText(getActivity()
+							.getApplicationContext(),
+							getText(R.string.msg_connection_none),
+							Toast.LENGTH_LONG);
+					toast.setGravity(Gravity.CENTER, 0, 0);
+					toast.show();
+					return;
+				}
+				case Network.RESULT_NET_ERROR: {
+					Toast toast = Toast.makeText(getActivity()
+							.getApplicationContext(),
+							getText(R.string.msg_net_error), Toast.LENGTH_LONG);
+					toast.setGravity(Gravity.CENTER, 0, 0);
+					toast.show();
+					return;
+				}
+				case Network.RESULT_VER_LOW:
+				{
+					Toast toast = Toast.makeText(getActivity()
+							.getApplicationContext(),
+							getText(R.string.msg_ver_low), Toast.LENGTH_LONG);
+					toast.setGravity(Gravity.CENTER, 0, 0);
+					toast.show();
+					return;
+				}
+				case Network.RESULT_ERROR:
+				// case Network.RESULT_RESPONSE_NULL:
+				{
+					Toast toast = Toast.makeText(getActivity()
+							.getApplicationContext(),
+							getText(R.string.msg_net_resulterror),
+							Toast.LENGTH_LONG);
+					toast.setGravity(Gravity.CENTER, 0, 0);
+					toast.show();
+					return;
+				}
+
+				case Network.RESULT_FALSE: {
+					m_etPassword
+							.setError(getString(R.string.error_incorrect_password));
+					m_etPassword.requestFocus();
+					return;
+					
+				}
+				default: {
+					Toast toast = Toast.makeText(getActivity()
+							.getApplicationContext(),
+							getText(R.string.msg_net_resulterror) + ":"
+									+ errorcode, Toast.LENGTH_LONG);
+					toast.setGravity(Gravity.CENTER, 0, 0);
+					toast.show();
+					break;
+				}
+				}
+			}
+		}
+
+		@Override
+		protected void onCancelled() {
+			mAuthTask = null;
+			showProgress(false);
+		}
+	}
+}

+ 419 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Login/RetrievePasswordActivity.java

@@ -0,0 +1,419 @@
+package com.usai.redant.apexdrivers.Login;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.TargetApi;
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.usai.redant.apexdrivers.Network.Network;
+import com.usai.redant.apexdrivers.R;
+
+/**
+ * Activity which displays a login screen to the user, offering registration as
+ * well.
+ */
+public class RetrievePasswordActivity extends AppCompatActivity
+{
+
+	/**
+	 * Keep track of the login task to ensure we can cancel it if requested.
+	 */
+	private UserLoginTask	mAuthTask	= null;
+
+	// Values for email and password at the time of the login attempt.
+	private String			m_sEmail;
+	private String			m_sUser;
+
+	// UI references.
+	private EditText		mEmailView;
+	private EditText		m_userView;
+	private View			mLoginFormView;
+	private View			mLoginStatusView;
+	private TextView		mLoginStatusMessageView;
+
+
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item)
+	{
+		Intent intent = new Intent();
+		switch (item.getItemId())
+		{
+			case android.R.id.home:
+				finish();
+				break;
+
+			default:
+				break;
+		}
+		return super.onOptionsItemSelected(item);
+	}
+
+	private void setCustomActionBar() {
+		ActionBar.LayoutParams lp =new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT, Gravity.CENTER);
+		View mActionBarView = LayoutInflater.from(this).inflate(R.layout.actionbar_customtitle, null);
+
+		TextView titleview = mActionBarView.findViewById(R.id.title);
+		titleview.setText("Retrieve Password");
+		setTitle("Retrieve Password");
+
+		ActionBar actionBar = getSupportActionBar();
+		actionBar.setCustomView(mActionBarView, lp);
+//		actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
+//		actionBar.setDisplayShowCustomEnabled(true);
+		actionBar.setDisplayHomeAsUpEnabled(true);
+
+
+		actionBar.setDisplayShowTitleEnabled(true);
+	}
+	@Override
+	protected void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+
+		setContentView(R.layout.activity_retrieve_password);
+
+		setCustomActionBar();
+		// Set up the login form.
+		m_userView = (EditText) findViewById(R.id.user);
+		// m_sEmail = getIntent().getStringExtra(EXTRA_EMAIL);
+		mEmailView = (EditText) findViewById(R.id.email);
+		// mEmailView.setText(m_sEmail);
+
+		mEmailView
+				.setOnEditorActionListener(new TextView.OnEditorActionListener()
+				{
+					@Override
+					public boolean onEditorAction(TextView textView, int id,
+							KeyEvent keyEvent)
+					{
+						if (id == R.id.btn_ok
+								|| id == EditorInfo.IME_ACTION_DONE)
+						{
+
+							InputMethodManager inputMethodManager = (InputMethodManager) getApplicationContext()
+									.getSystemService(
+											Context.INPUT_METHOD_SERVICE);
+
+							// EditText editText =
+							// (EditText)findViewById(R.id.xxxx);
+							inputMethodManager.hideSoftInputFromWindow(
+									mEmailView.getWindowToken(), 0); // ����
+							retrivev();
+							return true;
+						}
+						return false;
+					}
+				});
+
+		mLoginFormView = findViewById(R.id.login_form);
+		mLoginStatusView = findViewById(R.id.login_status);
+		mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);
+
+		findViewById(R.id.btn_ok).setOnClickListener(new View.OnClickListener()
+		{
+			@Override
+			public void onClick(View view)
+			{
+				InputMethodManager inputMethodManager = (InputMethodManager) getApplicationContext()
+						.getSystemService(Context.INPUT_METHOD_SERVICE);
+
+				// EditText editText =
+				// (EditText)findViewById(R.id.xxxx);
+				inputMethodManager.hideSoftInputFromWindow(
+						mEmailView.getWindowToken(), 0); // ����
+				retrivev();
+			}
+		});
+		findViewById(R.id.btn_close).setOnClickListener(
+				new View.OnClickListener()
+				{
+					@Override
+					public void onClick(View view)
+					{
+						finish();
+					}
+				});
+	}
+
+	//
+	// @Override
+	// public boolean onCreateOptionsMenu(Menu menu) {
+	// super.onCreateOptionsMenu(menu);
+	// getMenuInflater().inflate(R.menu.retrieve_password, menu);
+	// return true;
+	// }
+
+	/**
+	 * Attempts to sign in or register the account specified by the login form.
+	 * If there are form errors (invalid email, missing fields, etc.), the
+	 * errors are presented and no actual login attempt is made.
+	 */
+	public void retrivev()
+	{
+		if (mAuthTask != null)
+		{
+			return;
+		}
+
+		// Reset errors.
+		mEmailView.setError(null);
+		m_userView.setError(null);
+
+		// Store values at the time of the login attempt.
+		m_sEmail = mEmailView.getText().toString();
+		m_sUser = m_userView.getText().toString();
+
+		boolean cancel = false;
+		View focusView = null;
+
+		// Check for a valid password.
+		if (TextUtils.isEmpty(m_sUser))
+		{
+			m_userView.setError(getString(R.string.error_field_required));
+			focusView = m_userView;
+			cancel = true;
+		}
+
+		// Check for a valid email address.
+		if (TextUtils.isEmpty(m_sEmail))
+		{
+			mEmailView.setError(getString(R.string.error_field_required));
+			focusView = mEmailView;
+			cancel = true;
+		}
+		else if (!m_sEmail.contains("@"))
+		{
+			mEmailView.setError(getString(R.string.error_invalid_email));
+			focusView = mEmailView;
+			cancel = true;
+		}
+
+		if (cancel)
+		{
+			// There was an error; don't attempt login and focus the first
+			// form field with an error.
+			focusView.requestFocus();
+		}
+		else
+		{
+			// Show a progress spinner, and kick off a background task to
+			// perform the user login attempt.
+			mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
+			showProgress(true);
+			mAuthTask = new UserLoginTask();
+			mAuthTask.execute((Void) null);
+		}
+	}
+
+	/**
+	 * Shows the progress UI and hides the login form.
+	 */
+	@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
+	private void showProgress(final boolean show)
+	{
+		// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
+		// for very easy animations. If available, use these APIs to fade-in
+		// the progress spinner.
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
+		{
+			int shortAnimTime = getResources().getInteger(
+					android.R.integer.config_shortAnimTime);
+
+			mLoginStatusView.setVisibility(View.VISIBLE);
+			mLoginStatusView.animate().setDuration(shortAnimTime)
+					.alpha(show ? 1 : 0)
+					.setListener(new AnimatorListenerAdapter()
+					{
+						@Override
+						public void onAnimationEnd(Animator animation)
+						{
+							mLoginStatusView.setVisibility(show ? View.VISIBLE
+									: View.GONE);
+						}
+					});
+
+			mLoginFormView.setVisibility(View.VISIBLE);
+			mLoginFormView.animate().setDuration(shortAnimTime)
+					.alpha(show ? 0 : 1)
+					.setListener(new AnimatorListenerAdapter()
+					{
+						@Override
+						public void onAnimationEnd(Animator animation)
+						{
+							mLoginFormView.setVisibility(show ? View.GONE
+									: View.VISIBLE);
+						}
+					});
+		}
+		else
+		{
+			// The ViewPropertyAnimator APIs are not available, so simply show
+			// and hide the relevant UI components.
+			mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
+			mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
+		}
+	}
+
+	/**
+	 * Represents an asynchronous login/registration task used to authenticate
+	 * the user.
+	 */
+	public class UserLoginTask extends AsyncTask<Void, Void, Boolean>
+	{
+		int	errorcode;
+
+		@Override
+		protected Boolean doInBackground(Void... params)
+		{
+			errorcode = Network.retrieve_pass(m_sUser, m_sEmail);
+			if (errorcode == Network.RESULT_TRUE)
+				return true;
+			else
+			{
+				return false;
+			}
+
+		}
+
+		@Override
+		protected void onPostExecute(final Boolean success)
+		{
+			Log.d("onPostExecute", "entry");
+			mAuthTask = null;
+			showProgress(false);
+			// if (netconnect == )
+			// {
+			//
+			// }
+
+			if (success)
+			{
+				Builder builder = new Builder(
+						RetrievePasswordActivity.this);
+				builder.setMessage(getString(R.string.str_email_sent));
+
+				builder.setTitle(getString(R.string.str_retrieve_success));
+
+				builder.setPositiveButton(getString(android.R.string.ok), new OnClickListener()
+				{
+
+					@Override
+					public void onClick(DialogInterface dialog, int which)
+					{
+						dialog.dismiss();
+
+						RetrievePasswordActivity.this.finish();
+					}
+				});
+
+				// builder.setNegativeButton("取消", new OnClickListener() {
+				//
+				// @Override
+				// public void onClick(DialogInterface dialog, int which) {
+				// dialog.dismiss();
+				// }
+				// });
+
+				builder.create().show();
+
+			}
+			else
+			{
+				switch (errorcode)
+				{
+					case Network.RESULT_NET_NOTAVAILABLE:
+					{
+						Toast toast = Toast.makeText(getApplicationContext(),
+								getText(R.string.msg_connection_none),
+								Toast.LENGTH_LONG);
+						toast.setGravity(Gravity.CENTER, 0, 0);
+						toast.show();
+						return;
+					}
+					case Network.RESULT_NET_ERROR:
+					{
+						Toast toast = Toast.makeText(getApplicationContext(),
+								getText(R.string.msg_net_error),
+								Toast.LENGTH_LONG);
+						toast.setGravity(Gravity.CENTER, 0, 0);
+						toast.show();
+						return;
+					}
+					case Network.RESULT_ERROR:
+					// case Network.RESULT_RESPONSE_NULL:
+					{
+						Toast toast = Toast.makeText(getApplicationContext(),
+								getText(R.string.msg_net_resulterror),
+								Toast.LENGTH_LONG);
+						toast.setGravity(Gravity.CENTER, 0, 0);
+						toast.show();
+						return;
+					}
+
+					case Network.RESULT_FALSE:
+					{
+						Builder builder = new Builder(
+								RetrievePasswordActivity.this);
+						builder.setMessage(getString(R.string.str_invalid_pore));
+
+						builder.setTitle(getString(R.string.str_retrieve_failed));
+
+						builder.setPositiveButton(getString(android.R.string.ok), new OnClickListener()
+						{
+
+							@Override
+							public void onClick(DialogInterface dialog,
+									int which)
+							{
+								dialog.dismiss();
+
+								// RetrievePasswordActivity.this.finish();
+							}
+						});
+						builder.create().show();
+						return;
+
+					}
+					default:
+					{
+						Toast toast = Toast.makeText(getApplicationContext(),
+								getText(R.string.msg_net_resulterror) + ":"
+										+ errorcode, Toast.LENGTH_LONG);
+						toast.setGravity(Gravity.CENTER, 0, 0);
+						toast.show();
+						break;
+					}
+				}
+			}
+		}
+
+		@Override
+		protected void onCancelled()
+		{
+			mAuthTask = null;
+			showProgress(false);
+		}
+	}
+}

+ 41 - 9
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/MainActivity.java

@@ -1,28 +1,60 @@
 package com.usai.redant.apexdrivers;
 
 import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
 import android.support.v7.app.AppCompatActivity;
+import android.widget.RelativeLayout;
 
-import com.usai.redant.rautils.Utils.RAUtil;
-import com.usai.redant.rautils.Utils.dbgUtil;
+import com.usai.redant.apexdrivers.Home.HomeFragment;
+import com.usai.redant.apexdrivers.Login.LoginFragment;
 
-public class MainActivity extends AppCompatActivity {
+
+public class MainActivity extends AppCompatActivity implements LoginFragment.LoginCallBack {
+
+
+    private RelativeLayout mRootContainer;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
-        Test();
+
+        mRootContainer = findViewById(R.id.root_container);
+
+        initView();
+    }
+
+    private void initView() {
+
+        FragmentManager manager = getSupportFragmentManager();
+        FragmentTransaction transaction = manager.beginTransaction();
+
+        if (ApexDriverApplication.sharedApplication().isLogin()) {
+
+            HomeFragment homeFragment = new HomeFragment();
+            transaction.add(R.id.root_container, homeFragment);
+
+        } else {
+
+            LoginFragment loginFragment = new LoginFragment();
+            loginFragment.setCallBack(this);
+            transaction.add(R.id.root_container, loginFragment);
+        }
+
+        transaction.commit();
     }
 
-    void Test()
-    {
-        dbgUtil.Logd("TestLib","lib import successful");
+    @Override
+    public void onLogin() {
 
+        HomeFragment homeFragment = new HomeFragment();
 
-        RAUtil.LibTest();
+        FragmentManager manager = getSupportFragmentManager();
+        FragmentTransaction transaction = manager.beginTransaction();
 
+        transaction.replace(R.id.root_container,homeFragment);
 
-        RAUtil.LibTest1();
+        transaction.commit();
     }
 }

+ 228 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Network/Network.java

@@ -0,0 +1,228 @@
+package com.usai.redant.apexdrivers.Network;
+
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+
+import com.usai.redant.apexdrivers.R;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class Network extends com.usai.redant.rautils.Utils.Network {
+
+    public static String URL_HOST = "";
+    private static boolean FAKE_DATA = true;
+
+    public static boolean NetworkIsAvailable() {
+        return com.usai.redant.rautils.Utils.Network.networkIsAvailable(null);
+    }
+
+    public static int retrieve_pass(String user, String email)
+    {
+        String TAG = "net_dbg@retrieve_pass";
+        Log.d(TAG, "u:" + user + ";e:" + email);
+        if (!NetworkIsAvailable())
+        {
+            Log.d(TAG, "network not available!");
+            return Network.RESULT_NET_NOTAVAILABLE; // network not available
+        }
+        Bundle parms = new Bundle();
+        parms.putString("user", user);
+        parms.putString("email", email);
+
+        parms.putString("module_name", "Retrieve Password");
+        parms.putString("action", "handset_search");
+
+
+        String jstr = getJson(URL_HOST, parms);
+        /*
+         * error occur while get authorization info from server. include can not
+         * reach server , wrong parms ,server get wrong , etc.
+         */
+        if (jstr == null || jstr.length() <= 0)
+        {
+            Log.d(TAG, "json is wrong");
+            return Network.RESULT_NET_ERROR;
+        }
+        JSONObject jsobj;
+
+        // array = new JSONArray(json);
+        try
+        {
+            jsobj = new JSONObject(jstr);
+            if (jsobj.length() > 0)
+            {
+                int iresult = jsobj.getInt("result");
+
+                if (iresult != Network.AP_USER_AUTH)
+                {
+                    Log.d(TAG, "USER NOT AUTHORIZED CODE=" + jsobj.getInt("result"));
+                    return RESULT_FALSE;
+                }
+                return RESULT_TRUE;
+
+            }
+            return RESULT_NET_ERROR;
+        }
+        catch (JSONException e)
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        return RESULT_NET_ERROR;
+    }
+
+    public static int login(String user, String password) {
+        return RESULT_TRUE;
+    }
+
+    public static JSONObject requestOrderList(Context context) {
+
+        if (FAKE_DATA) {
+            return loadFakeData(context, R.raw.fake_order_list);
+        }
+
+        Bundle params = new Bundle();
+        String jsonStr = getJson(URL_HOST,params);
+        if (jsonStr == null || jsonStr.isEmpty()) {
+            return null;
+        }
+
+        try {
+            JSONObject json = new JSONObject(jsonStr);
+            return json;
+        } catch (JSONException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static JSONObject requestOrderDetail(Context context,String orderID) {
+
+        if (FAKE_DATA) {
+            return loadFakeData(context, R.raw.fake_order_detail);
+        }
+
+        if (orderID == null) {
+            return null;
+        }
+
+        Bundle params = new Bundle();
+        params.putString("orderID",orderID);
+
+        String jsonStr = getJson(URL_HOST,params);
+        if (jsonStr == null || jsonStr.isEmpty()) {
+            return null;
+        }
+
+        try {
+            JSONObject json = new JSONObject(jsonStr);
+            return json;
+        } catch (JSONException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static JSONObject requestOrderUpdateInfo(Context context,String orderID, int actionID) {
+
+        if (FAKE_DATA) {
+            return loadFakeData(context, R.raw.fake_order_edit);
+        }
+
+        if (orderID == null) {
+            return null;
+        }
+
+        Bundle params = new Bundle();
+        params.putString("orderID",orderID);
+
+        String jsonStr = getJson(URL_HOST,params);
+        if (jsonStr == null || jsonStr.isEmpty()) {
+            return null;
+        }
+
+        try {
+            JSONObject json = new JSONObject(jsonStr);
+            return json;
+        } catch (JSONException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static JSONObject report(String url, Bundle params) {
+
+        if (FAKE_DATA) {
+            try {
+                return new JSONObject("{\n" +
+                        "  \"result\": 2\n" +
+                        "}");
+            } catch (JSONException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+
+        if (url == null || url.isEmpty()) {
+            try {
+                return new JSONObject("{\n" +
+                        "  \"result\": 0\n" +
+                        "}");
+            } catch (JSONException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+
+        if (params == null) {
+            params = new Bundle();
+        }
+
+        String jsonStr = getJson(URL_HOST,params);
+        if (jsonStr == null || jsonStr.isEmpty()) {
+            return null;
+        }
+
+        try {
+            JSONObject json = new JSONObject(jsonStr);
+            return json;
+        } catch (JSONException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    private static JSONObject loadFakeData(Context context, int rawId) {
+
+        try
+        {
+            InputStream in = context.getResources().openRawResource(rawId);
+            BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"));
+            StringBuffer sb = new StringBuffer();
+
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                sb.append(line).append("\n");
+            }
+
+            JSONObject json = new JSONObject(sb.toString());
+            return json;
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+}

+ 14 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateBaseModel.java

@@ -0,0 +1,14 @@
+package com.usai.redant.apexdrivers.Update.Model;
+
+public class UpdateBaseModel {
+
+    public final static int UpdateTypeLabel = 0;
+    public final static int UpdateTypeInput = 1;
+    public final static int UpdateTypeMultInput= 2;
+    public final static int UpdateTypePhoto = 3;
+
+    public int type;
+    public String key;
+    public String title;
+
+}

+ 8 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateInputModel.java

@@ -0,0 +1,8 @@
+package com.usai.redant.apexdrivers.Update.Model;
+
+public class UpdateInputModel extends UpdateBaseModel {
+
+    public boolean scannable;
+    public String value;
+
+}

+ 7 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateLabelModel.java

@@ -0,0 +1,7 @@
+package com.usai.redant.apexdrivers.Update.Model;
+
+public class UpdateLabelModel extends UpdateBaseModel {
+
+    public String value;
+
+}

+ 7 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdateMultInputModel.java

@@ -0,0 +1,7 @@
+package com.usai.redant.apexdrivers.Update.Model;
+
+public class UpdateMultInputModel extends UpdateBaseModel {
+
+    public String value;
+
+}

+ 13 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/Model/UpdatePhotoModel.java

@@ -0,0 +1,13 @@
+package com.usai.redant.apexdrivers.Update.Model;
+
+import android.graphics.Bitmap;
+
+public class UpdatePhotoModel extends UpdateBaseModel {
+
+    public Bitmap photo;
+
+    public String getPhotoName() {
+        return key + ".jpg";
+    }
+
+}

+ 213 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/UpdateActivity.java

@@ -0,0 +1,213 @@
+package com.usai.redant.apexdrivers.Update;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.widget.ExpandableListView;
+
+import com.usai.redant.apexdrivers.CodeScanner.CaptureActivity;
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.apexdrivers.Update.Model.UpdateInputModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdatePhotoModel;
+import com.usai.redant.rautils.Utils.Network;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+public class UpdateActivity extends AppCompatActivity implements UpdateAdapter.UpdateAdapterDelegate {
+
+    private final static String OrderIDKey = "OrderID";
+    private final static String ActionIDKey = "ActionID";
+    private final static String ActionTitleKey = "ActionTitle";
+
+    public static Intent build(Context ctx, String orderID, int actionID,String actionTitle) {
+
+        Intent intent = new Intent(ctx, UpdateActivity.class);
+        if (orderID != null) {
+            intent.putExtra(OrderIDKey,orderID);
+        }
+        if (actionTitle != null) {
+            intent.putExtra(ActionTitleKey,actionTitle);
+        }
+        intent.putExtra(ActionIDKey,actionID);
+
+        return intent;
+    }
+
+    private String mOrderID;
+    private int mActionID;
+
+    private Context mCtx = this;
+    private UpdateActivity self = this;
+    private UpdateHandler mHandler;
+    private JSONObject mJson;
+    private ArrayList<UpdateSectionModel> mSectionArray = new ArrayList<>();
+    private UpdateAdapter mAdapter;
+
+    private ExpandableListView mListView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_update);
+
+        android.support.v7.app.ActionBar actionBar = getSupportActionBar();
+        if(actionBar != null){
+            actionBar.setHomeButtonEnabled(true);
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
+
+        String title = getIntent().getStringExtra(ActionTitleKey);
+        setTitle(title);
+
+        mOrderID = getIntent().getStringExtra(OrderIDKey);
+        mActionID = getIntent().getIntExtra(ActionIDKey,0);
+
+        mHandler = new UpdateHandler(self);
+
+        mListView = findViewById(R.id.update_list_view);
+        mAdapter = new UpdateAdapter(mCtx,mSectionArray,self);
+
+        mListView.setGroupIndicator(null);
+        mListView.setAdapter(mAdapter);
+
+        loadData();
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                this.finish(); // back button
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void loadData() {
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                JSONObject json = com.usai.redant.apexdrivers.Network.Network.requestOrderUpdateInfo(mCtx,mOrderID,mActionID);
+
+                Message msg = new Message();
+                msg.what = UpdateHandler.UpdateActionReloadData;
+                msg.obj = json;
+                mHandler.sendMessage(msg);
+            }
+
+        }).start();
+
+    }
+
+    /**
+     * Adapter Delegate
+     * */
+
+    @Override
+    public void scannerButtonDidClick(UpdateInputModel model) {
+
+        Intent intent = new Intent();
+
+        intent.setClass(mCtx, CaptureActivity.class);
+        startActivityForResult(intent, 0);
+
+    }
+
+    @Override
+    public void photoButtonDidClick(UpdatePhotoModel model) {
+
+    }
+
+    /**
+     * Handler
+     * */
+    private static class UpdateHandler extends Handler {
+
+        public static final int UpdateActionReloadData = 0;
+
+        private WeakReference<UpdateActivity> mWeakActivity;
+
+        UpdateHandler(UpdateActivity activity) {
+            if (activity != null) {
+                mWeakActivity = new WeakReference<>(activity);
+            }
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+
+            UpdateActivity activity = mWeakActivity.get();
+            switch (msg.what) {
+                case UpdateActionReloadData: {
+
+                    JSONObject json = (JSONObject) msg.obj;
+                    if (json != null) {
+
+                        try {
+
+                            int restul = json.getInt("result");
+                            if (restul == Network.RESULT_TRUE) {
+                                activity.mJson = json;
+                                JSONArray sectionArr = json.optJSONArray("sections");
+                                if (sectionArr != null) {
+
+                                    activity.mSectionArray.clear();
+                                    for (int i = 0; i < sectionArr.length(); i++) {
+
+                                        JSONObject section = sectionArr.getJSONObject(i);
+                                        UpdateSectionModel sectionModel = new UpdateSectionModel();
+                                        sectionModel.title = section.optString("title");
+                                        sectionModel.setItems(section.optJSONArray("items"));
+
+                                        activity.mSectionArray.add(sectionModel);
+                                    }
+
+                                }
+
+                            } else {
+                                // error
+                            }
+
+                        } catch (JSONException e) {
+                            e.printStackTrace();
+                            // error
+                        }
+                    } else {
+                        // error
+                    }
+                    /**
+                     * 手动调用打开/关闭 Group,否则默认关闭
+                     * */
+                    if (activity.mSectionArray.size() > 0) {
+                        for (int i = 0; i < activity.mSectionArray.size(); i++) {
+                            activity.mListView.expandGroup(i);
+                        }
+                    }
+
+                    activity.mAdapter.notifyDataSetChanged();
+
+                }
+                break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    /**
+     *
+     * */
+}

+ 327 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/UpdateAdapter.java

@@ -0,0 +1,327 @@
+package com.usai.redant.apexdrivers.Update;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import com.usai.redant.apexdrivers.R;
+import com.usai.redant.apexdrivers.Update.Model.UpdateBaseModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdateInputModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdateLabelModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdateMultInputModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdatePhotoModel;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+public class UpdateAdapter extends BaseExpandableListAdapter {
+
+    private Context mCtx;
+    private ArrayList<UpdateSectionModel> mSections;
+    private WeakReference<UpdateAdapterDelegate> mDelegate;
+    UpdateAdapter(Context context, ArrayList<UpdateSectionModel> sections, UpdateAdapterDelegate delegate) {
+        mCtx = context;
+        mSections = sections;
+        mDelegate = new WeakReference<>(delegate);
+    }
+
+    @Override
+    public int getGroupCount() {
+        if (mSections == null) {
+            return 0;
+        }
+        return mSections.size();
+    }
+
+    @Override
+    public int getChildrenCount(int groupPosition) {
+        UpdateSectionModel model = mSections.get(groupPosition);
+        return model.itemCount();
+    }
+
+    @Override
+    public Object getGroup(int groupPosition) {
+        UpdateSectionModel model = mSections.get(groupPosition);
+        return model;
+    }
+
+    @Override
+    public Object getChild(int groupPosition, int childPosition) {
+        UpdateSectionModel sectionModel = mSections.get(groupPosition);
+        UpdateBaseModel model = sectionModel.itemModelForIndex(childPosition);
+        return model;
+    }
+
+    @Override
+    public long getGroupId(int groupPosition) {
+        return groupPosition;
+    }
+
+    @Override
+    public long getChildId(int groupPosition, int childPosition) {
+        return childPosition;
+    }
+
+    @Override
+    public int getChildTypeCount() {
+
+        return 4;
+    }
+
+    @Override
+    public int getChildType(int groupPosition, int childPosition) {
+
+        UpdateSectionModel sectionModel = mSections.get(groupPosition);
+        UpdateBaseModel model = sectionModel.itemModelForIndex(childPosition);
+        return model.type;
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    @Override
+    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
+        if (mCtx == null) {
+            return null;
+        }
+
+        SectionHolder holder;
+        if (convertView == null) {
+
+            convertView = LayoutInflater.from(mCtx).inflate(R.layout.section_header,null);
+            holder = new SectionHolder(convertView);
+
+        } else {
+            holder = (SectionHolder) convertView.getTag();
+        }
+        UpdateSectionModel sectionModel = mSections.get(groupPosition);
+        holder.bindSecionModel(sectionModel);
+
+
+        return convertView;
+    }
+
+    @Override
+    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
+
+        UpdateSectionModel sectionModel = mSections.get(groupPosition);
+        UpdateBaseModel model = sectionModel.itemModelForIndex(childPosition);
+
+        switch (getChildType(groupPosition,childPosition)) {
+            case UpdateBaseModel.UpdateTypeLabel: {
+
+                LabelHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.update_label_cell,null);
+                    holder = new LabelHolder(convertView);
+
+                } else {
+
+                    holder = (LabelHolder)convertView.getTag();
+                }
+
+                UpdateLabelModel labelModel = (UpdateLabelModel)model;
+                holder.bindModel(labelModel);
+
+            }
+            break;
+            case UpdateBaseModel.UpdateTypeInput: {
+
+                ScannerInputHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.update_scanner_input_cell,null);
+                    holder = new ScannerInputHolder(convertView);
+
+                } else {
+
+                    holder = (ScannerInputHolder)convertView.getTag();
+                }
+
+                UpdateInputModel inputModel = (UpdateInputModel)model;
+                holder.bindModel(inputModel);
+
+            }
+            break;
+            case UpdateBaseModel.UpdateTypeMultInput: {
+
+                MultInputHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.update_multinput_cell,null);
+                    holder = new MultInputHolder(convertView);
+
+                } else {
+
+                    holder = (MultInputHolder)convertView.getTag();
+                }
+
+                UpdateMultInputModel multInputModel = (UpdateMultInputModel)model;
+                holder.bindModel(multInputModel);
+
+            }
+            break;
+            case UpdateBaseModel.UpdateTypePhoto: {
+
+                PhotoHolder holder;
+                if (convertView == null) {
+
+                    convertView = LayoutInflater.from(mCtx).inflate(R.layout.update_photo_cell,null);
+                    holder = new PhotoHolder(convertView);
+
+                } else {
+
+                    holder = (PhotoHolder)convertView.getTag();
+                }
+
+                UpdatePhotoModel photoModel = (UpdatePhotoModel)model;
+                holder.bindModel(photoModel);
+            }
+            break;
+        }
+
+        return convertView;
+    }
+
+    @Override
+    public boolean isChildSelectable(int groupPosition, int childPosition) {
+        return false;
+    }
+
+    /**
+     * Holder
+     * */
+    private class SectionHolder {
+
+        TextView titleTv;
+        Button expandBtn;
+        SectionHolder(View view) {
+
+            titleTv = view.findViewById(R.id.header_title_tv);
+            expandBtn = view.findViewById(R.id.section_switch_btn);
+            expandBtn.setVisibility(View.GONE);
+
+            view.setTag(this);
+        }
+
+        public void bindSecionModel(UpdateSectionModel model) {
+            titleTv.setText(model.title);
+        }
+    }
+
+    private class LabelHolder {
+
+        TextView titleTv,valueTv;
+
+        LabelHolder(View view) {
+
+            titleTv = view.findViewById(R.id.update_label_title_tv);
+            valueTv = view.findViewById(R.id.update_label_value_tv);
+            view.setTag(this);
+        }
+
+        public void bindModel(UpdateLabelModel model) {
+            titleTv.setText(model.title);
+            valueTv.setText(model.value);
+        }
+    }
+
+    private class ScannerInputHolder {
+
+        TextView titleTv;
+        EditText valueEt;
+        ImageButton scannerBtn;
+        WeakReference<UpdateInputModel> weakInput;
+
+        ScannerInputHolder(View view) {
+
+            titleTv = view.findViewById(R.id.update_scanner_input_title_tv);
+            valueEt = view.findViewById(R.id.update_input_tv);
+            scannerBtn = view.findViewById(R.id.update_scanner_btn);
+            scannerBtn.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (weakInput != null && mDelegate != null) {
+                        UpdateInputModel model = weakInput.get();
+                        mDelegate.get().scannerButtonDidClick(model);
+                    }
+                }
+            });
+
+            view.setTag(this);
+        }
+
+        public void bindModel(UpdateInputModel model) {
+
+            titleTv.setText(model.title);
+            valueEt.setText(model.value);
+            if (model.scannable) {
+                scannerBtn.setVisibility(View.VISIBLE);
+            } else {
+                scannerBtn.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    private class MultInputHolder {
+
+        TextView titleTv;
+        EditText valueEt;
+
+        MultInputHolder(View view) {
+
+            titleTv = view.findViewById(R.id.update_multiple_input_title_tv);
+            valueEt = view.findViewById(R.id.update_multiple_input_value_tv);
+            view.setTag(this);
+        }
+
+        public void bindModel(UpdateMultInputModel model) {
+
+            titleTv.setText(model.title);
+            valueEt.setText(model.value);
+        }
+    }
+
+    private class PhotoHolder {
+
+        TextView titleTv;
+        ImageButton photoBtn;
+        WeakReference<UpdatePhotoModel> weakPhoto;
+        PhotoHolder(View view) {
+
+            titleTv = view.findViewById(R.id.update_photo_title_tv);
+            photoBtn = view.findViewById(R.id.update_photo_btn);
+            photoBtn.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (weakPhoto != null && mDelegate != null) {
+                        UpdatePhotoModel model = weakPhoto.get();
+                        mDelegate.get().photoButtonDidClick(model);
+                    }
+                }
+            });
+            view.setTag(this);
+        }
+
+        public void bindModel(UpdatePhotoModel model) {
+            titleTv.setText(model.title);
+            photoBtn.setImageBitmap(model.photo);
+
+            weakPhoto = new WeakReference<>(model);
+        }
+    }
+
+    public interface UpdateAdapterDelegate {
+        void scannerButtonDidClick(UpdateInputModel model);
+        void photoButtonDidClick(UpdatePhotoModel model);
+    }
+}

+ 88 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/Update/UpdateSectionModel.java

@@ -0,0 +1,88 @@
+package com.usai.redant.apexdrivers.Update;
+
+import com.usai.redant.apexdrivers.Update.Model.UpdateBaseModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdateInputModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdateLabelModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdateMultInputModel;
+import com.usai.redant.apexdrivers.Update.Model.UpdatePhotoModel;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+
+public class UpdateSectionModel {
+
+    public String title;
+    public ArrayList<UpdateBaseModel> items = new ArrayList<>();
+
+    public void setItems(JSONArray items) {
+        this.items.clear();
+
+        if (items != null) {
+
+            for (int i = 0; i < items.length(); i++) {
+                JSONObject item = items.optJSONObject(i);
+                if (item != null) {
+                    int type = item.optInt("type");
+                    switch (type) {
+                        case UpdateBaseModel.UpdateTypeLabel: {
+
+                            UpdateLabelModel model = new UpdateLabelModel();
+                            model.type = type;
+                            model.title = item.optString("title");
+                            model.key = item.optString("key");
+                            model.value = item.optString("value");
+                            this.items.add(model);
+                        }
+                        break;
+                        case UpdateBaseModel.UpdateTypeInput: {
+
+                            UpdateInputModel model = new UpdateInputModel();
+                            model.type = type;
+                            model.title = item.optString("title");
+                            model.key = item.optString("key");
+                            model.value = item.optString("value");
+                            model.scannable = item.optBoolean("scannable");
+                            this.items.add(model);
+                        }
+                        break;
+                        case UpdateBaseModel.UpdateTypeMultInput: {
+
+                            UpdateMultInputModel model = new UpdateMultInputModel();
+                            model.type = type;
+                            model.title = item.optString("title");
+                            model.key = item.optString("key");
+                            model.value = item.optString("value");
+                            this.items.add(model);
+                        }
+                        break;
+                        case UpdateBaseModel.UpdateTypePhoto: {
+
+                            UpdatePhotoModel model = new UpdatePhotoModel();
+                            model.type = type;
+                            model.title = item.optString("title");
+                            model.key = item.optString("key");
+                            this.items.add(model);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    public int itemCount() {
+        return items.size();
+    }
+
+    public UpdateBaseModel itemModelForIndex(int index) {
+
+        if (index < 0 || index >= items.size()) {
+            return null;
+        }
+
+        return items.get(index);
+    }
+
+}

+ 112 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/AutoFocusManager.java

@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.hardware.Camera;
+import android.os.AsyncTask;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.usai.redant.apexdrivers.camera.PreferencesActivity;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+final class AutoFocusManager implements Camera.AutoFocusCallback {
+
+  private static final String TAG = AutoFocusManager.class.getSimpleName();
+
+  private static final long AUTO_FOCUS_INTERVAL_MS = 2000L;
+  private static final Collection<String> FOCUS_MODES_CALLING_AF;
+  static {
+    FOCUS_MODES_CALLING_AF = new ArrayList<String>(2);
+    FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
+    FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
+  }
+
+  private boolean active;
+  private final boolean useAutoFocus;
+  private final Camera camera;
+  private AsyncTask<?,?,?> outstandingTask;
+
+  AutoFocusManager(Context context, Camera camera) {
+    this.camera = camera;
+    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
+    String currentFocusMode = camera.getParameters().getFocusMode();
+    useAutoFocus =
+        sharedPrefs.getBoolean(PreferencesActivity.KEY_AUTO_FOCUS, true) &&
+        FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
+    Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
+    start();
+  }
+
+  @Override
+  public synchronized void onAutoFocus(boolean success, Camera theCamera) {
+    if (active) {
+      outstandingTask = new AutoFocusTask();
+      outstandingTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+  }
+
+  synchronized void start() {
+    if (useAutoFocus) {
+      active = true;
+      try {
+        camera.autoFocus(this);
+      } catch (RuntimeException re) {
+        // Have heard RuntimeException reported in Android 4.0.x+; continue?
+        Log.w(TAG, "Unexpected exception while focusing", re);
+      }
+    }
+  }
+
+  synchronized void stop() {
+    if (useAutoFocus) {
+      try {
+        camera.cancelAutoFocus();
+      } catch (RuntimeException re) {
+        // Have heard RuntimeException reported in Android 4.0.x+; continue?
+        Log.w(TAG, "Unexpected exception while cancelling focusing", re);
+      }
+    }
+    if (outstandingTask != null) {
+      outstandingTask.cancel(true);
+      outstandingTask = null;
+    }
+    active = false;
+  }
+
+  private final class AutoFocusTask extends AsyncTask<Object,Object,Object> {
+    @Override
+    protected Object doInBackground(Object... voids) {
+      try {
+        Thread.sleep(AUTO_FOCUS_INTERVAL_MS);
+      } catch (InterruptedException e) {
+        // continue
+      }
+      synchronized (AutoFocusManager.this) {
+        if (active) {
+          start();
+        }
+      }
+      return null;
+    }
+  }
+
+}

+ 306 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/CameraConfigurationManager.java

@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A class which deals with reading, parsing, and setting the camera parameters which are used to
+ * configure the camera hardware.
+ */
+final class CameraConfigurationManager {
+
+  private static final String TAG = "CameraConfiguration";
+
+  // This is bigger than the size of a small screen, which is still supported. The routine
+  // below will still select the default (presumably 320x240) size for these. This prevents
+  // accidental selection of very low resolution on some devices.
+  private static final int MIN_PREVIEW_PIXELS = 480 * 320; // normal screen
+  //private static final float MAX_EXPOSURE_COMPENSATION = 1.5f;
+  //private static final float MIN_EXPOSURE_COMPENSATION = 0.0f;
+  private static final double MAX_ASPECT_DISTORTION = 0.15;
+
+  private final Context context;
+  private Point screenResolution;
+  private Point cameraResolution;
+
+  CameraConfigurationManager(Context context) {
+    this.context = context;
+  }
+
+  /**
+   * Reads, one time, values from the camera that are needed by the app.
+   */
+  void initFromCameraParameters(Camera camera) {
+    Camera.Parameters parameters = camera.getParameters();
+    WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+    Display display = manager.getDefaultDisplay();
+    Point theScreenResolution = new Point();
+    display.getSize(theScreenResolution);
+    screenResolution = theScreenResolution;
+    Log.i(TAG, "Screen resolution: " + screenResolution);
+    cameraResolution = findBestPreviewSizeValue(parameters, screenResolution);
+    Log.i(TAG, "Camera resolution: " + cameraResolution);
+  }
+
+  void setDesiredCameraParameters(Camera camera, boolean safeMode) {
+    Camera.Parameters parameters = camera.getParameters();
+
+    if (parameters == null) {
+      Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");
+      return;
+    }
+
+    Log.i(TAG, "Initial camera parameters: " + parameters.flatten());
+
+    if (safeMode) {
+      Log.w(TAG, "In camera config safe mode -- most settings will not be honored");
+    }
+
+    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+    initializeTorch(parameters, prefs, safeMode);
+
+    String focusMode = null;
+    if (prefs.getBoolean(PreferencesActivity.KEY_AUTO_FOCUS, true)) {
+      if (safeMode || prefs.getBoolean(PreferencesActivity.KEY_DISABLE_CONTINUOUS_FOCUS, false)) {
+        focusMode = findSettableValue(parameters.getSupportedFocusModes(),
+                                      Camera.Parameters.FOCUS_MODE_AUTO);
+      } else {
+        focusMode = findSettableValue(parameters.getSupportedFocusModes(),
+                                      Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
+                                      Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
+                                      Camera.Parameters.FOCUS_MODE_AUTO);
+      }
+    }
+    // Maybe selected auto-focus but not available, so fall through here:
+    if (!safeMode && focusMode == null) {
+      focusMode = findSettableValue(parameters.getSupportedFocusModes(),
+                                    Camera.Parameters.FOCUS_MODE_MACRO,
+                                    Camera.Parameters.FOCUS_MODE_EDOF);
+    }
+    if (focusMode != null) {
+      parameters.setFocusMode(focusMode);
+    }
+
+    if (prefs.getBoolean(PreferencesActivity.KEY_INVERT_SCAN, false)) {
+      String colorMode = findSettableValue(parameters.getSupportedColorEffects(),
+                                           Camera.Parameters.EFFECT_NEGATIVE);
+      if (colorMode != null) {
+        parameters.setColorEffect(colorMode);
+      }
+    }
+
+    parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
+    camera.setParameters(parameters);
+
+    Camera.Parameters afterParameters = camera.getParameters();
+    Camera.Size afterSize = afterParameters.getPreviewSize();
+    if (afterSize!= null && (cameraResolution.x != afterSize.width || cameraResolution.y != afterSize.height)) {
+      Log.w(TAG, "Camera said it supported preview size " + cameraResolution.x + 'x' + cameraResolution.y +
+                 ", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height);
+      cameraResolution.x = afterSize.width;
+      cameraResolution.y = afterSize.height;
+    }
+  }
+
+  Point getCameraResolution() {
+    return cameraResolution;
+  }
+
+  Point getScreenResolution() {
+    return screenResolution;
+  }
+
+  boolean getTorchState(Camera camera) {
+    if (camera != null) {
+      Camera.Parameters parameters = camera.getParameters();
+      if (parameters != null) {
+        String flashMode = camera.getParameters().getFlashMode();
+        return flashMode != null &&
+            (Camera.Parameters.FLASH_MODE_ON.equals(flashMode) ||
+             Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode));
+      }
+    }
+    return false;
+  }
+
+  void setTorch(Camera camera, boolean newSetting) {
+    Camera.Parameters parameters = camera.getParameters();
+    doSetTorch(parameters, newSetting, false);
+    camera.setParameters(parameters);
+  }
+
+  private void initializeTorch(Camera.Parameters parameters, SharedPreferences prefs, boolean safeMode) {
+    boolean currentSetting = FrontLightMode.readPref(prefs) == FrontLightMode.ON;
+    doSetTorch(parameters, currentSetting, safeMode);
+  }
+
+  private void doSetTorch(Camera.Parameters parameters, boolean newSetting, boolean safeMode) {
+    String flashMode;
+    if (newSetting) {
+      flashMode = findSettableValue(parameters.getSupportedFlashModes(),
+                                    Camera.Parameters.FLASH_MODE_TORCH,
+                                    Camera.Parameters.FLASH_MODE_ON);
+    } else {
+      flashMode = findSettableValue(parameters.getSupportedFlashModes(),
+                                    Camera.Parameters.FLASH_MODE_OFF);
+    }
+    if (flashMode != null) {
+      parameters.setFlashMode(flashMode);
+    }
+
+    /*
+    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+    if (!prefs.getBoolean(PreferencesActivity.KEY_DISABLE_EXPOSURE, false)) {
+      if (!safeMode) {
+        int minExposure = parameters.getMinExposureCompensation();
+        int maxExposure = parameters.getMaxExposureCompensation();
+        if (minExposure != 0 || maxExposure != 0) {
+          float step = parameters.getExposureCompensationStep();
+          int desiredCompensation;
+          if (newSetting) {
+            // Light on; set low exposue compensation
+            desiredCompensation = Math.max((int) (MIN_EXPOSURE_COMPENSATION / step), minExposure);
+          } else {
+            // Light off; set high compensation
+            desiredCompensation = Math.min((int) (MAX_EXPOSURE_COMPENSATION / step), maxExposure);
+          }
+          Log.i(TAG, "Setting exposure compensation to " + desiredCompensation + " / " + (step * desiredCompensation));
+          parameters.setExposureCompensation(desiredCompensation);
+        } else {
+          Log.i(TAG, "Camera does not support exposure compensation");
+        }
+      }
+    }
+     */
+  }
+
+  private Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) {
+
+    List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes();
+    if (rawSupportedSizes == null) {
+      Log.w(TAG, "Device returned no supported preview sizes; using default");
+      Camera.Size defaultSize = parameters.getPreviewSize();
+      return new Point(defaultSize.width, defaultSize.height);
+    }
+
+    // Sort by size, descending
+    List<Camera.Size> supportedPreviewSizes = new ArrayList<Camera.Size>(rawSupportedSizes);
+    Collections.sort(supportedPreviewSizes, new Comparator<Camera.Size>() {
+      @Override
+      public int compare(Camera.Size a, Camera.Size b) {
+        int aPixels = a.height * a.width;
+        int bPixels = b.height * b.width;
+        if (bPixels < aPixels) {
+          return -1;
+        }
+        if (bPixels > aPixels) {
+          return 1;
+        }
+        return 0;
+      }
+    });
+
+    if (Log.isLoggable(TAG, Log.INFO)) {
+      StringBuilder previewSizesString = new StringBuilder();
+      for (Camera.Size supportedPreviewSize : supportedPreviewSizes) {
+        previewSizesString.append(supportedPreviewSize.width).append('x')
+            .append(supportedPreviewSize.height).append(' ');
+      }
+      Log.i(TAG, "Supported preview sizes: " + previewSizesString);
+    }
+
+    double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
+
+    // Remove sizes that are unsuitable
+    Iterator<Camera.Size> it = supportedPreviewSizes.iterator();
+    while (it.hasNext()) {
+      Camera.Size supportedPreviewSize = it.next();
+      int realWidth = supportedPreviewSize.width;
+      int realHeight = supportedPreviewSize.height;
+      if (realWidth * realHeight < MIN_PREVIEW_PIXELS) {
+        it.remove();
+        continue;
+      }
+
+      boolean isCandidatePortrait = realWidth < realHeight;
+      int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
+      int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
+      double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
+      double distortion = Math.abs(aspectRatio - screenAspectRatio);
+      if (distortion > MAX_ASPECT_DISTORTION) {
+        it.remove(); 
+        continue;
+      }
+
+      if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
+        Point exactPoint = new Point(realWidth, realHeight);
+        Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
+        return exactPoint;
+      }
+    }
+
+    // If no exact match, use largest preview size. This was not a great idea on older devices because
+    // of the additional computation needed. We're likely to get here on newer Android 4+ devices, where
+    // the CPU is much more powerful.
+    if (!supportedPreviewSizes.isEmpty()) {
+      Camera.Size largestPreview = supportedPreviewSizes.get(0);
+      Point largestSize = new Point(largestPreview.width, largestPreview.height);
+      Log.i(TAG, "Using largest suitable preview size: " + largestSize);
+      return largestSize;
+    }
+
+    // If there is nothing at all suitable, return current preview size
+    Camera.Size defaultPreview = parameters.getPreviewSize();
+    Point defaultSize = new Point(defaultPreview.width, defaultPreview.height);
+    Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize);
+    return defaultSize;
+  }
+
+  private static String findSettableValue(Collection<String> supportedValues,
+                                          String... desiredValues) {
+    Log.i(TAG, "Supported values: " + supportedValues);
+    String result = null;
+    if (supportedValues != null) {
+      for (String desiredValue : desiredValues) {
+        if (supportedValues.contains(desiredValue)) {
+          result = desiredValue;
+          break;
+        }
+      }
+    }
+    Log.i(TAG, "Settable value: " + result);
+    return result;
+  }
+
+}

+ 312 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/CameraManager.java

@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import com.google.zxing.PlanarYUVLuminanceSource;
+import com.usai.redant.apexdrivers.camera.open.OpenCameraInterface;
+
+
+import java.io.IOException;
+
+/**
+ * This object wraps the Camera service object and expects to be the only one talking to it. The
+ * implementation encapsulates the steps needed to take preview-sized images, which are used for
+ * both preview and decoding.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public final class CameraManager {
+
+  private static final String TAG = CameraManager.class.getSimpleName();
+
+  private static final int MIN_FRAME_WIDTH = 240;
+  private static final int MIN_FRAME_HEIGHT = 240;
+  private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920
+  private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080
+
+  private final Context context;
+  private final CameraConfigurationManager configManager;
+  private Camera camera;
+  private AutoFocusManager autoFocusManager;
+  private Rect framingRect;
+  private Rect framingRectInPreview;
+  private boolean initialized;
+  private boolean previewing;
+  private int requestedFramingRectWidth;
+  private int requestedFramingRectHeight;
+  /**
+   * Preview frames are delivered here, which we pass on to the registered handler. Make sure to
+   * clear the handler so it will only receive one message.
+   */
+  private final PreviewCallback previewCallback;
+
+  public CameraManager(Context context) {
+    this.context = context;
+    this.configManager = new CameraConfigurationManager(context);
+    previewCallback = new PreviewCallback(configManager);
+  }
+
+  /**
+   * Opens the camera driver and initializes the hardware parameters.
+   *
+   * @param holder The surface object which the camera will draw preview frames into.
+   * @throws IOException Indicates the camera driver failed to open.
+   */
+  public synchronized void openDriver(SurfaceHolder holder) throws IOException {
+    Camera theCamera = camera;
+    if (theCamera == null) {
+      theCamera = OpenCameraInterface.open();
+      if (theCamera == null) {
+        throw new IOException();
+      }
+      camera = theCamera;
+    }
+    theCamera.setPreviewDisplay(holder);
+
+    if (!initialized) {
+      initialized = true;
+      configManager.initFromCameraParameters(theCamera);
+      if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {
+        setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);
+        requestedFramingRectWidth = 0;
+        requestedFramingRectHeight = 0;
+      }
+    }
+
+    Camera.Parameters parameters = theCamera.getParameters();
+    String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save these, temporarily
+    try {
+      configManager.setDesiredCameraParameters(theCamera, false);
+    } catch (RuntimeException re) {
+      // Driver failed
+      Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters");
+      Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened);
+      // Reset:
+      if (parametersFlattened != null) {
+        parameters = theCamera.getParameters();
+        parameters.unflatten(parametersFlattened);
+        try {
+          theCamera.setParameters(parameters);
+          configManager.setDesiredCameraParameters(theCamera, true);
+        } catch (RuntimeException re2) {
+          // Well, darn. Give up
+          Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration");
+        }
+      }
+    }
+
+  }
+
+  public synchronized boolean isOpen() {
+    return camera != null;
+  }
+
+  /**
+   * Closes the camera driver if still in use.
+   */
+  public synchronized void closeDriver() {
+    if (camera != null) {
+      camera.release();
+      camera = null;
+      // Make sure to clear these each time we close the camera, so that any scanning rect
+      // requested by intent is forgotten.
+      framingRect = null;
+      framingRectInPreview = null;
+    }
+  }
+
+  /**
+   * Asks the camera hardware to begin drawing preview frames to the screen.
+   */
+  public synchronized void startPreview() {
+    Camera theCamera = camera;
+    if (theCamera != null && !previewing) {
+      theCamera.startPreview();
+      previewing = true;
+      autoFocusManager = new AutoFocusManager(context, camera);
+    }
+  }
+
+  /**
+   * Tells the camera to stop drawing preview frames.
+   */
+  public synchronized void stopPreview() {
+    if (autoFocusManager != null) {
+      autoFocusManager.stop();
+      autoFocusManager = null;
+    }
+    if (camera != null && previewing) {
+      camera.stopPreview();
+      previewCallback.setHandler(null, 0);
+      previewing = false;
+    }
+  }
+
+  /**
+   * Convenience method for {@link com.usai.test1.android.CaptureActivity}
+   */
+  public synchronized void setTorch(boolean newSetting) {
+    if (newSetting != configManager.getTorchState(camera)) {
+      if (camera != null) {
+        if (autoFocusManager != null) {
+          autoFocusManager.stop();
+        }
+        configManager.setTorch(camera, newSetting);
+        if (autoFocusManager != null) {
+          autoFocusManager.start();
+        }
+      }
+    }
+  }
+
+  /**
+   * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
+   * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
+   * respectively.
+   *
+   * @param handler The handler to send the message to.
+   * @param message The what field of the message to be sent.
+   */
+  public synchronized void requestPreviewFrame(Handler handler, int message) {
+    Camera theCamera = camera;
+    if (theCamera != null && previewing) {
+      previewCallback.setHandler(handler, message);
+      theCamera.setOneShotPreviewCallback(previewCallback);
+    }
+  }
+
+  /**
+   * Calculates the framing rect which the UI should draw to show the user where to place the
+   * barcode. This target helps with alignment as well as forces the user to hold the device
+   * far enough away to ensure the image will be in focus.
+   *
+   * @return The rectangle to draw on screen in window coordinates.
+   */
+  public synchronized Rect getFramingRect() {
+    if (framingRect == null) {
+      if (camera == null) {
+        return null;
+      }
+      Point screenResolution = configManager.getScreenResolution();
+      if (screenResolution == null) {
+        // Called early, before init even finished
+        return null;
+      }
+
+      int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+      int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+      int leftOffset = (screenResolution.x - width) / 2;
+      int topOffset = (screenResolution.y - height) / 2;
+      framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
+      Log.d(TAG, "Calculated framing rect: " + framingRect);
+    }
+    return framingRect;
+  }
+  
+  private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {
+    int dim = 5 * resolution / 8; // Target 5/8 of each dimension
+    if (dim < hardMin) {
+      return hardMin;
+    }
+    if (dim > hardMax) {
+      return hardMax;
+    }
+    return dim;
+  }
+
+  /**
+   * Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
+   * not UI / screen.
+   */
+  public synchronized Rect getFramingRectInPreview() {
+    if (framingRectInPreview == null) {
+      Rect framingRect = getFramingRect();
+      if (framingRect == null) {
+        return null;
+      }
+      Rect rect = new Rect(framingRect);
+      Point cameraResolution = configManager.getCameraResolution();
+      Point screenResolution = configManager.getScreenResolution();
+      if (cameraResolution == null || screenResolution == null) {
+        // Called early, before init even finished
+        return null;
+      }
+      rect.left = rect.left * cameraResolution.x / screenResolution.x;
+      rect.right = rect.right * cameraResolution.x / screenResolution.x;
+      rect.top = rect.top * cameraResolution.y / screenResolution.y;
+      rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
+      framingRectInPreview = rect;
+    }
+    return framingRectInPreview;
+  }
+
+  /**
+   * Allows third party apps to specify the scanning rectangle dimensions, rather than determine
+   * them automatically based on screen resolution.
+   *
+   * @param width The width in pixels to scan.
+   * @param height The height in pixels to scan.
+   */
+  public synchronized void setManualFramingRect(int width, int height) {
+    if (initialized) {
+      Point screenResolution = configManager.getScreenResolution();
+      if (width > screenResolution.x) {
+        width = screenResolution.x;
+      }
+      if (height > screenResolution.y) {
+        height = screenResolution.y;
+      }
+      int leftOffset = (screenResolution.x - width) / 2;
+      int topOffset = (screenResolution.y - height) / 2;
+      framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
+      Log.d(TAG, "Calculated manual framing rect: " + framingRect);
+      framingRectInPreview = null;
+    } else {
+      requestedFramingRectWidth = width;
+      requestedFramingRectHeight = height;
+    }
+  }
+
+  /**
+   * A factory method to build the appropriate LuminanceSource object based on the format
+   * of the preview buffers, as described by Camera.Parameters.
+   *
+   * @param data A preview frame.
+   * @param width The width of the image.
+   * @param height The height of the image.
+   * @return A PlanarYUVLuminanceSource instance.
+   */
+  public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
+    Rect rect = getFramingRectInPreview();
+    if (rect == null) {
+      return null;
+    }
+    // Go ahead and assume it's YUV rather than die.
+    return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
+                                        rect.width(), rect.height(), false);
+  }
+
+}

+ 43 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/FrontLightMode.java

@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera;
+
+import android.content.SharedPreferences;
+
+import com.usai.redant.apexdrivers.camera.PreferencesActivity;
+
+/**
+ * Enumerates settings of the prefernce controlling the front light.
+ */
+public enum FrontLightMode {
+
+  /** Always on. */
+  ON,
+  /** On only when ambient light is low. */
+  AUTO,
+  /** Always off. */
+  OFF;
+
+  private static FrontLightMode parse(String modeString) {
+    return modeString == null ? OFF : valueOf(modeString);
+  }
+
+  public static FrontLightMode readPref(SharedPreferences sharedPrefs) {
+    return parse(sharedPrefs.getString(PreferencesActivity.KEY_FRONT_LIGHT_MODE, null));
+  }
+
+}

+ 56 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/PreferencesActivity.java

@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * The main settings activity.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ * @author Sean Owen
+ */
+public final class PreferencesActivity extends Activity {
+
+  public static final String KEY_DECODE_1D = "preferences_decode_1D";
+  public static final String KEY_DECODE_QR = "preferences_decode_QR";
+  public static final String KEY_DECODE_DATA_MATRIX = "preferences_decode_Data_Matrix";
+  public static final String KEY_CUSTOM_PRODUCT_SEARCH = "preferences_custom_product_search";
+
+  public static final String KEY_PLAY_BEEP = "preferences_play_beep";
+  public static final String KEY_VIBRATE = "preferences_vibrate";
+  public static final String KEY_COPY_TO_CLIPBOARD = "preferences_copy_to_clipboard";
+  public static final String KEY_FRONT_LIGHT_MODE = "preferences_front_light_mode";
+  public static final String KEY_BULK_MODE = "preferences_bulk_mode";
+  public static final String KEY_REMEMBER_DUPLICATES = "preferences_remember_duplicates";
+  public static final String KEY_SUPPLEMENTAL = "preferences_supplemental";
+  public static final String KEY_AUTO_FOCUS = "preferences_auto_focus";
+  public static final String KEY_INVERT_SCAN = "preferences_invert_scan";
+  public static final String KEY_SEARCH_COUNTRY = "preferences_search_country";
+
+  public static final String KEY_DISABLE_CONTINUOUS_FOCUS = "preferences_disable_continuous_focus";
+  //public static final String KEY_DISABLE_EXPOSURE = "preferences_disable_exposure";
+
+  @Override
+  protected void onCreate(Bundle icicle) {
+    super.onCreate(icicle);
+    getFragmentManager().beginTransaction().replace(android.R.id.content, new PreferencesFragment()).commit();
+
+  }
+
+}

+ 73 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/PreferencesFragment.java

@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+
+import com.usai.redant.apexdrivers.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public final class PreferencesFragment 
+    extends PreferenceFragment
+    implements SharedPreferences.OnSharedPreferenceChangeListener {
+  
+  private CheckBoxPreference decode1D;
+  private CheckBoxPreference decodeQR;
+  private CheckBoxPreference decodeDataMatrix;
+  
+  @Override
+  public void onCreate(Bundle icicle) {
+    super.onCreate(icicle);
+    addPreferencesFromResource(R.xml.preferences);
+    
+    PreferenceScreen preferences = getPreferenceScreen();
+    preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+    decode1D = (CheckBoxPreference) preferences.findPreference(PreferencesActivity.KEY_DECODE_1D);
+    decodeQR = (CheckBoxPreference) preferences.findPreference(PreferencesActivity.KEY_DECODE_QR);
+    decodeDataMatrix = (CheckBoxPreference) preferences.findPreference(PreferencesActivity.KEY_DECODE_DATA_MATRIX);
+    disableLastCheckedPref();
+  }
+  
+  @Override
+  public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+    disableLastCheckedPref();
+  }
+
+  private void disableLastCheckedPref() {
+    Collection<CheckBoxPreference> checked = new ArrayList<CheckBoxPreference>(3);
+    if (decode1D.isChecked()) {
+      checked.add(decode1D);
+    }
+    if (decodeQR.isChecked()) {
+      checked.add(decodeQR);
+    }
+    if (decodeDataMatrix.isChecked()) {
+      checked.add(decodeDataMatrix);
+    }
+    boolean disable = checked.size() < 2;
+    CheckBoxPreference[] checkBoxPreferences = {decode1D, decodeQR, decodeDataMatrix};
+    for (CheckBoxPreference pref : checkBoxPreferences) {
+      pref.setEnabled(!(disable && checked.contains(pref)));
+    }
+  }
+}

+ 56 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/PreviewCallback.java

@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera;
+
+import android.graphics.Point;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+final class PreviewCallback implements Camera.PreviewCallback {
+
+  private static final String TAG = PreviewCallback.class.getSimpleName();
+
+  private final CameraConfigurationManager configManager;
+  private Handler previewHandler;
+  private int previewMessage;
+
+  PreviewCallback(CameraConfigurationManager configManager) {
+    this.configManager = configManager;
+  }
+
+  void setHandler(Handler previewHandler, int previewMessage) {
+    this.previewHandler = previewHandler;
+    this.previewMessage = previewMessage;
+  }
+
+  @Override
+  public void onPreviewFrame(byte[] data, Camera camera) {
+    Point cameraResolution = configManager.getCameraResolution();
+    Handler thePreviewHandler = previewHandler;
+    if (cameraResolution != null && thePreviewHandler != null) {
+      Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
+          cameraResolution.y, data);
+      message.sendToTarget();
+      previewHandler = null;
+    } else {
+      Log.d(TAG, "Got preview callback, but no handler or resolution available");
+    }
+  }
+
+}

+ 62 - 0
ApexDrivers/app/src/main/java/com/usai/redant/apexdrivers/camera/open/OpenCameraInterface.java

@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.usai.redant.apexdrivers.camera.open;
+
+import android.hardware.Camera;
+import android.util.Log;
+
+public final class OpenCameraInterface {
+
+  private static final String TAG = OpenCameraInterface.class.getName();
+
+  private OpenCameraInterface() {
+  }
+
+  /**
+   * Opens a rear-facing camera with {@link Camera#open(int)}, if one exists, or opens camera 0.
+   */
+  public static Camera open() {
+    
+    int numCameras = Camera.getNumberOfCameras();
+    if (numCameras == 0) {
+      Log.w(TAG, "No cameras!");
+      return null;
+    }
+
+    int index = 0;
+    while (index < numCameras) {
+      Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+      Camera.getCameraInfo(index, cameraInfo);
+      if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
+        break;
+      }
+      index++;
+    }
+    
+    Camera camera;
+    if (index < numCameras) {
+      Log.i(TAG, "Opening camera #" + index);
+      camera = Camera.open(index);
+    } else {
+      Log.i(TAG, "No camera facing back; returning camera #0");
+      camera = Camera.open(0);
+    }
+
+    return camera;
+  }
+
+}

+ 28 - 0
ApexDrivers/app/src/main/res/drawable-v24/btn_bg.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- 按壓時 -->
+    <item android:state_pressed="true">
+        <!--rectangle 長方形 可以畫出直角形,圓角形,弧形等-->
+        <shape android:shape="rectangle">
+            <!--設定圓角,當設置的圓角半徑很大,就可變成弧形邊了-->
+            <corners android:radius="5dp" />
+            <!--邊框-->
+            <stroke android:width="0.5dp" android:color="@color/icon_red" />
+            <!--漸層顏色-->
+            <!--<gradient android:angle="-90" android:endColor="#017DAB" android:startColor="#0099CC" />-->
+            <solid android:color="#99FFFFFF" />
+        </shape>
+    </item>
+
+    <!-- 預設時 -->
+    <item android:color="@android:color/black">
+        <shape android:shape="rectangle">
+            <corners android:radius="5dp" />
+            <stroke android:width="0.5dp" android:color="@color/icon_gray" />
+            <!--<gradient android:angle="-90" android:endColor="#1D2C50" android:startColor="#0E2252" />-->
+            <solid android:color="#99FFFFFF" />
+        </shape>
+    </item>
+
+</selector>

+ 24 - 0
ApexDrivers/app/src/main/res/layout/actionbar_customtitle.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_centerInParent="true"
+
+        android:ellipsize="end"
+        android:gravity="center"
+        android:singleLine="true"
+        android:textColor="@color/icon_gray"
+        android:textSize="17sp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.6"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+</android.support.constraint.ConstraintLayout>

+ 16 - 0
ApexDrivers/app/src/main/res/layout/activity_detail.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".Detail.DetailActivity">
+
+    <ExpandableListView
+        android:id="@+id/detail_list_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
+
+</android.support.constraint.ConstraintLayout>

+ 4 - 4
ApexDrivers/app/src/main/res/layout/activity_main.xml

@@ -6,10 +6,10 @@
     android:layout_height="match_parent"
     tools:context=".MainActivity">
 
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="Hello World!"
+    <RelativeLayout
+        android:id="@+id/root_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"

+ 96 - 0
ApexDrivers/app/src/main/res/layout/activity_retrieve_password.xml

@@ -0,0 +1,96 @@
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context=".RetrievePasswordActivity" >
+
+    <!-- Login progress -->
+
+    <LinearLayout
+        android:id="@+id/login_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:gravity="center_horizontal"
+        android:orientation="vertical"
+        android:visibility="gone" >
+
+        <ProgressBar
+            style="?android:attr/progressBarStyleLarge"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp" />
+
+        <TextView
+            android:id="@+id/login_status_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            android:text="Connecting..."
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+    </LinearLayout>
+
+    <!-- Login form -->
+
+    <ScrollView
+        android:id="@+id/login_form"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <LinearLayout
+            style="@style/LoginFormContainer"
+            android:orientation="vertical" >
+
+            <EditText
+                android:id="@+id/user"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="User name"
+                android:imeActionId="@+id/login"
+                android:imeActionLabel="@string/action_sign_in_short"
+                android:imeOptions="actionUnspecified"
+                android:maxLines="1"
+                android:singleLine="true" />
+
+            <EditText
+                android:id="@+id/email"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="@string/prompt_email"
+                android:inputType="textEmailAddress"
+                android:maxLines="1"
+                android:singleLine="true" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" >
+
+                <Button
+                    android:id="@+id/btn_close"
+                    android:layout_width="wrap_content"
+                    android:layout_height="39dp"
+                    android:background="@drawable/btn_bg"
+                    android:layout_marginTop="16dp"
+                    android:layout_marginLeft="4dp"
+                    android:layout_marginRight="4dp"
+                    android:layout_weight="1"
+                    android:paddingLeft="32dp"
+                    android:paddingRight="32dp"
+                    android:text="Close" />
+
+                <Button
+                    android:id="@+id/btn_ok"
+                    android:layout_width="wrap_content"
+                    android:layout_height="39dp"
+                    android:background="@drawable/btn_bg"
+                    android:layout_marginTop="16dp"
+                    android:layout_marginLeft="4dp"
+                    android:layout_marginRight="4dp"
+                    android:layout_weight="1"
+                    android:paddingLeft="32dp"
+                    android:paddingRight="32dp"
+                    android:text="Ok" />
+
+            </LinearLayout>
+        </LinearLayout>
+    </ScrollView>
+
+</merge>

+ 16 - 0
ApexDrivers/app/src/main/res/layout/activity_update.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".Update.UpdateActivity">
+
+    <ExpandableListView
+        android:id="@+id/update_list_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
+
+</android.support.constraint.ConstraintLayout>

+ 215 - 0
ApexDrivers/app/src/main/res/layout/capture.xml

@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+  <SurfaceView android:id="@+id/preview_view"
+               android:layout_width="fill_parent"
+               android:layout_height="fill_parent"/>
+
+  <com.usai.redant.raimage.ViewfinderView
+      android:id="@+id/viewfinder_view"
+      android:layout_width="fill_parent"
+      android:layout_height="fill_parent"/>
+
+  <!-- <LinearLayout android:id="@+id/result_view"
+                android:orientation="vertical"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:background="@color/result_view"
+                android:visibility="gone"
+                android:baselineAligned="false">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:padding="@dimen/standard_padding">
+
+      <LinearLayout
+          android:orientation="vertical"
+          android:layout_width="wrap_content"
+          android:layout_height="fill_parent"
+          android:gravity="right|center_vertical">
+
+        <ImageView android:id="@+id/barcode_image_view"
+                   android:layout_width="160dip"
+                   android:layout_height="wrap_content"
+                   android:maxWidth="160dip"
+                   android:maxHeight="160dip"
+                   android:layout_marginBottom="@dimen/half_padding"
+                   android:adjustViewBounds="true"
+                   android:scaleType="centerInside"/>
+
+        <LinearLayout
+          android:orientation="horizontal"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content">
+
+          <TextView android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/msg_default_format"
+                    android:textColor="@color/result_minor_text"
+                    android:textStyle="bold"
+                    android:paddingRight="@dimen/half_padding"/>
+
+          <TextView android:id="@+id/format_text_view"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/result_minor_text"/>
+
+        </LinearLayout>
+
+        <LinearLayout
+          android:orientation="horizontal"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content">
+
+          <TextView android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/msg_default_type"
+                    android:textColor="@color/result_minor_text"
+                    android:textStyle="bold"
+                    android:paddingRight="@dimen/half_padding"/>
+
+          <TextView android:id="@+id/type_text_view"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/result_minor_text"/>
+
+        </LinearLayout>
+
+        <LinearLayout
+          android:orientation="horizontal"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content">
+
+          <TextView android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/msg_default_time"
+                    android:textColor="@color/result_minor_text"
+                    android:textStyle="bold"
+                    android:paddingRight="@dimen/half_padding"/>
+
+          <TextView android:id="@+id/time_text_view"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/result_minor_text"/>
+
+        </LinearLayout>
+
+        <LinearLayout
+          android:orientation="horizontal"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content">
+
+          <TextView android:id="@+id/meta_text_view_label"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/msg_default_meta"
+                    android:textColor="@color/result_minor_text"
+                    android:textStyle="bold"
+                    android:paddingRight="@dimen/half_padding"/>
+
+          <TextView android:id="@+id/meta_text_view"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/result_minor_text"/>
+
+        </LinearLayout>
+
+      </LinearLayout>
+
+      <ScrollView
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content">
+
+        <LinearLayout
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:orientation="vertical">
+
+          <TextView android:id="@+id/contents_text_view"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/result_text"
+                    android:textColorLink="@color/result_text"
+                    android:textSize="22sp"
+                    android:paddingLeft="12dip"
+                    android:autoLink="web"/>
+
+          <TextView android:id="@+id/contents_supplement_text_view"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/result_text"
+                    android:textColorLink="@color/result_text"
+                    android:paddingLeft="12dip"
+                    android:autoLink="web"/>
+
+        </LinearLayout>
+
+      </ScrollView>
+
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/result_button_view"
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal"
+                  android:gravity="center">
+
+      <Button style="@style/ResultButton"
+              android:visibility="gone"/>
+
+      <Button style="@style/ResultButton"
+              android:visibility="gone"/>
+
+      <Button style="@style/ResultButton"
+              android:visibility="gone"/>
+
+      <Button style="@style/ResultButton"
+              android:visibility="gone"/>
+
+    </LinearLayout>
+
+  </LinearLayout> -->
+
+  <TextView android:id="@+id/status_view"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|center_horizontal"
+            android:background="@color/transparent"
+            android:text="@string/msg_default_status"
+            android:textColor="@color/status_text"/>
+
+  <TextView
+      android:id="@+id/textView1"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text=""
+      android:layout_gravity="center_horizontal"
+      android:textAppearance="?android:attr/textAppearanceLarge" />
+  <Button
+      android:id="@+id/btn_switch"
+      android:layout_width="50dp"
+      android:layout_height="50dp"
+      android:layout_marginRight="20dp"
+      android:layout_gravity="center_vertical|right"
+      android:text="" />
+
+</merge>

+ 9 - 0
ApexDrivers/app/src/main/res/layout/detail_action_cell.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+
+
+</LinearLayout>

+ 56 - 0
ApexDrivers/app/src/main/res/layout/detail_location_cell.xml

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/detail_location_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Pick Up"
+        />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/detail_location_title_tv"
+        android:layout_alignLeft="@id/detail_location_title_tv"
+        android:layout_alignRight="@id/detail_location_title_tv"
+        >
+
+        <TextView
+            android:id="@+id/detail_location_value_tv"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginBottom="5dp"
+            android:textSize="17sp"
+            android:textColor="#000000"
+            android:text="dahkfhdakfgagjdfgajfda\ndagdjfag\n"
+            />
+
+        <RelativeLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            >
+
+            <Button
+                android:id="@+id/detail_location_nav_btn"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:textSize="17sp"
+                android:textColor="#44aaff"
+                android:text="Navigation"
+                android:textAllCaps="false"
+                />
+
+        </RelativeLayout>
+
+    </LinearLayout>
+
+
+</RelativeLayout>

+ 15 - 0
ApexDrivers/app/src/main/res/layout/detail_mult_line_cell.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+    <TextView
+        android:id="@+id/detail_multiple_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="201805300010"
+        />
+
+</RelativeLayout>

+ 29 - 0
ApexDrivers/app/src/main/res/layout/detail_single_line_cell.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+    <TextView
+        android:id="@+id/detail_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Order ID"
+        />
+
+    <TextView
+        android:id="@+id/detail_value_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/detail_title_tv"
+        android:layout_alignLeft="@id/detail_title_tv"
+        android:layout_alignRight="@id/detail_title_tv"
+        android:layout_marginBottom="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="201805300010"
+        />
+
+</RelativeLayout>

+ 17 - 0
ApexDrivers/app/src/main/res/layout/fragment_home.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+
+    <ExpandableListView
+        android:id="@+id/home_list_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:groupIndicator="@null"
+        >
+
+    </ExpandableListView>
+
+</android.support.constraint.ConstraintLayout>

+ 127 - 0
ApexDrivers/app/src/main/res/layout/fragment_login.xml

@@ -0,0 +1,127 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+     >
+
+    <!-- Login progress -->
+
+    <LinearLayout
+        android:id="@+id/login_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@+id/login_form"
+        android:layout_centerHorizontal="true"
+        android:layout_gravity="center"
+        android:gravity="center_horizontal"
+        android:orientation="vertical"
+        android:visibility="gone" >
+
+        <ProgressBar
+            style="?android:attr/progressBarStyleLarge"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="8dp" />
+
+        <TextView
+            android:id="@+id/login_status_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            android:text="@string/login_progress_signing_in"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+    </LinearLayout>
+
+    <!-- Login form -->
+
+    <LinearLayout
+        android:id="@+id/login_form"
+        style="@style/LoginFormContainer"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:orientation="vertical" >
+
+        <EditText
+            android:id="@+id/user"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="@string/prompt_user"
+            android:inputType="textAutoComplete"
+            android:maxLines="1"
+            android:singleLine="true"
+            android:text="" />
+
+        <EditText
+            android:id="@+id/password"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="@string/prompt_password"
+            android:imeActionId="@+id/login"
+            android:imeActionLabel="@string/action_sign_in_short"
+            android:imeOptions="actionUnspecified"
+            android:inputType="textPassword"
+            android:maxLines="1"
+            android:singleLine="true"
+            android:text="" />
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" >
+
+            <CheckBox
+                android:id="@+id/cb_save"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignBottom="@+id/sign_in_button"
+                android:checked="true"
+                android:text="@string/str_savepass"
+                android:visibility="invisible" />
+
+            <Button
+                android:id="@+id/sign_in_button"
+                android:layout_width="wrap_content"
+                android:layout_height="39dp"
+                android:layout_alignParentRight="true"
+                android:layout_alignParentTop="true"
+                android:background="@drawable/btn_bg"
+                android:paddingLeft="32dp"
+                android:paddingRight="32dp"
+                android:text="@string/action_sign_in_register" />
+
+        </RelativeLayout>
+
+        <TextView
+            android:id="@+id/tv_retrieve_pass"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="5dp"
+            android:layout_marginTop="5dp"
+            android:clickable="true"
+            android:focusable="true"
+            android:text="@string/str_retrievepass"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@android:color/holo_blue_dark" />
+
+    </LinearLayout>
+
+    
+
+    <TextView
+        android:id="@+id/tv_ver"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:layout_margin="10dp"
+        android:text="TextView" />
+
+    <ImageView
+        android:layout_width="276dp"
+        android:layout_height="120dp"
+        android:layout_centerHorizontal="true"
+        android:layout_below="@id/tv_ver"
+        android:layout_above="@id/login_form"
+        />
+
+</RelativeLayout>

+ 103 - 0
ApexDrivers/app/src/main/res/layout/home_order_cell.xml

@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+    <TextView
+        android:id="@+id/title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_margin="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Pickup Order New"
+        />
+
+    <ImageView
+        android:id="@+id/status_view"
+        android:layout_width="70dp"
+        android:layout_height="70dp"
+        android:layout_below="@id/title_tv"
+        android:layout_marginLeft="5dp"
+        android:layout_marginRight="5dp"
+        />
+
+    <TextView
+        android:id="@+id/order_no_key_tv"
+        android:layout_width="wrap_content"
+        android:layout_height="20dp"
+        android:layout_alignTop="@id/status_view"
+        android:layout_toRightOf="@id/status_view"
+        android:layout_marginRight="2dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Order No.:"
+        />
+
+    <TextView
+        android:id="@+id/order_no_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_alignTop="@id/status_view"
+        android:layout_toRightOf="@id/order_no_key_tv"
+        android:layout_alignRight="@id/title_tv"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="AFS180530001200"
+        />
+
+    <TextView
+        android:id="@+id/container_no_key_tv"
+        android:layout_width="wrap_content"
+        android:layout_height="20dp"
+        android:layout_below="@id/order_no_tv"
+        android:layout_toRightOf="@id/status_view"
+        android:layout_marginRight="2dp"
+        android:layout_marginTop="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Container No.:"
+        />
+
+    <TextView
+        android:id="@+id/container_no_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_below="@id/order_no_tv"
+        android:layout_toRightOf="@id/container_no_key_tv"
+        android:layout_alignRight="@id/title_tv"
+        android:layout_marginTop="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="TCNU6432476"
+        />
+
+    <TextView
+        android:id="@+id/date_key_tv"
+        android:layout_width="wrap_content"
+        android:layout_height="20dp"
+        android:layout_below="@id/container_no_tv"
+        android:layout_toRightOf="@id/status_view"
+        android:layout_marginRight="2dp"
+        android:layout_marginTop="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Date:"
+        />
+
+    <TextView
+        android:id="@+id/date_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_below="@id/container_no_tv"
+        android:layout_toRightOf="@id/date_key_tv"
+        android:layout_alignRight="@id/title_tv"
+        android:layout_marginTop="5dp"
+        android:layout_marginBottom="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="5/30/2018"
+        />
+
+
+</RelativeLayout>

+ 18 - 0
ApexDrivers/app/src/main/res/layout/pop_cell.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="40dp">
+
+    <TextView
+        android:id="@+id/pop_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:textAlignment="center"
+        android:gravity="center"
+        android:text="201805300010"
+        />
+
+</android.support.constraint.ConstraintLayout>

+ 15 - 0
ApexDrivers/app/src/main/res/layout/pop_list_view.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#ffffff"
+    >
+
+    <ListView
+        android:id="@+id/pop_list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
+
+</android.support.constraint.ConstraintLayout>

+ 32 - 0
ApexDrivers/app/src/main/res/layout/section_header.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="50dp"
+                android:background="#cccccc"
+    >
+
+    <Button
+        android:id="@+id/section_switch_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_alignParentRight="true"
+        android:layout_margin="5dp"
+        android:textSize="17sp"
+        android:textColor="#ffffff"
+        android:text="Hide"
+        android:textAllCaps="false"
+        />
+
+    <TextView
+        android:id="@+id/header_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_marginLeft="5dp"
+        android:layout_toLeftOf="@id/section_switch_btn"
+        android:textSize="25sp"
+        android:textColor="#000000"
+        android:text="New Order"
+        />
+
+</RelativeLayout>

+ 30 - 0
ApexDrivers/app/src/main/res/layout/update_label_cell.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="55dp">
+
+    <TextView
+        android:id="@+id/update_label_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_margin="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Order ID"
+        />
+
+    <TextView
+        android:id="@+id/update_label_value_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_below="@id/update_label_title_tv"
+        android:layout_alignLeft="@id/update_label_title_tv"
+        android:layout_alignRight="@id/update_label_title_tv"
+        android:layout_marginBottom="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="AFS20180530001200"
+        />
+
+
+</RelativeLayout>

+ 29 - 0
ApexDrivers/app/src/main/res/layout/update_multinput_cell.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="135dp">
+
+    <TextView
+        android:id="@+id/update_multiple_input_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_margin="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Instruction"
+        />
+
+    <EditText
+        android:id="@+id/update_multiple_input_value_tv"
+        android:layout_width="match_parent"
+        android:layout_height="100dp"
+        android:layout_below="@id/update_multiple_input_title_tv"
+        android:layout_alignLeft="@id/update_multiple_input_title_tv"
+        android:layout_alignRight="@id/update_multiple_input_title_tv"
+        android:layout_marginBottom="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="滴滴哒"
+        />
+
+</RelativeLayout>

+ 27 - 0
ApexDrivers/app/src/main/res/layout/update_photo_cell.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="130dp">
+
+    <ImageButton
+        android:id="@+id/update_photo_btn"
+        android:layout_width="120dp"
+        android:layout_height="120dp"
+        android:layout_alignParentRight="true"
+        android:layout_margin="5dp"
+        />
+
+    <TextView
+        android:id="@+id/update_photo_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="5dp"
+        android:layout_toLeftOf="@id/update_photo_btn"
+        android:layout_centerVertical="true"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="Container Photo"
+        />
+
+</RelativeLayout>

+ 48 - 0
ApexDrivers/app/src/main/res/layout/update_scanner_input_cell.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+
+    <TextView
+        android:id="@+id/update_scanner_input_title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:layout_margin="5dp"
+        android:textSize="17sp"
+        android:textColor="#000000"
+        android:text="File ID"
+        />
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/update_scanner_input_title_tv"
+        android:layout_alignLeft="@id/update_scanner_input_title_tv"
+        android:layout_alignRight="@id/update_scanner_input_title_tv"
+        android:layout_marginBottom="5dp"
+        >
+
+        <ImageButton
+            android:id="@+id/update_scanner_btn"
+            android:layout_width="30dp"
+            android:layout_height="30dp"
+            android:layout_centerVertical="true"
+            android:layout_alignParentRight="true"
+            android:layout_marginLeft="5dp"
+            />
+
+        <EditText
+            android:id="@+id/update_input_tv"
+            android:layout_width="match_parent"
+            android:layout_height="40dp"
+            android:layout_toLeftOf="@id/update_scanner_btn"
+            android:layout_centerVertical="true"
+            android:singleLine="true"
+            android:maxLines="1"
+            />
+
+    </RelativeLayout>
+
+</RelativeLayout>

BIN
ApexDrivers/app/src/main/res/raw/beep.ogg


+ 239 - 0
ApexDrivers/app/src/main/res/raw/fake_order_detail.json

@@ -0,0 +1,239 @@
+{
+    "result": 2,
+    "sections": [
+                 {
+                 "title": "Overview",
+                 "values": [
+                            {
+                            "title": "Order ID",
+                            "value": "201805300010",
+                            "type": 0
+                            },
+                            {
+                            "title": "Dispatcher",
+                            "value": "Jack",
+                            "type": 0
+                            },
+                            {
+                            "title": "Container No.",
+                            "value": "TCNU6432476",
+                            "type": 0
+                            },
+                            {
+                            "title": "Type",
+                            "value": "Pickup Order Import",
+                            "type": 0
+                            },
+                            {
+                            "title": "Status",
+                            "value": "C2-Delivered Empty",
+                            "type": 0
+                            },
+                            {
+                            "title": "Action",
+                            "value": "Delivered",
+                            "type": 0
+                            },
+                            {
+                            "title": "Instuctions",
+                            "value": "据知情人士介绍,微软公司最近就收购 GitHub 一事召开相关会议。这意味着双方再次开启多年以来断断续续的对话通道。\\\\n之所以选择这一时间,主要考虑到 GitHub 作为软件开发者群体中的高人气平台供应方,最近一直难以找到理想的 CEO 候选人。",
+                            "type": 0
+                            }
+                            ]
+                 },
+                 {
+                 "title": "Action",
+                 "values": [
+                            {
+                            "actions": [
+                                        {
+                                        "actionType": "0",
+                                        "actionTitle": "Reject",
+                                        "url": "",
+                                        "params": {
+                                        "action": "reject",
+                                        "orderID": "20180530001200"
+                                        }
+                                        },
+                                        {
+                                        "actionType": "0",
+                                        "actionTitle": "Accept",
+                                        "url": "",
+                                        "params": {
+                                        "action": "accept",
+                                        "orderID": "20180530001200"
+                                        }
+                                        },
+                                        {
+                                        "actionType": "1",
+                                        "actionTitle": "Update Action",
+                                        "actionSubType": "0",
+                                        "enums": [
+                                                  {
+                                                  "actionTitle": "Action 0",
+                                                  "actionID": "0"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 1",
+                                                  "actionID": "1"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 2",
+                                                  "actionID": "2"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 3",
+                                                  "actionID": "3"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 4",
+                                                  "actionID": "4"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 5",
+                                                  "actionID": "5"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 6",
+                                                  "actionID": "6"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 7",
+                                                  "actionID": "7"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 8",
+                                                  "actionID": "8"
+                                                  },
+                                                  {
+                                                  "actionTitle": "Action 9",
+                                                  "actionID": "9"
+                                                  }
+                                                  ]
+                                        }
+                                        ],
+                            "type": 2
+                            }
+                            ]
+                 },
+                 {
+                 "title": "Datetime",
+                 "values": [
+                            {
+                            "type": 1,
+                            "value": "DEMURRAGE LFD\n\nTERMINAL PICKUP APPT\n\nDELIVERY  APPT(setup wiwhse)\n\nPICKUP ON\n据知情人士介绍,微软公司最近就收购 GitHub 一事召开相关会议。这意味着双方再次开启多年以来断断续续的对话通道。\\n之所以选择这一时间,主要考虑到 GitHub 作为软件开发者群体中的高人气平台供应方,最近一直难以找到理想的 CEO 候选人。\\GitHub 公司 2015 年的估值为 20 亿美元,这主要归功于红杉资本为其砸下的 2.5 亿美元投资。此外,多位消息人士告诉我们,GitHub 方面的财务状况相当不错。然而,最终收购价格可能达到 50 亿美元甚至更高,而且考虑到谈判正在进行,目前尚不清楚微软是否愿意支付这么可观的价码。"
+                            }
+                            ]
+                 },
+                 {
+                 "title": "Container Info",
+                 "values": [
+                            {
+                            "type": 3,
+                            "title": "Pick Up",
+                            "location": "TRANS PACIFIC CONTAINER SERVICE\n\nBERTH 30 2800 7TH ST\n\nOAKLAND,CA\n\n"
+                            },
+                            {
+                            "title": "TEL",
+                            "value": "510-8600,FAX:510-8600",
+                            "type": 0
+                            },
+                            {
+                            "title": "EMAIL",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "ATTN",
+                            "value": "",
+                            "type": 0
+                            }
+                            ]
+                 },
+                 {
+                 "title": "Chasis Info",
+                 "values": [
+                            {
+                            "type": 3,
+                            "title": "Pick Up",
+                            "location": "TRANS PACIFIC CONTAINER SERVICE\n\nBERTH 30 2800 7TH ST\n\nOAKLAND,CA\n\n"
+                            },
+                            {
+                            "title": "TEL",
+                            "value": "510-8600,FAX:510-8600",
+                            "type": 0
+                            },
+                            {
+                            "title": "EMAIL",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "ATTN",
+                            "value": "",
+                            "type": 0
+                            }
+                            ]
+                 },
+                 {
+                 "title": "Container Info",
+                 "values": [
+                            {
+                            "title": "Container No.",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "Quantity",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "Size",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "Sch B No.",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "Value",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "Marks",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "Description",
+                            "value": "",
+                            "type": 0
+                            }
+                            ]
+                 },
+                 {
+                 "title": "File Info",
+                 "values": [
+                            {
+                            "title": "File No.",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "BOL No.",
+                            "value": "",
+                            "type": 0
+                            },
+                            {
+                            "title": "Shipper",
+                            "value": "",
+                            "type": 0
+                            }
+                            ]
+                 }
+                 ]
+}

+ 92 - 0
ApexDrivers/app/src/main/res/raw/fake_order_edit.json

@@ -0,0 +1,92 @@
+{
+    "result": 2,
+    "sections": [
+                 {
+                 "title": "Update Action",
+                 "items": [
+                           {
+                           "type": 0,
+                           "title": "Order ID",
+                           "value": "AFS20180530001200"
+                           },
+                           {
+                           "type": 0,
+                           "title": "Dispatcher",
+                           "value": "Jack Li"
+                           },
+                           {
+                           "type": 0,
+                           "title": "Current Action",
+                           "value": "Delivered"
+                           },
+                           {
+                           "type": 1,
+                           "title": "File No.",
+                           "key": "file_no_0",
+                           "value": "AFS20180530001200",
+                           "scannable": true
+                           },
+                           {
+                           "type": 1,
+                           "title": "File No.",
+                           "key": "file_no_1",
+                           "value": "AFS20180530001200",
+                           "scannable": false
+                           },
+                           {
+                           "type": 2,
+                           "key": "instruction_0",
+                           "title": "Instruction",
+                           "value": "不同于一般的 bug,性能问题因为并没有统一的标准,而且与用户的机器环境相关性较大,所以往往是在产品上线后才被发现,也导致解决问题的周期很长。微信读书 1.3.0 版本之前,性能问题基本都来自于用户反馈(包括测试人员),受限于测试时间和用户反馈的积极性,性能问题往往到了比较严重的程度,开发人员才真正发现问题。\n\n但是,移动应用要保证良好的用户体验,产品在性能方面的表现极其重要。为了尽可能早、尽可能全面地收集产品的性能问题,就避免不了对产品做性能监控。我们主要从两个维度进行了监控"
+                           },
+                           {
+                           "type": 3,
+                           "key": "container_photo_0",
+                           "title": "Container Photo",
+                           "path": "photoPath"
+                           },
+                           {
+                           "type": 0,
+                           "title": "Order ID",
+                           "value": "AFS20180530001200"
+                           },
+                           {
+                           "type": 0,
+                           "title": "Dispatcher",
+                           "value": "Jack Li"
+                           },
+                           {
+                           "type": 0,
+                           "title": "Current Action",
+                           "value": "Delivered"
+                           },
+                           {
+                           "type": 1,
+                           "title": "File No.",
+                           "key": "file_no_2",
+                           "value": "AFS20180530001200",
+                           "scannable": true
+                           },
+                           {
+                           "type": 1,
+                           "title": "File No.",
+                           "key": "file_no_3",
+                           "value": "AFS20180530001200",
+                           "scannable": false
+                           },
+                           {
+                           "type": 2,
+                           "title": "Instruction",
+                           "key": "instruction_1",
+                           "value": "不同于一般的 bug,性能问题因为并没有统一的标准,而且与用户的机器环境相关性较大,所以往往是在产品上线后才被发现,也导致解决问题的周期很长。微信读书 1.3.0 版本之前,性能问题基本都来自于用户反馈(包括测试人员),受限于测试时间和用户反馈的积极性,性能问题往往到了比较严重的程度,开发人员才真正发现问题。\n\n但是,移动应用要保证良好的用户体验,产品在性能方面的表现极其重要。为了尽可能早、尽可能全面地收集产品的性能问题,就避免不了对产品做性能监控。我们主要从两个维度进行了监控"
+                           },
+                           {
+                           "type": 3,
+                           "key": "container_photo_1",
+                           "title": "Container Photo",
+                           "path": "photoPath"
+                           }
+                           ]
+                 }
+                 ]
+}

+ 95 - 0
ApexDrivers/app/src/main/res/raw/fake_order_list.json

@@ -0,0 +1,95 @@
+{
+  "result": 2,
+  "sections": [
+    {
+      "type": 2,
+      "title": "New Order",
+      "orders": [
+        {
+          "orderID": "00000001",
+          "orderNo": "AFS180530001200",
+          "containerNo": "TCNU6432476",
+          "date": "5/30/2018",
+          "status": 2,
+          "title": "Pickup Order New"
+        },
+        {
+          "orderID": "00000002",
+          "orderNo": "AFS180530001201",
+          "containerNo": "TCNU6432477",
+          "date": "5/30/2018",
+          "status": 2,
+          "title": "Pickup Order New"
+        },
+        {
+          "orderID": "00000003",
+          "orderNo": "AFS180530001202",
+          "containerNo": "TCNU6432478",
+          "date": "5/30/2018",
+          "status": 2,
+          "title": "Pickup Order New"
+        }
+      ]
+    },
+    {
+      "type": 1,
+      "title": "Processing Order",
+      "orders": [
+        {
+          "orderID": "00000001",
+          "orderNo": "AFS180530001200",
+          "containerNo": "TCNU6432476",
+          "date": "5/30/2018",
+          "status": 1,
+          "title": "Pickup Order New"
+        },
+        {
+          "orderID": "00000002",
+          "orderNo": "AFS180530001201",
+          "containerNo": "TCNU6432477",
+          "date": "5/30/2018",
+          "status": 1,
+          "title": "Pickup Order New"
+        },
+        {
+          "orderID": "00000003",
+          "orderNo": "AFS180530001202",
+          "containerNo": "TCNU6432478",
+          "date": "5/30/2018",
+          "status": 1,
+          "title": "Pickup Order New"
+        }
+      ]
+    },
+    {
+      "type": 0,
+      "title": "Finish Order",
+      "orders": [
+        {
+          "orderID": "00000001",
+          "orderNo": "AFS180530001200",
+          "containerNo": "TCNU6432476",
+          "date": "5/30/2018",
+          "status": 0,
+          "title": "Pickup Order New"
+        },
+        {
+          "orderID": "00000002",
+          "orderNo": "AFS180530001201",
+          "containerNo": "TCNU6432477",
+          "date": "5/30/2018",
+          "status": 0,
+          "title": "Pickup Order New"
+        },
+        {
+          "orderID": "00000003",
+          "orderNo": "AFS180530001202",
+          "containerNo": "TCNU6432478",
+          "date": "5/30/2018",
+          "status": 0,
+          "title": "Pickup Order New"
+        }
+      ]
+    }
+  ]
+}

+ 47 - 0
ApexDrivers/app/src/main/res/values/arrays.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <string-array name="country_codes">
+    <item>-</item>
+    <item>AR</item>
+    <item>AU</item>
+    <item>BR</item>
+    <item>BG</item>
+    <item>CA</item>
+    <item>CH</item>
+    <item>CN</item>
+    <item>CZ</item>
+    <item>DE</item>
+    <item>DK</item>
+    <item>ES</item>
+    <item>FI</item>
+    <item>FR</item>
+    <item>GB</item>
+    <item>GR</item>
+    <item>HU</item>
+    <item>ID</item>
+    <item>IT</item>
+    <item>JP</item>
+    <item>KR</item>
+    <item>NL</item>
+    <item>PL</item>
+    <item>PT</item>
+    <item>RO</item>    
+    <item>RU</item>
+    <item>SE</item>
+    <item>SK</item>
+    <item>SI</item>
+    <item>TR</item>
+    <item>TW</item>
+    <item>US</item>
+  </string-array>
+  <string-array name="preferences_front_light_values">
+    <item>ON</item>
+    <item>AUTO</item>
+    <item>OFF</item>
+  </string-array>
+  <string-array name="preferences_front_light_options">
+    <item>@string/preferences_front_light_on</item>
+    <item>@string/preferences_front_light_auto</item>
+    <item>@string/preferences_front_light_off</item>
+  </string-array>
+</resources>

+ 15 - 0
ApexDrivers/app/src/main/res/values/colors.xml

@@ -3,4 +3,19 @@
     <color name="colorPrimary">#3F51B5</color>
     <color name="colorPrimaryDark">#303F9F</color>
     <color name="colorAccent">#FF4081</color>
+
+    <color name="icon_gray">#444445</color>
+    <color name="icon_red">#b22123</color>
+
+    <color name="transparent">#00000000</color>
+    <color name="status_text">#ffffffff</color>
+
+    <color name="viewfinder_mask">#60000000</color>
+    <color name="result_view">#b0000000</color>
+    <color name="viewfinder_laser">#ffcc0000</color>
+    <color name="possible_result_points">#c0ffbd21</color>
+
+    <color name="message_success">#ee00ff00</color>
+    <color name="message_fail">#eeff0000</color>
+
 </resources>

+ 3 - 0
ApexDrivers/app/src/main/res/values/dimens.xml

@@ -0,0 +1,3 @@
+<resources>
+    <dimen name="fab_margin">16dp</dimen>
+</resources>

+ 25 - 0
ApexDrivers/app/src/main/res/values/ids.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+  <item type="id" name="decode"/>
+  <item type="id" name="decode_failed"/>
+  <item type="id" name="decode_succeeded"/>
+  <item type="id" name="launch_product_query"/>
+  <item type="id" name="quit"/>
+  <item type="id" name="restart_preview"/>
+  <item type="id" name="return_scan_result"/>
+</resources>

+ 64 - 0
ApexDrivers/app/src/main/res/values/strings.xml

@@ -1,3 +1,67 @@
 <resources>
     <string name="app_name">Apex &amp; Drivers</string>
+
+    <string name="str_ver">ver:</string>
+
+    <string name="error_field_required">This field is required</string>
+    <string name="error_invalid_email">This email address is invalid</string>
+    <string name="login_progress_signing_in">Signing in&#8230;</string>
+    <string name="str_email_sent">Email has been sent.</string>
+    <string name="str_retrieve_success">Retrieve successfully!</string>
+    <string name="msg_connection_none">No available connection </string>
+    <string name="msg_net_error">Can not connect to server</string>
+    <string name="msg_net_resulterror">An error occur on server,please contact our sales.CODE</string>
+    <string name="str_invalid_pore">Invalid user name or email</string>
+    <string name="str_retrieve_failed">Retrieve failed</string>
+
+    <string name="error_incorrect_password">This password is incorrect</string>
+    <string name="msg_ver_low">Client version is too low</string>
+    <string name="action_sign_in_short">Sign in</string>
+    <string name="prompt_email">Email</string>
+    <string name="prompt_user">User</string>
+    <string name="prompt_password">Password</string>
+    <string name="str_savepass">Save Password</string>
+    <string name="action_sign_in_register"><b>Login</b></string>
+    <string name="str_retrievepass">Retrieve password</string>
+    <string name="title_activity_detail">DetailActivity</string>
+
+    <string name="msg_default_status">Place a barcode inside the viewfinder rectangle to scan it.</string>
+
+    <string name="preferences_actions_title">When a barcode is found\u2026</string>
+    <string name="preferences_auto_focus_title">Use auto focus</string>
+    <string name="preferences_bulk_mode_summary">Scan and save many barcodes continuously</string>
+    <string name="preferences_bulk_mode_title">Bulk scan mode</string>
+    <string name="preferences_copy_to_clipboard_title">Copy to clipboard</string>
+    <string name="preferences_custom_product_search_summary" formatted="false">Substitutions: %s = contents, %f = format, %t = type</string>
+    <string name="preferences_custom_product_search_title">Custom search URL</string>
+    <string name="preferences_decode_1D_title">1D barcodes</string>
+    <string name="preferences_decode_Data_Matrix_title">Data Matrix</string>
+    <string name="preferences_decode_QR_title">QR Codes</string>
+    <string name="preferences_device_bug_workarounds_title">Device Bug Workarounds</string>
+    <string name="preferences_disable_continuous_focus_summary">Use only standard focus mode</string>
+    <string name="preferences_disable_continuous_focus_title">No continuous focus</string>
+    <string name="preferences_front_light_summary">Improves scanning in low light on some phones, but may cause glare. Does not work on all phones.</string>
+    <string name="preferences_front_light_title">Use front light</string>
+    <string name="preferences_front_light_auto">Automatic</string>
+    <string name="preferences_front_light_off">Off</string>
+    <string name="preferences_front_light_on">On</string>
+    <string name="preferences_general_title">General settings</string>
+    <string name="preferences_invert_scan_title">Invert scan</string>
+    <string name="preferences_invert_scan_summary">Scan for white barcodes on black background. Not available on some devices.</string>
+    <string name="preferences_play_beep_title">Beep</string>
+    <string name="preferences_remember_duplicates_summary">Store multiple scans of the same barcode in History</string>
+    <string name="preferences_remember_duplicates_title">Remember duplicates</string>
+    <string name="preferences_result_title">Result settings</string>
+    <string name="preferences_scanning_title">When scanning for barcodes, decode\u2026</string>
+    <string name="preferences_search_country">Search country</string>
+    <string name="preferences_try_bsplus">Try Barcode Scanner+</string>
+    <string name="preferences_try_bsplus_summary">Enhanced with new features and interface</string>
+    <string name="preferences_supplemental_summary">Try to retrieve more information about the barcode contents</string>
+    <string name="preferences_supplemental_title">Retrieve more info</string>
+    <string name="preferences_vibrate_title">Vibrate</string>
+
+    <string name="msg_camera_framework_bug">Sorry, the Android camera encountered a problem. You may need to restart the device.</string>
+    <string name="button_ok">OK</string>
+
+
 </resources>

+ 15 - 0
ApexDrivers/app/src/main/res/values/styles.xml

@@ -8,4 +8,19 @@
         <item name="colorAccent">@color/colorAccent</item>
     </style>
 
+    <style name="LoginFormContainer">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:padding">16dp</item>
+    </style>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
+
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
+
 </resources>

+ 110 - 0
ApexDrivers/app/src/main/res/xml/preferences.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2008 ZXing authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+  <PreferenceCategory android:title="@string/preferences_scanning_title">
+    <CheckBoxPreference
+        android:key="preferences_decode_1D"
+        android:defaultValue="true"
+        android:title="@string/preferences_decode_1D_title"/>
+    <CheckBoxPreference
+        android:key="preferences_decode_QR"
+        android:defaultValue="true"
+        android:title="@string/preferences_decode_QR_title"/>
+    <CheckBoxPreference
+        android:key="preferences_decode_Data_Matrix"
+        android:defaultValue="true"
+        android:title="@string/preferences_decode_Data_Matrix_title"/>
+  </PreferenceCategory>
+  <PreferenceCategory android:title="@string/preferences_actions_title">
+    <CheckBoxPreference
+        android:key="preferences_play_beep"
+        android:defaultValue="true"
+        android:title="@string/preferences_play_beep_title"/>
+    <CheckBoxPreference
+        android:key="preferences_vibrate"
+        android:defaultValue="false"
+        android:title="@string/preferences_vibrate_title"/>
+    <CheckBoxPreference
+        android:key="preferences_copy_to_clipboard"
+        android:defaultValue="true"
+        android:title="@string/preferences_copy_to_clipboard_title"/>
+    <CheckBoxPreference
+        android:key="preferences_remember_duplicates"
+        android:defaultValue="false"
+        android:title="@string/preferences_remember_duplicates_title"
+        android:summary="@string/preferences_remember_duplicates_summary"/>
+    <CheckBoxPreference
+        android:key="preferences_supplemental"
+        android:defaultValue="true"
+        android:title="@string/preferences_supplemental_title"
+        android:summary="@string/preferences_supplemental_summary"/>
+  </PreferenceCategory>
+  <PreferenceCategory android:title="@string/preferences_result_title">
+    <EditTextPreference
+        android:key="preferences_custom_product_search"
+        android:title="@string/preferences_custom_product_search_title"
+        android:summary="@string/preferences_custom_product_search_summary"/>
+  </PreferenceCategory>
+  <PreferenceCategory android:title="@string/preferences_general_title">
+    <ListPreference
+        android:entries="@array/preferences_front_light_options"
+        android:entryValues="@array/preferences_front_light_values"
+        android:key="preferences_front_light_mode"
+        android:defaultValue="OFF"
+        android:title="@string/preferences_front_light_title"
+        android:summary="@string/preferences_front_light_summary"/>
+    <CheckBoxPreference
+        android:key="preferences_auto_focus"
+        android:defaultValue="true"
+        android:title="@string/preferences_auto_focus_title"/>
+    <CheckBoxPreference
+        android:key="preferences_invert_scan"
+        android:defaultValue="false"
+        android:title="@string/preferences_invert_scan_title"
+        android:summary="@string/preferences_invert_scan_summary"/>
+    <CheckBoxPreference
+        android:key="preferences_bulk_mode"
+        android:defaultValue="false"
+        android:title="@string/preferences_bulk_mode_title"
+        android:summary="@string/preferences_bulk_mode_summary"/>
+    <ListPreference
+        android:key="preferences_search_country"
+        android:defaultValue="-"
+        android:entries="@array/country_codes"
+        android:entryValues="@array/country_codes"
+        android:title="@string/preferences_search_country"/>
+  </PreferenceCategory>
+  <PreferenceCategory android:title="@string/preferences_device_bug_workarounds_title">
+    <CheckBoxPreference
+        android:key="preferences_disable_continuous_focus"
+        android:defaultValue="true"
+        android:title="@string/preferences_disable_continuous_focus_title"
+        android:summary="@string/preferences_disable_continuous_focus_summary"/>
+    <!--
+    <CheckBoxPreference
+        android:key="preferences_disable_exposure"
+        android:defaultValue="false"
+        android:title="@string/preferences_disable_exposure_title"/>
+     -->
+  </PreferenceCategory>
+  <PreferenceCategory android:title="@string/preferences_try_bsplus">
+    <Preference android:title="@string/preferences_try_bsplus"
+                android:summary="@string/preferences_try_bsplus_summary">
+      <intent android:action="android.intent.action.VIEW" android:data="market://details?id=com.srowen.bs.android" />
+    </Preference>
+  </PreferenceCategory>
+</PreferenceScreen>