Преглед изворни кода

RedAnt Mobile
移植ra image 编译通过,

Ray Zhang пре 8 година
родитељ
комит
761bdedbb6
100 измењених фајлова са 16940 додато и 3 уклоњено
  1. 5 0
      RedAnt Mobile/app/app.iml
  2. 7 0
      RedAnt Mobile/app/build.gradle
  3. BIN
      RedAnt Mobile/app/libs/bcprov-jdk15on-157.jar
  4. BIN
      RedAnt Mobile/app/libs/core-2.3.0.jar
  5. BIN
      RedAnt Mobile/app/libs/httpmime-4.1.1.jar
  6. 132 1
      RedAnt Mobile/app/src/main/AndroidManifest.xml
  7. 112 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/camera/AutoFocusManager.java
  8. 307 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/camera/CameraConfigurationManager.java
  9. 311 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/camera/CameraManager.java
  10. 43 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/camera/FrontLightMode.java
  11. 56 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/camera/PreviewCallback.java
  12. 62 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/camera/open/OpenCameraInterface.java
  13. 77 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/AboutActivity.java
  14. 87 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/AmbientLightManager.java
  15. 130 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/BeepManager.java
  16. 33 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/BootReceiver.java
  17. 887 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/CaptureActivity.java
  18. 170 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/CaptureActivityHandler.java
  19. 114 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/CrashHandler.java
  20. 102 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/DecodeFormatManager.java
  21. 122 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/DecodeHandler.java
  22. 236 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/DecodeHintManager.java
  23. 104 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/DecodeThread.java
  24. 49 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/FinishListener.java
  25. 243 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/HttpHelper.java
  26. 116 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/InactivityTimer.java
  27. 261 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/Intents.java
  28. 63 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/LicenseActivity.java
  29. 1848 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/MainActivity.java
  30. 286 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/ModeActivity.java
  31. 113 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/Model/ManufactureListActivity.java
  32. 42 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/Model/ModelActivity.java
  33. 52 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/POP/PopActivity.java
  34. 602 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/CustomLayoutManager.java
  35. 61 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/GridItemDecoration.java
  36. 36 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/GridLayoutRecycler/RAGridLayoutManager.java
  37. 174 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/GridLayoutRecycler/RAPreviewRecyclerView.java
  38. 199 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/NewPhotoPreviewActivity.java
  39. 417 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/PhotoGridActivity.java
  40. 242 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/PhotoListActivity.java
  41. 38 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/RAGridView.java
  42. 202 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/XuanImageView/RotationGestureDetector.java
  43. 1033 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/XuanImageView/XuanImageView.java
  44. 13 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/XuanImageView/XuanImageViewSettings.java
  45. 206 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoPreviewActivity.java
  46. 56 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PreferencesActivity.java
  47. 73 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PreferencesFragment.java
  48. 319 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/ServerSettingActivity.java
  49. 32 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/SplashActivity.java
  50. 445 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/TaskActivity.java
  51. 619 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/UploadList/UploadListActivity.java
  52. 436 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/UploadQueueActivity.java
  53. 552 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/UploadService.java
  54. 35 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/ViewfinderResultPointCallback.java
  55. 189 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/ViewfinderView.java
  56. 197 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/uploadSettingActivity.java
  57. 684 2
      RedAnt Mobile/app/src/main/java/com/usai/redant/redantmobile/LoginActivity.java
  58. 129 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/redantmobile/RedAntApplication.java
  59. 242 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/AES.java
  60. 43 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/MD5.java
  61. 1627 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/Network.java
  62. 129 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/RAOperationQueue.java
  63. 725 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/RAUploadManager.java
  64. 569 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/RAUtil.java
  65. 69 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/SqlOpenHelper.java
  66. 262 0
      RedAnt Mobile/app/src/main/java/com/usai/redant/util/dbgUtil.java
  67. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/bar2.png
  68. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_camera.png
  69. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_reload.png
  70. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_scan.png
  71. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_upload.png
  72. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_launcher.png
  73. 20 0
      RedAnt Mobile/app/src/main/res/drawable-hdpi/imagebutton.xml
  74. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/no_pic.png
  75. BIN
      RedAnt Mobile/app/src/main/res/drawable-hdpi/picture_frame.png
  76. BIN
      RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_camera.png
  77. BIN
      RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_reload.png
  78. BIN
      RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_scan.png
  79. BIN
      RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_upload.png
  80. BIN
      RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_launcher.png
  81. BIN
      RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_camera.png
  82. BIN
      RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_reload.png
  83. BIN
      RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_scan.png
  84. BIN
      RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_upload.png
  85. BIN
      RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_launcher.png
  86. BIN
      RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_camera.png
  87. BIN
      RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_reload.png
  88. BIN
      RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_scan.png
  89. BIN
      RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_upload.png
  90. BIN
      RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_launcher.png
  91. BIN
      RedAnt Mobile/app/src/main/res/drawable-xxhdpi/red_ant_logo.png
  92. 18 0
      RedAnt Mobile/app/src/main/res/drawable/black_border.xml
  93. BIN
      RedAnt Mobile/app/src/main/res/drawable/check_check.png
  94. BIN
      RedAnt Mobile/app/src/main/res/drawable/check_none.png
  95. 13 0
      RedAnt Mobile/app/src/main/res/drawable/preview_index_corner.xml
  96. 9 0
      RedAnt Mobile/app/src/main/res/drawable/switch_thumb.xml
  97. 8 0
      RedAnt Mobile/app/src/main/res/drawable/switch_track.xml
  98. 15 0
      RedAnt Mobile/app/src/main/res/drawable/thumb_off.xml
  99. 17 0
      RedAnt Mobile/app/src/main/res/drawable/thumb_on.xml
  100. 15 0
      RedAnt Mobile/app/src/main/res/drawable/track_off.xml

+ 5 - 0
RedAnt Mobile/app/app.iml

@@ -97,6 +97,7 @@
     <orderEntry type="library" exported="" name="support-core-ui-26.0.0-alpha1" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="runner-0.5" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="espresso-idling-resource-2.2.2" level="project" />
+    <orderEntry type="library" exported="" name="core-2.3.0" level="project" />
     <orderEntry type="library" exported="" name="support-fragment-26.0.0-alpha1" level="project" />
     <orderEntry type="library" exported="" name="constraint-layout-1.0.2" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="hamcrest-library-1.3" level="project" />
@@ -109,15 +110,19 @@
     <orderEntry type="library" exported="" name="support-core-utils-26.0.0-alpha1" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="rules-0.5" level="project" />
     <orderEntry type="library" exported="" name="constraint-layout-solver-1.0.2" level="project" />
+    <orderEntry type="library" exported="" name="httpmime-4.1.1" level="project" />
     <orderEntry type="library" exported="" name="support-vector-drawable-26.0.0-alpha1" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="javax.annotation-api-1.2" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="javax.inject-1" level="project" />
     <orderEntry type="library" exported="" name="appcompat-v7-26.0.0-alpha1" level="project" />
+    <orderEntry type="library" exported="" name="bcprov-jdk15on-157" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="javawriter-2.1.1" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" />
     <orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" />
+    <orderEntry type="library" exported="" name="recyclerview-v7-26.0.0-alpha1" level="project" />
     <orderEntry type="library" exported="" name="support-compat-26.0.0-alpha1" level="project" />
     <orderEntry type="library" exported="" name="support-annotations-26.0.0-alpha1" level="project" />
     <orderEntry type="library" exported="" name="animated-vector-drawable-26.0.0-alpha1" level="project" />
+    <orderEntry type="library" exported="" name="org.apache.http.legacy-android-26" level="project" />
   </component>
 </module>

+ 7 - 0
RedAnt Mobile/app/build.gradle

@@ -24,7 +24,14 @@ dependencies {
     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
         exclude group: 'com.android.support', module: 'support-annotations'
     })
+    compile files('libs/core-2.3.0.jar')
+    compile files('libs/httpmime-4.1.1.jar')
+    compile files('libs/bcprov-jdk15on-157.jar')
     compile 'com.android.support:appcompat-v7:26.+'
     compile 'com.android.support.constraint:constraint-layout:1.0.2'
+    compile 'com.android.support:recyclerview-v7:26.+'
     testCompile 'junit:junit:4.12'
 }
+android {
+    useLibrary 'org.apache.http.legacy'
+}

BIN
RedAnt Mobile/app/libs/bcprov-jdk15on-157.jar


BIN
RedAnt Mobile/app/libs/core-2.3.0.jar


BIN
RedAnt Mobile/app/libs/httpmime-4.1.1.jar


+ 132 - 1
RedAnt Mobile/app/src/main/AndroidManifest.xml

@@ -2,7 +2,19 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.usai.redant.redantmobile">
 
+    <uses-permission android:name="android.permission.CAMERA"/>
+    <uses-permission android:name="android.permission.VIBRATE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
+
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
+
     <application
+        android:name=".RedAntApplication"
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
@@ -24,6 +36,125 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
-    </application>
+
+
+    <activity
+        android:name="com.usai.redant.raimage.MainActivity"
+        android:label="@string/app_name"
+        android:stateNotNeeded="true"
+        android:theme="@style/Theme.AppCompat.Light">
+
+        <!--
+             <intent-filter>
+            <action android:name="android.intent.action.MAIN" />
+
+            <category android:name="android.intent.category.LAUNCHER" />
+        </intent-filter>
+        -->
+    </activity>
+    <activity
+        android:name="com.usai.redant.raimage.CaptureActivity"
+        android:clearTaskOnLaunch="true"
+        android:label="Scan"
+        android:screenOrientation="sensorLandscape"
+        android:stateNotNeeded="true"
+        android:theme="@style/CaptureTheme"
+        android:windowSoftInputMode="stateAlwaysHidden">
+
+        <!--
+             <intent-filter>
+            <action android:name="android.intent.action.MAIN" />
+
+            <category android:name="android.intent.category.LAUNCHER" />
+        </intent-filter>
+        -->
+    </activity>
+    <activity
+        android:name="com.usai.redant.raimage.UploadQueueActivity"
+        android:label="Upload queue"
+        android:screenOrientation="sensorLandscape"
+        android:theme="@style/CaptureTheme"/>
+    <activity
+        android:name="com.usai.redant.raimage.PreferencesActivity"
+        android:label="@string/preferences_name"
+        android:stateNotNeeded="true"/>
+    <activity
+        android:name="com.usai.redant.raimage.PhotoPreviewActivity"
+        android:label="Photo preview"
+        android:screenOrientation="sensorLandscape"
+        android:windowSoftInputMode="stateHidden|adjustResize"/>
+
+    <receiver android:name="com.usai.redant.raimage.BootReceiver">
+        <intent-filter android:priority="2147483647">
+            <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
+        </intent-filter>
+    </receiver>
+
+    <service
+        android:name="com.usai.redant.raimage.UploadService"
+        android:label="usai upload service">
+        <intent-filter>
+            <action android:name="com.usai.raimage.uploadservice"/>
+        </intent-filter>
+    </service>
+
+    <activity
+        android:name="com.usai.redant.raimage.AboutActivity"
+        android:label="@string/title_activity_about"
+        android:screenOrientation="sensorLandscape"/>
+    <activity
+        android:name="com.usai.redant.raimage.LicenseActivity"
+        android:label="@string/title_activity_license"
+        android:screenOrientation="sensorLandscape"/>
+    <activity
+        android:name="com.usai.redant.raimage.ServerSettingActivity"
+        android:label="@string/title_activity_service_setting"
+        android:screenOrientation="portrait"/>
+
+
+
+    <activity
+        android:name="com.usai.redant.raimage.ModeActivity"
+        android:theme="@style/Base.Theme.AppCompat.Light"/>
+    <activity
+        android:name="com.usai.redant.raimage.uploadSettingActivity"
+        android:theme="@style/Base.Theme.AppCompat.Light"/>
+    <activity
+        android:name="com.usai.redant.raimage.POP.PopActivity"
+        android:label="@string/app_name"
+        android:stateNotNeeded="true"
+        android:theme="@style/Theme.AppCompat.Light"
+        android:windowSoftInputMode="stateHidden|adjustResize"/>
+    <activity
+        android:name="com.usai.redant.raimage.Model.ModelActivity"
+        android:label="@string/app_name"
+        android:stateNotNeeded="true"
+        android:theme="@style/Theme.AppCompat.Light"
+        android:windowSoftInputMode="stateHidden|adjustResize"/>
+    <activity
+        android:name="com.usai.redant.raimage.PhotoList.PhotoListActivity"
+        android:stateNotNeeded="true"
+        android:theme="@style/Theme.AppCompat.Light"/>
+    <activity
+        android:name="com.usai.redant.raimage.PhotoList.NewPhotoPreviewActivity"
+        android:label="@string/app_name"
+        android:stateNotNeeded="true"
+        android:theme="@style/Theme.AppCompat.Light"/>
+    <activity
+        android:name="com.usai.redant.raimage.Model.ManufactureListActivity"
+        android:theme="@style/Theme.AppCompat.Light"/>
+    <activity
+        android:name="com.usai.redant.raimage.UploadList.UploadListActivity"
+        android:theme="@style/Theme.AppCompat.Light"/>
+    <activity
+        android:name="com.usai.redant.raimage.TaskActivity"
+        android:theme="@style/Theme.AppCompat.Light"/>
+
+    <activity android:name="com.usai.redant.raimage.PhotoList.PhotoGridActivity"
+        android:stateNotNeeded="true"
+        android:theme="@style/Theme.AppCompat.Light">
+    </activity>
+</application>
 
 </manifest>

+ 112 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/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.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.raimage.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;
+    }
+  }
+
+}

+ 307 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/camera/CameraConfigurationManager.java

@@ -0,0 +1,307 @@
+/*
+ * 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.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 com.usai.redant.raimage.PreferencesActivity;
+
+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;
+  }
+
+}

+ 311 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/camera/CameraManager.java

@@ -0,0 +1,311 @@
+/*
+ * 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.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.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
RedAnt Mobile/app/src/main/java/com/usai/redant/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.camera;
+
+import android.content.SharedPreferences;
+
+import com.usai.redant.raimage.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
RedAnt Mobile/app/src/main/java/com/usai/redant/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.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
RedAnt Mobile/app/src/main/java/com/usai/redant/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.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;
+  }
+
+}

+ 77 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/AboutActivity.java

@@ -0,0 +1,77 @@
+package com.usai.redant.raimage;
+
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.redantmobile.RedAntApplication;
+
+public class AboutActivity extends Activity
+{
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_about);
+		 TextView tv_ver = (TextView) findViewById(R.id.tv_version);
+
+		 TextView zxing = (TextView) findViewById(R.id.zxing);
+		 zxing.setOnClickListener(new OnClickListener()
+		{
+			
+			@Override
+			public void onClick(View v)
+			{
+				
+				Intent intent = new Intent();
+				intent.setClass(AboutActivity.this, LicenseActivity.class);
+				startActivity(intent);
+				
+				
+			}
+		});
+		
+		try
+		{
+			
+			tv_ver.setText(getText(R.string.str_ver)
+					+ RedAntApplication.getInstance()
+							.getPackageManager()
+							.getPackageInfo("com.usai.redant.photo", 0).versionName);
+		}
+		catch (NameNotFoundException e1)
+		{
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		}
+	}
+
+//	@Override
+//	public boolean onCreateOptionsMenu(Menu menu)
+//	{
+//		// Inflate the menu; this adds items to the action bar if it is present.
+//		getMenuInflater().inflate(R.menu.about, menu);
+//		return true;
+//	}
+//
+//	@Override
+//	public boolean onOptionsItemSelected(MenuItem item)
+//	{
+//		// Handle action bar item clicks here. The action bar will
+//		// automatically handle clicks on the Home/Up button, so long
+//		// as you specify a parent activity in AndroidManifest.xml.
+//		int id = item.getItemId();
+//		if (id == R.id.action_settings)
+//		{
+//			return true;
+//		}
+//		return super.onOptionsItemSelected(item);
+//	}
+}

+ 87 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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.camera.CameraManager;
+import com.usai.redant.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
+  }
+
+}

+ 130 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/BeepManager.java

@@ -0,0 +1,130 @@
+/*
+ * 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.raimage;
+
+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.redantmobile.R;
+
+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;
+  }
+
+}

+ 33 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/BootReceiver.java

@@ -0,0 +1,33 @@
+package com.usai.redant.raimage;
+
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class BootReceiver extends BroadcastReceiver {
+
+	// Context
+	public void UnlockReceiver(Context context) {
+
+	}
+
+	@Override
+	public void onReceive(Context context, Intent intent) {
+		// TODO Auto-generated method stub
+		if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
+			
+			Intent intentservice = new Intent();
+			intentservice.setClass(context, UploadService.class);
+			if (intent.getExtras() != null)
+				intentservice.putExtras(intent.getExtras());
+			intentservice.setAction(intent.getAction());
+			context.startService(intentservice);
+			
+			
+			// Log.e("hg","�յ��㲥");
+		} 
+	}
+
+}

+ 887 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/CaptureActivity.java

@@ -0,0 +1,887 @@
+/*
+ * 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.raimage;
+
+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.camera.CameraManager;
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.util.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
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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.camera.CameraManager;
+import com.usai.redant.redantmobile.R;
+
+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();
+    }
+  }
+
+}

+ 114 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/CrashHandler.java

@@ -0,0 +1,114 @@
+package com.usai.redant.raimage;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+
+public class CrashHandler implements Thread.UncaughtExceptionHandler{
+
+    public interface InfoPreserver {
+        public void saveUserInformation();
+        public void handleCrashInfo(String deviceInfo, String exception);
+    }
+    // 当前应用上下文
+    private Context ctx;
+
+    // 系统默认UncaughtException处理类
+    private Thread.UncaughtExceptionHandler mDefaultHandler;
+
+    private static CrashHandler sharedInstance;
+    public InfoPreserver preserver;
+
+    private CrashHandler() {
+
+    }
+
+    public static synchronized CrashHandler getSharedInstance() {
+        if (sharedInstance == null) {
+            sharedInstance = new CrashHandler();
+        }
+        return sharedInstance;
+    }
+
+    public void init(Context ctx) {
+        this.ctx = ctx;
+        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
+        Thread.setDefaultUncaughtExceptionHandler(this);
+    }
+
+
+    @Override
+    public void uncaughtException(Thread t, Throwable e) {
+        // 如果不能处理异常,并且系统处理器不为空,则交给系统处理
+        if (!handleException(e) && mDefaultHandler != null) {
+            mDefaultHandler.uncaughtException(t,e);
+        } else {
+            android.os.Process.killProcess(android.os.Process.myPid());
+            System.exit(1);
+        }
+    }
+
+    private boolean handleException(Throwable e) {
+
+        if (e == null) {
+            return false;
+        }
+
+        if (preserver != null) {
+            preserver.saveUserInformation();
+            preserver.handleCrashInfo(getDeviceInfo(),getThrowableStackString(e));
+        }
+
+
+        return true;
+    }
+
+    private String getDeviceInfo() {
+        try {
+            PackageManager pm = ctx.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
+            String appVer = "App Version: " + pi.versionName + "_" + pi.versionCode + "\n";
+            String osVer = "OS Version: " + Build.VERSION.RELEASE + "_" + Build.VERSION.SDK_INT + "\n";
+            String manufacture = "Manufacturer: " + Build.MANUFACTURER + "\n";
+            String model = "Model: " + Build.MODEL;
+            return appVer + osVer + manufacture + model;
+        } catch (PackageManager.NameNotFoundException e) {
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+
+    private String getThrowableStackString(Throwable throwable) {
+        if (throwable == null) {
+            return null;
+        }
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        throwable.printStackTrace(pw);
+        pw.flush();
+        LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
+        StringBuffer lines = new StringBuffer();
+        try {
+            String line = reader.readLine();
+            while (line != null) {
+                lines.append(line + "\n");
+                line = reader.readLine();
+            }
+        } catch (IOException ex) {
+            lines.append(ex.toString() + "\n");
+        }
+
+        return lines.toString();
+    }
+
+
+}

+ 102 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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.redantmobile.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
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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;
+  }
+
+}

+ 104 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/DecodeThread.java

@@ -0,0 +1,104 @@
+/*
+ * 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.raimage;
+
+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 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
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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();
+  }
+
+}

+ 243 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/HttpHelper.java

@@ -0,0 +1,243 @@
+/*
+ * Copyright 2011 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.raimage;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * Utility methods for retrieving content over HTTP using the more-supported {@code java.net} classes
+ * in Android.
+ */
+public final class HttpHelper {
+
+  private static final String TAG = HttpHelper.class.getSimpleName();
+
+  private static final Collection<String> REDIRECTOR_DOMAINS = new HashSet<String>(Arrays.asList(
+    "amzn.to", "bit.ly", "bitly.com", "fb.me", "goo.gl", "is.gd", "j.mp", "lnkd.in", "ow.ly",
+    "R.BEETAGG.COM", "r.beetagg.com", "SCN.BY", "su.pr", "t.co", "tinyurl.com", "tr.im"
+  ));
+
+  private HttpHelper() {
+  }
+  
+  public enum ContentType {
+    /** HTML-like content type, including HTML, XHTML, etc. */
+    HTML,
+    /** JSON content */
+    JSON,
+    /** XML */
+    XML,
+    /** Plain text content */
+    TEXT,
+  }
+
+  /**
+   * Downloads the entire resource instead of part.
+   *
+   * @see #downloadViaHttp(String, HttpHelper.ContentType, int)
+   */
+  public static CharSequence downloadViaHttp(String uri, ContentType type) throws IOException {
+    return downloadViaHttp(uri, type, Integer.MAX_VALUE);
+  }
+
+  /**
+   * @param uri URI to retrieve
+   * @param type expected text-like MIME type of that content
+   * @param maxChars approximate maximum characters to read from the source
+   * @return content as a {@code String}
+   * @throws IOException if the content can't be retrieved because of a bad URI, network problem, etc.
+   */
+  public static CharSequence downloadViaHttp(String uri, ContentType type, int maxChars) throws IOException {
+    String contentTypes;
+    switch (type) {
+      case HTML:
+        contentTypes = "application/xhtml+xml,text/html,text/*,*/*";
+        break;
+      case JSON:
+        contentTypes = "application/json,text/*,*/*";
+        break;
+      case XML:
+        contentTypes = "application/xml,text/*,*/*";
+        break;
+      case TEXT:
+      default:
+        contentTypes = "text/*,*/*";
+    }
+    return downloadViaHttp(uri, contentTypes, maxChars);
+  }
+
+  private static CharSequence downloadViaHttp(String uri, String contentTypes, int maxChars) throws IOException {
+    int redirects = 0;
+    while (redirects < 5) {
+      URL url = new URL(uri);
+      HttpURLConnection connection = safelyOpenConnection(url);
+      connection.setInstanceFollowRedirects(true); // Won't work HTTP -> HTTPS or vice versa
+      connection.setRequestProperty("Accept", contentTypes);
+      connection.setRequestProperty("Accept-Charset", "utf-8,*");
+      connection.setRequestProperty("User-Agent", "ZXing (Android)");
+      try {
+        int responseCode = safelyConnect(uri, connection);
+        switch (responseCode) {
+          case HttpURLConnection.HTTP_OK:
+            return consume(connection, maxChars);
+          case HttpURLConnection.HTTP_MOVED_TEMP:
+            String location = connection.getHeaderField("Location");
+            if (location != null) {
+              uri = location;
+              redirects++;
+              continue;
+            }
+            throw new IOException("No Location");
+          default:
+            throw new IOException("Bad HTTP response: " + responseCode);
+        }
+      } finally {
+        connection.disconnect();
+      }
+    }
+    throw new IOException("Too many redirects");
+  }
+
+  private static String getEncoding(URLConnection connection) {
+    String contentTypeHeader = connection.getHeaderField("Content-Type");
+    if (contentTypeHeader != null) {
+      int charsetStart = contentTypeHeader.indexOf("charset=");
+      if (charsetStart >= 0) {
+        return contentTypeHeader.substring(charsetStart + "charset=".length());
+      }
+    }
+    return "UTF-8";
+  }
+
+  private static CharSequence consume(URLConnection connection, int maxChars) throws IOException {
+    String encoding = getEncoding(connection);
+    StringBuilder out = new StringBuilder();
+    Reader in = null;
+    try {
+      in = new InputStreamReader(connection.getInputStream(), encoding);
+      char[] buffer = new char[1024];
+      int charsRead;
+      while (out.length() < maxChars && (charsRead = in.read(buffer)) > 0) {
+        out.append(buffer, 0, charsRead);
+      }
+    } finally {
+      if (in != null) {
+        try {
+          in.close();
+        } catch (IOException ioe) {
+          // continue
+        } catch (NullPointerException npe) {
+          // another apparent Android / Harmony bug; continue
+        }
+      }
+    }
+    return out;
+  }
+
+  public static URI unredirect(URI uri) throws IOException {
+    if (!REDIRECTOR_DOMAINS.contains(uri.getHost())) {
+      return uri;
+    }
+    URL url = uri.toURL();
+    HttpURLConnection connection = safelyOpenConnection(url);
+    connection.setInstanceFollowRedirects(false);
+    connection.setDoInput(false);
+    connection.setRequestMethod("HEAD");
+    connection.setRequestProperty("User-Agent", "ZXing (Android)");
+    try {
+      int responseCode = safelyConnect(uri.toString(), connection);
+      switch (responseCode) {
+        case HttpURLConnection.HTTP_MULT_CHOICE:
+        case HttpURLConnection.HTTP_MOVED_PERM:
+        case HttpURLConnection.HTTP_MOVED_TEMP:
+        case HttpURLConnection.HTTP_SEE_OTHER:
+        case 307: // No constant for 307 Temporary Redirect ?
+          String location = connection.getHeaderField("Location");
+          if (location != null) {
+            try {
+              return new URI(location);
+            } catch (URISyntaxException e) {
+              // nevermind
+            }
+          }
+      }
+      return uri;
+    } finally {
+      connection.disconnect();
+    }
+  }
+  
+  private static HttpURLConnection safelyOpenConnection(URL url) throws IOException {
+    URLConnection conn;
+    try {
+      conn = url.openConnection();
+    } catch (NullPointerException npe) {
+      // Another strange bug in Android?
+      Log.w(TAG, "Bad URI? " + url);
+      throw new IOException(npe);
+    }
+    if (!(conn instanceof HttpURLConnection)) {
+      throw new IOException();
+    }
+    return (HttpURLConnection) conn;
+  }
+
+  private static int safelyConnect(String uri, HttpURLConnection connection) throws IOException {
+    try {
+      connection.connect();
+    } catch (NullPointerException npe) {
+      // this is an Android bug: http://code.google.com/p/android/issues/detail?id=16895
+      throw new IOException(npe);
+    } catch (IllegalArgumentException iae) {
+      // Also seen this in the wild, not sure what to make of it. Probably a bad URL
+      throw new IOException(iae);
+    } catch (SecurityException se) {
+      // due to bad VPN settings?
+      Log.w(TAG, "Restricted URI? " + uri);
+      throw new IOException(se);
+    } catch (IndexOutOfBoundsException ioobe) {
+      // Another Android problem? https://groups.google.com/forum/?fromgroups#!topic/google-admob-ads-sdk/U-WfmYa9or0
+      throw new IOException(ioobe);
+    }
+    try {
+      return connection.getResponseCode();
+    } catch (NullPointerException npe) {
+      // this is maybe this Android bug: http://code.google.com/p/android/issues/detail?id=15554
+      throw new IOException(npe);
+    } catch (IllegalArgumentException iae) {
+      // Again seen this in the wild for bad header fields in the server response! or bad reads
+      Log.w(TAG, "Bad server status? " + uri);
+      throw new IOException(iae);
+    } catch (StringIndexOutOfBoundsException sioobe) {
+      // Another Android bug: https://code.google.com/p/android/issues/detail?id=18856
+      throw new IOException(sioobe);
+    }
+  }
+
+}

+ 116 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+/**
+ * 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() {
+    }
+  }
+}

+ 63 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/LicenseActivity.java

@@ -0,0 +1,63 @@
+package com.usai.redant.raimage;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.webkit.WebView;
+
+import com.usai.redant.redantmobile.R;
+
+import org.apache.http.util.EncodingUtils;
+
+import java.io.InputStream;
+
+public class LicenseActivity extends Activity
+{
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_license);
+		WebView wv = (WebView) findViewById(R.id.webView1);
+		String content = "";
+		try
+		{
+			InputStream in = getResources().openRawResource(R.raw.license);
+			// 获取文件的字节数
+			int lenght = in.available();
+			// 创建byte数组
+			byte[] buffer = new byte[lenght];
+			// 将文件中的数据读到byte数组中
+			in.read(buffer);
+			content = EncodingUtils.getString(buffer, "UTF-8");
+		}
+		catch (Exception e)
+		{
+			e.printStackTrace();
+		}
+		wv.getSettings().setDefaultTextEncodingName("UTF-8");
+		wv.loadData(content, "text/html", null);		
+	}
+
+//	@Override
+//	public boolean onCreateOptionsMenu(Menu menu)
+//	{
+//		// Inflate the menu; this adds items to the action bar if it is present.
+//		getMenuInflater().inflate(R.menu.license, menu);
+//		return true;
+//	}
+//
+//	@Override
+//	public boolean onOptionsItemSelected(MenuItem item)
+//	{
+//		// Handle action bar item clicks here. The action bar will
+//		// automatically handle clicks on the Home/Up button, so long
+//		// as you specify a parent activity in AndroidManifest.xml.
+//		int id = item.getItemId();
+//		if (id == R.id.action_settings)
+//		{
+//			return true;
+//		}
+//		return super.onOptionsItemSelected(item);
+//	}
+}

+ 1848 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/MainActivity.java

@@ -0,0 +1,1848 @@
+package com.usai.redant.raimage;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.usai.redant.raimage.Model.ManufactureListActivity;
+import com.usai.redant.raimage.PhotoList.PhotoGridActivity;
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.redantmobile.RedAntApplication;
+import com.usai.redant.util.AES;
+import com.usai.redant.util.MD5;
+import com.usai.redant.util.Network;
+import com.usai.redant.util.RAUtil;
+import com.usai.redant.util.dbgUtil;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+
+public class MainActivity extends AppCompatActivity
+{
+
+
+    protected String mode=null;
+    protected String name=null;
+    private VerifyCodeTask verifytask=null;
+    private QueryManufacturer qmtask=null;
+    private JSONArray manufacture_arr=null;
+    private AlertDialog qmdialog =null;
+    private AlertDialog vfdialog =null;
+    public void verifyandupload(Bundle params)
+    {
+        if (verifytask != null)
+        {
+            return;
+        }
+
+        String title = "Verifying "+name;
+
+//        if (MainActivity.this.getClass().equals(ModelActivity.class)) {
+//            title = "Verifying Model";
+//        }
+
+        vfdialog=new AlertDialog.Builder(MainActivity.this)
+                .setTitle(title)
+                .setMessage("Please Wait")
+
+                .show();
+
+        verifytask = new VerifyCodeTask();
+        verifytask.execute(params);
+
+    }
+    public void querymanufacturer(Bundle params)
+    {
+        if (qmtask != null)
+        {
+            return;
+        }
+
+
+
+        qmdialog=new AlertDialog.Builder(MainActivity.this)
+                .setTitle("Searching manufacturer")
+                .setMessage("Please Wait")
+
+                .show();
+        qmtask = new QueryManufacturer();
+        qmtask.execute(params);
+
+    }
+    public class QueryManufacturer extends AsyncTask<Bundle, Void, Boolean>
+    {
+
+        JSONObject json	= null;
+
+        // int netconnect;
+
+        @Override
+        protected Boolean doInBackground(Bundle... params)
+        {
+            json = Network.Query_Manufacturer(params[0]);
+            try {
+                if (json.getInt("result") == Network.RESULT_TRUE)
+                    return true;
+                else
+                    return false;
+            } catch (Exception e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+
+        @Override
+        protected void onPostExecute(final Boolean success)
+        {
+
+            Log.i("onPostExecute", "entry");
+            qmtask = null;
+            qmdialog.hide();
+//            showProgress(false);
+
+            if (success)
+            {
+
+
+                try {
+                    manufacture_arr=json.getJSONArray("manufacturer");
+                    if(manufacture_arr.length()==1) {
+                        String manufacture = manufacture_arr.getString(0);
+                        setManufacture(manufacture);
+                    }
+                    else
+                    {
+                        if(manufacture_arr.length()==0)
+                    {
+//                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                "No manufacturer found, wrong model?",
+//                                Toast.LENGTH_LONG);
+//                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                        toast.show();
+
+
+                        new AlertDialog.Builder(MainActivity.this)
+                                .setTitle("Warning")
+                                .setMessage("No manufacturer found, wrong model?")
+                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                    }
+                                })
+                                .show();
+
+                    }
+                        setManufacture("");
+                    }
+
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+
+
+                //验证成功
+
+
+//                Intent intent = new Intent("REDANT.RAImage.ADD_TASK");
+//
+//                ArrayList<Bundle> taskArr = new ArrayList<Bundle>();
+//                String name = "POP";
+//
+////					if(MainActivity.this instanceof ModelActivity)
+////						name=name = "Model";
+//                if (MainActivity.this.getClass().equals(ModelActivity.class)) {
+//                    name = "Model";
+//                }
+//                for (String path : photoList) {
+//                    Bundle task = new Bundle();
+//
+//                    task.putString("path",path);
+//                    task.putString("file",RAUtil.lastPathComponent(path));
+//                    task.putString("url",RedAntApplication.active_address);
+//
+//                    String md5 = MD5.md5sum(path);
+//                    String encryptUser = AES.encrypt("usai",RedAntApplication.user);
+//                    String encryptPwd = AES.encrypt("usai",RedAntApplication.password);
+//
+//                    Bundle params = new Bundle();
+//                    params.putString("user",encryptUser);
+//                    params.putString("password",encryptPwd);
+//                    params.putString("mode",name);
+//                    params.putString("barcode",pidval.getText().toString());
+//                    params.putString("_operate","upload");
+//                    params.putString("platform","android");
+//                    params.putString("md5",md5);
+//
+//
+//                    if (MainActivity.this.getClass().equals(ModelActivity.class)) {
+//
+//                        if (!TextUtils.isEmpty(manufacture)) {
+//                            params.putString("manufacturer",manufacture);
+//                        }
+//                        if (!TextUtils.isEmpty(noteTextView.getText().toString())) {
+//                            params.putString("note",noteTextView.getText().toString());
+//                        }
+//                    }
+//
+//                    task.putBundle("params",params);
+//
+//                    taskArr.add(task);
+//                }
+//
+//                intent.putParcelableArrayListExtra("tasks",taskArr);
+//
+//                sendBroadcast(intent);
+//                clearfornew();
+            }
+            else
+            {
+                int result = 0;
+                try {
+                    result = json.getInt("result");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    result = Network.RESULT_NET_ERROR;
+
+                }
+                switch (result)
+                {
+                    case 0:
+                    {
+                        // model , piid not exist
+
+
+                        String msg = "User / password does not match.";
+
+//                        if (MainActivity.this.getClass().equals(ModelActivity.class)) {
+//                            msg = "Model does not exist.";
+//                        }
+//                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                msg,
+//                                Toast.LENGTH_LONG);
+//                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                        toast.show();
+//                        break;
+
+                        new AlertDialog.Builder(MainActivity.this)
+                                .setTitle("Warning")
+                                .setMessage(msg)
+                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                    }
+                                })
+                                .show();
+                        break;
+                    }
+//                    case 1:
+//                    {
+//                        //model / manufacturer not match
+//                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                "Model/Manufacturer does not match.",
+//                                Toast.LENGTH_LONG);
+//                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                        toast.show();
+//                        break;
+//                    }
+                    default:
+                    {
+//                        // net error.
+//                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                "Can not get manufacturer information.",
+//                                Toast.LENGTH_LONG);
+//                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                        toast.show();
+//                        return;
+
+                        new AlertDialog.Builder(MainActivity.this)
+                                .setTitle("Warning")
+                                .setMessage("Can not get manufacturer information.")
+                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                    }
+                                })
+                                .show();
+                        return;
+                    }
+
+                }
+
+            }
+        }
+
+        @Override
+        protected void onCancelled()
+        {
+            verifytask = null;
+
+        }
+    }
+    public class VerifyCodeTask extends AsyncTask<Bundle, Void, Boolean>
+    {
+
+        JSONObject json	= null;
+
+        // int netconnect;
+
+        @Override
+        protected Boolean doInBackground(Bundle... params)
+        {
+            json = Network.Verify_Code(params[0]);
+            try {
+                if (json.getInt("result") == Network.RESULT_TRUE)
+                    return true;
+                else
+                    return false;
+            } catch (Exception e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+
+        @Override
+        protected void onPostExecute(final Boolean success)
+        {
+            Log.i("onPostExecute", "entry");
+            verifytask = null;
+//            showProgress(false);
+
+            vfdialog.hide();
+
+            if (success)
+            {
+               //验证成功
+
+
+                Intent intent = new Intent("REDANT.RAImage.ADD_TASK");
+
+                ArrayList<Bundle> taskArr = new ArrayList<Bundle>();
+//                String name = "POP";
+//
+////					if(MainActivity.this instanceof ModelActivity)
+////						name=name = "Model";
+//                if (MainActivity.this.getClass().equals(ModelActivity.class)) {
+//                    name = "Model";
+//                }
+                for (String path : photoList) {
+                    Bundle task = new Bundle();
+
+                    task.putString("path",path);
+                    task.putString("file",RAUtil.lastPathComponent(path));
+                    task.putString("url", RedAntApplication.active_address);
+
+                    String md5 = MD5.md5sum(path);
+                    String encryptUser = AES.encrypt("usai",RedAntApplication.user);
+                    String encryptPwd = AES.encrypt("usai",RedAntApplication.password);
+
+                    Bundle params = new Bundle();
+                    params.putString("user",encryptUser);
+                    params.putString("password",encryptPwd);
+                    params.putString("mode",mode);
+                    params.putString("barcode",pidval.getText().toString());
+                    params.putString("_operate","upload");
+                    params.putString("platform","android");
+                    params.putString("md5",md5);
+
+
+                    if (mode.equals("Model")) {
+
+                        if (!TextUtils.isEmpty(manufacture)) {
+                            params.putString("manufacturer",manufacture);
+                        }
+                        if (!TextUtils.isEmpty(noteTextView.getText().toString())) {
+                            params.putString("note",noteTextView.getText().toString());
+                        }
+                    }
+
+                    task.putBundle("params",params);
+
+                    taskArr.add(task);
+                }
+
+                intent.putParcelableArrayListExtra("tasks",taskArr);
+
+                sendBroadcast(intent);
+                clearfornew();
+            }
+            else
+            {
+                int result = 0;
+                try {
+                    result = json.getInt("result");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    result = Network.RESULT_NET_ERROR;
+
+                }
+                switch (result)
+                {
+                    case 0:
+                    {
+                        // model , piid not exist
+
+
+                        String msg = name+" does not exist";
+
+//                        if (MainActivity.this.getClass().equals(ModelActivity.class)) {
+//                            msg = "Model does not exist.";
+//                        }
+//                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                msg,
+//                                Toast.LENGTH_LONG);
+//                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                        toast.show();
+//                        break;
+
+
+                        new AlertDialog.Builder(MainActivity.this)
+                                .setTitle("Warning")
+                                .setMessage(msg)
+                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                    }
+                                })
+                                .show();
+                        break;
+
+
+
+                    }
+                    case 1:
+                    {
+                        //model / manufacturer not match
+//                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                "Model/Manufacturer does not match.",
+//                                Toast.LENGTH_LONG);
+//                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                        toast.show();
+//                        break;
+
+
+                        new AlertDialog.Builder(MainActivity.this)
+                                .setTitle("Warning")
+                                .setMessage("Model/Manufacturer does not match.")
+                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                    }
+                                })
+                                .show();
+                        break;
+                    }
+                    default:
+                    {
+                        // net error.
+//                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                "can not verify input information.",
+//                                Toast.LENGTH_LONG);
+//                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                        toast.show();
+//                        return;
+
+//                        new AlertDialog.Builder(MainActivity.this)
+//                                .setTitle("Warning")
+//                                .setMessage("can not verify input information.")
+//                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+//                                    @Override
+//                                    public void onClick(DialogInterface dialog, int which) {
+//
+//                                    }
+//                                })
+//                                .show();
+
+
+                        			new AlertDialog.Builder(MainActivity.this)
+					.setTitle("Warning")
+					.setMessage("Can not verify input information, server is not reachable for now, add upload task anyway?")
+					.setPositiveButton("Yes", new DialogInterface.OnClickListener()
+                    {
+						@Override
+						public void onClick(DialogInterface dialog, int which)             {
+
+
+                            Intent intent = new Intent("REDANT.RAImage.ADD_TASK");
+
+                            ArrayList<Bundle> taskArr = new ArrayList<Bundle>();
+
+                            for (String path : photoList) {
+                                Bundle task = new Bundle();
+
+                                task.putString("path",path);
+                                task.putString("file",RAUtil.lastPathComponent(path));
+                                task.putString("url",RedAntApplication.active_address);
+
+                                String md5 = MD5.md5sum(path);
+                                String encryptUser = AES.encrypt("usai",RedAntApplication.user);
+                                String encryptPwd = AES.encrypt("usai",RedAntApplication.password);
+
+                                Bundle params = new Bundle();
+                                params.putString("user",encryptUser);
+                                params.putString("password",encryptPwd);
+                                params.putString("mode",mode);
+                                params.putString("barcode",pidval.getText().toString());
+                                params.putString("_operate","upload");
+                                params.putString("platform","android");
+                                params.putString("md5",md5);
+
+
+                                if (mode.equals("Model")) {
+
+                                    if (!TextUtils.isEmpty(manufacture)) {
+                                        params.putString("manufacturer",manufacture);
+                                    }
+                                    if (!TextUtils.isEmpty(noteTextView.getText().toString())) {
+                                        params.putString("note",noteTextView.getText().toString());
+                                    }
+                                }
+
+                                task.putBundle("params",params);
+
+                                taskArr.add(task);
+                            }
+
+                            intent.putParcelableArrayListExtra("tasks",taskArr);
+
+                            sendBroadcast(intent);
+                            clearfornew();
+                        }
+
+                    })
+					.setNegativeButton("No", new DialogInterface.OnClickListener() {
+						@Override
+						public void onClick(DialogInterface dialog, int which) {
+
+						}
+					})
+					.show();
+                        return;
+
+                    }
+
+                }
+
+            }
+        }
+
+        @Override
+        protected void onCancelled()
+        {
+            verifytask = null;
+
+        }
+    }
+
+    static final boolean newVersion = true;
+	// static final int ACTIVITY_CAMERA = 0;
+	// static final int ACTIVITY_VIEW = 1;
+	// static final String serverurl = "http://192.168.23.1/xampp/";
+	static final String TAG						= "MainActivity";
+	static final int	REQUEST_TAKE_PHOTO		= 1;
+	static final int	REQUEST_PREVIEW			= 4;
+	static final int	REQUEST_SCAN_BARCODE	= 2;
+	static final int	REQUEST_LOCKER			= 3;
+	static final int 	REQUEST_MANUFACTURE 	= 5;
+	// HashMap<String, String> hashMap = new HashMap<String, String>();
+
+	// ArrayList<String> pic_file = new ArrayList<String>();
+	// ArrayList<bitmap>
+	// ArrayList<>
+	// private String thumbpath = null;
+	private int			iwidth					= 640;
+	private int			iheight					= 480;
+	private File photoFile				= null;
+	Bitmap thumbBitmap				= null;
+	// private int iPhotoCount = 0;
+	public String LastFileName			= "";
+//	private boolean		m_blocked				= false;
+	TextView m_tvalert;
+	// private String user;
+	// private String password;
+	// String m_sName;
+	// String m_sPassword;
+	ArrayList<String> photoList				= new ArrayList<String>();
+
+	// @Override
+	// protected void onResume()
+	// {
+	// //sendBroadcast(new Intent("REDANT.POP.REQUEST_LOCATION_CHANGED"));
+	// super.onResume();
+	// }
+
+	/** RA Image */
+	protected ImageView thumbsImageView;
+	protected TextView countTextView;
+	protected EditText pidval;
+	protected EditText noteTextView;
+	protected ImageButton ibtnscan;
+	protected ImageButton captureButton;
+	protected ImageButton uploadButton;
+	protected Button manufactureBtn;
+    protected Button btnType;
+	private String manufacture;
+
+	void setManufacture(String value) {
+        if(manufactureBtn==null)
+            return;
+		manufacture = value;
+		if (TextUtils.isEmpty(value)) {
+			manufactureBtn.setText("Select Manufacturer");
+		} else  {
+			manufactureBtn.setText(value);
+		}
+	}
+
+	public void showWarning(String msg) {
+		if (TextUtils.isEmpty(msg)) {
+			msg = "Warning Message";
+		}
+		new AlertDialog.Builder(MainActivity.this)
+				.setTitle("Warning")
+				.setMessage(msg)
+				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+					@Override
+					public void onClick(DialogInterface dialog, int which) {
+
+					}
+				})
+				.show();
+	}
+
+//	public boolean checkCameraPermission() {
+//		int permission = ContextCompat.checkSelfPermission(MainActivity.this, "android.permission.CAMERA");
+//		if (permission == PackageManager.PERMISSION_DENIED) {
+//
+//			new AlertDialog.Builder(this)
+//					.setTitle("Warning")
+//					.setMessage("RA Image need camera permission")
+//					.setPositiveButton("Setting", new DialogInterface.OnClickListener() {
+//						@Override
+//						public void onClick(DialogInterface dialog, int which) {
+//							Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+//							intent.setData(Uri.parse("package:" + getPackageName()));
+//							startActivity(intent);
+//						}
+//					})
+//					.setNegativeButton("No", new DialogInterface.OnClickListener() {
+//						@Override
+//						public void onClick(DialogInterface dialog, int which) {
+//							finish();
+//						}
+//					})
+//					.show();
+//
+//			return false;
+//		}
+//		return true;
+//	}
+
+	protected void initView() {
+		thumbsImageView = (ImageView)findViewById(R.id.photo_iv);
+		countTextView = (TextView)findViewById(R.id.photo_count_lb);
+		pidval = (EditText)findViewById(R.id.barcode_et);
+
+        if (mode.equals("Model")) { // model
+
+            pidval.addTextChangedListener(new TextWatcher() {
+
+                @Override
+                public void onTextChanged(CharSequence s, int start, int before, int count) {
+                    // 输入的内容变化的监听
+//                Log.e("输入过程中执行该方法", "文字变化");
+                }
+
+                @Override
+                public void beforeTextChanged(CharSequence s, int start, int count,
+                                              int after) {
+                    // 输入前的监听
+//                Log.e("输入前确认执行该方法", "开始输入");
+
+                }
+
+                @Override
+                public void afterTextChanged(Editable s) {
+                    // 输入后的监听
+
+                    String model = s.toString();
+                    if(TextUtils.isEmpty(model))
+                        return;
+                    Log.e("输入结束执行该方法", "输入结束"+ s.toString());
+
+                    String encryptUser = AES.encrypt("usai",RedAntApplication.user);
+                    String encryptPwd = AES.encrypt("usai",RedAntApplication.password);
+
+                    Bundle params = new Bundle();
+                    params.putString("user",encryptUser);
+                    params.putString("password",encryptPwd);
+                    params.putString("barcode",model);
+                    params.putString("type","model");
+                    params.putString("_operate","handset_get_manufacturer");
+                    params.putString("platform","android");
+
+
+                    querymanufacturer(params);
+
+                }
+            });
+        }
+
+
+		noteTextView = (EditText)findViewById(R.id.note_et);
+		ibtnscan = (ImageButton)findViewById(R.id.scan_btn);
+		captureButton = (ImageButton)findViewById(R.id.camera_btn);
+		uploadButton = (ImageButton)findViewById(R.id.upload_btn);
+		manufactureBtn = (Button)findViewById(R.id.manufacture_btn);
+
+        btnType = (Button)findViewById(R.id.btn_type);
+        btnType.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                final EditText edit = new EditText(MainActivity.this);
+                String msg = "Please enter "+name;
+//                if (MainActivity.this.getClass().equals(ModelActivity.class)) { // model
+//
+//
+//                }
+//                else
+//                    if (MainActivity.this.getClass().equals(PopActivity.class))
+//                {
+//                    edit.setInputType(InputType.TYPE_CLASS_NUMBER);
+//                    msg = "Please enter PIID code";
+//                }
+
+                if(mode.equals("POP")||mode.equals("Returns"))
+                {
+                    edit.setInputType(InputType.TYPE_CLASS_NUMBER);
+                }
+
+                edit.setSingleLine(true);
+
+				new AlertDialog.Builder(MainActivity.this)
+						.setIconAttribute(android.R.attr.alertDialogIcon)
+						.setTitle(msg)
+						.setView(edit)
+						.setPositiveButton(android.R.string.ok,
+								new DialogInterface.OnClickListener()
+								{
+									public void onClick(DialogInterface dialog,
+											int whichButton)
+									{
+										String pid = ((EditText) edit)
+												.getText().toString();
+//										TextView pidval = (TextView) findViewById(R.id.pidval);
+										pidval.setText(pid);
+										updateUploadButton();
+
+										/* User clicked OK so do some stuff */
+									}
+								})
+						.setNegativeButton(android.R.string.cancel,
+								new DialogInterface.OnClickListener()
+								{
+									public void onClick(DialogInterface dialog,
+											int whichButton)
+									{
+										updateUploadButton();
+										/* User clicked cancel so do some stuff */
+									}
+								}).create().show();
+            }
+        });
+
+        /***/
+		thumbsImageView.setOnClickListener(new View.OnClickListener()
+		{
+
+			@Override
+			public void onClick(View v)
+			{
+
+				if (photoList.size() < 1) {
+					StartCamera();
+					return;
+				}
+
+
+//				Intent intent = new Intent(MainActivity.this,
+//						PhotoPreviewActivity.class);
+//				intent.putExtra("pic_list", (Serializable) photoList);
+//				startActivityForResult(intent, REQUEST_PREVIEW);
+
+//				Intent intent = new Intent(MainActivity.this,
+//						PhotoListActivity.class);
+//				intent.putExtra("pic_list", (Serializable) photoList);
+//				startActivityForResult(intent, REQUEST_PREVIEW);
+
+                Intent intent = new Intent(MainActivity.this, PhotoGridActivity.class);
+                intent.putExtra("pic_list", (Serializable) photoList);
+                startActivityForResult(intent, REQUEST_PREVIEW);
+
+			}
+		});
+
+        ibtnscan.setOnClickListener(new View.OnClickListener()
+        {
+
+            @Override
+            public void onClick(View v)
+            {
+                Log.d(TAG, "==============>Click Scan button");
+
+//®
+
+                Intent intent = new Intent();
+
+                intent.setClass(MainActivity.this, CaptureActivity.class);
+                startActivityForResult(intent, REQUEST_SCAN_BARCODE);
+            }
+        });
+
+        captureButton.setOnClickListener(new View.OnClickListener()
+        {
+
+            @Override
+            public void onClick(View v)
+            {
+
+                StartCamera();
+            }
+        });
+        uploadButton.setOnClickListener(new View.OnClickListener()
+        {
+
+            @Override
+            public void onClick(View v)
+            {
+				if (TextUtils.isEmpty(pidval.getText().toString())) {
+					String barcode_title = name;//"PIID";
+//					if (MainActivity.this.getClass().equals(ModelActivity.class)) { // model
+//						barcode_title = "Model";
+//					}
+					showWarning(barcode_title + " can not be blank!");
+					return;
+				}
+                if (name.equals("Model"))//(MainActivity.this.getClass().equals(ModelActivity.class))
+                {
+                    if (TextUtils.isEmpty(manufacture)) {
+                        showWarning("manufacture can not be blank!");
+                        return;
+                    }
+                }
+
+
+
+				if (photoList.size() < 1) {
+					showWarning("You must take at least one photo");
+					return;
+				}
+
+
+
+		//		boolean canstart = true;
+
+				ConnectivityManager connManager = (ConnectivityManager) RedAntApplication.getInstance()
+						.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+				NetworkInfo networkInfo = connManager
+						.getActiveNetworkInfo();
+				if (networkInfo == null)
+				{
+					dbgUtil.Logd(
+							"Current Network info",
+							"can not get Active NetworkInfo!");
+//					canstart = false;
+                    new AlertDialog.Builder(MainActivity.this)
+                            .setTitle("Warning")
+                            .setMessage("No available network, new task will not start, you must start it manually.")
+                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+
+                                }
+                            })
+                            .show();
+				}
+				else
+				{
+					NetworkInfo.State netState = networkInfo
+							.getState();
+					if (netState != NetworkInfo.State.CONNECTED)
+					{
+						dbgUtil.Logd(
+								"Current Network info",
+								"not Connected!State="
+										+ netState);
+//						canstart = false;
+
+                        new AlertDialog.Builder(MainActivity.this)
+                                .setTitle("Warning")
+                                .setMessage("No network connection, new task will not start, you must start it manually.")
+                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                    }
+                                })
+                                .show();
+
+					}
+					else
+                    {
+                        int iconntype = -1;
+                        iconntype = networkInfo
+                                .getType();
+
+                        SharedPreferences pref = RedAntApplication
+                                .getInstance()
+                                .getSharedPreferences(
+                                        "UploadManager",
+                                        0);
+                        boolean
+                                wifi_only
+                                =pref.getBoolean("wifi_only",
+                                false);
+                        if(wifi_only == true
+                                && iconntype !=
+                                ConnectivityManager.TYPE_WIFI
+                                && iconntype !=
+                                9/* earthnet */)
+                        {
+//						canstart = false;
+
+
+                            new AlertDialog.Builder(MainActivity.this)
+                                    .setTitle("Warning")
+                                    .setMessage("You have setup upload via WIFI only, new task will not start, you must start it manually.")
+                                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                        @Override
+                                        public void onClick(DialogInterface dialog, int which) {
+
+                                        }
+                                    })
+                                    .show();
+
+
+
+                        }
+                    }
+
+				}
+//				if(!canstart)
+//				{
+//
+
+////                    new AlertDialog.Builder(MainActivity.this)
+////                            .setTitle("Warning")
+////                            .setMessage("App is set to upload via WIFI only. Please change your setting or try upload later.")
+////                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+////                                @Override
+////                                public void onClick(DialogInterface dialog, int which) {
+////
+////                                }
+////                            })
+////                            .show();
+////                    return;
+//
+//				}
+				try {
+
+//                    String name = "POP";
+//
+////					if(MainActivity.this instanceof ModelActivity)
+////						name=name = "Model";
+//                    if (MainActivity.this.getClass().equals(ModelActivity.class)) {
+//                        name = "Model";
+//                    }
+                    String encryptUser = AES.encrypt("usai",RedAntApplication.user);
+                    String encryptPwd = AES.encrypt("usai",RedAntApplication.password);
+
+
+
+
+                    Bundle params = new Bundle();
+                    params.putString("user",encryptUser);
+                    params.putString("password",encryptPwd);
+                    params.putString("mode",mode);
+                    params.putString("barcode",pidval.getText().toString());
+                    params.putString("_operate","upload");
+                    params.putString("platform","android");
+
+                    if (mode.equals("Model")) {
+
+                        if (!TextUtils.isEmpty(manufacture)) {
+                            params.putString("manufacturer",manufacture);
+                        }
+
+                    }
+
+                    verifyandupload(params);
+
+
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+				return;
+
+            }
+        });
+
+		/**Model*/
+		if (mode.equals("Model")) {
+			if (manufactureBtn != null) {
+				manufactureBtn.setOnClickListener(new View.OnClickListener() {
+					@Override
+					public void onClick(View v) {
+						Intent intent = new Intent(MainActivity.this, ManufactureListActivity.class);
+
+                        JSONArray manufactureArr = manufacture_arr;
+
+                        if(manufactureArr==null/*||manufactureArr.length()==0*/)
+                        {
+
+                            try {
+                                JSONArray modeArr = RedAntApplication.server_info.getJSONArray("modellist");
+                                for (int i = 0;i < modeArr.length(); i++) {
+                                    JSONObject obj = modeArr.getJSONObject(i);
+                                    String name = obj.getString("name");
+                                    if (name.equals("Model")) {
+                                        manufactureArr = obj.getJSONArray("manifacturer");
+
+                                    }
+                                    break;
+                                }
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                        }
+                        ArrayList<String> mlist = new ArrayList<String>();
+                        for (int j = 0; j < manufactureArr.length(); j++) {
+                            String manufacture = null;
+                            try {
+                                manufacture = manufactureArr.getString(j);
+                            } catch (JSONException e) {
+                                e.printStackTrace();
+                            }
+                            mlist.add(manufacture);
+                        }
+
+                        intent.putStringArrayListExtra("mlist",mlist);
+						startActivityForResult(intent,REQUEST_MANUFACTURE);
+					}
+				});
+			}
+		}
+
+
+
+//        m_tvalert = (TextView) findViewById(R.id.tvalert);
+//        m_tvalert.setSelected(true);
+
+        sendBroadcast(new Intent("REDANT.POP.MODIFY_QUEUE"));
+        updateUploadButton();
+
+	}
+
+	protected void recovery(Bundle savedInstanceState) {
+        if (savedInstanceState != null)
+        {
+//			Bitmap savedBitmap = getBitmap(savedInstanceState
+//					.getByteArray("thumbBitmap"));
+			ArrayList<String> savedPhotoList =  savedInstanceState.getStringArrayList("photoList");
+            String savedPiid = savedInstanceState.getString("PIID");
+			String savedNote = savedInstanceState.getString("Note");
+			File savedPhotoFile = (File) savedInstanceState.getSerializable("photoFile");
+			String manufacture = savedInstanceState.getString("manufacture");
+
+//			if (savedBitmap != null) {
+//				thumbBitmap = savedBitmap;
+//			}
+
+
+
+
+            if (savedPhotoList != null) {
+				photoList = savedPhotoList;
+
+                if(photoList.size()>=1)
+                    thumbBitmap =  BitmapFactory.decodeFile(photoList.get(photoList.size() - 1));
+                if(thumbBitmap!=null)
+                    thumbsImageView.setImageBitmap(thumbBitmap);
+                else
+                    thumbsImageView.setImageResource(R.drawable.no_pic);
+                Log.e(TAG, "recovery: photolist"+photoList.size());
+            }
+            else
+
+            {
+                thumbsImageView.setImageResource(R.drawable.no_pic);
+            }
+
+
+
+            if (!TextUtils.isEmpty(savedPiid)) {
+				pidval.setText(savedPiid);
+				pidval.setSelection(savedPiid.length());
+			}
+            if (savedPhotoFile != null) {
+				photoFile = savedPhotoFile;
+			}
+            if (thumbBitmap != null)
+            {
+                thumbsImageView.setImageBitmap(thumbBitmap);
+            }
+            countTextView.setText(photoList.size() + " Photos");
+
+			/** Model */
+			if (mode.equals("Model")) {
+				if (!TextUtils.isEmpty(savedNote)) {
+					noteTextView.setText(savedNote);
+					noteTextView.setSelection(savedNote.length());
+				}
+				setManufacture(manufacture);
+			}
+
+        }
+    }
+
+    private File compressImageFile(File imgFile) {
+
+
+        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
+                .format(new Date());
+
+        String barcode_title = name;//"PIID";
+//        if (MainActivity.this.getClass().equals(ModelActivity.class)) { // model
+//            barcode_title = "Model";
+//        }
+        String imageFileName = barcode_title + timeStamp +".jpg";
+
+
+        File routedFile = RAUtil.routeBitmap(imgFile,imageFileName);
+
+		SharedPreferences preferences = RedAntApplication.getInstance().getSharedPreferences("UploadManager", 0);
+		boolean auto_compress = preferences.getBoolean("compress",true);
+		if (auto_compress) { // 压缩
+
+			String path = routedFile.getPath();
+
+//			Bitmap source = BitmapFactory.decodeFile(path);
+
+			Bitmap source = null;
+			try {
+				FileInputStream stream = new FileInputStream(routedFile);
+				source = BitmapFactory.decodeStream(stream);
+			} catch (FileNotFoundException e) {
+				return routedFile;
+			}
+
+			if (source == null) {
+				return routedFile;
+			}
+
+			int originWidth = source.getWidth();
+			int originHeight = source.getHeight();
+
+			int width = originWidth, height = originHeight;
+
+			if (originHeight > 1024 || originWidth > 1024)
+			{
+				if (originWidth > originHeight)
+				{
+					width = 1024;
+					height = originHeight * 1024 / originWidth;
+
+				}
+				else
+				{
+
+					height = 1024;
+					width = originWidth * 1024 / originHeight;
+
+				}
+			}
+			Bitmap scaled = Bitmap.createScaledBitmap(source, width, height, true);
+
+
+
+			String scalePath = path.replace(".jpg", "_scaled.jpg");
+			File scaleFile = new File(scalePath);
+			try {
+
+				FileOutputStream outputStream = new FileOutputStream(scaleFile);
+				scaled.compress(Bitmap.CompressFormat.JPEG, 95, outputStream);
+
+				outputStream.flush();
+				outputStream.close();
+
+                String rotedpath = routedFile.getAbsolutePath();
+                routedFile.delete();
+                RAUtil.updateGallery(rotedpath);
+//				scaleFile.renameTo(new File(path));
+				return scaleFile;
+
+			} catch (IOException e) {
+				e.printStackTrace();
+				return routedFile;
+			}
+
+
+		}
+		else
+        {
+            return routedFile;
+        }
+
+
+	}
+
+	private void StartCamera()
+	{
+
+//		if (!RAUtil.checkPermission(this,"android.permission.CAMERA")) {
+//			return;
+//		}
+
+		Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+		// Ensure that there's a camera activity to handle the intent
+
+		if (takePictureIntent.resolveActivity(getPackageManager()) != null)
+		{
+			// Create the File where the photo should go
+			// File photoFile = null;
+			if (photoFile != null)
+				photoFile = null;
+			try
+			{
+				photoFile = createImageFile();
+			}
+			catch (IOException ex)
+			{
+				// Error occurred while creating the File
+				// ...
+			}
+			// Continue only if the File was successfully created
+			Log.i(TAG, photoFile.toString());
+			if (photoFile != null)
+			{
+				Log.i(TAG, "start system camera====================>");
+				takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
+                        getImageContentUri(this,photoFile)/*Uri.fromFile(photoFile)*/);
+				startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
+			}
+		}
+	}
+
+    private Uri getImageContentUri(Context context, File imageFile) {
+        String filePath = imageFile.getAbsolutePath();
+        Cursor cursor = context.getContentResolver().query(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                new String[] { MediaStore.Images.Media._ID },
+                MediaStore.Images.Media.DATA + "=? ",
+                new String[] { filePath }, null);
+
+        if (cursor != null && cursor.moveToFirst()) {
+            int id = cursor.getInt(cursor
+                    .getColumnIndex(MediaStore.MediaColumns._ID));
+            Uri baseUri = Uri.parse("content://media/external/images/media");
+            return Uri.withAppendedPath(baseUri, "" + id);
+        } else {
+            if (imageFile.exists()) {
+                ContentValues values = new ContentValues();
+                values.put(MediaStore.Images.Media.DATA, filePath);
+                return context.getContentResolver().insert(
+                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+            } else {
+                return null;
+            }
+        }
+    }
+
+
+
+
+	@Override
+	protected void onResume()
+	{
+		sendBroadcast(new Intent("REDANT.POP.GPS_ON"));
+		super.onResume();
+
+	}
+
+	@Override
+	protected void onPause()
+	{
+		sendBroadcast(new Intent("REDANT.POP.GPS_OFF"));
+		// TODO Auto-generated method stub
+		super.onPause();
+	}
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState)
+	{
+		Log.d(TAG, "=======================>MainActivity Created!");
+		super.onCreate(savedInstanceState);
+
+
+
+
+        mode = getIntent().getStringExtra("mode");
+        name = getIntent().getStringExtra("name");
+
+        // m_sName = intent.getStringExtra("user");
+		// m_sPassword = intent.getStringExtra("password");
+
+		Log.d(TAG, "user=" + RedAntApplication.user + ",password="
+				+ RedAntApplication.password);
+		IntentFilter msgFilter = new IntentFilter();
+		Intent intent = getIntent();
+
+		msgFilter.addAction("REDANT.RAImage.UPLOAD_COMPLETE");
+
+		msgFilter.setPriority(2147483647);
+		registerReceiver(MainActivityReceiver, msgFilter);
+		Log.d(TAG, "=======================>msgFilter registed!");
+
+        if (newVersion) {
+            return;
+        }
+
+	}
+
+	@Override
+	protected void onDestroy()
+	{
+
+		Log.d(TAG, "=======================>MainActivity Destroyed!");
+		unregisterReceiver(MainActivityReceiver);
+		Log.d(TAG, "=======================>msgFilter unregisted!");
+		super.onDestroy();
+	}
+
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu)
+	{
+		if (newVersion) {
+			getMenuInflater().inflate(R.menu.mode_menu, menu);
+			return true;
+		}
+		// Inflate the menu; this adds items to the action bar if it is present.
+		getMenuInflater().inflate(R.menu.main, menu);
+		return true;
+	}
+
+	private File createImageFile() throws IOException
+	{
+		// Create an image file name
+		String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmSS")
+				.format(new Date());
+		String imageFileName = "JPEG_" + timeStamp + "_";
+		File storageDir = new File(Environment.getExternalStorageDirectory()
+				.getPath() + "/redant/pop/temp/");
+
+		File dir1 = new File(Environment.getExternalStorageDirectory()
+				.getPath() + "/redant");
+		File dir2 = new File(Environment.getExternalStorageDirectory()
+				.getPath() + "/redant/pop");
+		File dir3 = new File(Environment.getExternalStorageDirectory()
+				.getPath() + "/redant/pop/temp");
+
+		
+		if (!dir1.exists())
+		{
+			boolean b = dir1.mkdir();
+		}
+		if (!dir2.exists())
+		{
+			boolean b = dir2.mkdir();
+		}
+		if (!dir3.exists())
+		{
+			boolean b = dir3.mkdir();
+		}
+		// Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+		// Log.d(TAG, "DIR:" + storageDir);
+		LastFileName = storageDir + imageFileName + ".jpg";
+		Log.d(TAG, "File:" + LastFileName);
+		File image = File.createTempFile(imageFileName, /* prefix */
+				".jpg", /* suffix */
+				storageDir /* directory */
+		);
+
+        Log.d(TAG, "File:" + image.getAbsolutePath());
+//        RAUtil.updateGallery(LastFileName);
+
+		// Save a file: path for use with ACTION_VIEW intents
+		// mCurrentPhotoPath = "file:" + image.getAbsolutePath();
+		return image;
+	}
+
+	boolean createDir(String path)
+	{
+		Log.i(TAG, "readFile:createDir=" + path);
+		boolean ret = false;
+		try
+		{
+			File file = new File(path);
+			if (!file.exists())
+				file.mkdirs();
+			if (!file.isDirectory())
+			{
+				ret = file.mkdirs();
+			}
+		}
+		catch (Exception e)
+		{
+			Log.d(TAG, e.toString());
+		}
+		return ret;
+	}
+
+	void updateUploadButton()
+	{
+        if(true)
+        return;
+
+
+
+		if (photoList.size() > 0 && pidval.getText().length() > 0)
+		{
+			uploadButton.setVisibility(View.VISIBLE);
+
+		}
+		else
+		{
+			uploadButton.setVisibility(View.INVISIBLE);
+
+		}
+
+	}
+
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see android.app.Activity#onActivityResult(int, int,
+	 * android.content.Intent)
+	 */
+	@Override
+	public void onActivityResult(int requestCode, int resultCode, Intent data)
+	{
+
+        super.onActivityResult(requestCode, resultCode, data);
+
+		if (requestCode == REQUEST_TAKE_PHOTO)
+			// ������������յ�ͼƬ
+			if (resultCode == Activity.RESULT_OK) // ��������
+
+			{
+
+				Log.d(TAG, photoFile.toString());
+				File scaleFile = compressImageFile(photoFile);
+				if (scaleFile != null) {
+					photoFile = scaleFile;
+				}
+
+
+				photoList.add(photoFile.toString());
+
+
+//                Log.d(TAG, "File:" + image.getAbsolutePath());
+        RAUtil.updateGallery(photoFile.toString());
+				StartCamera();
+				// iPhotoCount++;
+//				super.onActivityResult(requestCode, resultCode, data);
+
+			}
+			else
+			{
+
+				ImageView thumbsImageView = (ImageView) findViewById(R.id.ivThumbs);
+				if (newVersion) {
+					thumbsImageView = this.thumbsImageView;
+				}
+				if (photoList.size() > 0)
+				{
+					thumbBitmap =  BitmapFactory.decodeFile(photoList.get(photoList.size() - 1));
+//
+//
+// ThumbnailUtils.extractThumbnail(BitmapFactory
+//							.decodeFile(photoList.get(photoList.size() - 1)),
+//							iwidth, iheight);
+					if (thumbBitmap != null)
+						thumbsImageView.setImageBitmap(thumbBitmap);
+				}
+
+				String photopath=photoFile.getAbsolutePath();
+				photoFile.delete();
+                RAUtil.updateGallery(photopath);
+				TextView countTextView = (TextView) findViewById(R.id.tvPhotoCount);
+				if (newVersion) {
+					countTextView = this.countTextView;
+				}
+				countTextView.setText(photoList.size() + " Photos");
+				// ImageButton ibtnUpload = (ImageButton)
+				// findViewById(R.id.ibtnOk);
+				updateUploadButton();
+
+			}
+
+//		else if (requestCode == REQUEST_LOCKER)
+//		{
+//			if (resultCode == Activity.RESULT_OK)
+//				m_blocked = false;
+//		}
+		else if (requestCode == REQUEST_PREVIEW)
+		{
+			for (int i = 0; i < photoList.size(); i++)
+			{
+				File file = new File(photoList.get(i));
+				if (!file.exists())
+				{
+					photoList.remove(i);
+					i--;
+				}
+			}
+			TextView countTextView = (TextView) findViewById(R.id.tvPhotoCount);
+			if (newVersion) {
+				countTextView = this.countTextView;
+			}
+			countTextView.setText(photoList.size() + " Photos");
+			if (photoList.size() == 0)
+			{
+				ImageView thumbsImageView = (ImageView) findViewById(R.id.ivThumbs);
+				if (newVersion) {
+					thumbsImageView = this.thumbsImageView;
+				}
+				thumbsImageView.setImageResource(R.drawable.no_pic);
+				thumbBitmap = null;
+			} else {
+                thumbBitmap =  BitmapFactory.decodeFile(photoList.get(photoList.size() - 1));
+//                        ThumbnailUtils.extractThumbnail(BitmapFactory
+//								.decodeFile(photoList.get(photoList.size() - 1)),
+//						iwidth, iheight);
+				if (thumbBitmap != null)
+					thumbsImageView.setImageBitmap(thumbBitmap);
+			}
+		}
+		else if (requestCode == REQUEST_SCAN_BARCODE)
+		{
+			if (resultCode == Activity.RESULT_OK)
+			{
+				Bundle bundle = data.getExtras();
+				String pid = bundle.getString("pid");
+				Log.d(TAG,
+						"REQUEST_SCAN_BARCODE==========>pid="
+								+ bundle.getString("pid"));
+				if (newVersion) {
+
+                    if (mode.equals("POP")||mode.equals("Returns"))
+                    {
+                        if(!RAUtil.isNumeric(pid))
+                        {
+
+                            new AlertDialog.Builder(MainActivity.this)
+                                    .setTitle("Warning")
+                                    .setMessage(name+" must be a number")
+                                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                        @Override
+                                        public void onClick(DialogInterface dialog, int which) {
+
+                                        }
+                                    })
+                                    .show();
+                            return;
+
+
+
+//                            Toast toast = Toast.makeText(getApplicationContext(),
+//                                    "Piid must be a number",
+//                                    Toast.LENGTH_LONG);
+//                            toast.setGravity(Gravity.CENTER, 0, 0);
+//                            toast.show();
+//                            return;
+                        }
+
+                    }
+					pidval.setText(pid);
+					updateUploadButton();
+
+				} else  {
+					TextView pidval = (TextView) findViewById(R.id.pidval);
+
+					pidval.setText(pid);
+					updateUploadButton();
+				}
+			}
+		} else if (requestCode == REQUEST_MANUFACTURE) {
+			if (resultCode == RESULT_OK) {
+				String manufacture = data.getStringExtra("manufacture");
+				setManufacture(manufacture);
+			}
+		}
+
+	}
+
+	public void saveMyBitmap(String bitName, Bitmap mBitmap)
+	{
+		File f = new File("/sdcard/" + bitName + ".png");
+		try
+		{
+			f.createNewFile();
+		}
+		catch (IOException e)
+		{
+			// TODO Auto-generated catch block
+			// DebugMessage.put("�ڱ���ͼƬʱ����" + e.toString());
+		}
+		FileOutputStream fOut = null;
+		try
+		{
+			fOut = new FileOutputStream(f);
+		}
+		catch (FileNotFoundException e)
+		{
+			e.printStackTrace();
+		}
+		mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
+		try
+		{
+			fOut.flush();
+		}
+		catch (IOException e)
+		{
+			e.printStackTrace();
+		}
+		try
+		{
+			fOut.close();
+		}
+		catch (IOException e)
+		{
+			e.printStackTrace();
+		}
+	}
+
+	// boolean confirm_upload()
+	// {
+	// boolean bret = false;
+	// final Boolean b;
+	//
+	// return bret;
+	// }
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item)
+	{
+		if (newVersion) {
+			switch (item.getItemId()) {
+				case R.id.upload_list_btn : {
+					Intent intent = new Intent(this, TaskActivity.class);
+					startActivity(intent);
+				}
+				break;
+				case android.R.id.home: {
+                    clear();
+					finish();
+				}
+				break;
+			}
+			return super.onOptionsItemSelected(item);
+		}
+
+		return super.onOptionsItemSelected(item);
+	}
+
+	@Override
+	protected void onSaveInstanceState(Bundle outState)
+	{
+        Log.e(TAG, "onSaveInstanceState: photolist"+photoList.size());
+		// TODO Auto-generated method stub
+		super.onSaveInstanceState(outState);
+		if (photoFile != null)
+			outState.putSerializable("photoFile", photoFile);
+
+//		if (thumbBitmap != null)
+//			outState.putByteArray("thumbBitmap", getBytes(thumbBitmap));
+
+        // ("thumbBitmap",
+																		// (Object)thumbBitmap);
+																		// outState.putString("thumbpath",
+																		// thumbpath);
+		// outState.putString("m_sName", m_sName);
+		// outState.putString("m_sPassword", m_sPassword);
+
+		outState.putStringArrayList("photoList", photoList);
+		// Log.d(TAG, "save thumbpath==" + thumbpath);
+		//outState.putInt("iPhotoCount", photoList.size());
+
+		if (newVersion) {
+			outState.putString("PIID", pidval.getText().toString());
+			if (mode.equals("Model")) {
+				outState.putString("Note",noteTextView.getText().toString());
+				outState.putString("manufacture",manufacture);
+			}
+		} else  {
+			TextView pidval = (TextView) findViewById(R.id.pidval);
+			outState.putString("PIID", pidval.getText().toString());
+		}
+	}
+
+	public static byte[] getBytes(Bitmap bitmap)
+	{
+		// ʵ�����ֽ����������
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		bitmap.compress(Bitmap.CompressFormat.PNG, 0, baos);// ѹ��λͼ
+		return baos.toByteArray();// ���������ֽ�����
+	}
+
+	public static Bitmap getBitmap(byte[] data)
+	{
+		if (data == null)
+			return null;
+		return BitmapFactory.decodeByteArray(data, 0, data.length);// ���ֽ��������λͼ
+	}
+
+    @Override
+    public void onBackPressed() {
+        clear();
+        super.onBackPressed();
+    }
+
+
+
+    private void clear()
+	{
+        Log.e(TAG, "clear:" );
+        for (int i = 0; i < photoList.size(); i++)
+		{
+
+
+
+
+            //应要求修改,退出上传界面后,不删除未传的图片
+
+//            new File(photoList.get(i)).delete();
+//            RAUtil.updateGallery(photoList.get(i));
+
+
+
+		}
+        photoList.clear();
+
+
+	}
+
+	private void clearfornew()
+	{
+
+        Log.e(TAG, "clearfornew: " );
+        photoList.clear();
+//		TextView pidval = (TextView) findViewById(R.id.pidval);
+		pidval.setText("");
+		updateUploadButton();
+//		ImageView thumbsImageView = (ImageView) findViewById(R.id.ivThumbs);
+		thumbsImageView.setImageResource(R.drawable.no_pic);
+		thumbBitmap = null;
+//		TextView countTextView = (TextView) findViewById(R.id.tvPhotoCount);
+		countTextView.setText("no photo");
+
+        manufacture_arr=null;
+        setManufacture("");
+		if(noteTextView!=null)
+			noteTextView.setText("");
+
+	}
+
+	private final BroadcastReceiver MainActivityReceiver	= new BroadcastReceiver()
+															{
+
+																public void onReceive(
+																		Context context,
+																		Intent intent)
+																{
+																	String action = intent
+																			.getAction();
+                                                                    if("REDANT.RAImage.UPLOAD_COMPLETE".equals(action))
+                                                                    {
+
+                                                                        String result = intent.getStringExtra("result");
+                                                                        String message="";
+                                                                        if(result.equals("finish"))
+                                                                        {
+                                                                            message="Upload complete.";
+                                                                        }
+                                                                        else
+                                                                        {
+                                                                            message="Upload complete with some warring.";
+                                                                        }
+
+//                                                                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                                                                message,
+//                                                                                Toast.LENGTH_LONG);
+//                                                                        toast.setGravity(Gravity.CENTER, 0, 0);
+//                                                                        toast.show();
+
+
+                                                                        new AlertDialog.Builder(MainActivity.this)
+                                                                                .setTitle("Upload list")
+                                                                                .setMessage(message)
+                                                                                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                                                                    @Override
+                                                                                    public void onClick(DialogInterface dialog, int which) {
+
+                                                                                    }
+                                                                                })
+                                                                                .show();
+                                                                        Log.e("Finish_msg", "MainActivity onReceive: ");
+                                                                    }
+																}
+															};
+
+}

+ 286 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/ModeActivity.java

@@ -0,0 +1,286 @@
+package com.usai.redant.raimage;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+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.v7.app.AppCompatActivity;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.ForegroundColorSpan;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.usai.redant.raimage.Model.ModelActivity;
+import com.usai.redant.raimage.POP.PopActivity;
+import com.usai.redant.redantmobile.LoginActivity;
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.redantmobile.RedAntApplication;
+import com.usai.redant.util.Network;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+//import com.usai.redant.util.Network;
+
+public class ModeActivity extends AppCompatActivity {
+
+    private ListView mode_list;
+    private Button upload_setting_btn;
+    private ImageView company_icon_iv;
+    private TextView company_name_tv;
+    private List<JSONObject> dataSource;
+    private ModeAdapter adapter;
+    /** Message Handler */
+    private Handler msgHanlder = new Handler() {
+
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            switch (msg.what) {
+                case 1024:{
+                    company_icon_iv.setImageBitmap((Bitmap)msg.obj);
+                }
+            }
+        }
+
+    };
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_mode);
+
+        /**获取控件*/
+        mode_list = (ListView)findViewById(R.id.mode_list);
+        upload_setting_btn = (Button)findViewById(R.id.upload_setting_btn);
+        company_icon_iv = (ImageView)findViewById(R.id.company_name_icon);
+        company_name_tv = (TextView)findViewById(R.id.company_name_text);
+
+        /**设置数据*/
+        try {
+
+            // company
+            final String icon_link = RedAntApplication.server_info.getString("company_icon");
+            String company_name = RedAntApplication.server_info.getString("company_name");
+
+            if (!TextUtils.isEmpty(company_name)) {
+                company_name_tv.setText(company_name);
+            }
+
+            if (!TextUtils.isEmpty(icon_link)) {
+                new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        // http://192.168.0.130/bo.png
+                        Bitmap img = Network.getImageFromLink(icon_link);
+                        if (img != null) {
+                            Message msg = new Message();
+                            msg.what = 1024;
+                            msg.obj = img;
+                            msgHanlder.sendMessage(msg);
+                        }
+                    }
+                }).start();
+            }
+
+            // mode list
+            JSONArray modeArr = RedAntApplication.server_info.getJSONArray("modellist");
+            if (modeArr.length() > 0) {
+                dataSource = new ArrayList<JSONObject>();
+                for (int i = 0; i < modeArr.length();i++) {
+                    JSONObject obj = modeArr.getJSONObject(i);
+                    dataSource.add(obj);
+                }
+                adapter = new ModeAdapter(this,R.layout.mode_cell,dataSource);
+                mode_list.setAdapter(adapter);
+            }
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        /**List View 点击事件*/
+        mode_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                JSONObject mode = dataSource.get(position);
+               try {
+                   int enable = mode.getInt("enable");
+                   if (enable != 0) {
+                       showActivityMode(mode);
+                   }
+
+               } catch (Exception e) {
+                   e.printStackTrace();
+               }
+
+            }
+        });
+
+        /**上传设置按钮点击*/
+        upload_setting_btn.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showUploadSetting();
+            }
+        });
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.logout_menu,menu);
+
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.logout_item: {
+//                Log.d("Mode List", "Menu Item Click " + item.getTitle());
+                logout();
+            }
+                break;
+        }
+        return true;
+    }
+
+    /***/
+    void showActivityMode(JSONObject mode) {
+
+       try {
+           String name = mode.getString("name");
+
+           String code_name = mode.getString("code_name");
+           if (name.equals("POP")) {
+               Intent intent = new Intent(this,PopActivity.class);
+               intent.putExtra("mode","POP");
+               intent.putExtra("name",code_name);
+               startActivity(intent);
+           } else if (name.equals("Model")) {
+               Intent intent = new Intent(this,ModelActivity.class);
+               intent.putExtra("mode","Model");
+               intent.putExtra("name",code_name);
+               startActivity(intent);
+           }
+           else  if (name.equals("Receiving")) {
+               Intent intent = new Intent(this,PopActivity.class);
+               intent.putExtra("mode","Receiving");
+               intent.putExtra("name",code_name);
+               startActivity(intent);
+           }
+           else  if (name.equals("Returns")) {
+               Intent intent = new Intent(this,PopActivity.class);
+               intent.putExtra("mode","Returns");
+               intent.putExtra("name",code_name);
+               startActivity(intent);
+           }
+       } catch (Exception e) {
+           e.printStackTrace();
+       }
+
+    }
+
+    /**上传设置*/
+    void showUploadSetting() {
+        Intent intent = new Intent(ModeActivity.this,uploadSettingActivity.class);
+        startActivity(intent);
+    }
+
+    void logout() {
+        RedAntApplication.user = null;
+        RedAntApplication.password = null;
+        RedAntApplication.server_info = null;
+        Intent intent = new Intent(ModeActivity.this,LoginActivity.class);
+        startActivity(intent);
+        finish();
+    }
+
+    /**数据源*/
+    class ModeAdapter extends ArrayAdapter<JSONObject> {
+        private int resourceID;
+        public ModeAdapter(Context ctx, int resourceId, List<JSONObject> list) {
+            super(ctx,resourceId,list);
+            resourceID = resourceId;
+        }
+
+        @NonNull
+        @Override
+        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+
+            JSONObject mode = getItem(position);
+            ViewHolder holder = null;
+            View cell;
+            if (convertView == null) {
+                cell = LayoutInflater.from(getContext()).inflate(resourceID,null);
+                holder = new ViewHolder();
+                holder.mode = (TextView) cell.findViewById(R.id.mode_name_tv);
+                cell.setTag(holder);
+            } else  {
+                cell = convertView;
+                holder = (ViewHolder)cell.getTag();
+            }
+
+            try {
+
+                String name = mode.getString("name").toString();
+                String desc = mode.optString("description",null).toString();
+//                desc = "dfhajkdhfadfjagdjfgajkdgajdgjafgdsjgajkdfakdadaljlflaalsallsadf44566";
+                if (name != null && name.length() > 0 && desc != null && desc.length() > 0) {
+                    String str = name + " -- " + desc;
+                    Spannable span = new SpannableString(str);
+                    /**
+                     *
+                     * Spanned.SPAN_EXCLUSIVE_EXCLUSIVE --- 不包含两端start和end所在的端点         (a,b)
+                     * Spanned.SPAN_EXCLUSIVE_INCLUSIVE --- 不包含端start,但包含end所在的端点     (a,b]
+                     * Spanned.SPAN_INCLUSIVE_EXCLUSIVE --- 包含两端start,但不包含end所在的端点   [a,b)
+                     * Spanned.SPAN_INCLUSIVE_INCLUSIVE--- 包含两端start和end所在的端点           [a,b]
+                     * */
+                    span.setSpan(new AbsoluteSizeSpan(17,true), name.length() + 1, str.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    span.setSpan(new ForegroundColorSpan(Color.RED),name.length() + 1,str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    span.setSpan(new AbsoluteSizeSpan(20,true), 0, name.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    span.setSpan(new ForegroundColorSpan(Color.BLACK),0,name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    holder.mode.setText(span);
+                } else {
+                    holder.mode.setText(name);
+                }
+
+
+                int enable = mode.getInt("enable");
+
+                if (enable == 0) {
+                    cell.setBackgroundColor(getResources().getColor(R.color.dark_gray));
+                } else  {
+                    cell.setBackgroundColor(getResources().getColor(R.color.clear_color));
+                }
+                return cell;
+            } catch (Exception e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+
+        class ViewHolder {
+            TextView mode;
+        }
+    }
+}

+ 113 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/Model/ManufactureListActivity.java

@@ -0,0 +1,113 @@
+package com.usai.redant.raimage.Model;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.usai.redant.redantmobile.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ManufactureListActivity extends AppCompatActivity {
+
+    private ListView manufacureList;
+    private ArrayList<String> dataSource;
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_manufacture_list);
+
+
+
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle("RA Image");
+
+        dataSource=getIntent().getStringArrayListExtra("mlist");
+
+        if(dataSource==null)
+            dataSource = new ArrayList<String>();
+
+
+
+        /**Data*/
+
+        /***/
+        manufacureList = (ListView)findViewById(R.id.manufacture_list);
+        ManufactureAdapter adapter = new ManufactureAdapter(this,R.layout.manufacture_cell,dataSource);
+        manufacureList.setAdapter(adapter);
+
+        manufacureList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                String manufacture = dataSource.get(position);
+                Intent intent = new Intent();
+                intent.putExtra("manufacture",manufacture);
+                setResult(RESULT_OK,intent);
+                finish();
+            }
+        });
+
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+
+        switch (item.getItemId()) {
+            case android.R.id.home: {
+                finish();
+            }
+            break;
+        }
+        return true;
+    }
+
+    class ManufactureAdapter extends ArrayAdapter<String> {
+        private int resourceID;
+        public ManufactureAdapter(Context ctx, int resourceId, List<String> list) {
+            super(ctx,resourceId,list);
+            resourceID = resourceId;
+        }
+
+        @NonNull
+        @Override
+        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+
+            String manufacture = dataSource.get(position);
+
+            View cell = null;
+            ViewHolder holder = null;
+            if (convertView != null) {
+                cell = convertView;
+                holder = (ViewHolder)cell.getTag();
+            } else  {
+                cell = LayoutInflater.from(getContext()).inflate(resourceID,null);
+                holder = new ViewHolder();
+                cell.setTag(holder);
+                holder.manufacutre_tv = (TextView) cell.findViewById(R.id.manufacture_cell_tv);
+            }
+
+            holder.manufacutre_tv.setText(manufacture);
+
+            return cell;
+        }
+
+        class ViewHolder {
+            public TextView manufacutre_tv;
+        }
+    }
+}

+ 42 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/Model/ModelActivity.java

@@ -0,0 +1,42 @@
+package com.usai.redant.raimage.Model;
+
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+
+import com.usai.redant.raimage.MainActivity;
+import com.usai.redant.redantmobile.R;
+
+public class ModelActivity extends MainActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_model);
+
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle(mode);
+
+        initView();
+
+        recovery(savedInstanceState);
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+//    @Override
+//    public boolean onOptionsItemSelected(MenuItem item) {
+//
+//        switch (item.getItemId()) {
+//            case android.R.id.home: {
+//                finish();
+//            }
+//            break;
+//        }
+//        return true;
+//    }
+}

+ 52 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/POP/PopActivity.java

@@ -0,0 +1,52 @@
+package com.usai.redant.raimage.POP;
+
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.widget.TextView;
+
+import com.usai.redant.raimage.MainActivity;
+import com.usai.redant.redantmobile.R;
+//import com.usai.redant.redantmobile.R;
+
+public class PopActivity extends MainActivity {
+
+    TextView barcode_tv = null;
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_pop);
+
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle(mode);
+
+        barcode_tv=(TextView)findViewById(R.id.barcode_tv);
+
+        barcode_tv.setText(name);
+        initView();
+
+        recovery(savedInstanceState);
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+
+//    @Override
+//    public boolean onOptionsItemSelected(MenuItem item) {
+//
+//        switch (item.getItemId()) {
+//            case android.R.id.home: {
+//                finish();
+//            }
+//            break;
+//        }
+//        return true;
+//    }
+
+    /**Method*/
+
+}

+ 602 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/CustomLayoutManager.java

@@ -0,0 +1,602 @@
+package com.usai.redant.raimage.PhotoList;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.support.annotation.IntDef;
+import android.support.v7.widget.LinearSmoothScroller;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * CustomLayoutManager
+ * HowToCustomLayoutManager <com.vilyever.howtocustomlayoutmanager>
+ * Created by vilyever on 2016/1/7.
+ * Feature:
+ * 展示一个斜线布局的示例
+ * 支持横向纵向滑动
+ */
+public class CustomLayoutManager extends RecyclerView.LayoutManager {
+    /** Convenience Var to call this */
+    final CustomLayoutManager self = this;
+
+    int screen_w,screen_h;
+
+    /**
+     * init with orientation and itemLineCount
+     * @param orientation {@link com.usai.redant.raimage.PhotoList.CustomLayoutManager.State#orientation}
+//     * @param itemLineCount {@link com.usai.redant.raimage.PhotoList.CustomLayoutManager.State#itemLineCount}
+     */
+    public CustomLayoutManager(@Orientation int orientation, int screen_w, int screen_h) {
+        setOrientation(orientation);
+        this.screen_w = screen_w;
+        this.screen_h = screen_h;
+    }
+
+    /** @see RecyclerView.LayoutManager#onLayoutChildren(RecyclerView.Recycler, RecyclerView.State) */
+    @Override
+    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        if (state.isPreLayout()) { // 跳过preLayout,preLayout主要用于支持动画,暂时先使用自带的简单的fading
+            return;
+        }
+        self.detachAndScrapAttachedViews(recycler); // 分离所有的itemView
+
+        self.getState().contentWidth = 0;
+        self.getState().contentHeight = 0;
+
+        if (getItemCount() == 0) {
+            self.getState().scrolledX = 0;
+            self.getState().scrolledY = 0;
+            self.getState().totalSpreadCount = 0;
+            return;
+        }
+
+        self.getState().totalSpreadCount = 1;
+
+        int offsetX = 15; // 当前X偏移,下一个item的left为此值
+        int offsetY = 0; // 当前Y偏移,下一个item的top为此值
+        int occupiedLineBlock = 0; // 当前line已被占用的块数
+
+        /**
+         * {@link #orientation} 为 {@link #HORIZONTAL} 时,当前line的最大宽度
+         * {@link #orientation} 为 {@link #VERTICAL} 时,当前line的最大高度
+         */
+        int currentLineSpreadLength = 0;
+
+        /**
+         * {@link #orientation} 为 {@link #HORIZONTAL} 时,当前line的总高度
+         * {@link #orientation} 为 {@link #VERTICAL} 时,当前line的总宽度
+         */
+        int currentLineLength = 0;
+
+        /**
+         * {@link #orientation} 为 {@link #HORIZONTAL} 时,所有line的最大高度
+         * {@link #orientation} 为 {@link #VERTICAL} 时,所有line的最大宽度
+         */
+        int maxLineLength = 0;
+
+        /**
+         * 计算所有item的frame,以及总宽高
+         */
+        for (int i = 0; i < getItemCount(); i++) {
+            View scrap = recycler.getViewForPosition(i); // 根据position获取一个碎片view,可以从回收的view中获取,也可能新构造一个
+
+
+            self.addView(scrap);
+            self.measureChildWithMargins(scrap, 0, 0);  // 计算此碎片view包含边距的尺寸
+
+            int width = self.getDecoratedMeasuredWidth(scrap);  // 获取此碎片view包含边距和装饰的宽度width
+            int height = self.getDecoratedMeasuredHeight(scrap); // 获取此碎片view包含边距和装饰的高度height
+
+            LayoutParams layoutParams = (LayoutParams) scrap.getLayoutParams();
+            occupiedLineBlock += Math.max(layoutParams.occupationLineBlocks, 1); // 记录当前line已占用的块数,每个item至少占1块
+
+            /**宽度超过屏幕宽度就移动到下一行*/
+            int col = screen_w / width;
+            int margin = (screen_w - col * width) / (col + 1);
+            if (getOrientation() == VERTICAL) {
+                if (i == 0) {
+                    offsetX = margin;
+                }
+            }
+
+            /** 占用的块数若超过了{@link com.vilyever.howtocustomlayoutmanager.CustomLayoutManager.State#itemLineCount},切换到下一line */
+            if (occupiedLineBlock > col/*self.getState().itemLineCount*/) {
+                if (self.getState().orientation == HORIZONTAL) {
+                    offsetX += currentLineSpreadLength; // 横向偏移当前line的最大宽度
+                    offsetY = 0; // 纵向重置到0
+                    self.getState().contentWidth += currentLineSpreadLength; // contentWidth增加当前line的最大宽度
+                }
+                else {
+                    offsetX = margin; // 横向重置到0
+                    offsetY += currentLineSpreadLength + margin; // 纵向偏移当前line的最大高度
+                    self.getState().contentHeight += currentLineSpreadLength; // contentHeight增加当前line的最大高度
+                }
+
+                occupiedLineBlock = layoutParams.occupationLineBlocks; // 切换到新line布置item
+                currentLineSpreadLength = 0; // 新line还没有item,不占空间
+                maxLineLength = Math.max(maxLineLength, currentLineLength); // 记录之前所有line的最大长度
+                currentLineLength = 0; // 重置
+                self.getState().totalSpreadCount++;
+            }
+
+
+
+
+
+            Rect frame = self.getState().itemsFrames.get(i); // 若先前生成过Rect,重复使用
+            if (frame == null) {
+                frame = new Rect();
+            }
+
+            frame.set(offsetX, offsetY, offsetX + width, offsetY + height);
+            self.getState().itemsFrames.put(i, frame); // 记录每个item的frame
+            self.getState().itemsAttached.put(i, false); // 因为先前已经回收了所有item,此处将item显示标识置否
+
+            if (self.getState().orientation == HORIZONTAL) {
+                offsetY += height; // 纵向偏移,横向不变
+                currentLineSpreadLength = Math.max(currentLineSpreadLength, width); // 记录当前line最大宽度
+                currentLineLength += height; // 记录当前line总高度
+            }
+            else {
+                offsetX += width + margin; // 横向偏移,纵向不变
+                currentLineSpreadLength = Math.max(currentLineSpreadLength, height); // 记录当前line最大高度
+                currentLineLength += width; // 记录当前line总宽度
+            }
+
+            self.detachAndScrapView(scrap, recycler); // 回收本次计算的碎片view
+        }
+
+        if (self.getState().orientation == HORIZONTAL) {
+            self.getState().contentWidth += currentLineSpreadLength; // contentWidth增加最后line的最大宽度
+            self.getState().contentHeight = maxLineLength; // contentHeight设为所有line的最大高度
+        }
+        else {
+            self.getState().contentWidth = maxLineLength; // contentWidth设为所有line的最大宽度
+            self.getState().contentHeight += currentLineSpreadLength; // contentWidth增加最后line的最大高度
+        }
+
+        self.getState().contentWidth = Math.max(self.getState().contentWidth, self.getHorizontalSpace()); // 内容宽度最小为RecyclerView容器宽度
+        self.getState().contentHeight = Math.max(self.getState().contentHeight, self.getVerticalSpace()); // 内容高度最小为RecyclerView容器高度
+
+        // 依照新内容宽高调整记录的滑动距离,防止滑动偏移过大
+        self.fixScrollOffset();
+
+        self.layoutItems(recycler, state); // 放置当前scroll offset处要展示的item
+    }
+
+    /** @see RecyclerView.LayoutManager#canScrollHorizontally() */
+    @Override
+    public boolean canScrollHorizontally() {
+        return self.getState().canScrollHorizontal;
+    }
+
+    /** @see RecyclerView.LayoutManager#scrollHorizontallyBy(int, RecyclerView.Recycler, RecyclerView.State) */
+    @Override
+    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
+        int willScroll = dx;
+        /**
+         * 限制滑动距离的最小值和最大值
+         */
+        if (self.getState().scrolledX + dx < 0) {
+            willScroll = -self.getState().scrolledX;
+        }
+        else if (self.getState().scrolledX + dx > self.getState().contentWidth - self.getHorizontalSpace()) {
+            willScroll = self.getState().contentWidth - self.getHorizontalSpace() - self.getState().scrolledX;
+        }
+
+        // 如果将要滑动的距离为0,返回-dx以显示边缘光晕
+        if (willScroll == 0) {
+            return -dx;
+        }
+
+        self.getState().scrolledX += willScroll;
+
+        // 平移容器内的item
+        self.offsetChildrenHorizontal(-willScroll);
+        // 移除屏幕外的item,添加当前可显示的新item
+        self.layoutItems(recycler, state);
+
+        return willScroll;
+    }
+
+    /** @see RecyclerView.LayoutManager#canScrollVertically() */
+    @Override
+    public boolean canScrollVertically() {
+        return self.getState().canScrollVertical;
+    }
+
+    /** @see RecyclerView.LayoutManager#scrollVerticallyBy(int, RecyclerView.Recycler, RecyclerView.State) */
+    @Override
+    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
+        int willScroll = dy;
+
+        /**
+         * 限制滑动距离的最小值和最大值
+         */
+        if (self.getState().scrolledY + dy < 0) {
+            willScroll = -self.getState().scrolledY;
+        }
+        else if (self.getState().scrolledY + dy > self.getState().contentHeight - self.getVerticalSpace()) {
+            willScroll = self.getState().contentHeight - self.getVerticalSpace() - self.getState().scrolledY;
+        }
+
+        // 如果将要滑动的距离为0,返回-dy以显示边缘光晕
+        if (willScroll == 0) {
+            return -dy;
+        }
+
+        self.getState().scrolledY += willScroll;
+
+        // 平移容器内的item
+        self.offsetChildrenVertical(-willScroll);
+        // 移除屏幕外的item,添加当前可显示的新item
+        self.layoutItems(recycler, state);
+
+        return willScroll;
+    }
+
+    @Override
+    public void scrollToPosition(int position) {
+        position = Math.max(position, 0);
+        position = Math.min(position, self.getItemCount());
+
+        self.getState().scrolledX = self.getState().itemsFrames.get(position).left;
+        self.getState().scrolledY = self.getState().itemsFrames.get(position).top;
+        self.fixScrollOffset();
+
+        self.requestLayout();
+    }
+
+    @Override
+    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
+        position = Math.max(position, 0);
+        position = Math.min(position, self.getItemCount());
+
+        /*
+         * LinearSmoothScroller's default behavior is to scroll the contents until
+         * the child is fully visible. It will snap to the top-left or bottom-right
+         * of the parent depending on whether the direction of travel was positive
+         * or negative.
+         */
+        LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) {
+            /*
+             * LinearSmoothScroller, at a minimum, just need to know the vector
+             * (x/y distance) to travel in order to get from the current positioning
+             * to the target.
+             */
+            @Override
+            public PointF computeScrollVectorForPosition(int targetPosition) {
+                int oldScrollX = self.getState().scrolledX;
+                int oldScrollY = self.getState().scrolledY;
+
+                self.getState().scrolledX = self.getState().itemsFrames.get(targetPosition).left;
+                self.getState().scrolledY = self.getState().itemsFrames.get(targetPosition).top;
+                self.fixScrollOffset();
+
+                int newScrollX = self.getState().scrolledX;
+                int newScrollY = self.getState().scrolledY;
+
+                self.getState().scrolledX = oldScrollX;
+                self.getState().scrolledY = oldScrollY;
+
+                return new PointF(newScrollX - oldScrollX, newScrollY - oldScrollY);
+            }
+        };
+        scroller.setTargetPosition(position);
+        self.startSmoothScroll(scroller);
+    }
+
+    /** @see RecyclerView.LayoutManager#generateDefaultLayoutParams() */
+    @Override
+    public LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+    }
+    /** @see RecyclerView.LayoutManager#generateLayoutParams(ViewGroup.LayoutParams) */
+    @Override
+    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp instanceof ViewGroup.MarginLayoutParams) {
+            return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
+        } else {
+            return new LayoutParams(lp);
+        }
+    }
+    /** @see RecyclerView.LayoutManager#generateLayoutParams(Context, AttributeSet) */
+    @Override
+    public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
+        return new LayoutParams(c, attrs);
+    }
+    /** @see RecyclerView.LayoutManager#checkLayoutParams(RecyclerView.LayoutParams) */
+    @Override
+    public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
+        return lp instanceof LayoutParams;
+    }
+
+    public static class LayoutParams extends RecyclerView.LayoutParams {
+
+        /**
+         * 占用块数
+         * 不同方向布局时,占用行数或列数的值
+         * {@link State#itemLineCount}
+         * default is 1, must > 0
+         */
+        public int occupationLineBlocks = 1;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+        public LayoutParams(ViewGroup.MarginLayoutParams source) {
+            super(source);
+        }
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+        public LayoutParams(RecyclerView.LayoutParams source) {
+            super(source);
+        }
+    }
+
+    /**
+     * 摆放当前状态下要展示的item
+     * @param recycler         Recycler to use for fetching potentially cached views for a
+     *                         position
+     * @param state            Transient state of RecyclerView
+     */
+    private void layoutItems(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        if (state.isPreLayout()) { // 跳过preLayout,preLayout主要用于支持动画
+            return;
+        }
+
+        // 当前scroll offset状态下的显示区域
+        Rect displayFrame = new Rect(self.getState().scrolledX, self.getState().scrolledY, self.getState().scrolledX + self.getHorizontalSpace(), self.getState().scrolledY + self.getVerticalSpace());
+
+        /**
+         * 移除已显示的但在当前scroll offset状态下处于屏幕外的item
+         */
+        Rect childFrame = new Rect();
+        for (int i = 0; i < self.getChildCount(); i++) {
+            View child = self.getChildAt(i);
+            childFrame.left = self.getDecoratedLeft(child);
+            childFrame.top = self.getDecoratedTop(child);
+            childFrame.right = self.getDecoratedRight(child);
+            childFrame.bottom = self.getDecoratedBottom(child);
+
+            if (!Rect.intersects(displayFrame, childFrame)) {
+                self.getState().itemsAttached.put(self.getPosition(child), false);
+                self.removeAndRecycleView(child, recycler);
+            }
+        }
+
+        /**
+         * 摆放需要显示的item
+         * 由于RecyclerView实际上并没有scroll,也就是说RecyclerView容器的滑动效果是依赖于LayoutManager对item进行平移来实现的
+         * 故在放置item时要将item的计算位置平移到实际位置
+         */
+        for (int i = 0; i < self.getItemCount(); i++) {
+            if (Rect.intersects(displayFrame, self.getState().itemsFrames.get(i))) {
+                /**
+                 * 在onLayoutChildren时由于移除了所有的item view,可以遍历全部item进行添加
+                 * 在scroll时就不同了,由于scroll时会先将已显示的item view进行平移,然后移除屏幕外的item view,此时仍然在屏幕内显示的item view就无需再次添加了
+                 */
+                if (!self.getState().itemsAttached.get(i)) {
+                    View scrap = recycler.getViewForPosition(i);
+                    self.measureChildWithMargins(scrap, 0, 0);
+                    self.addView(scrap);
+
+                    Rect frame = self.getState().itemsFrames.get(i);
+                    self.layoutDecorated(scrap,
+                            frame.left - self.getState().scrolledX,
+                            frame.top - self.getState().scrolledY,
+                            frame.right - self.getState().scrolledX,
+                            frame.bottom - self.getState().scrolledY); // Important!布局到RecyclerView容器中,所有的计算都是为了得出任意position的item的边界来布局
+
+                    self.getState().itemsAttached.put(i, true);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * 记录当前LayoutManager的一些信息
+     */
+    private State state;
+    public State getState() {
+        if (state == null) {
+            state = new State();
+        }
+        return state;
+    }
+    class State {
+        /**
+         * 存放所有item的位置和尺寸
+         */
+        SparseArray<Rect> itemsFrames;
+
+        /**
+         * 记录item是否已经展示
+         */
+        SparseBooleanArray itemsAttached;
+
+        /**
+         * 横向滑动距离
+         * @see #scrollHorizontallyBy(int, RecyclerView.Recycler, RecyclerView.State)
+         */
+        int scrolledX;
+
+        /**
+         * 纵向滑动距离
+         * @see #scrollVerticallyBy(int, RecyclerView.Recycler, RecyclerView.State)
+         */
+        int scrolledY;
+
+        /**
+         * 内容宽度
+         * note:最小宽度为容器宽度
+         */
+        int contentWidth;
+
+        /**
+         * 内容高度
+         * note:最小高度为容器高度
+         */
+        int contentHeight;
+
+        /**
+         * 是否允许横向滑动
+         * 默认允许
+         */
+        boolean canScrollHorizontal;
+
+        /**
+         * 是否允许纵向滑动
+         * 默认允许
+         */
+        boolean canScrollVertical;
+
+        /**
+         * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}
+         */
+        int orientation;
+
+        /**
+         * {@link #orientation} 为 {@link #HORIZONTAL} 时,每列显示的item数
+         * {@link #orientation} 为 {@link #VERTICAL} 时,每行显示的item数
+         * 每个item有可能占用多格 {@link com.usai.redant.raimage.PhotoList.CustomLayoutManager.LayoutParams#occupationLineBlocks}
+         */
+        int itemLineCount;
+
+        /**
+         * {@link #orientation} 为 {@link #HORIZONTAL} 时,表示列数
+         * {@link #orientation} 为 {@link #VERTICAL} 时,表示行数
+         */
+        int totalSpreadCount;
+
+        public State() {
+            itemsFrames = new SparseArray<>();
+            itemsAttached = new SparseBooleanArray();
+            scrolledX = 0;
+            scrolledY = 0;
+            contentWidth = 0;
+            contentHeight = 0;
+            canScrollHorizontal = true;
+            canScrollVertical = true;
+            itemLineCount = 1;
+            totalSpreadCount = 0;
+        }
+    }
+
+    /**
+     * 启用/禁用横向滑动
+     * @param canScrollHorizontal 启用/禁用
+     * @return {@link State#canScrollHorizontal}
+     */
+    public CustomLayoutManager setCanScrollHorizontal(boolean canScrollHorizontal) {
+        self.getState().canScrollHorizontal = canScrollHorizontal;
+        return this;
+    }
+    public boolean getCanScrollHorizontal() {
+        return self.getState().canScrollHorizontal;
+    }
+
+    /**
+     * 启用/禁用纵向滑动
+     * @param canScrollVertical 启用/禁用
+     * @return {@link State#canScrollVertical}
+     */
+    public CustomLayoutManager setCanScrollVertical(boolean canScrollVertical) {
+        self.getState().canScrollVertical = canScrollVertical;
+        return this;
+    }
+    public boolean getCanScrollVertical() {
+        return self.getState().canScrollVertical;
+    }
+
+    /**
+     * 纵然此LayoutManager在水平方向和垂直方向都可以滑动
+     * 此LayoutManager仍然带有orientation属性
+     * orientation将影响item摆放的次序
+     *
+     * 若Direction为Vertical,item的摆放顺序为从左到右,一行铺满后填充下一行
+     * 若Direction为Horizontal,item的摆放顺序为从上到下,一列铺满后填充下一列
+     */
+    @IntDef({HORIZONTAL, VERTICAL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Orientation {}
+    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+    public static final int VERTICAL = LinearLayout.VERTICAL;
+    public CustomLayoutManager setOrientation(@Orientation int orientation) {
+        if (orientation != HORIZONTAL && orientation != VERTICAL) {
+            throw new IllegalArgumentException("invalid orientation:" + orientation);
+        }
+        assertNotInLayoutOrScroll(null);
+        if (orientation == self.getState().orientation) {
+            return this;
+        }
+        self.getState().orientation = orientation;
+        self.requestLayout();
+        return this;
+    }
+    @Orientation
+    public int getOrientation() {
+        return self.getState().orientation;
+    }
+
+    public CustomLayoutManager setItemLineCount(int itemLineCount) {
+        assertNotInLayoutOrScroll(null);
+        if (itemLineCount == self.getState().itemLineCount) {
+            return this;
+        }
+        self.getState().itemLineCount = itemLineCount;
+        self.requestLayout();
+        return this;
+    }
+    public int getItemLineCount() {
+        return self.getState().itemLineCount;
+    }
+
+    /**
+     * 依照内容宽高调整记录的滑动距离,防止滑动偏移过大
+     */
+    private void fixScrollOffset() {
+        if (self.getState().contentWidth == self.getHorizontalSpace()) {
+            self.getState().scrolledX = 0;
+        }
+        if (self.getState().scrolledX > (self.getState().contentWidth - self.getHorizontalSpace())) {
+            self.getState().scrolledX = self.getState().contentWidth - self.getHorizontalSpace();
+        }
+        if (self.getState().contentHeight == self.getVerticalSpace()) {
+            self.getState().scrolledY = 0;
+        }
+        if (self.getState().scrolledY > (self.getState().contentHeight - self.getVerticalSpace())) {
+            self.getState().scrolledY = self.getState().contentHeight - self.getVerticalSpace();
+        }
+    }
+
+    /**
+     * 容器去除padding后的宽度
+     * @return 实际可摆放item的空间
+     */
+    private int getHorizontalSpace() {
+        return self.getWidth() - self.getPaddingRight() - self.getPaddingLeft();
+    }
+
+    /**
+     * 容器去除padding后的高度
+     * @return 实际可摆放item的空间
+     */
+    private int getVerticalSpace() {
+        return self.getHeight() - self.getPaddingBottom() - self.getPaddingTop();
+    }
+}

+ 61 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/GridItemDecoration.java

@@ -0,0 +1,61 @@
+package com.usai.redant.raimage.PhotoList;
+
+
+import android.graphics.Rect;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+
+public class GridItemDecoration extends RecyclerView.ItemDecoration {
+
+
+    private int spanCount;
+    private int spacing;
+    private boolean includeEdge;
+
+    public GridItemDecoration(int spanCount, int spacing, boolean includeEdge) {
+        this.spanCount = spanCount;
+        this.spacing = spacing;
+        this.includeEdge = includeEdge;
+    }
+
+    @Override
+    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+
+
+
+        GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
+        //判断总的数量是否可以整除
+        int totalCount = layoutManager.getItemCount();
+        int columns = layoutManager.getSpanCount();// 列
+        int rowCount = totalCount % columns; // 行
+        int childPosition = parent.getChildAdapterPosition(view); // 当前位置
+
+        if (layoutManager.getOrientation() == GridLayoutManager.VERTICAL) {//竖直方向的
+
+            if (childPosition > rowCount * layoutManager.getSpanCount()) { // 最后一行
+                outRect.bottom = spacing;
+            } else if (childPosition % layoutManager.getSpanCount() == layoutManager.getSpanCount() - 1) { // 最后一列
+                outRect.right = spacing;
+            }
+            outRect.top = spacing;
+            outRect.left = spacing;
+
+        } else {
+            if (rowCount == 0 && childPosition > totalCount - layoutManager.getSpanCount() - 1) {
+                //后面几项需要右边
+                outRect.right = spacing;
+            } else if (rowCount != 0 && childPosition > totalCount - rowCount - 1) {
+                outRect.right = spacing;
+            }
+            if ((childPosition + 1) % layoutManager.getSpanCount() == 0) {//被整除的需要下边
+                outRect.bottom = spacing;
+            }
+            outRect.top = spacing;
+            outRect.left = spacing;
+        }
+
+    }
+
+}

+ 36 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/GridLayoutRecycler/RAGridLayoutManager.java

@@ -0,0 +1,36 @@
+package com.usai.redant.raimage.PhotoList.GridLayoutRecycler;
+
+import android.content.Context;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+
+/**
+ * Created by macmini1 on 2017/6/19.
+ */
+
+
+public class RAGridLayoutManager extends GridLayoutManager {
+
+    private int measuredWidth = 0;
+    private int measuredHeight = 0;
+
+    public RAGridLayoutManager(Context ctx, int spanCount) {
+        super(ctx,spanCount);
+    }
+
+    public RAGridLayoutManager(Context ctx, int spanCount, int orientaion, boolean reverseLayout) {
+        super(ctx,spanCount,orientaion,reverseLayout);
+    }
+
+    public RAGridLayoutManager(Context ctx, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(ctx,attrs,defStyleAttr,defStyleRes);
+    }
+
+    @Override
+    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
+
+        super.onMeasure(recycler,state,widthSpec,heightSpec);
+
+    }
+}

+ 174 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/GridLayoutRecycler/RAPreviewRecyclerView.java

@@ -0,0 +1,174 @@
+package com.usai.redant.raimage.PhotoList.GridLayoutRecycler;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+/**
+ * Created by macmini1 on 2017/6/19.
+ */
+
+public class RAPreviewRecyclerView extends RecyclerView {
+
+
+    private int totalPage = 0;
+    private int curPage = 0;
+
+    /**
+     * 0: 停止滚动
+     * 1: 开始滚动
+     * 2: 手指移开
+     *
+     * */
+    private int scrollState = 0;
+    private int shortestDistance;
+    private float slideDistance;
+    private float scrollX = 0; // X轴当前的位置
+
+    public PageIndicator indicator;
+
+    public RAPreviewRecyclerView(Context context) {
+        this(context, null);
+    }
+
+    public RAPreviewRecyclerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public RAPreviewRecyclerView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+    }
+
+    @Override
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        super.onMeasure(widthSpec, heightSpec);
+        shortestDistance = getMeasuredWidth() / 3;
+        totalPage = getAdapter().getItemCount();
+    }
+
+    /**
+     * 取消惯性滑动
+     * 阻尼:1000为将惯性滚动速度缩小1000倍,近似drag操作。
+     * */
+    @Override
+    public boolean fling(int velocityX, int velocityY) {
+        return super.fling(velocityX / 1000, velocityY / 1000);
+    }
+
+    /**滚动*/
+    @Override
+    public void onScrolled(int dx, int dy) {
+//        Log.d("Scroll","scroll X: " + dx);
+        scrollX += dx;
+        if (scrollState == 1) {
+            slideDistance += dx;
+        }
+        super.onScrolled(dx, dy);
+    }
+
+    @Override
+    public void onScrollStateChanged(int state) {
+
+        switch (state) {
+            case 2: {
+                scrollState = 2;
+            }
+                break;
+            case 1:
+                scrollState = 1;
+                break;
+            case 0:
+                if (slideDistance == 0) {
+                    break;
+                }
+                scrollState = 0;
+
+//                if (slideDistance < 0) { // 上页
+//                    curPage = (int) Math.ceil(scrollX / getWidth());
+////                    Log.d("Scroll","<0 scroll X: " + scrollX + " Cur :" + curPage);
+//                    if (curPage * getWidth() - scrollX < shortestDistance) {
+//                        curPage += 1;
+//                    }
+//                } else { // 下页
+//                    curPage = (int) Math.ceil(scrollX / getWidth()) + 1;
+////                    Log.d("Scroll",">0 scroll X: " + scrollX + " Cur :" + curPage);
+//                    if (curPage <= totalPage) {
+//                        if (scrollX - (curPage - 2) * getWidth() < shortestDistance) {
+//                            // 如果这一页滑出距离不足,则定位到前一页
+//                            curPage -= 1;
+//                        }
+//                    } else {
+//                        curPage = totalPage;
+//                    }
+//                }
+
+                int offsetX = computeHorizontalScrollOffset();
+                int width = getWidth();
+                curPage = (int) Math.ceil(offsetX / width);
+
+                if (slideDistance < 0) {
+                    if ((curPage * width) - offsetX > shortestDistance) {
+                        curPage--;
+                    }
+                } else  {
+                    if ((curPage * width) - offsetX < shortestDistance) {
+                        curPage++;
+                        if (curPage >= totalPage) {
+                            curPage = totalPage - 1;
+                        }
+                    }
+                }
+
+
+                // 执行自动滚动
+                scrollToPosition(curPage);
+                // 修改指示器选中项
+                if (indicator != null) {
+                    indicator.changePageIndex(curPage,totalPage);
+                }
+                slideDistance = 0;
+                break;
+        }
+        super.onScrollStateChanged(state);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent e) {
+
+        int action = e.getAction();
+        if (action == ACTION_DOWN) {
+
+        }
+
+        if (action == ACTION_UP) {
+
+        }
+
+        if (action == ACTION_MOVE) {
+
+        }
+
+        return super.onTouchEvent(e);
+    }
+
+    @Override
+    public void computeScroll() {
+
+        super.computeScroll();
+    }
+
+    public void scrollToPage(int page) {
+        curPage = page;
+        scrollToPosition(curPage);
+    }
+
+    public interface PageIndicator {
+        void changePageIndex(int index, int total);
+    }
+}

+ 199 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/NewPhotoPreviewActivity.java

@@ -0,0 +1,199 @@
+package com.usai.redant.raimage.PhotoList;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.usai.redant.raimage.PhotoList.XuanImageView.XuanImageView;
+import com.usai.redant.raimage.PhotoList.XuanImageView.XuanImageViewSettings;
+import com.usai.redant.redantmobile.R;
+
+import java.util.ArrayList;
+
+public class NewPhotoPreviewActivity extends AppCompatActivity {
+
+    private TextView indexTV;
+//    private RAPreviewRecyclerView recyclerView;
+
+    private ViewPager pager;
+    private ArrayList<String> photos;
+//    private ArrayList<XuanImageView> ivContainer;
+    private int currentIdx;
+    private PreviewAdapter adapter;
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_new_photo_preview);
+
+        /**Action Bar*/
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle("RA Image");
+
+
+//        ivContainer = new ArrayList<XuanImageView>();
+        /**View*/
+        indexTV = (TextView)findViewById(R.id.index_tv);
+//        recyclerView = (RAPreviewRecyclerView) findViewById(R.id.preview_recycler);
+
+
+        /** Setting */
+        Intent intent = getIntent();
+        photos = (ArrayList<String>) intent.getSerializableExtra("photos");
+        currentIdx = intent.getIntExtra("index",0);
+
+        if (photos.size() > 0) {
+            indexTV.setText(currentIdx + 1 + " / " + photos.size());
+        }
+
+//        LinearLayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
+//        recyclerView.setLayoutManager(layoutManager);
+//        // 设置Item增加、移除动画
+//        recyclerView.setItemAnimator(new DefaultItemAnimator());
+//        // 设置Adapter
+//        recyclerView.setAdapter(adapter = new PreviewAdapter());
+//
+//        recyclerView.indicator = new RAPreviewRecyclerView.PageIndicator() {
+//            @Override
+//            public void changePageIndex(int index, int total) {
+//                indexTV.setText(index + 1 + " / " + total);
+//            }
+//        };
+//
+//        recyclerView.scrollToPage(currentIdx);
+
+
+        pager = (ViewPager)findViewById(R.id.preview_recycler);
+        pager.setAdapter(new PagerAdapter() {
+            @Override
+            public int getCount() {
+                return photos.size();
+            }
+
+            @Override
+            public boolean isViewFromObject(View view, Object object) {
+                return view == object;
+            }
+
+            @Override
+            public Object instantiateItem(ViewGroup container, int position) {
+
+                XuanImageView xuanImageView = new XuanImageView(getBaseContext());
+                xuanImageView.setAutoRotateCategory(XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM);
+
+                String path = photos.get(position);
+
+                // 低性能机器
+//                Bitmap bitmap = scaleImage(path,500,500);
+//                xuanImageView.setImageBitmap(bitmap);
+
+                // 机能好的机器
+                Bitmap bitmap = BitmapFactory.decodeFile(path);
+                xuanImageView.setImageBitmap(bitmap);
+
+                container.addView(xuanImageView);
+
+//                ivContainer.add(xuanImageView);
+
+                return  xuanImageView;
+
+            }
+
+            @Override
+            public void destroyItem(ViewGroup container, int position, Object object) {
+//                ivContainer.remove(position);
+            }
+        });
+
+        pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+            @Override
+            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+            }
+
+            @Override
+            public void onPageSelected(int position) {
+                indexTV.setText(position + 1 + " / " + photos.size());
+                currentIdx = position;
+            }
+
+            @Override
+            public void onPageScrollStateChanged(int state) {
+
+            }
+        });
+
+        pager.setCurrentItem(currentIdx);
+
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+
+        switch (item.getItemId()) {
+            case android.R.id.home: {
+                finish();
+            }
+            break;
+        }
+        return true;
+    }
+
+    /**Adapter*/
+    public class PreviewAdapter extends RecyclerView.Adapter<PreviewAdapter.PreviewHolder> {
+
+        class PreviewHolder extends RecyclerView.ViewHolder {
+            XuanImageView imageView;
+            public PreviewHolder(View view) {
+                super(view);
+                imageView = (XuanImageView)view.findViewById(R.id.preview_item);
+            }
+        }
+
+        @Override
+        public PreviewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            PreviewHolder holder = new PreviewHolder(LayoutInflater.from(NewPhotoPreviewActivity.this).inflate(R.layout.photo_preview_item,parent,false));
+            return holder;
+        }
+
+        @Override
+        public void onBindViewHolder(PreviewHolder holder, int position) {
+            String path = photos.get(position);
+//            File file = new File(path);
+//            Uri uri = Uri.fromFile(file);
+//            holder.imageView.setImageURI(uri);
+
+            Bitmap bitmap = scaleImage(path,150,150);
+
+            holder.imageView.setImageBitmap(bitmap);
+        }
+
+        @Override
+        public int getItemCount() {
+            return photos.size();
+        }
+    }
+
+
+    /** View Pager */
+
+    public Bitmap scaleImage(String path, int width, int height) {
+        Bitmap source = BitmapFactory.decodeFile(path);
+
+        Bitmap scaled = Bitmap.createScaledBitmap(source, source.getWidth() / 2, source.getHeight() / 2, true);
+        return scaled;
+    }
+
+}

+ 417 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/PhotoGridActivity.java

@@ -0,0 +1,417 @@
+package com.usai.redant.raimage.PhotoList;
+
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.ThumbnailUtils;
+import android.os.Bundle;
+import android.os.Environment;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.util.RAUtil;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class PhotoGridActivity extends AppCompatActivity implements RAGridView.GridViewMeasure {
+
+    private RAGridView gridView;
+    private GridViewAdapter adapter;
+    private Button deleteBtn;
+    private ArrayList<HashMap<String,String>> photoDic;
+
+    private static int land_col = 5;
+    private static int portrait_col = 3;
+    private int col;
+
+    private boolean measuring;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_photo_grid);
+
+        Intent intent = getIntent();
+        ArrayList<String> photos = (ArrayList<String>) intent.getSerializableExtra("pic_list");
+        photoDic = new ArrayList<HashMap<String, String>>();
+        for (int i = 0; i < photos.size(); i++) { // 默认全部未选中
+
+            HashMap<String,String> dic = new HashMap<String, String>();
+            dic.put("path",photos.get(i));
+            dic.put("delete","0");
+
+            photoDic.add(dic);
+        }
+
+
+        gridView = (RAGridView) findViewById(R.id.photo_grid_view);
+        gridView.measureWorker = this;
+
+
+        deleteBtn = (Button)findViewById(R.id.grid_photo_delete_btn);
+        deleteBtn.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+
+                Iterator<HashMap<String,String>> iterator = photoDic.iterator();
+                while (iterator.hasNext()) {
+                    HashMap<String,String> item = iterator.next();
+                    int delete = Integer.valueOf(item.get("delete"));
+                    if (delete == 1) {
+                        // 删除文件
+                        new File(item.get("path")).delete();
+                        RAUtil.updateGallery(item.get("path"));
+                        iterator.remove();
+                        int index = photoDic.indexOf(item);
+                    }
+                }
+                adapter.notifyDataSetChanged();
+
+            }
+        });
+
+
+        int h = getWindowManager().getDefaultDisplay().getHeight();
+        int w = getWindowManager().getDefaultDisplay().getWidth();
+
+
+        if (w > h) {
+            col = land_col;
+        } else {
+            col = portrait_col;
+        }
+        gridView.setNumColumns(col);
+
+        Log.d("List", "onCreate: setAdapter");
+        // 设置Adapter
+        gridView.setAdapter(adapter = new GridViewAdapter());
+
+
+        /**Action Bar*/
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle("RA Image");
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        Log.d("List", "onStart");
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home: {
+                finish();
+            }
+            break;
+        }
+        return true;
+    }
+
+    private void showPhotoPreview(int index) {
+        ArrayList<String> photos = new ArrayList<String>();
+        Iterator<HashMap<String,String>> iterator = photoDic.iterator();
+        while (iterator.hasNext()) {
+            HashMap<String,String> item = iterator.next();
+            photos.add(item.get("path"));
+        }
+//        Toast.makeText(PhotoGridActivity.this,"Click" + index,Toast.LENGTH_LONG).show();
+        Intent intent = new Intent(this,NewPhotoPreviewActivity.class);
+        intent.putExtra("photos",(Serializable)photos);
+        intent.putExtra("index",index);
+        startActivity(intent);
+    }
+
+
+
+    /**缩小图片*/
+    public Bitmap scaleImage(String path) {
+        Bitmap source = BitmapFactory.decodeFile(path);
+
+        int originWidth = source.getWidth();
+        int originHeight = source.getHeight();
+
+        int width = originWidth, height = originHeight;
+
+        if (originHeight > 1024 || originWidth > 1024)
+        {
+            if (originWidth > originHeight)
+            {
+                width = 1024;
+                height = originHeight * 1024 / originWidth;
+
+            }
+            else
+            {
+
+                height = 1024;
+                width = originWidth * 1024 / originHeight;
+
+            }
+        }
+        Bitmap scaled = Bitmap.createScaledBitmap(source, width, height, true);
+        return scaled;
+    }
+
+    @Override
+    public void measuring(boolean m) {
+        this.measuring = m;
+    }
+
+
+    private ExecutorService executorService = Executors.newSingleThreadExecutor();
+
+    /**Adapter*/
+    private class GridViewAdapter extends BaseAdapter {
+
+        private class PhotoViewHolder {
+            public ImageView photoView;
+            public ImageButton checkBtn;
+
+            public PhotoViewHolder(View view) {
+                photoView = (ImageView)view.findViewById(R.id.photo_list_iv);
+                checkBtn = (ImageButton)view.findViewById(R.id.photo_list_checkBtn);
+            }
+        }
+
+
+        @Override
+        public int getCount() {
+            return photoDic.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return position;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            /**系统多次调用以测量*/
+
+            PhotoViewHolder holder = null;
+            View cell;
+            if (convertView == null) {
+                cell = (View) LayoutInflater.from(PhotoGridActivity.this).inflate(R.layout.photo_list_item,null);
+                holder = new PhotoViewHolder(cell);
+                cell.setTag(holder);
+            } else {
+                cell = convertView;
+                holder = (PhotoViewHolder)cell.getTag();
+            }
+
+            if (measuring == true) {
+                measuring = false;
+//                return cell;
+            }
+
+
+            final HashMap<String,String> item = photoDic.get(position);
+            final String path = item.get("path");
+
+
+//            Bitmap bitmap = scaleImage(path);
+
+//            Log.d("Decode", "begin path: " + path);
+//             Bitmap bitmap = BitmapFactory.decodeFile(path);
+//            Log.d("Decode", "end path: " + path);
+//
+//            Bitmap scale = ThumbnailUtils.extractThumbnail(bitmap, 300, 300);
+//
+//            holder.photoView.setImageBitmap(scale);
+
+            if (thumbPhotoIsExists(path)) {
+                Bitmap bitmap = BitmapFactory.decodeFile(thumbFile(path).getAbsolutePath());
+                holder.photoView.setImageBitmap(bitmap);
+            } else {
+                holder.photoView.setImageBitmap(null);
+                final String filePath = path;
+                final PhotoViewHolder photoHolder = holder;
+//                new Thread(new Runnable() {
+//                    @Override
+//                    public void run() {
+//                        Bitmap bitmap = BitmapFactory.decodeFile(filePath);
+//
+//                        final Bitmap scale = ThumbnailUtils.extractThumbnail(bitmap, 300, 300);
+//
+//                        File thumbFile = thumbFile(filePath);
+//                        savePhotoToFile(scale,thumbFile);
+//
+//                        runOnUiThread(new Runnable() {
+//                            @Override
+//                            public void run() {
+//                                photoHolder.photoView.setImageBitmap(scale);
+//                            }
+//                        });
+//                    }
+//                }).start();
+
+                executorService.submit(new Runnable() {
+                    @Override
+                    public void run() {
+                        Log.d("Run", "begin " + filePath);
+
+                        Bitmap scale = null;
+                        if (thumbPhotoIsExists(filePath)) {
+                            scale = BitmapFactory.decodeFile(thumbFile(filePath).getAbsolutePath());
+                        } else {
+                            Bitmap bitmap = BitmapFactory.decodeFile(filePath);
+                            scale = ThumbnailUtils.extractThumbnail(bitmap, 300, 300);
+                            File thumbFile = thumbFile(filePath);
+                            savePhotoToFile(scale,thumbFile);
+                            bitmap.recycle();
+                        }
+
+                        final Bitmap scale_img = scale;
+                        runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                photoHolder.photoView.setImageBitmap(scale_img);
+
+                            }
+                        });
+                        Log.d("Run", "finish " + filePath);
+                    }
+                });
+            }
+
+
+
+
+            holder.checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_none));
+
+            int delete = Integer.valueOf(item.get("delete"));
+            if (delete == 1) {
+                holder.checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_check));
+            }
+
+            final int idx = position;
+            holder.checkBtn.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    ImageButton checkBtn = (ImageButton)v;
+                    checkBtn.setSelected(!checkBtn.isSelected());
+                    if (checkBtn.isSelected()) {
+                        checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_check));
+                        item.put("delete","1");
+                        photoDic.set(idx,item);
+                    } else  {
+                        checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_none));
+                        item.put("delete","0");
+                        photoDic.set(idx,item);
+                    }
+                }
+            });
+
+            holder.photoView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    showPhotoPreview(idx);
+                }
+            });
+
+
+
+            /**解决Item被拉伸压缩*/
+            int itemWidth = (int)(getResources().getDisplayMetrics().widthPixels -  (col + 1) * 10)  / col;
+            int itemHeight = itemWidth;
+
+            AbsListView.LayoutParams param = (AbsListView.LayoutParams) cell.getLayoutParams();
+
+            if (param == null) {
+                /**解决第一个Item不响应*/
+                param = new AbsListView.LayoutParams(itemWidth, itemHeight);
+            } else {
+                param.width = itemWidth;
+                param.height = itemHeight;
+            }
+            cell.setLayoutParams(param);
+
+            Log.d("List", "Return Cell");
+            return cell;
+        }
+
+
+    }
+
+    private void savePhotoToFile(Bitmap bitmap, File photoFile) {
+        if (photoFile == null || bitmap == null) {
+            return;
+        }
+        try {
+
+            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(photoFile));
+            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
+            bos.flush();
+            bos.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+
+        }
+    }
+
+    private String photoDirectory() {
+
+        String dir = Environment.getExternalStorageDirectory().getPath() + "/redant/.thumb/";
+        File file = new File(dir);
+        if (!file.exists()) {
+            if (file.mkdirs()) {
+                return dir;
+            } else {
+                return null;
+            }
+        }
+        return dir;
+    }
+
+    private File thumbFile(String path) {
+        File file = new File(path);
+        String name = file.getName();
+        String thumbDir = photoDirectory();
+        if (thumbDir != null) {
+            String thumbPath = thumbDir + name;
+            return new File(thumbPath);
+        }
+        return null;
+    }
+
+    private boolean thumbPhotoIsExists(String path) {
+
+        File thumbFile = thumbFile(path);
+        if (thumbFile != null && thumbFile.exists()) {
+            return true;
+        }
+
+        return false;
+    }
+}

+ 242 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/PhotoListActivity.java

@@ -0,0 +1,242 @@
+package com.usai.redant.raimage.PhotoList;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.DefaultItemAnimator;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.util.RAUtil;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+public class PhotoListActivity extends AppCompatActivity {
+
+    private PhotoListAdapter adapter;
+    private GridLayoutManager layoutManager;
+    private Button deleteBtn;
+    private ArrayList<HashMap<String,String>> photoDic;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_photo_list);
+
+        Intent intent = getIntent();
+        ArrayList<String> photos = (ArrayList<String>) intent.getSerializableExtra("pic_list");
+        photoDic = new ArrayList<HashMap<String, String>>();
+        for (int i = 0; i < photos.size(); i++) { // 默认全部未选中
+
+            HashMap<String,String> dic = new HashMap<String, String>();
+            dic.put("path",photos.get(i));
+            dic.put("delete","0");
+
+            photoDic.add(dic);
+        }
+
+
+        RecyclerView recycler = (RecyclerView)findViewById(R.id.id_recyclerview);
+        deleteBtn = (Button)findViewById(R.id.photo_delete_btn);
+
+        deleteBtn.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+//                for (int i = 0;i < photoDic.size(); i++) {
+//                    int delete = Integer.valueOf(deletIndexs.get(i));
+//                    if (delete == 1) {
+//                        // 删除文件
+//                        new File(photos.get(i)).delete();
+//                        photos.remove(i);
+//                        deletIndexs.set(i,"0");
+//
+//                    }
+//                    adapter.notifyDataSetChanged();
+//                }
+
+                Iterator<HashMap<String,String>> iterator = photoDic.iterator();
+                while (iterator.hasNext()) {
+                    HashMap<String,String> item = iterator.next();
+                    int delete = Integer.valueOf(item.get("delete"));
+                    if (delete == 1) {
+                        // 删除文件
+                        new File(item.get("path")).delete();
+                        RAUtil.updateGallery(item.get("path"));
+                        iterator.remove();
+                        int index = photoDic.indexOf(item);
+                    }
+                }
+                adapter.notifyDataSetChanged();
+
+            }
+        });
+
+
+        int h = getWindowManager().getDefaultDisplay().getHeight();
+        int w = getWindowManager().getDefaultDisplay().getWidth();
+
+        // 设置布局管理器
+//        layoutManager = new GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
+//        layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+//            @Override
+//            public int getSpanSize(int position) {
+//                return 1;
+//            }
+//        });
+//        recycler.setLayoutManager(layoutManager);
+        recycler.setLayoutManager(new CustomLayoutManager(CustomLayoutManager.VERTICAL,w,h));
+        // 添加分割线
+//        recycler.addItemDecoration(new GridItemDecoration(3, getResources().getDimensionPixelSize(R.dimen.padding_middle), true));
+        // 设置Item增加、移除动画
+        recycler.setItemAnimator(new DefaultItemAnimator());
+        // 设置Adapter
+        recycler.setAdapter(adapter = new PhotoListAdapter());
+
+
+        /**Action Bar*/
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle("RA Image");
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+         switch (item.getItemId()) {
+             case android.R.id.home: {
+                 finish();
+             }
+             break;
+         }
+         return true;
+    }
+
+    private void showPhotoPreview(int index) {
+        ArrayList<String> photos = new ArrayList<String>();
+        Iterator<HashMap<String,String>> iterator = photoDic.iterator();
+        while (iterator.hasNext()) {
+            HashMap<String,String> item = iterator.next();
+            photos.add(item.get("path"));
+        }
+        Toast.makeText(PhotoListActivity.this,"Click" + index, Toast.LENGTH_LONG).show();
+        Intent intent = new Intent(this,NewPhotoPreviewActivity.class);
+        intent.putExtra("photos",(Serializable)photos);
+        intent.putExtra("index",index);
+        startActivity(intent);
+    }
+
+    /**Adapter*/
+    public class PhotoListAdapter extends RecyclerView.Adapter<PhotoListAdapter.PhotoViewHolder> {
+
+        /** ViewHolder */
+        public class PhotoViewHolder extends RecyclerView.ViewHolder {
+            public ImageView photoView;
+            public ImageButton checkBtn;
+            public PhotoViewHolder(View view) {
+                super(view);
+                photoView = (ImageView)view.findViewById(R.id.photo_list_iv);
+                checkBtn = (ImageButton)view.findViewById(R.id.photo_list_checkBtn);
+            }
+        }
+
+        @Override
+        public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            PhotoViewHolder holder = new PhotoViewHolder(LayoutInflater.from(PhotoListActivity.this).inflate(R.layout.photo_list_item,parent,false));
+            return holder;
+        }
+
+        @Override
+        public void onBindViewHolder(PhotoViewHolder holder, final int position) {
+            final HashMap<String,String> item = photoDic.get(position);
+            String path = item.get("path");
+//            File file = new File(path);
+//            Uri uri = Uri.fromFile(file);
+//            holder.photoView.setImageURI(uri);
+
+            Bitmap bitmap = scaleImage(path,200,200);
+
+            holder.photoView.setImageBitmap(bitmap);
+
+            holder.checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_none));
+
+            int delete = Integer.valueOf(item.get("delete"));
+            if (delete == 1) {
+                holder.checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_check));
+            }
+
+            holder.checkBtn.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    ImageButton checkBtn = (ImageButton)v;
+                    checkBtn.setSelected(!checkBtn.isSelected());
+                    if (checkBtn.isSelected()) {
+                        checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_check));
+                        item.put("delete","1");
+                        photoDic.set(position,item);
+                    } else  {
+                        checkBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.check_none));
+                        item.put("delete","0");
+                        photoDic.set(position,item);
+                    }
+                }
+            });
+
+            holder.photoView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    showPhotoPreview(position);
+                }
+            });
+        }
+
+        @Override
+        public int getItemCount() {
+            return photoDic.size();
+        }
+    }
+
+    /**缩小图片*/
+    public Bitmap scaleImage(String path, int width, int height) {
+        Bitmap source = BitmapFactory.decodeFile(path);
+
+//        int originWidth = source.getWidth();
+//        int originHeight = source.getHeight();
+//
+//        int width = originWidth, height = originHeight;
+//
+//        if (originHeight > 1024 || originWidth > 1024)
+//        {
+//            if (originWidth > originHeight)
+//            {
+//                width = 1024;
+//                height = originHeight * 1024 / originWidth;
+//
+//            }
+//            else
+//            {
+//
+//                height = 1024;
+//                width = originWidth * 1024 / originHeight;
+//
+//            }
+//        }
+        Bitmap scaled = Bitmap.createScaledBitmap(source, width, height, true);
+        return scaled;
+    }
+}

+ 38 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/RAGridView.java

@@ -0,0 +1,38 @@
+package com.usai.redant.raimage.PhotoList;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.GridView;
+
+
+public class RAGridView extends GridView {
+
+    public interface GridViewMeasure {
+        void measuring(boolean m);
+    }
+
+    public GridViewMeasure measureWorker;
+
+    public RAGridView(Context context) {
+        this(context,null);
+    }
+
+    public RAGridView(Context ctx, AttributeSet attrs) {
+        this(ctx,attrs,0);
+    }
+
+    public RAGridView(Context ctx, AttributeSet attrs, int defStyleAttr) {
+        super(ctx,attrs,defStyleAttr);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (measureWorker != null) {
+            measureWorker.measuring(true);
+        }
+        Log.d("Decode", "onMeasure: ------------------------------");
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        Log.d("Decode", "onMeasure: ------------------------------");
+    }
+}

+ 202 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/XuanImageView/RotationGestureDetector.java

@@ -0,0 +1,202 @@
+package com.usai.redant.raimage.PhotoList.XuanImageView;
+
+import android.util.Log;
+import android.view.MotionEvent;
+
+/**
+ * Created by xuanyihuang on 9/4/16.
+ */
+
+public class RotationGestureDetector {
+    private int mXuanImageViewWith;
+    private static final int INVALID_POINTER_ID = -1;
+    private float sX, sY, fX, fY;
+    private float nfX, nfY, nsX, nsY;
+    private int ptrID1, ptrID2;
+    private int ptrID1_Index, ptrID2_Index, ptr_Index;
+    private float mAngle;
+    private float mPreviousAngle;
+    private float mAngleAtPresent;
+    private float mPreviousAngleAtPresent;
+    private float mPivotX;
+    private float mPivotY;
+    private boolean mIsRotated;
+    private int mPointerCount;
+    private float mBasicRotationTrigger;
+    private float mRotationTrigger;
+
+    private OnRotationGestureListener mListener;
+
+    public float getAngle() {
+        return mAngle;
+    }
+
+    public float getPreviousAngle(){
+        return  mPreviousAngle;
+    }
+
+    public float getPivotX(){
+        return mPivotX;
+    }
+
+    public float getPivotY(){
+        return mPivotY;
+    }
+
+    public void setAngle(float angle){
+        mAngle = angle;
+    }
+
+    public void setPreviousAngle(float angle){
+        mPreviousAngle = angle;
+    }
+
+    public boolean IsRotated(){
+        return  mIsRotated;
+    }
+
+    public RotationGestureDetector(OnRotationGestureListener listener, int XuanImageViewWidth){
+        mXuanImageViewWith = XuanImageViewWidth;
+        mListener = listener;
+        ptrID1 = INVALID_POINTER_ID;
+        ptrID2 = INVALID_POINTER_ID;
+        ptrID1_Index = INVALID_POINTER_ID;
+        ptrID2_Index = INVALID_POINTER_ID;
+        ptr_Index = INVALID_POINTER_ID;
+        mAngle = 0;
+        mPreviousAngle = 0;
+        mPivotX = 0;
+        mPivotY = 0;
+        mIsRotated = false;
+        mPointerCount = 0;
+        mBasicRotationTrigger = 10; //basic rotation trigger : 10 degrees
+        mRotationTrigger = mBasicRotationTrigger;
+    }
+
+    public boolean onTouchEvent(MotionEvent event){
+        Log.d("RotationGestureDetector", event + "");
+        switch (event.getAction() & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN:
+                //ptrID1 : first finger pressing down
+                ptrID1 = event.getPointerId(event.getActionIndex());
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+                //ptrID2: second finger pressing down
+                mPointerCount = event.getPointerCount();
+                if(mPointerCount == 2) {
+                    ptrID2 = event.getPointerId(event.getActionIndex());
+                    ptrID1_Index = event.findPointerIndex(ptrID1);
+                    ptrID2_Index = event.findPointerIndex(ptrID2);
+                    try {
+                        sX = event.getX(ptrID1_Index);
+                        sY = event.getY(ptrID1_Index);
+                        fX = event.getX(ptrID2_Index);
+                        fY = event.getY(ptrID2_Index);
+                        determineRotationTrigger();
+                    }catch(Exception e){
+                        //pointer index out of range exception
+                        return true;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                Log.d("canStillRotate" , "" + canStillRotate());
+                if(canStillRotate()){
+                    ptrID1_Index = event.findPointerIndex(ptrID1);
+                    ptrID2_Index = event.findPointerIndex(ptrID2);
+                    try {
+                        nsX = event.getX(ptrID1_Index);
+                        nsY = event.getY(ptrID1_Index);
+                        nfX = event.getX(ptrID2_Index);
+                        nfY = event.getY(ptrID2_Index);
+                    } catch (Exception e){
+                        //pointer index out of range exception
+                        return true;
+                    }
+                    mPivotX = (nsX + nfX) / 2.0f;
+                    mPivotY = (nsY + nfY) / 2.0f;
+
+                    mAngleAtPresent = angleBetweenLines(fX, fY, sX, sY, nfX, nfY, nsX, nsY);
+
+                    if (mListener != null) {
+                        if(mIsRotated){
+                            mPreviousAngle = mAngle;
+                            mAngle = mPreviousAngle + (mAngleAtPresent - mPreviousAngleAtPresent);
+                            mPreviousAngleAtPresent = mAngleAtPresent;
+                            mListener.OnRotate(this);
+                        }
+                        else if(Math.abs(mAngleAtPresent) >= mRotationTrigger){
+                            sX = nsX;
+                            sY = nsY;
+                            fX = nfX;
+                            fY = nfY;
+                            mPreviousAngleAtPresent = 0;
+                            mIsRotated = true;
+                        }
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                invalidateTouchPointers();
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                ptr_Index = event.getActionIndex();
+                if(ptrID1 == event.getPointerId(ptr_Index) || ptrID2 == event.getPointerId(ptr_Index)){
+                    invalidateTouchPointers();
+                    if(mListener != null){
+                        if(mIsRotated) {
+                            mListener.StopRotate(this);
+                            mIsRotated = false;
+                        }
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                invalidateTouchPointers();
+                break;
+        }
+
+        return true;
+    }
+
+    private boolean canStillRotate() {
+        return (ptrID1 != INVALID_POINTER_ID) && (ptrID2 != INVALID_POINTER_ID) ;
+    }
+
+    private void invalidateTouchPointers(){
+        ptrID1 = INVALID_POINTER_ID;
+        ptrID2 = INVALID_POINTER_ID;
+    }
+
+    private float angleBetweenLines (float fX, float fY, float sX, float sY, float nfX, float nfY, float nsX, float nsY)
+    {
+        float angle1 = (float) Math.atan2( (fY - sY), (fX - sX) );
+        float angle2 = (float) Math.atan2( (nfY - nsY), (nfX - nsX) );
+
+        //angle range: [-180 degrees, +180 degrees]
+        float angle = ((float) Math.toDegrees(angle2 - angle1)) % 360;
+        if (angle < -180.f) angle += 360.0f;
+        if (angle > 180.f) angle -= 360.0f;
+
+        Log.d("AngleBetweenLines :","" + angle);
+        return angle;
+    }
+
+    private double lineDistance(float fX, float fY, float sX, float sY){
+        return  Math.sqrt((fX - sX) * (fX - sX) + (fY - sY) * (fY - sY));
+    }
+
+    private void determineRotationTrigger(){
+        // need further optimization
+        if(lineDistance(fX,fY,sX,sY) <= (mXuanImageViewWith / 3)){
+            mRotationTrigger = mBasicRotationTrigger * 2;
+        }
+        else
+            mRotationTrigger = mBasicRotationTrigger;
+    }
+
+    public interface OnRotationGestureListener {
+        boolean OnRotate(RotationGestureDetector rotationGestureDetector);
+        boolean StopRotate(RotationGestureDetector rotationGestureDetector);
+    }
+}

+ 1033 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/XuanImageView/XuanImageView.java

@@ -0,0 +1,1033 @@
+package com.usai.redant.raimage.PhotoList.XuanImageView;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+import com.usai.redant.redantmobile.R;
+
+/**
+ * Created by xuanyihuang on 8/30/16.
+ */
+
+public class XuanImageView extends android.support.v7.widget.AppCompatImageView{
+    private int XuanImageViewWidth;
+    private int XuanImageViewHeight;
+    private int XuanImageViewCenterX;
+    private int XuanImageViewCenterY;
+    private int ImageCenterX;
+    private int ImageCenterY;
+    private int mOrientation;   //1 for portrait, 2 for landscape
+    private int mAutoRotateCategory;
+    private float mInitScale;   //for landscape
+    private float mInitPortraitScale;
+    private float mTempInitPortraitScale;
+    private float mMaxScale;
+    private float mPortraitMaxScale;
+    private float mTempPortraitMaxScale;
+    private boolean mRotationToggle;
+    private float mMaxScaleMultiple;
+    private float mDoubleTabScaleMultiple;
+    private float mDoubleTabScale;
+    private float mPortraitDoubleTabScale;
+    private float mTempPortraitDoubleTabScale;
+    private Matrix mScaleMatrix;
+    private ScaleGestureDetector mScaleGestureDetector;
+    private GestureDetector mGestureDetector;
+    private float mLastScaleFocusX;
+    private float mLastScaleFocusY;
+    private boolean isAutoScale;
+    private float mSpringBackGradientScaleUpLevel;
+    private float mSpringBackGradientScaleDownLevel;
+    private float mDoubleTapGradientScaleUpLevel;
+    private float mDoubleTapGradientScaleDownLevel;
+    private int mLastPointerCount;
+    private float mLastX;
+    private float mLastY;
+    private float mAngle;
+    private float mPreviousAngle;
+    private RotationGestureDetector mRotateGestureDetector;
+    private boolean isAutoRotated;
+    private double allowableFloatError;
+    private double allowablePortraitFloatError;
+    private float currentScaleLevel;
+    private float currentAbsScaleLevel;
+    private float autoRotationTrigger;
+    private int autoRotationRunnableDelay;
+    private int autoRotationRunnableTimes;
+    private int doubleTabScaleRunnableDelay;
+    private int springBackRunnableDelay;
+    private boolean hasDrawable;
+    private boolean knowViewSize;
+
+    public XuanImageView(Context context) {
+        this(context, null);
+    }
+
+    public XuanImageView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public XuanImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        initialize(context, attrs);
+    }
+
+    private void initialize(Context context, AttributeSet attrs) {
+        setScaleType(ScaleType.MATRIX);
+        mScaleMatrix = new Matrix();
+
+        mScaleGestureDetector = new ScaleGestureDetector(context, constructOnScaleGestureListener());
+        mGestureDetector = new GestureDetector(context, constructOnGestureListener());
+
+        initCustomAttrs(context, attrs);
+
+        mOrientation = XuanImageViewSettings.ORIENTATION_LANDSCAPE;   //1 for portrait, 2 for landscape
+        isAutoScale = false;
+        mLastPointerCount = 0;
+        mAngle = 0;
+        mPreviousAngle = 0;
+        currentScaleLevel = 1;
+    }
+
+    private ScaleGestureDetector.OnScaleGestureListener constructOnScaleGestureListener() {
+        return new ScaleGestureDetector.OnScaleGestureListener() {
+            @Override
+            public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
+                float scaleFactor = scaleGestureDetector.getScaleFactor();
+
+                currentScaleLevel = getCurrentScaleLevel();
+                currentAbsScaleLevel = Math.abs(currentScaleLevel);
+                Log.d("CurrentAbsScaleLevel", "" + currentAbsScaleLevel);
+
+                boolean isRotating = false;
+                boolean justScale = false;
+
+                if(mRotateGestureDetector.IsRotated()){
+                    // is rotating
+                    isRotating = true;
+                }
+                else{
+                    // not rotating, just scaling
+                    if(mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION){
+                        if((currentScaleLevel <= mMaxScale && scaleFactor > 1.0f) || (currentScaleLevel >= mInitScale && scaleFactor < 1.0f))
+                            justScale = true;
+
+                    }
+                    else if(mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM){
+                        if (mOrientation == XuanImageViewSettings.ORIENTATION_LANDSCAPE) {
+                            if ((currentAbsScaleLevel <= mMaxScale && scaleFactor > 1.0f) || (currentAbsScaleLevel >= mInitScale && scaleFactor < 1.0f))
+                                justScale = true;
+                        } else if (mOrientation == XuanImageViewSettings.ORIENTATION_PORTRAIT) {
+                            if ((currentAbsScaleLevel <= mTempPortraitMaxScale && scaleFactor > 1.0f) || (currentAbsScaleLevel >= mTempInitPortraitScale && scaleFactor < 1.0f))
+                                justScale = true;
+                        }
+                    }
+                }
+
+
+                if(isRotating) {
+                    mScaleMatrix.postScale(scaleFactor, scaleFactor, mRotateGestureDetector.getPivotX(), mRotateGestureDetector.getPivotY());
+                }
+                else if(justScale)
+                {
+                    mScaleMatrix.postScale(scaleFactor, scaleFactor, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY());
+                    checkBorderAndCenterWhenScale();
+                }
+
+
+                setImageMatrix(mScaleMatrix);
+                mLastScaleFocusX = scaleGestureDetector.getFocusX();
+                mLastScaleFocusY = scaleGestureDetector.getFocusY();
+
+                return true;
+            }
+
+            @Override
+            public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
+                Log.d("onScaleBegin-->", "");
+                return true;
+            }
+
+            @Override
+            public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
+                Log.d("onScaleEnd-->", "");
+            }
+        };
+    }
+
+    private GestureDetector.OnGestureListener constructOnGestureListener() {
+        return new GestureDetector.SimpleOnGestureListener() {
+            @Override
+            public boolean onDoubleTap(MotionEvent e) {
+                currentScaleLevel = getCurrentScaleLevel();
+                currentAbsScaleLevel = Math.abs(currentScaleLevel);
+                float x = e.getX();
+                float y = e.getY();
+
+                if (isAutoScale)
+                    return true;
+
+
+                if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION) {
+                    if (currentScaleLevel < mDoubleTabScale) {
+                        postDelayed(new AutoScaleRunnable(mDoubleTabScale, x, y, mDoubleTapGradientScaleUpLevel, mDoubleTapGradientScaleDownLevel), doubleTabScaleRunnableDelay);
+                        isAutoScale = true;
+                    } else {
+                        postDelayed(new AutoScaleRunnable(mInitScale, x, y, mDoubleTapGradientScaleUpLevel, mDoubleTapGradientScaleDownLevel), doubleTabScaleRunnableDelay);
+                        isAutoScale = true;
+                    }
+                } else if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM) {
+                    if (mOrientation == XuanImageViewSettings.ORIENTATION_LANDSCAPE) {
+                        if (currentAbsScaleLevel < mDoubleTabScale) {
+                            postDelayed(new AutoScaleRunnable(mDoubleTabScale * (currentScaleLevel / currentAbsScaleLevel), x, y, mDoubleTapGradientScaleUpLevel, mDoubleTapGradientScaleDownLevel), doubleTabScaleRunnableDelay);
+                            isAutoScale = true;
+                        } else {
+                            postDelayed(new AutoScaleRunnable(mInitScale * (currentScaleLevel / currentAbsScaleLevel), x, y, mDoubleTapGradientScaleUpLevel, mDoubleTapGradientScaleDownLevel), doubleTabScaleRunnableDelay);
+                            isAutoScale = true;
+                        }
+                    } else if (mOrientation == XuanImageViewSettings.ORIENTATION_PORTRAIT) {
+                        if (currentAbsScaleLevel < mTempPortraitDoubleTabScale) {
+                            postDelayed(new AutoScaleRunnable(mTempPortraitDoubleTabScale * (currentScaleLevel / currentAbsScaleLevel), x, y, mDoubleTapGradientScaleUpLevel, mDoubleTapGradientScaleDownLevel), doubleTabScaleRunnableDelay);
+                            isAutoScale = true;
+                        } else {
+                            postDelayed(new AutoScaleRunnable(mTempInitPortraitScale * (currentScaleLevel / currentAbsScaleLevel), x, y, mDoubleTapGradientScaleUpLevel, mDoubleTapGradientScaleDownLevel), doubleTabScaleRunnableDelay);
+                            isAutoScale = true;
+                        }
+                    }
+                }
+
+                return true;
+            }
+        };
+    }
+
+
+    private RotationGestureDetector.OnRotationGestureListener constructOnRotationGestureListener(){
+        return new RotationGestureDetector.OnRotationGestureListener() {
+            @Override
+            public boolean OnRotate(RotationGestureDetector rotationGestureDetector) {
+                mAngle = rotationGestureDetector.getAngle();
+                mPreviousAngle = rotationGestureDetector.getPreviousAngle();
+                mScaleMatrix.postRotate(mAngle - mPreviousAngle, rotationGestureDetector.getPivotX(), rotationGestureDetector.getPivotY());
+
+                setImageMatrix(mScaleMatrix);
+
+                return true;
+            }
+
+            @Override
+            public boolean StopRotate(RotationGestureDetector rotationGestureDetector) {
+                if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION)
+                    AutoRotateRestoration(rotationGestureDetector);
+                else if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM)
+                    AutoRotateMagnetism(rotationGestureDetector);
+
+                return true;
+            }
+        };
+    }
+
+    private void initCustomAttrs(Context context, AttributeSet attrs){
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.xuanimageview);
+        mRotationToggle = a.getBoolean(R.styleable.xuanimageview_RotationToggle, true);
+        mAutoRotateCategory = a.getInteger(R.styleable.xuanimageview_AutoRotateCategory, XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION);
+        mMaxScaleMultiple = a.getFloat(R.styleable.xuanimageview_MaxScaleMultiple, 4);
+        mDoubleTabScaleMultiple = a.getFloat(R.styleable.xuanimageview_DoubleTabScaleMultiple, 2);
+        mSpringBackGradientScaleUpLevel = a.getFloat(R.styleable.xuanimageview_SpringBackGradientScaleUpLevel, 1.01f);
+        mSpringBackGradientScaleDownLevel = a.getFloat(R.styleable.xuanimageview_SpringBackGradientScaleDownLevel, 0.99f);
+        mDoubleTapGradientScaleUpLevel = a.getFloat(R.styleable.xuanimageview_DoubleTapGradientScaleUpLevel, 1.05f);
+        mDoubleTapGradientScaleDownLevel = a.getFloat(R.styleable.xuanimageview_DoubleTapGradientScaleDownLevel, 0.95f);
+        autoRotationTrigger = a.getFloat(R.styleable.xuanimageview_AutoRotationTrigger, 60);
+        springBackRunnableDelay = a.getInteger(R.styleable.xuanimageview_SpringBackRunnableDelay, 10);
+        doubleTabScaleRunnableDelay = a.getInteger(R.styleable.xuanimageview_DoubleTapScaleRunnableDelay, 10);
+        autoRotationRunnableDelay = a.getInteger(R.styleable.xuanimageview_AutoRotationRunnableDelay, 5);
+        autoRotationRunnableTimes = a.getInteger(R.styleable.xuanimageview_AutoRotationRunnableTimes, 10);
+        try {
+            allowableFloatError = Double.parseDouble(a.getString(R.styleable.xuanimageview_AllowableFloatError));
+        }catch (Exception e){
+            allowableFloatError = 1E-6;   // for normal display aspect ratio
+//        allowableFloatError = 3E-3;   // for Galaxy S8
+        }
+        try {
+            allowablePortraitFloatError = Double.parseDouble(a.getString(R.styleable.xuanimageview_AllowablePortraitFloatError));
+        }catch (Exception e){
+            allowablePortraitFloatError = 1E-12;  // for normal display aspect ratio
+//        allowablePortraitFloatError = 5E-8;   //for Galaxy S8
+        }
+        a.recycle();
+    }
+
+    @Override
+    public void setImageDrawable(Drawable drawable) {
+        super.setImageDrawable(drawable);
+
+        if (drawable == null) {
+            hasDrawable = false;
+            return;
+        }
+
+        if (!drawableHasSize(drawable))
+            return;
+
+        hasDrawable = true;
+        initDrawableMatrix();
+    }
+
+    @Override
+    public void setImageResource(int resId) {
+        Drawable drawable = null;
+        try {
+            drawable = getResources().getDrawable(resId);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        setImageDrawable(drawable);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        knowViewSize = true;
+        initDrawableMatrix();
+    }
+
+    private boolean drawableHasSize(Drawable drawable) {
+        if ((drawable.getIntrinsicHeight() <= 0 || drawable.getIntrinsicWidth() <= 0)
+                && (drawable.getMinimumHeight() <= 0 || drawable.getMinimumWidth() <= 0)
+                && (drawable.getBounds().height() <= 0 || drawable.getBounds().width() <= 0))
+            return false;
+        else
+            return true;
+    }
+
+    private void initDrawableMatrix() {
+        if (!hasDrawable)
+            return;
+        if (!knowViewSize)
+            return;
+
+        if (mScaleMatrix == null)
+            mScaleMatrix = new Matrix();
+        else
+            mScaleMatrix.reset();
+
+        // get width and height of XuanImageView
+        XuanImageViewWidth = getWidth();
+        XuanImageViewHeight = getHeight();
+
+        //get the center point of XuanImageView
+        XuanImageViewCenterX = XuanImageViewWidth / 2;
+        XuanImageViewCenterY = XuanImageViewHeight / 2;
+
+        // instantiate mRotationGestureDetector after dimension of XuanImageView is got.
+        mRotateGestureDetector = new RotationGestureDetector(constructOnRotationGestureListener(), XuanImageViewWidth);
+
+        //get width and height of the image
+        Drawable imageDrawable = getDrawable();
+        if (imageDrawable == null)
+            return;
+        int imageWidth = imageDrawable.getIntrinsicWidth();
+        int imageHeight = imageDrawable.getIntrinsicHeight();
+
+        //image is scaled to fit the size of XuanImageView at the very beginning.
+        float scale = Math.min(XuanImageViewWidth * 1.0f / imageWidth, XuanImageViewHeight * 1.0f / imageHeight);
+        float portraitscale = Math.min(XuanImageViewWidth * 1.0f / imageHeight, XuanImageViewHeight * 1.0f / imageWidth);
+
+        mInitScale = scale;
+        mInitPortraitScale = portraitscale;
+        mMaxScale = mMaxScaleMultiple * scale;
+        mPortraitMaxScale = mMaxScaleMultiple * portraitscale;
+        mDoubleTabScale = mDoubleTabScaleMultiple * scale;
+        mPortraitDoubleTabScale = mDoubleTabScaleMultiple * portraitscale;
+
+        //center of image overlaps with that of XuanImageView
+        int deltaX = XuanImageViewWidth / 2 - imageWidth / 2;
+        int deltaY = XuanImageViewHeight / 2 - imageHeight / 2;
+
+        mScaleMatrix.postTranslate(deltaX, deltaY);
+        mScaleMatrix.postScale(scale, scale, XuanImageViewWidth / 2, XuanImageViewHeight / 2);
+        setImageMatrix(mScaleMatrix);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent motionEvent) {
+        if (mRotateGestureDetector == null)
+            return true;
+
+        boolean parentDisallowInterceptTouchEventFlag = true;
+
+        // for DoubleTap gesture
+        mGestureDetector.onTouchEvent(motionEvent);
+
+        // for Scale gesture
+        mScaleGestureDetector.onTouchEvent(motionEvent);
+
+
+        currentScaleLevel = getCurrentScaleLevel();
+        currentAbsScaleLevel = Math.abs(currentScaleLevel);
+        if (mRotationToggle) {
+            if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION) {
+                if (mRotateGestureDetector.IsRotated() || Math.abs(currentScaleLevel - mInitScale) < allowableFloatError
+                        || ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP)
+                        || ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP)) {
+                    if (!mRotateGestureDetector.IsRotated())
+                        parentDisallowInterceptTouchEventFlag = false;
+
+                    // for Rotation gesture
+                    mRotateGestureDetector.onTouchEvent(motionEvent);
+                }
+            } else if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM) {
+                if (mOrientation == XuanImageViewSettings.ORIENTATION_LANDSCAPE) {
+                    if (mRotateGestureDetector.IsRotated() || Math.abs(currentAbsScaleLevel - mInitScale) < allowableFloatError
+                            || ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP)
+                            || ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP)) {
+                        if (!mRotateGestureDetector.IsRotated())
+                            parentDisallowInterceptTouchEventFlag = false;
+
+                        // for Rotation gesture
+                        mRotateGestureDetector.onTouchEvent(motionEvent);
+
+                    }
+                } else if (mOrientation == XuanImageViewSettings.ORIENTATION_PORTRAIT) {
+                    if (mRotateGestureDetector.IsRotated() || Math.abs(currentAbsScaleLevel - mTempInitPortraitScale) < allowablePortraitFloatError
+                            || ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP)
+                            || ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP)) {
+                        if (!mRotateGestureDetector.IsRotated())
+                            parentDisallowInterceptTouchEventFlag = false;
+
+                        // for Rotation gesture
+                        mRotateGestureDetector.onTouchEvent(motionEvent);
+                    }
+                }
+            }
+        }
+
+        //pointerCount won't be 0
+        int pointerCount = motionEvent.getPointerCount();
+        float pivotX = 0;
+        float pivotY = 0;
+        for (int i = 0; i < pointerCount; i++) {
+            pivotX += motionEvent.getX(i);
+            pivotY += motionEvent.getY(i);
+        }
+        pivotX /= pointerCount;   //get integer result of the division
+        pivotY /= pointerCount;
+
+        // when image is being dragged, generally, pointCount == mLastCount holds, so old state is not saved.
+        if (pointerCount != mLastPointerCount) {
+            mLastX = pivotX;
+            mLastY = pivotY;
+            mLastPointerCount = pointerCount;
+        }
+
+        RectF rectF = getMatrixRectF();
+
+        switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN:
+                if (getParent() != null)
+                    getParent().requestDisallowInterceptTouchEvent(parentDisallowInterceptTouchEventFlag);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (getParent() != null)
+                    getParent().requestDisallowInterceptTouchEvent(parentDisallowInterceptTouchEventFlag);
+                float deltaX = pivotX - mLastX;
+                float deltaY = pivotY - mLastY;
+
+                if (getDrawable() != null) {
+                    if (!mRotateGestureDetector.IsRotated()) {
+                        if (rectF.width() <= XuanImageViewWidth)
+                            deltaX = 0;
+                        if (rectF.height() <= XuanImageViewHeight)
+                            deltaY = 0;
+                    }
+                    mScaleMatrix.postTranslate(deltaX, deltaY);
+
+                    if (!mRotateGestureDetector.IsRotated())
+                        checkBorderAndCenterWhenTranslate();
+                    setImageMatrix(mScaleMatrix);
+                }
+                mLastX = pivotX;
+                mLastY = pivotY;
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                //one finger loosening (multi-touch)
+                if (pointerCount - 1 < 2) {
+                    if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION) {
+                        //spring back to mInitScale or mMaxScale
+                        if ((currentScaleLevel < mInitScale) && !isAutoRotated) {
+                            postDelayed(new AutoScaleRunnable(mInitScale, mLastScaleFocusX, mLastScaleFocusY, mSpringBackGradientScaleUpLevel, mSpringBackGradientScaleDownLevel), springBackRunnableDelay);
+                            isAutoScale = true;
+                        } else if ((currentScaleLevel > mMaxScale) && !isAutoRotated) {
+                            postDelayed(new AutoScaleRunnable(mMaxScale, mLastScaleFocusX, mLastScaleFocusY, mSpringBackGradientScaleUpLevel, mSpringBackGradientScaleDownLevel), springBackRunnableDelay);
+                            isAutoScale = true;
+                        }
+                    } else if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM) {
+                        if (mOrientation == XuanImageViewSettings.ORIENTATION_LANDSCAPE) {
+                            if (currentAbsScaleLevel < mInitScale && !isAutoRotated) {
+                                postDelayed(new AutoScaleRunnable(mInitScale * (currentScaleLevel / currentAbsScaleLevel), mLastScaleFocusX, mLastScaleFocusY, mSpringBackGradientScaleUpLevel, mSpringBackGradientScaleDownLevel), springBackRunnableDelay);
+                                isAutoScale = true;
+                            } else if ((currentAbsScaleLevel > mMaxScale) && !isAutoRotated) {
+                                postDelayed(new AutoScaleRunnable(mMaxScale * (currentScaleLevel / currentAbsScaleLevel), mLastScaleFocusX, mLastScaleFocusY, mSpringBackGradientScaleUpLevel, mSpringBackGradientScaleDownLevel), springBackRunnableDelay);
+                                isAutoScale = true;
+                            }
+                        } else if (mOrientation == XuanImageViewSettings.ORIENTATION_PORTRAIT) {
+                            if (currentAbsScaleLevel < mTempInitPortraitScale && !isAutoRotated) {
+                                postDelayed(new AutoScaleRunnable(mTempInitPortraitScale * (currentScaleLevel / currentAbsScaleLevel), mLastScaleFocusX, mLastScaleFocusY, mSpringBackGradientScaleUpLevel, mSpringBackGradientScaleDownLevel), springBackRunnableDelay);
+                                isAutoScale = true;
+                            } else if ((currentAbsScaleLevel > mTempPortraitMaxScale) && !isAutoRotated) {
+                                postDelayed(new AutoScaleRunnable(mTempPortraitMaxScale * (currentScaleLevel / currentAbsScaleLevel), mLastScaleFocusX, mLastScaleFocusY, mSpringBackGradientScaleUpLevel, mSpringBackGradientScaleDownLevel), springBackRunnableDelay);
+                                isAutoScale = true;
+                            }
+                        }
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                mLastPointerCount = 0;
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                mLastPointerCount = 0;
+        }
+
+
+        return true;
+    }
+
+    private void checkBorderAndCenterWhenScale() {
+
+        RectF rectF = getMatrixRectF();
+        float deltaX = 0;
+        float deltaY = 0;
+
+        /**
+         * If width or height of image is bigger than that of XuanImageView,
+         * should prevent image's edge being far away from XuanImageView's edge.
+         */
+        if (rectF.width() >= XuanImageViewWidth) {
+            if (rectF.left > 0)
+                deltaX = -rectF.left;
+            if (rectF.right < XuanImageViewWidth)
+                deltaX = XuanImageViewWidth - rectF.right;
+
+        }
+        if (rectF.height() >= XuanImageViewHeight) {
+            if (rectF.top > 0)
+                deltaY = -rectF.top;
+            if (rectF.bottom < XuanImageViewHeight)
+                deltaY = XuanImageViewHeight - rectF.bottom;
+        }
+
+        /**
+         * If width or height of image is smaller than that of XuanImageView,
+         * make sure the image, in width dimension or height dimension, is centered.
+         */
+        if (rectF.width() < XuanImageViewWidth) {
+            deltaX = XuanImageViewWidth / 2.0f - rectF.left - rectF.width() / 2.0f;
+        }
+        if (rectF.height() < XuanImageViewHeight) {
+            deltaY = XuanImageViewHeight / 2.0f - rectF.top - rectF.height() / 2.0f;
+
+        }
+
+        mScaleMatrix.postTranslate(deltaX, deltaY);
+    }
+
+    private void checkBorderAndCenterWhenTranslate() {
+        /**
+         *  No need to check Center here because it has been handled before checkBorderAndCenterWhenTranslate() is invoked.
+         *  See "case MotionEvent.ACTION_MOVE: " in  onTouch(View view, MotionEvent motionEvent).
+         */
+        RectF rectF = getMatrixRectF();
+
+        float deltaX = 0;
+        float deltaY = 0;
+
+        /**
+         * If width or height of image is bigger than that of XuanImageView,
+         * should prevent image's edge being far away from XuanImageView's edge.
+         */
+        if (rectF.width() >= XuanImageViewWidth) {
+            if (rectF.left > 0)
+                deltaX = -rectF.left;
+            if (rectF.right < XuanImageViewWidth)
+                deltaX = XuanImageViewWidth - rectF.right;
+
+        }
+        if (rectF.height() >= XuanImageViewHeight) {
+            if (rectF.top > 0)
+                deltaY = -rectF.top;
+            if (rectF.bottom < XuanImageViewHeight)
+                deltaY = XuanImageViewHeight - rectF.bottom;
+        }
+
+        mScaleMatrix.postTranslate(deltaX, deltaY);
+    }
+
+
+    private float getCurrentScaleLevel() {
+        float matrixArray[] = new float[9];
+        mScaleMatrix.getValues(matrixArray);
+
+        return matrixArray[Matrix.MSCALE_X];
+    }
+
+    private RectF getMatrixRectF() {
+        Matrix matrix = mScaleMatrix;
+        RectF rectF = new RectF();
+        Drawable image = getDrawable();
+        if (image != null) {
+            rectF.set(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
+            matrix.mapRect(rectF);
+        }
+
+        return rectF;
+    }
+
+    private boolean calculateImageCenterCoordinates() {
+        RectF rectF = getMatrixRectF();
+        ImageCenterX = (int) ((rectF.left + rectF.right) / 2);
+        ImageCenterY = (int) ((rectF.top + rectF.bottom) / 2);
+
+        return true;
+    }
+
+    public void AutoRotateMagnetism(RotationGestureDetector rotationGestureDetector) {
+        mAngle = rotationGestureDetector.getAngle();//mAngle's range: [-180 degress, 180 degress]
+        float autoRotateAngle;
+        int quotient;
+        float remainder;
+
+        quotient = ((int) mAngle) / 90;
+        remainder = mAngle % 90;
+
+        if (remainder >= autoRotationTrigger) {
+            autoRotateAngle = 90 - remainder;
+            if ((quotient + 1) % 2 == 0)
+                mOrientation = XuanImageViewSettings.ORIENTATION_LANDSCAPE;
+            else
+                mOrientation = XuanImageViewSettings.ORIENTATION_PORTRAIT;
+        } else if (remainder <= -autoRotationTrigger) {
+            autoRotateAngle = -90 - remainder;
+            if ((quotient - 1) % 2 == 0)
+                mOrientation = XuanImageViewSettings.ORIENTATION_LANDSCAPE;
+            else
+                mOrientation = XuanImageViewSettings.ORIENTATION_PORTRAIT;
+        } else {
+            autoRotateAngle = -remainder;
+            if (quotient % 2 == 0)
+                mOrientation = XuanImageViewSettings.ORIENTATION_LANDSCAPE;
+            else
+                mOrientation = XuanImageViewSettings.ORIENTATION_PORTRAIT;
+        }
+
+        postDelayed(new AutoRotateRunnable(autoRotateAngle, getCurrentScaleLevel() / (float) Math.cos(Math.toRadians(mAngle)), autoRotationRunnableTimes), autoRotationRunnableDelay);
+        isAutoRotated = true;
+
+        rotationGestureDetector.setAngle(mAngle + autoRotateAngle);
+        rotationGestureDetector.setPreviousAngle(mAngle + autoRotateAngle);
+    }
+
+    public void AutoRotateRestoration(RotationGestureDetector rotationGestureDetector) {
+        mAngle = rotationGestureDetector.getAngle();//mAngle's range: [-180 degress, 180 degress]
+        float autoRotateAngle;
+
+        if (mAngle >= autoRotationTrigger)
+            autoRotateAngle = 360 - mAngle;
+        else if (mAngle <= -autoRotationTrigger)
+            autoRotateAngle = -360 - mAngle;
+        else
+            autoRotateAngle = -mAngle;
+
+        postDelayed(new AutoRotateRunnable(autoRotateAngle, getCurrentScaleLevel() / (float) Math.cos(Math.toRadians(mAngle)), autoRotationRunnableTimes), autoRotationRunnableDelay);
+        isAutoRotated = true;
+
+        rotationGestureDetector.setAngle(0.0f);
+        rotationGestureDetector.setPreviousAngle(0.0f);
+    }
+
+    private class AutoScaleRunnable implements Runnable {
+        float targetScale;
+        float targetAbsScale;
+        float FocusX;
+        float FocusY;
+        float scaleFactor;
+
+        AutoScaleRunnable(float targetScale, float FocusX, float FocusY, float GradientScaleUp, float GradientScaleDown) {
+            this.targetScale = targetScale;
+            this.targetAbsScale = Math.abs(targetScale);
+            this.FocusX = FocusX;
+            this.FocusY = FocusY;
+            currentScaleLevel = getCurrentScaleLevel();
+            currentAbsScaleLevel = Math.abs(currentScaleLevel);
+            if (currentAbsScaleLevel < targetAbsScale)
+                scaleFactor = GradientScaleUp;
+            else if (currentAbsScaleLevel > targetAbsScale)
+                scaleFactor = GradientScaleDown;
+            else if (currentAbsScaleLevel == targetAbsScale)
+                scaleFactor = 1.0f;
+        }
+
+        @Override
+        public void run() {
+            mScaleMatrix.postScale(scaleFactor, scaleFactor, FocusX, FocusY);
+            checkBorderAndCenterWhenScale();
+            setImageMatrix(mScaleMatrix);
+
+            currentScaleLevel = getCurrentScaleLevel();
+            currentAbsScaleLevel = Math.abs(currentScaleLevel);
+            if ((scaleFactor < 1.0f && currentAbsScaleLevel > targetAbsScale)
+                    || (scaleFactor > 1.0f && currentAbsScaleLevel < targetAbsScale)) {
+                postDelayed(this, springBackRunnableDelay);
+            } else {
+                scaleFactor = targetScale / currentScaleLevel;
+
+                mScaleMatrix.postScale(scaleFactor, scaleFactor, FocusX, FocusY);
+                checkBorderAndCenterWhenScale();
+                setImageMatrix(mScaleMatrix);
+
+                isAutoScale = false;
+            }
+
+        }
+    }
+
+
+    private class AutoRotateRunnable implements Runnable {
+        float targetRotateAngle;
+        long TotalRotateTimes;
+        float AnglePerTime;
+        float AccumulativeRotateTimes;
+        float AccumulativeRotateAngles;
+        float initScaleLevel;
+        double ScalePerTime;
+
+        AutoRotateRunnable(float targetRotateAngle, float initScaleLevel, long TotalRotateTimes) {
+            this.targetRotateAngle = targetRotateAngle;
+            this.TotalRotateTimes = TotalRotateTimes;
+            AnglePerTime = targetRotateAngle / this.TotalRotateTimes;
+            AccumulativeRotateTimes = 0;
+            AccumulativeRotateAngles = 0.0f;
+            this.initScaleLevel = initScaleLevel;
+            if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION) {
+                ScalePerTime = Math.pow(mInitScale / initScaleLevel, 1.0 / TotalRotateTimes);
+            } else if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM) {
+                if (mOrientation == XuanImageViewSettings.ORIENTATION_LANDSCAPE)
+                    ScalePerTime = Math.pow(mInitScale / initScaleLevel, 1.0 / TotalRotateTimes);
+                else if (mOrientation == XuanImageViewSettings.ORIENTATION_PORTRAIT)
+                    ScalePerTime = Math.pow(mInitPortraitScale / initScaleLevel, 1.0 / TotalRotateTimes);
+            }
+
+        }
+
+        @Override
+        public void run() {
+            calculateImageCenterCoordinates();
+
+            mScaleMatrix.postRotate(AnglePerTime, ImageCenterX, ImageCenterY);
+            mScaleMatrix.postScale((float) ScalePerTime, (float) ScalePerTime, ImageCenterX, ImageCenterY);
+            mScaleMatrix.postTranslate((XuanImageViewCenterX - ImageCenterX) / (TotalRotateTimes - AccumulativeRotateTimes), (XuanImageViewCenterY - ImageCenterY) / (TotalRotateTimes - AccumulativeRotateTimes));
+            setImageMatrix(mScaleMatrix);
+            AccumulativeRotateTimes++;
+            AccumulativeRotateAngles += AnglePerTime;
+
+
+            if (AccumulativeRotateTimes < TotalRotateTimes) {
+                postDelayed(this, autoRotationRunnableDelay);
+            } else {
+                currentScaleLevel = getCurrentScaleLevel();
+                currentAbsScaleLevel = Math.abs(currentScaleLevel);
+                calculateImageCenterCoordinates();
+                mScaleMatrix.postRotate(targetRotateAngle - AccumulativeRotateAngles, ImageCenterX, ImageCenterY);
+                if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION) {
+                    mScaleMatrix.postScale(Math.abs(mInitScale / currentScaleLevel), Math.abs(mInitScale / currentScaleLevel), ImageCenterX, ImageCenterY);
+                } else if (mAutoRotateCategory == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM) {
+                    if (mOrientation == XuanImageViewSettings.ORIENTATION_LANDSCAPE) {
+                        mScaleMatrix.postScale(Math.abs(mInitScale / currentScaleLevel), Math.abs(mInitScale / currentScaleLevel), ImageCenterX, ImageCenterY);
+                    } else if (mOrientation == XuanImageViewSettings.ORIENTATION_PORTRAIT) {
+//                        mScaleMatrix.postScale(Math.abs(mInitPortraitScale / getCurrentScaleLevel()), Math.abs(mInitPortraitScale / getCurrentScaleLevel()), ImageCenterX, ImageCenterY);
+                        mTempInitPortraitScale = Math.abs(currentScaleLevel);
+                        mTempPortraitMaxScale = mTempInitPortraitScale * mMaxScaleMultiple;
+                        mTempPortraitDoubleTabScale = mTempInitPortraitScale * mDoubleTabScaleMultiple;
+                    }
+                }
+                mScaleMatrix.postTranslate(XuanImageViewCenterX - ImageCenterX, XuanImageViewCenterY - ImageCenterY);
+
+                checkBorderAndCenterWhenScale();
+
+                setImageMatrix(mScaleMatrix);
+                isAutoRotated = false;
+            }
+
+
+        }
+    }
+
+    /**
+     * Set a boolean value to determine whether rotation function is turned on.
+     *
+     * @param toggle determine whether rotation function is turned on
+     */
+    public void setRotationToggle(boolean toggle) {
+        mRotationToggle = toggle;
+    }
+
+    /**
+     * @return current RotationToggle
+     */
+    public boolean getRotationToggle() {
+        return mRotationToggle;
+    }
+
+    /**
+     * Set AutoRotateCategory, there are two alternative values of it : XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION, XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM.
+     *
+     * @param category
+     */
+    public void setAutoRotateCategory(int category) {
+        if (category == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION || category == XuanImageViewSettings.AUTO_ROTATE_CATEGORY_MAGNETISM)
+            mAutoRotateCategory = category;
+        else
+            mAutoRotateCategory = XuanImageViewSettings.AUTO_ROTATE_CATEGORY_RESTORATION;
+    }
+
+    /**
+     * @return current AutoRotateCategory
+     */
+    public int getAutoRotateCategory() {
+        return mAutoRotateCategory;
+    }
+
+    /**
+     * An image is scaled to an InitScale to fit the size of XuanImageView at the very beginning.
+     * MaxScale = MaxScaleMultiple * InitScale holds.
+     *
+     * @param maxScaleMultiple
+     */
+    public void setMaxScaleMultiple(float maxScaleMultiple) {
+        mMaxScaleMultiple = maxScaleMultiple;
+    }
+
+    /**
+     * @return current MaxScaleMultiple
+     */
+    public float getMaxScaleMultiple() {
+        return mMaxScaleMultiple;
+    }
+
+    /**
+     * When image's current scale level is smaller than DoubleTabScale, the image will scale up to DoubleTapScale if an double-tap gesture is detected.
+     * DoubleTapScale = DoubleTabScaleMultiple * InitScale holds.
+     *
+     * @param doubleTabScaleMultiple
+     */
+    public void setDoubleTabScaleMultiple(float doubleTabScaleMultiple) {
+        mDoubleTabScaleMultiple = doubleTabScaleMultiple;
+    }
+
+    /**
+     * @return current DoubleTabScaleMultiple
+     */
+    public float getDoubleTabScaleMultiple() {
+        return mDoubleTabScaleMultiple;
+    }
+
+    /**
+     * If current scale level is smaller than InitScale and image is not in rotation state,
+     * the image will scale up to InitScale with SpringBackGradientScaleUpLevel step by step.
+     * Default springBackGradientScaleUpLevel is  1.01f.
+     *
+     * @param springBackGradientScaleUpLevel
+     */
+    public void setSpringBackGradientScaleUpLevel(float springBackGradientScaleUpLevel) {
+        mSpringBackGradientScaleUpLevel = springBackGradientScaleUpLevel;
+    }
+
+    /**
+     * @return current SpringBackGradientScaleUpLevel
+     */
+    public float getSpringBackGradientScaleUpLevel() {
+        return mSpringBackGradientScaleUpLevel;
+    }
+
+    /**
+     * If current scale level is bigger than MaxScale and image is not in rotation state,
+     * the image will scale down to MaxScale with SpringBackGradientScaleDownLevel step by step.
+     * Default springBackGradientScaleDownLevel is 0.99f.
+     *
+     * @param springBackGradientScaleDownLevel
+     */
+    public void setSpringBackGradientScaleDownLevel(float springBackGradientScaleDownLevel) {
+        mSpringBackGradientScaleDownLevel = springBackGradientScaleDownLevel;
+    }
+
+    /**
+     * @return current SpringBackGradientScaleDownLevel
+     */
+    public float getSpringBackGradientScaleDownLevel() {
+        return mSpringBackGradientScaleDownLevel;
+    }
+
+    /**
+     * When image's current scale level is smaller than DoubleTabScale,
+     * the image will scale up to DoubleTapScale with DoubleTapGradientScaleUpLevel step by step if a double-tap gesture is detected.
+     * Default doubleTalGradientScaleUpLevel is 1.05f.
+     *
+     * @param doubleTapGradientScaleUpLevel
+     */
+    public void setDoubleTapGradientScaleUpLevel(float doubleTapGradientScaleUpLevel) {
+        mDoubleTapGradientScaleUpLevel = doubleTapGradientScaleUpLevel;
+    }
+
+    /**
+     * @return current DoubleTapGradientScaleUpLevel
+     */
+    public float getDoubleTapGradientScaleUpLevel() {
+        return mDoubleTapGradientScaleUpLevel;
+    }
+
+    /**
+     * When image's current scale level is bigger than DoubleTabScale,
+     * the image will scale down to InitScale with DoubleTapGradientScaleDownLevel step by step if a double-tap gesture is detected.
+     * Default doubleTabGradientScaleDownLevel is 0.95f.
+     *
+     * @param doubleTapGradientScaleDownLevel
+     */
+    public void setDoubleTabGradientScaleDownLevel(float doubleTapGradientScaleDownLevel) {
+        mDoubleTapGradientScaleDownLevel = doubleTapGradientScaleDownLevel;
+    }
+
+    /**
+     * @return current DoubleTapGradientScaleDownLevel
+     */
+    public float getDoubleTapGradientScaleDownLevel() {
+        return mDoubleTapGradientScaleDownLevel;
+    }
+
+    /**
+     * When image's current rotation angle is bigger than AutoRotationTrigger, the image will rotate in the same direction and scale back to it's initial state if rotation gesture is released.
+     * When image's current rotation angle is smaller than AutoRotationTrigger, the image will rotate in the opposite direction and scale back to it's initial state if rotation gesture is released.
+     * Default AutoRotationTrigger is 60 (degrees).
+     *
+     * @param autoRotationTrigger
+     */
+    public void setAutoRotationTrigger(float autoRotationTrigger) {
+        this.autoRotationTrigger = autoRotationTrigger;
+    }
+
+    /**
+     * @return current AutoRotationTrigger
+     */
+    public float getAutoRotationTrigger() {
+        return autoRotationTrigger;
+    }
+
+    /**
+     * Default SpringBackRunnableDelay is 10 (milliseconds).
+     *
+     * @param delay
+     */
+    public void setSpringBackRunnableDelay(int delay) {
+        springBackRunnableDelay = delay;
+    }
+
+    /**
+     * @return current SpringBackRunnableDelay
+     */
+    public int getSpringBackRunnableDelay() {
+        return springBackRunnableDelay;
+    }
+
+    /**
+     * Default DoubleTapRunnableDelay is 10 (milliseconds).
+     *
+     * @param delay
+     */
+    public void setDoubleTapScaleRunnableDelay(int delay) {
+        doubleTabScaleRunnableDelay = delay;
+    }
+
+    /**
+     * @return current DoubleTabScaleRunnableDelay
+     */
+    public int getDoubleTabScaleRunnableDelay() {
+        return doubleTabScaleRunnableDelay;
+    }
+
+    /**
+     * Default AutoRotationRunnableDelay is 5 (milliseconds).
+     *
+     * @param delay
+     */
+    public void setAutoRotationRunnableDelay(int delay) {
+        autoRotationRunnableDelay = delay;
+    }
+
+    /**
+     * @return current AutoRotationRunnableDelay
+     */
+    public int getAutoRotationRunnalbleDelay() {
+        return autoRotationRunnableDelay;
+    }
+
+    /**
+     * Default AutoRotationRunnableTimes is 10 (times).
+     *
+     * @param times
+     */
+    public void setAutoRotationRunnableTimes(int times) {
+        autoRotationRunnableTimes = times;
+    }
+
+    /**
+     * @return current AutoRotationRunnableTimes
+     */
+    public int getAutoRotationRunnableTimes() {
+        return autoRotationRunnableTimes;
+    }
+
+
+    /**
+     * Notice the Image can only start to be rotated when it's in initial state. But the image may be scaled up or down a little bit by ScaleGestureDetector
+     * in advance when you try to rotate it, hence, currentScaleLevel is not precisely equal to initScaleLevel. Here, an AllowableFloatError is existed to handle
+     * this situation. When Math.abs(currentScaleLevel - initScaleLevel) is smaller than allowableFloatError, RotateGestureDetector.onTouchEvent() can be invoked.
+     * Default allowableFloatError is 1E-6, it should be compatible with most of devices. For devices whose display resolution and aspect ratio is not normal, allowableFloatError may
+     * need to be tuned. eg., for Galaxy S8, 3E-3 works well. Of course, 3E-3 also works for most of devices because 1E-6 is smaller than 3E-3.
+     * @param allowableFloatError
+     */
+    public void setAllowableFloatError(double allowableFloatError){
+        this.allowableFloatError = allowableFloatError;
+    }
+
+    public double getAllowableFloatError(){
+        return allowableFloatError;
+    }
+
+    /**
+     * In  AUTO_ROTATE_CATEGORY_MAGNETISM mode, the image may be showed under a fixed rotation angle like 90 degrees, 270 degrees,
+     * 450 degrees, ect., then allowablePortraitFloatError should handle the situation when currentPortraitScaleLevel is not precisely
+     * equal to initPortraitScaleLevel.
+     * Default allowablePortraitFloatError is 1E-12, it should be compatible with most of devices. For devices whose display resolution and aspect ratio is not normal, allowablePortraitFloatError may
+     * need to be tuned. eg., for Galaxy S8, 5E-8 works well. Of course, 5E-8 also works for most of devices because 1E-12 is smaller than 5E-8.
+     * @see XuanImageView#setAllowableFloatError(double)
+     *
+     * @param allowablePortraitFloatError
+     */
+    public void setAllowablePortraitFloatError(double allowablePortraitFloatError){
+        this.allowablePortraitFloatError = allowablePortraitFloatError;
+    }
+
+    public double getAllowablePortraitFloatError(){
+        return allowablePortraitFloatError;
+    }
+
+}

+ 13 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoList/XuanImageView/XuanImageViewSettings.java

@@ -0,0 +1,13 @@
+package com.usai.redant.raimage.PhotoList.XuanImageView;
+
+/**
+ * Created by xuanyihuang on 20/12/2016.
+ */
+
+public class XuanImageViewSettings {
+    public static int ORIENTATION_PORTRAIT = 1;
+    public static int ORIENTATION_LANDSCAPE = 2;
+
+    public static int AUTO_ROTATE_CATEGORY_RESTORATION = 1;
+    public static int AUTO_ROTATE_CATEGORY_MAGNETISM = 2;
+}

+ 206 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/PhotoPreviewActivity.java

@@ -0,0 +1,206 @@
+package com.usai.redant.raimage;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.ThumbnailUtils;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.animation.AnimationUtils;
+import android.widget.Gallery.LayoutParams;
+import android.widget.HorizontalScrollView;
+import android.widget.ImageSwitcher;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ViewSwitcher;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.util.RAUtil;
+
+import java.io.File;
+import java.util.ArrayList;
+
+public class PhotoPreviewActivity extends Activity implements
+		ViewSwitcher.ViewFactory
+{
+	private ImageSwitcher mSwitcher;
+
+	View current_view	= null;
+	ArrayList<String> pic_file;
+
+//	
+//
+//	@Override
+//	protected void onDestroy()
+//	{
+//		Intent intent = new Intent();
+//		setResult(Activity.RESULT_OK, intent);
+//		super.onDestroy();
+//	}
+
+	@Override
+	public void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+		// requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+		setContentView(R.layout.activity_photo_preview);
+
+		mSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
+		mSwitcher.setFactory(this);
+		mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
+				android.R.anim.fade_in));
+		mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
+				android.R.anim.fade_out));
+
+		pic_file = (ArrayList<String>) getIntent().getSerializableExtra(
+				"pic_list");
+
+		findViewById(R.id.hsv);
+		HorizontalScrollView hsv = (HorizontalScrollView) findViewById(R.id.hsv);
+
+		LinearLayout ll = (LinearLayout) findViewById(R.id.linearLayout);
+
+		for (int i = 0; i < pic_file.size(); i++)
+		{
+			ImageView imgview = new ImageView(this);
+			//
+			// Bitmap thumb = thumbs.get(i);
+			// if (thumb == null)
+			// {
+			Log.d("getView", "create thumb position:" + i);
+
+			// thumbs.put(i, thumb);
+			// }
+			// Thread thread = new Thread()
+
+			// i.setImageResource(mThumbIds[position]);
+			imgview.setAdjustViewBounds(true);
+			LinearLayout.LayoutParams searchParams = new LinearLayout.LayoutParams(
+					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1);
+			searchParams.leftMargin = 40;
+			searchParams.topMargin = 10;
+			searchParams.bottomMargin = 10;
+			imgview.setScaleType(ImageView.ScaleType.FIT_CENTER);
+			imgview.setLayoutParams(searchParams);
+			imgview.setBackgroundResource(R.drawable.picture_frame);
+			imgview.setTag(i);
+			Loadtask t = new Loadtask();
+			t.execute(imgview, null);
+			imgview.setOnClickListener(new OnClickListener()
+			{
+
+				@Override
+				public void onClick(View v)
+				{
+					current_view = v;
+					Integer idx = (Integer) v.getTag();
+					Uri uri = Uri.fromFile(new File(pic_file.get(idx)));
+					mSwitcher.setImageURI(uri);
+
+					// v.setSelected(true);
+					// TODO Auto-generated method stub
+
+				}
+			});
+
+			ll.addView(imgview);
+
+			if (i == 0)
+				current_view = imgview;
+
+		}
+		mSwitcher.setImageURI(Uri.fromFile(new File(pic_file.get(0))));
+		// hsv.inflate(context, resource, root)
+
+		// Gallery g = (Gallery) findViewById(R.id.gallery);
+		// g.setAdapter(new ImageAdapter(this));
+		// g.setOnItemSelectedListener(this);
+	}
+
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu)
+	{
+		// Inflate the menu; this adds items to the action bar if it is present.
+		getMenuInflater().inflate(R.menu.preview, menu);
+		return true;
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item)
+	{
+		// TODO Auto-generated method stub
+		switch (item.getItemId())
+		{
+			case R.id.action_delete:
+			{
+				LinearLayout ll = (LinearLayout) findViewById(R.id.linearLayout);
+				// ImageView iv= (ImageView) ll.findViewWithTag(current_path);
+				ll.removeView(current_view);
+				mSwitcher.setImageURI(null);
+				Integer idx = (Integer) current_view.getTag();
+				new File(pic_file.get(idx)).delete();
+				RAUtil.updateGallery(pic_file.get(idx));
+				current_view = null;
+				// // pic_file.remove(idx);
+			}
+				break;
+			default:
+				break;
+		}
+		return super.onOptionsItemSelected(item);
+	}
+
+	public View makeView()
+	{
+		ImageView i = new ImageView(this);
+		i.setBackgroundColor(0xFF000000);
+		i.setScaleType(ImageView.ScaleType.FIT_CENTER);
+		i.setLayoutParams(new ImageSwitcher.LayoutParams(
+				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+		return i;
+	}
+
+	// HashMap<Integer, Bitmap> thumbs = new HashMap<Integer, Bitmap>();
+	// private Integer[] mThumbIds = {
+	// };
+
+	// private Integer[] mImageIds = {
+	// };
+	public class Loadtask extends AsyncTask<ImageView, Integer, Boolean>
+	{
+		// int err_code = ERR_CODE_NONE;
+		ImageView iv		= null;
+		Bitmap thumb	= null;
+
+		// int netconnect;
+
+		@Override
+		protected Boolean doInBackground(ImageView... params)
+		{
+			iv = params[0];
+			Integer idx = (Integer) iv.getTag();
+			thumb = ThumbnailUtils.extractThumbnail(
+					BitmapFactory.decodeFile(pic_file.get(idx)), 160, 120);
+			return true;
+		}
+
+		@Override
+		protected void onPostExecute(final Boolean success)
+		{
+			iv.setImageBitmap(thumb);
+		}
+
+		@Override
+		protected void onCancelled()
+		{
+
+		}
+	}
+}

+ 56 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+
+import com.usai.redant.redantmobile.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)));
+    }
+  }
+}

+ 319 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/ServerSettingActivity.java

@@ -0,0 +1,319 @@
+package com.usai.redant.raimage;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.Toast;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.redantmobile.RedAntApplication;
+
+public class ServerSettingActivity extends Activity
+{
+	static final int	REQUEST_SCAN_BARCODE	= 2;
+
+//	public boolean checkCameraPermission() {
+//		int permission = ContextCompat.checkSelfPermission(ServerSettingActivity.this, "android.permission.CAMERA");
+//		if (permission == PackageManager.PERMISSION_DENIED) {
+//
+//			new AlertDialog.Builder(this)
+//					.setTitle("Warning")
+//					.setMessage("RA Image need camera permission")
+//					.setPositiveButton("Setting", new DialogInterface.OnClickListener() {
+//						@Override
+//						public void onClick(DialogInterface dialog, int which) {
+//							Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+//							intent.setData(Uri.parse("package:" + getPackageName()));
+//							startActivity(intent);
+//						}
+//					})
+//					.setNegativeButton("No", new DialogInterface.OnClickListener() {
+//						@Override
+//						public void onClick(DialogInterface dialog, int which) {
+//							finish();
+//						}
+//					})
+//					.show();
+//
+//			return false;
+//		}
+//		return true;
+//	}
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_service_setting);
+
+		SharedPreferences pref = RedAntApplication.getInstance()
+				.getSharedPreferences("RA Image", 0);
+
+//		String ia = pref.getString("ia", null);
+//		String ea = pref.getString("ea", null);
+		String aa = pref.getString("aa", null);
+		String station_name = pref.getString("station name", null);
+//		RadioGroup rg = (RadioGroup) findViewById(R.id.radioGroup1);
+
+//		if (!TextUtils.isEmpty(aa) && aa.equals(ia))
+//			rg.check(R.id.radio0);
+
+//		if (!TextUtils.isEmpty(aa) && aa.equals(ea))
+//			rg.check(R.id.radio1);
+
+		EditText et_ia = (EditText) findViewById(R.id.et_ia);
+//		EditText et_ea = (EditText) findViewById(R.id.et_ea);
+		EditText et_name = (EditText) findViewById(R.id.et_name);
+//		et_ea.setText(ea);
+		et_ia.setText(aa);
+		et_name.setText(station_name);
+
+		ImageButton ibtn = (ImageButton) findViewById(R.id.ibtn_scan);
+		ibtn.setOnClickListener(new OnClickListener()
+		{
+
+			@Override
+			public void onClick(View v)
+			{
+			//	Log.d(TAG, "==============>Click Scan button");
+//				if (!RAUtil.checkPermission(ServerSettingActivity.this,"android.permission.CAMERA")) {
+//
+//					return;
+//				}
+
+				Intent intent = new Intent();
+
+				intent.setClass(ServerSettingActivity.this,
+						CaptureActivity.class);
+				startActivityForResult(intent, REQUEST_SCAN_BARCODE);
+
+			}
+		});
+	}
+
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu)
+	{
+		// Inflate the menu; this adds items to the action bar if it is present.
+		getMenuInflater().inflate(R.menu.server_setting, menu);
+		return true;
+	}
+
+	@Override
+	public void onActivityResult(int requestCode, int resultCode, Intent data)
+	{
+
+		if (requestCode == REQUEST_SCAN_BARCODE)
+		{
+			if (resultCode == Activity.RESULT_OK)
+			{
+				Bundle bundle = data.getExtras();
+				String jstr = bundle.getString("pid");
+				
+				if (jstr == null || jstr.length() <= 0)
+				{
+					//Log.d(TAG, "json is wrong");
+					toast();
+					return ;//Network.RESULT_NET_ERROR;
+				}	
+				String address[]=jstr.split(";");
+				EditText et_ia = (EditText) findViewById(R.id.et_ia);
+//				EditText et_ea = (EditText) findViewById(R.id.et_ea);
+				EditText et_name = (EditText) findViewById(R.id.et_name);
+				if (address.length==3)
+				{
+					et_ia.setText(address[2].trim());
+					et_name.setText(address[0].trim());
+				}
+				else if(address.length==2)
+				{
+					et_ia.setText(address[1].trim());
+					et_name.setText(address[0].trim());
+				}
+				else
+				{
+					toast();
+					return;
+				}
+
+//				et_ea.setText(address[2].trim());
+
+//				JSONObject jsobj;
+//				try
+//				{
+//					jsobj = new JSONObject(jstr);
+//					if (jsobj.length() > 0)
+//					{
+//						String name = jsobj.getString("name");
+//						String ia = jsobj.getString("ia");
+//						String ea = jsobj.getString("ea");
+//						EditText et_ia = (EditText) findViewById(R.id.et_ia);
+//						EditText et_ea = (EditText) findViewById(R.id.et_ea);
+//						et_ea.setText(ea);
+//						et_ia.setText(ia);
+////						int iresult = jsobj.getInt("result");
+////						if (iresult == Network.AP_USER_AUTH)
+////						{
+////							return ;//RESULT_TRUE;
+////						}
+////
+////						else
+////						{
+////
+////							return ;//RESULT_FALSE;
+////						}
+//					}
+//					return ;
+//				}
+//				catch (JSONException e)
+//				{
+//					// TODO Auto-generated catch block
+//					e.printStackTrace();
+//					return ;
+//				}
+				//Log.d(TAG,
+//						"REQUEST_SCAN_BARCODE==========>pid="
+//								+ bundle.getString("pid"));
+//				TextView pidval = (TextView) findViewById(R.id.pidval);
+//				pidval.setText(pid);
+//				updateUploadButton();
+			}
+		}
+		super.onActivityResult(requestCode, resultCode, data);
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item)
+	{
+		// Handle action bar item clicks here. The action bar will
+		// automatically handle clicks on the Home/Up button, so long
+		// as you specify a parent activity in AndroidManifest.xml.
+		int id = item.getItemId();
+		if (id == R.id.action_save)
+		{
+			EditText et_ia = (EditText) findViewById(R.id.et_ia);
+//			EditText et_ea = (EditText) findViewById(R.id.et_ea);
+			EditText et_name = (EditText) findViewById(R.id.et_name);
+			String ia = et_ia.getText().toString();
+//			String ea = et_ea.getText().toString();
+			String name = et_name.getText().toString();
+			if (TextUtils.isEmpty(ia) )
+			{
+				showdialog("Server address can not be empty!");
+				return true;
+			}
+
+			SharedPreferences pref = RedAntApplication.getInstance()
+					.getSharedPreferences("RA Image", 0);
+			SharedPreferences.Editor editor = pref.edit();
+
+
+
+
+			if (TextUtils.isEmpty(name))
+			{
+				showdialog("Station name can not be empty!");
+				return true;
+			}
+			else {
+				
+				editor.putString("station name", name);
+			}
+			if (!TextUtils.isEmpty(ia))
+			{
+
+				if (!ia.substring(ia.length() - 1).equals("/"))
+					ia = ia + "/";
+				editor.putString("aa", ia);
+				RedAntApplication.active_address = ia;
+
+			}
+//			if (!TextUtils.isEmpty(ea))
+//			{
+//				if (!ea.substring(ea.length() - 1).equals("/"))
+//					ea = ea + "/";
+//				editor.putString("ea", ea);
+//			}
+//			RadioGroup rg = (RadioGroup) findViewById(R.id.radioGroup1);
+//			if (rg.getCheckedRadioButtonId() == R.id.radio0)
+//			{
+//				if (!TextUtils.isEmpty(ia))
+//				{
+//					editor.putString("aa", ia);
+//					RedAntApplication.active_address = ia;
+//				}
+//				else
+//				{
+//					showdialog("Active server address can not be empty!");
+//					return true;
+//				}
+//			}
+//			else
+//			{
+//				if (!TextUtils.isEmpty(ea))
+//				{
+//					editor.putString("aa", ea);
+//					RedAntApplication.active_address = ea;
+//				}
+//				else
+//				{
+//					showdialog("Active server address can not be empty!");
+//					return true;
+//				}
+//			}
+
+			RedAntApplication.station_name = name;
+
+			editor.remove("Lat");
+			editor.remove("Lon");
+			editor.commit();
+			//sendBroadcast(new Intent("REDANT.POP.RESET_LOCATION"));
+
+
+			String result = pref.getString("aa","");
+			Intent intent = new Intent();
+			intent.putExtra("server", result);
+                /*
+                 * 调用setResult方法表示我将Intent对象返回给之前的那个Activity,这样就可以在onActivityResult方法中得到Intent对象,
+                 */
+			setResult(1001, intent);
+			finish();
+			return true;
+		}
+		return super.onOptionsItemSelected(item);
+	}
+
+	private void toast()
+	{
+		Toast toast = Toast.makeText(this,"Wrong server setting format",
+				Toast.LENGTH_LONG);
+		toast.setGravity(Gravity.CENTER, 0, 0);
+		toast.show();
+	}
+	private void showdialog(String msg)
+	{
+		new AlertDialog.Builder(ServerSettingActivity.this)
+				.setIcon(android.R.drawable.ic_dialog_info).setTitle("Error!")
+				.setMessage(msg)
+				.setPositiveButton("OK", new DialogInterface.OnClickListener()
+				{
+					public void onClick(DialogInterface dialog, int whichButton)
+					{
+
+						// finish();
+						/* User clicked OK so do some stuff */
+					}
+				}).show();
+	}
+}

+ 32 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/SplashActivity.java

@@ -0,0 +1,32 @@
+package com.usai.redant.raimage;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ImageView;
+
+import com.usai.redant.redantmobile.LoginActivity;
+import com.usai.redant.redantmobile.R;
+
+public class SplashActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_splash);
+
+
+        ImageView iv = (ImageView) findViewById(R.id.splashImage);
+        iv.setImageResource(R.drawable.splash);
+
+        new Handler().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                Intent intent = new Intent(SplashActivity.this,LoginActivity.class);
+                startActivity(intent);
+                finish();
+            }
+        },1500);
+    }
+}

+ 445 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/TaskActivity.java

@@ -0,0 +1,445 @@
+package com.usai.redant.raimage;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.redantmobile.RedAntApplication;
+import com.usai.redant.util.RAUploadManager;
+import com.usai.redant.util.dbgUtil;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+//import android.support.v7.widget.ListViewCompat;
+
+public class TaskActivity extends AppCompatActivity {
+
+    ArrayList<Bundle> task_arr= new ArrayList<>();
+    ListView tasklist;
+
+
+    private RAUploadManager uploadManager;
+
+
+    private UploadService.MyBinder binder;
+    private UploadService uploadServiceservice;
+    private ServiceConnection serviceConnection;
+
+    boolean serviceConnectionFlag;
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_task);
+
+
+//设置返回键
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle("RA Image");
+
+
+
+
+
+        tasklist = (ListView)findViewById(R.id.task_list);
+
+        tasklist.setAdapter(new TaskAdapter(this,R.layout.upload_list_cell/*,task_arr*/));
+
+
+
+
+        serviceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+
+
+                Log.d("_LIST","-------connected service  tid="+ Thread.currentThread().getId());
+                serviceConnectionFlag = true;
+
+                binder = (UploadService.MyBinder)service;
+                uploadServiceservice = binder.getService();
+
+                uploadManager = uploadServiceservice.uploadManager;
+                task_arr = (ArrayList<Bundle>) uploadManager.get_arr_queue().clone(); //uploadManager.arr_queue;
+
+                Collections.reverse(task_arr);
+                final TaskAdapter adapter = (TaskAdapter)tasklist.getAdapter();
+
+                adapter.notifyDataSetChanged();
+
+
+                uploadManager.uiUpdateListener = new RAUploadManager.UIUpdateListener() {
+                    @Override
+                    public void updateCell(long index, Bundle taskinfo) {
+                        if(true) {
+
+                            runOnUiThread(new Runnable() {
+                                @Override
+                                public void run() {
+
+                                    adapter.notifyDataSetChanged();
+                                }
+                            });
+
+                            return;
+                        }
+
+                    }
+
+                    @Override
+                    public void updateList(final ArrayList<Bundle> newlist) {
+                        if(true) {
+
+                            runOnUiThread(new Runnable() {
+                                @Override
+                                public void run() {
+                                    task_arr = (ArrayList<Bundle>) newlist.clone();
+                                    Collections.reverse(task_arr);
+                                    adapter.notifyDataSetChanged();
+                                }
+                            });
+
+                            return;
+                        }
+
+                    }
+                };
+
+
+//                tasklist.getAdapter().no.notifyDataSetChanged();
+//                runOnUiThread(new Runnable() {
+//                    @Override
+//                    public void run() {
+//                        adapter = new uploadAdapter(R.layout.upload_list_cell);
+//                        uploadList.setAdapter(adapter);
+//                    }
+//                });
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                serviceConnectionFlag = false;
+                uploadManager.uiUpdateListener = null;
+            }
+        };
+
+        bindService();
+
+    }
+
+    @Override
+    protected void onDestroy() {
+
+        unbindService(serviceConnection);
+
+        super.onDestroy();
+    }
+
+
+    private void bindService() {
+        Intent intent = new Intent(TaskActivity.this, UploadService.class);
+
+        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+    }
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.upload_list_menu,menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home: {
+                finish();
+            }
+            break;
+            case R.id.clear_upload_list_btn: {
+//                for(int i=0;i<10;i++)
+//                runOnUiThread(new Runnable() {
+//                    @Override
+//                    public void run() {
+//
+//                        Log.d("_LIST","running  tid="+Thread.currentThread().getId());
+//                        Log.d("_LIST", "uploadlist UI  size:  "+ displaylist.size());
+//                        long timeStart = System.currentTimeMillis();
+////                        displaylist = (ArrayList<Bundle>) newlist.clone();
+//                        adapter.notifyDataSetChanged();
+//
+//
+//                        Log.d("_LIST", "uploadlist UI: COST" + (System.currentTimeMillis() - timeStart));
+//                    }
+//                });
+                clearUploadList();
+            }
+            break;
+        }
+        return true;
+    }
+
+    private void clearUploadList() {
+        if (task_arr.size() == 0) {
+            new AlertDialog.Builder(this)
+                    .setTitle("Warning")
+                    .setMessage("Upload list is empty.")
+                    .setPositiveButton("OK",null)
+                    .show();
+            return;
+        }
+
+        new AlertDialog.Builder(this)
+                .setTitle("Clear upload list")
+                .setMessage("Are you sure remove all error/finish task?")
+                .setPositiveButton("YES", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        // clear
+                        if (serviceConnectionFlag == true && uploadServiceservice != null) {
+                            uploadManager.clearTask();
+//                            adapter.notifyDataSetChanged();
+                        }
+
+                    }
+                })
+                .setNegativeButton("NO", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+
+                    }
+                })
+                .show();
+
+    }
+    class TaskAdapter extends ArrayAdapter
+    {
+
+        public TaskAdapter(@NonNull Context context, @LayoutRes int resource/*, @NonNull ArrayList<Bundle> objects*/) {
+            super(context, resource/*, objects*/);
+        }
+
+        @Override
+        public int getCount() {
+            return task_arr.size();
+        }
+
+        @Override
+        public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+
+            Log.d("_LIST","running  tid="+ Thread.currentThread().getId());
+            long timeStart = System.currentTimeMillis();
+
+            final Bundle item = task_arr.get(position);
+//            Bundle taskinfo = item.getBundle("params");
+//            String barcode = taskinfo.getString("barcode");
+
+            RAUploadManager.TaskStatus istatus = RAUploadManager.TaskStatus.values()[item.getInt("status",0)];
+            String status="";
+            switch(istatus)
+            {
+                case TaskStatusStart:
+                    status="uploading";
+                    break;
+                case TaskStatusStop:
+                    status="stop";
+                    break;
+                case TaskStatusError:
+                    status="warning";
+                    break;
+                case TaskStatusWait:
+                    status="waiting";
+                    break;
+                case TaskStatusFinish:
+                    status="finish";
+                    break;
+
+                default:
+                    status="warning";
+                    break;
+            }
+            double percent = item.getDouble("progress",(double)item.getInt("progress",0));
+            String err = item.getString("msg");
+            String name = item.getString("file","");
+
+            View cell;
+            ViewHolder holder;
+            if (convertView != null) {
+
+                cell = convertView;
+                holder = (ViewHolder)cell.getTag();
+                Log.d("_LIST", "getView: " + holder);
+
+            } else {
+//                cell = LayoutInflater.from(getApplicationContext()).inflate(resourceId,null);
+                cell = View.inflate(getApplicationContext(), R.layout.upload_list_cell, null);
+                holder = new ViewHolder();
+                holder.name_tv = (TextView) cell.findViewById(R.id.upload_name_tv);
+                holder.progressBar = (ProgressBar) cell.findViewById(R.id.upload_progressBar);
+                holder.state_tv = (TextView) cell.findViewById(R.id.upload_state_tv);
+                holder.progress_tv = (TextView) cell.findViewById(R.id.upload_progress_tv);
+                holder.err_tv = (TextView) cell.findViewById(R.id.upload_err_tv);
+                holder.btn_reload = (ImageButton) cell.findViewById(R.id.btn_reload);
+                cell.setTag(holder);
+            }
+                holder.btn_reload.setImageResource(R.drawable.ic_action_reload);
+                if(istatus!= RAUploadManager.TaskStatus.TaskStatusError&& istatus!= RAUploadManager.TaskStatus.TaskStatusStop)
+                {
+                    holder.btn_reload.setVisibility(View.GONE);
+                }
+                else
+                {
+                    holder.btn_reload.setVisibility(View.VISIBLE);
+                    Log.d("_LIST", "new listener: position" + position);
+                    holder.btn_reload.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+
+
+                            Bundle task = task_arr.get(position);
+
+                            Log.d("_LIST", "retry: " + task.getString("file","file is null") +"position" + position);
+
+
+
+//                            boolean canstart = true;
+
+                            ConnectivityManager connManager = (ConnectivityManager) RedAntApplication.getInstance()
+                                    .getSystemService(Context.CONNECTIVITY_SERVICE);
+
+                            NetworkInfo networkInfo = connManager
+                                    .getActiveNetworkInfo();
+                            if (networkInfo == null)
+                            {
+                                dbgUtil.Logd(
+                                        "Current Network info",
+                                        "can not get Active NetworkInfo!");
+//                                canstart = false;
+                                Toast toast = Toast.makeText(getApplicationContext(),
+                                        "No available network. Please try upload manually later.",
+                                        Toast.LENGTH_LONG);
+                                toast.setGravity(Gravity.CENTER, 0, 0);
+                                toast.show();
+                                return;
+                            }
+                            else
+                            {
+                                NetworkInfo.State netState = networkInfo
+                                        .getState();
+                                if (netState != NetworkInfo.State.CONNECTED)
+                                {
+                                    dbgUtil.Logd(
+                                            "Current Network info",
+                                            "not Connected!State="
+                                                    + netState);
+//                                    canstart = false;
+
+                                    Toast toast = Toast.makeText(getApplicationContext(),
+                                            "App network connection. Please try upload manually later.",
+                                            Toast.LENGTH_LONG);
+                                    toast.setGravity(Gravity.CENTER, 0, 0);
+                                    toast.show();
+                                    return;
+                                }
+                                else
+                                {
+                                    int iconntype = -1;
+                                    iconntype = networkInfo
+                                            .getType();
+
+                                    SharedPreferences pref = RedAntApplication
+                                            .getInstance()
+                                            .getSharedPreferences(
+                                                    "UploadManager",
+                                                    0);
+                                    boolean
+                                            wifi_only
+                                            =pref.getBoolean("wifi_only",
+                                            false);
+                                    if(wifi_only == true
+                                            && iconntype !=
+                                            ConnectivityManager.TYPE_WIFI
+                                            && iconntype !=
+                                            9/* earthnet */)
+                                    {
+//                                    canstart = false;
+
+                                        Toast toast = Toast.makeText(getApplicationContext(),
+                                                "App is set to upload via WIFI only. Please change your setting or try upload manually later.",
+                                                Toast.LENGTH_LONG);
+                                        toast.setGravity(Gravity.CENTER, 0, 0);
+                                        toast.show();
+                                        return;
+                                    }
+                                }
+
+                            }
+//                            if(!canstart)
+//                            {
+//                                Toast toast = Toast.makeText(getApplicationContext(),
+//                                        "App is set to upload via WIFI only. Please change your setting or try upload manually later.",
+//                                        Toast.LENGTH_LONG);
+//                                toast.setGravity(Gravity.CENTER, 0, 0);
+//                                toast.show();
+//                                return;
+//                            }
+
+                            v.setVisibility(View.GONE);
+                            uploadManager.startTask(task);
+
+                        }
+                    });
+                }
+
+
+
+            holder.name_tv.setText(name);
+//            holder.progressBar.setProgress(100 *(int)percent);
+            holder.progressBar.setProgress((int) (100 * percent));
+            holder.state_tv.setText(status);
+//            holder.progress_tv.setText(100*percent+"%");
+            holder.progress_tv.setText(String.format("%.2f%%",100*percent));
+            holder.err_tv.setText(err);
+
+
+
+            Log.d("_LIST", "getView(): POSITION   "+position+" file   " + item.getString("file","no file"));
+            return cell;
+        }
+
+        private class ViewHolder {
+            public TextView name_tv;
+            public ProgressBar progressBar;
+            public TextView state_tv;
+            public TextView progress_tv;
+            public TextView err_tv;
+            public ImageButton btn_reload;
+        }
+    }
+}

+ 619 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/UploadList/UploadListActivity.java

@@ -0,0 +1,619 @@
+package com.usai.redant.raimage.UploadList;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.usai.redant.raimage.UploadService;
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.util.RAUploadManager;
+
+import java.util.ArrayList;
+
+//import com.usai.redant.redantmobile.R;
+
+//import com.usai.redant.raimage.UploadList.swipemenulistview.SwipeMenu;
+//import com.usai.redant.raimage.UploadList.swipemenulistview.SwipeMenuCreator;
+//import com.usai.redant.raimage.UploadList.swipemenulistview.SwipeMenuItem;
+//import com.usai.redant.raimage.UploadList.swipemenulistview.SwipeMenuListView;
+
+public class UploadListActivity extends AppCompatActivity {
+
+
+    private ArrayList<Bundle> displaylist = new ArrayList<Bundle>();
+
+    //    private SwipeMenuListView uploadList;
+    private ListView uploadList;
+    private uploadAdapter adapter;
+//    private ArrayList<Bundle> arr;
+
+    private RAUploadManager uploadManager;
+    private UploadService.MyBinder binder;
+    private UploadService uploadServiceservice;
+    private boolean serviceConnectionFlag = false; // 绑定服务标识
+    private ServiceConnection serviceConnection;
+    private RAUploadManager.UIUpdateListener uiUpdateListener = new RAUploadManager.UIUpdateListener() {
+//        @Override
+//        public void onProgress(long index, double percentage) {
+//
+//
+//            if(true)
+//            return;
+//
+//            final int position = (int)index;
+//            final double progress = percentage;
+//            runOnUiThread(new Runnable() {
+//                @Override
+//                public void run() {
+//                    Log.d("_LIST", "UploadImage onProgress: " + progress);
+//                    long timeStart = System.currentTimeMillis();
+////            Object item = uploadList.getItemAtPosition((int) index);
+//                    int startShowIndex = uploadList.getFirstVisiblePosition();
+//                    int lastShowIndex = uploadList.getLastVisiblePosition();
+//
+//                    if (position >= startShowIndex && position <= lastShowIndex) {
+//                        View cell = uploadList.getChildAt((int)position - startShowIndex);
+//                        uploadAdapter.ViewHolder holder= (uploadAdapter.ViewHolder)cell.getTag();
+//                        holder.progressBar.setProgress((int) (100 * progress));
+//                        holder.progress_tv.setText(String.format("%.1f%%",progress * 100));
+//                    }
+//
+//                    Log.d("_LIST", "UploadImage onProgress: end" + (System.currentTimeMillis() - timeStart));
+//                }
+//            });
+//
+//        }
+
+        @Override
+        public void updateCell(long index, final Bundle taskinfo)
+        {
+            if(true)
+                return;
+
+            if(true) {
+
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+
+                        adapter.notifyDataSetChanged();
+                    }
+                });
+
+                return;
+            }
+
+            final int position = (int)index;
+//            final double progress = arr.get(position).getDouble("progress");
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+
+                    double percent = taskinfo.getDouble("progress",0);
+
+//                    Log.d("_synchronized", "UploadImage onProgress: " + percent);
+                    long timeStart = System.currentTimeMillis();
+
+//            Object item = uploadList.getItemAtPosition((int) index);
+                    int startShowIndex = uploadList.getFirstVisiblePosition();
+                    int lastShowIndex = uploadList.getLastVisiblePosition();
+
+                    if (position >= startShowIndex && position <= lastShowIndex) {
+                        View cell = uploadList.getChildAt((int)position - startShowIndex);
+                        uploadAdapter.ViewHolder holder= (uploadAdapter.ViewHolder)cell.getTag();
+//                        holder.progressBar.setProgress((int) (100 * progress));
+//                        holder.progress_tv.setText(String.format("%.1f%%",progress * 100));
+
+
+                        RAUploadManager.TaskStatus istatus = RAUploadManager.TaskStatus.values()[taskinfo.getInt("status",0)];
+                        String status="";
+                        switch(istatus)
+                        {
+                            case TaskStatusStart:
+                                status="uploading";
+                                break;
+                            case TaskStatusStop:
+                                status="stop";
+                                break;
+                            case TaskStatusError:
+                                status="warning";
+                                break;
+                            case TaskStatusWait:
+                                status="waiting";
+                                break;
+                            case TaskStatusFinish:
+                                status="finish";
+                                break;
+
+                            default:
+                                status="warning";
+                                break;
+                        }
+
+
+                        Log.d("_LIST", "uploadlist UI update POSITION"+position +"    PROGRESS"+ percent*100);
+
+                        String err = taskinfo.getString("msg");
+                        String name = taskinfo.getString("file","");
+                        holder.name_tv.setText(name);
+                        holder.progressBar.setProgress((int)(100 *percent));
+                        holder.state_tv.setText(status);
+
+                        holder.progress_tv.setText(String.format("%.2f%%",100*percent));
+                        holder.err_tv.setText(err);
+                    }
+
+                    Log.d("_LIST", "uploadlist UI: COST" + (System.currentTimeMillis() - timeStart));
+                }
+            });
+        }
+        @Override
+//        public void updateList()
+        public void updateList(final ArrayList<Bundle> newlist)
+        {
+
+
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+
+                    Log.d("_LIST","running  tid="+ Thread.currentThread().getId());
+                    Log.d("_LIST", "uploadlist UI  size:  "+ newlist.size());
+                    long timeStart = System.currentTimeMillis();
+                    displaylist = (ArrayList<Bundle>) newlist.clone();
+                    adapter.notifyDataSetChanged();
+
+
+                    Log.d("_LIST", "uploadlist UI: COST" + (System.currentTimeMillis() - timeStart));
+                }
+            });
+
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_upload_list);
+
+        ActionBar mActionBar = getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle("RA Image");
+
+
+        // 初始化视图
+//        uploadList = (SwipeMenuListView)findViewById(R.id.upload_list);
+        uploadList = (ListView)findViewById(R.id.upload_list);
+        adapter = new uploadAdapter(R.layout.upload_list_cell);
+        uploadList.setAdapter(adapter);
+        serviceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                serviceConnectionFlag = true;
+
+                binder = (UploadService.MyBinder)service;
+                uploadServiceservice = binder.getService();
+
+
+
+
+                uploadManager = uploadServiceservice.uploadManager;
+                uploadManager.uiUpdateListener = uiUpdateListener;
+                displaylist = (ArrayList<Bundle>) uploadManager.get_arr_queue().clone(); //uploadManager.arr_queue;
+
+
+
+//                adapter.notifyDataSetChanged();
+//                runOnUiThread(new Runnable() {
+//                    @Override
+//                    public void run() {
+//                        adapter = new uploadAdapter(R.layout.upload_list_cell);
+//                        uploadList.setAdapter(adapter);
+//                    }
+//                });
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                serviceConnectionFlag = false;
+                uploadManager.uiUpdateListener = null;
+            }
+        };
+
+        bindService();
+
+//        SwipeMenuCreator creator = new SwipeMenuCreator() {
+//
+//            @Override
+//            public void create(SwipeMenu menu) {
+//                // Create different menus depending on the view type
+//                switch (menu.getViewType()) {
+//                    case 0: {
+//                        createRemoveMenuItem(menu);
+//                    }
+//                    break;
+//                    case 1: {
+//                        createStartMenuItem(menu);
+//                        createRemoveMenuItem(menu);
+//                    }
+//                    break;
+//                    case 2: {
+//                        createStartMenuItem(menu);
+//                    }
+//                    break;
+//                    case 3: {
+//
+//                    }
+//                    break;
+//                }
+//            }
+//        };
+//
+//        uploadList.setMenuCreator(creator);
+//
+//        uploadList.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() {
+//            @Override
+//            public boolean onMenuItemClick(int position, SwipeMenu menu, int index) {
+//                // action
+//                Bundle item = arr.get(position);
+//                int type = taskSwipeType(position);
+//                switch (type) {
+//                    case 0: {
+//                        if (index == 0) {
+//                            // remove
+//                            if (serviceConnectionFlag == true && uploadServiceservice != null) {
+//                                uploadManager.removeTask(item);
+//                            }
+//
+//                        }
+//                    }
+//                    break;
+//                    case 1: {
+//                        if (index == 0) {
+//                            // start
+//                            if (serviceConnectionFlag == true && uploadServiceservice != null) {
+//                                uploadManager.startTask(item);
+//                            }
+//
+//                        } else if (index == 1) {
+//                            // remove
+//                            if (serviceConnectionFlag == true && uploadServiceservice != null) {
+//                                uploadManager.removeTask(item);
+//                            }
+//
+//                        }
+//                    }
+//                    break;
+//                    case 2: {
+//                        if (index == 0) {
+//                            // start
+//                            if (serviceConnectionFlag == true && uploadServiceservice != null) {
+//                                uploadManager.startTask(item);
+//                            }
+//
+//                        }
+//                    }
+//                    break;
+//                    case 3: {
+//
+//                    }
+//                    break;
+//                }
+//
+//                return false;
+//            }
+//        });
+    }
+
+//    private void createRemoveMenuItem(SwipeMenu menu) {
+//        SwipeMenuItem openItem = new SwipeMenuItem(getApplicationContext());
+//        // set item background
+//        openItem.setBackground(new ColorDrawable(Color.rgb(0x9b, 0xbf,0x5a)));
+//        // set item width
+//        openItem.setWidth(dp2px(90));
+//        // set item title
+//        openItem.setTitle("Remove");
+//        // set item title fontsize
+//        openItem.setTitleSize(18);
+//        // set item title font color
+//        openItem.setTitleColor(Color.WHITE);
+//        // add to menu
+//        menu.addMenuItem(openItem);
+//    }
+//
+//    private void createStartMenuItem(SwipeMenu menu) {
+//        SwipeMenuItem openItem = new SwipeMenuItem(getApplicationContext());
+//        // set item background
+//        openItem.setBackground(new ColorDrawable(Color.rgb(0xff, 0x99,0x33)));
+//        // set item width
+//        openItem.setWidth(dp2px(90));
+//        // set item title
+//        openItem.setTitle("Restart");
+//        // set item title fontsize
+//        openItem.setTitleSize(18);
+//        // set item title font color
+//        openItem.setTitleColor(Color.WHITE);
+//        // add to menu
+//        menu.addMenuItem(openItem);
+//    }
+
+    @Override
+    protected void onDestroy() {
+
+        unbindService(serviceConnection);
+
+        super.onDestroy();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.upload_list_menu,menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home: {
+                finish();
+            }
+            break;
+            case R.id.clear_upload_list_btn: {
+//                for(int i=0;i<10;i++)
+//                runOnUiThread(new Runnable() {
+//                    @Override
+//                    public void run() {
+//
+//                        Log.d("_LIST","running  tid="+Thread.currentThread().getId());
+//                        Log.d("_LIST", "uploadlist UI  size:  "+ displaylist.size());
+//                        long timeStart = System.currentTimeMillis();
+////                        displaylist = (ArrayList<Bundle>) newlist.clone();
+//                        adapter.notifyDataSetChanged();
+//
+//
+//                        Log.d("_LIST", "uploadlist UI: COST" + (System.currentTimeMillis() - timeStart));
+//                    }
+//                });
+                clearUploadList();
+            }
+            break;
+        }
+        return true;
+    }
+
+    private void clearUploadList() {
+        if (displaylist.size() == 0) {
+            new AlertDialog.Builder(this)
+                    .setTitle("Warning")
+                    .setMessage("Upload list is empty.")
+                    .setPositiveButton("OK",null)
+                    .show();
+            return;
+        }
+
+        new AlertDialog.Builder(this)
+                .setTitle("Clear upload list")
+                .setMessage("Are you sure remove all error/finish task?")
+                .setPositiveButton("YES", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        // clear
+                        if (serviceConnectionFlag == true && uploadServiceservice != null) {
+                            uploadManager.clearTask();
+//                            adapter.notifyDataSetChanged();
+                        }
+
+                    }
+                })
+                .setNegativeButton("NO", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+
+                    }
+                })
+                .show();
+
+    }
+
+//
+//    private int taskSwipeType(int position) {
+//        Bundle item = arr.get(position);
+////        Bundle taskinfo = item.getBundle("params");
+//        RAUploadManager.TaskStatus istatus = RAUploadManager.TaskStatus.values()[item.getInt("status",0)];
+//        int type = 3;
+//        switch(istatus)
+//        {
+//            case TaskStatusWait:
+//            case TaskStatusStart:
+//                type = 3;
+//                break;
+//            case TaskStatusStop:
+//                type = 2;
+//                break;
+//            case TaskStatusError:
+//                type = 1;
+//                break;
+//            case TaskStatusFinish:
+//                type = 0;
+//                break;
+//            default:
+//                type = 3;
+//                break;
+//        }
+//        return type;
+//    }
+
+    private class uploadAdapter extends BaseAdapter {
+        private int resourceId;
+        public uploadAdapter(int resourceID) {
+
+            resourceId = resourceID;
+        }
+
+        @Override
+        public int getCount() {
+            return displaylist.size();
+        }
+
+        @Override
+        public Bundle getItem(int position) {
+            return displaylist.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+//        @Override
+//        public int getViewTypeCount() {
+//            return 4;
+//        }
+//
+//        @Override
+//        public int getItemViewType(int position) {
+//            /**
+//             * 0. <finish>      remove              </finish>
+//             * 1. <error>       start  remove       </error>
+//             * 2. <stop>        start               </stop>
+//             * 3. <start\wait>  none                </start\wait>
+//             * */
+//            return taskSwipeType(position);
+//        }
+
+        @NonNull
+        @Override
+        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+
+            Log.d("_LIST","running  tid="+ Thread.currentThread().getId());
+            long timeStart = System.currentTimeMillis();
+
+            final Bundle item = displaylist.get(position);
+//            Bundle taskinfo = item.getBundle("params");
+//            String barcode = taskinfo.getString("barcode");
+
+            RAUploadManager.TaskStatus istatus = RAUploadManager.TaskStatus.values()[item.getInt("status",0)];
+            String status="";
+            switch(istatus)
+            {
+                case TaskStatusStart:
+                    status="uploading";
+                    break;
+                case TaskStatusStop:
+                    status="stop";
+                    break;
+                case TaskStatusError:
+                    status="warning";
+                    break;
+                case TaskStatusWait:
+                    status="waiting";
+                    break;
+                case TaskStatusFinish:
+                    status="finish";
+                    break;
+
+                default:
+                    status="warning";
+                    break;
+            }
+            double percent = item.getDouble("progress",0);
+            String err = item.getString("msg");
+            String name = item.getString("file","");
+
+            View cell;
+            ViewHolder holder;
+            if (convertView != null) {
+
+                cell = convertView;
+                holder = (ViewHolder)cell.getTag();
+                Log.d("_LIST", "getView: " + holder);
+
+            } else  {
+//                cell = LayoutInflater.from(getApplicationContext()).inflate(resourceId,null);
+                cell = View.inflate(getApplicationContext(),resourceId,null);
+                holder = new ViewHolder();
+                holder.name_tv = (TextView)cell.findViewById(R.id.upload_name_tv);
+                holder.progressBar = (ProgressBar)cell.findViewById(R.id.upload_progressBar);
+                holder.state_tv = (TextView)cell.findViewById(R.id.upload_state_tv);
+                holder.progress_tv = (TextView)cell.findViewById(R.id.upload_progress_tv);
+                holder.err_tv = (TextView)cell.findViewById(R.id.upload_err_tv);
+                holder.btn_reload=(ImageButton) cell.findViewById(R.id.btn_reload);
+
+
+                holder.btn_reload.setImageResource(R.drawable.ic_action_reload);
+                if(istatus!= RAUploadManager.TaskStatus.TaskStatusError)
+                {
+                    holder.btn_reload.setVisibility(View.GONE);
+                }
+                else
+                {
+                    holder.btn_reload.setVisibility(View.VISIBLE);
+                    holder.btn_reload.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+
+                            uploadManager.startTask(item);
+
+                        }
+                    });
+                }
+                cell.setTag(holder);
+            }
+
+            holder.name_tv.setText(name);
+//            holder.progressBar.setProgress(100 *(int)percent);
+            holder.progressBar.setProgress((int) (100 * percent));
+            holder.state_tv.setText(status);
+//            holder.progress_tv.setText(100*percent+"%");
+            holder.progress_tv.setText(String.format("%.2f%%",100*percent));
+            holder.err_tv.setText(err);
+
+
+
+            Log.d("_LIST", "getView(): POSITION   "+position+" COST   " + (System.currentTimeMillis() - timeStart));
+            return cell;
+        }
+
+        private class ViewHolder {
+            public TextView name_tv;
+            public ProgressBar progressBar;
+            public TextView state_tv;
+            public TextView progress_tv;
+            public TextView err_tv;
+            public ImageButton btn_reload;
+        }
+    }
+
+
+    /** Service */
+    private void bindService() {
+        Intent intent = new Intent(UploadListActivity.this, UploadService.class);
+
+        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+    }
+
+    private int dp2px(int dp) {
+        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,getResources().getDisplayMetrics());
+    }
+}

+ 436 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/UploadQueueActivity.java

@@ -0,0 +1,436 @@
+package com.usai.redant.raimage;
+
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.util.Network;
+import com.usai.redant.util.dbgUtil;
+
+import java.io.File;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class UploadQueueActivity extends ListActivity
+{
+	private SQLiteDatabase m_db = null;
+	private Cursor m_cursor = null;
+	RecordsAdapter m_listadapter;
+	private TextView m_tvalert;
+	Timer timer = new Timer();
+	TimerTask task = new TimerTask()
+	{
+		boolean change = false;
+		public void run()
+		{
+		 
+			runOnUiThread(new Runnable()
+			{
+				public void run()
+				{
+					if (change)
+					{
+						change = false;
+						m_tvalert.setTextColor(Color.TRANSPARENT); // 这个是透明,=看不到文字
+					}
+					else
+					{
+						change = true;
+						m_tvalert.setTextColor(getResources().getColor(
+								R.color.message_success));
+					}
+				}
+			});
+		}
+	};
+	public class RecordsAdapter extends SimpleCursorAdapter
+	{
+
+
+		public RecordsAdapter(Context context, int layout, Cursor c,
+                              String[] from, int[] to)
+		{
+			
+			super(context, layout, c, from, to);
+			// TODO Auto-generated constructor stub
+		}
+
+		
+
+		@Override
+		public void bindView(View view, Context context, Cursor cursor)
+		{
+			 String path = cursor.getString(3);
+			 int err_code = cursor.getInt(1);
+
+			File f = new File(path);
+			final String filename=f.getName();
+		
+			final TextView filetext = (TextView) view.findViewById(R.id.filename);
+			filetext.setText(filename);
+			
+			final TextView err_codetext = (TextView) view.findViewById(R.id.err_code);
+			switch (err_code)
+			{
+				case Network.RESULT_LOCALFILE_ERROR:
+					err_codetext.setText("Local file error.");
+					break;
+				case Network.RESULT_NET_ERROR:
+					err_codetext.setText("Network error.");
+					break;
+				case Network.RESULT_USERAUTH_ERROR:
+					err_codetext.setText("User authorization error.");
+					break;
+				case Network.RESULT_ERROR:
+					err_codetext.setText("Unknown error.");
+					break;
+				case Network.RESULT_FALSE:
+					err_codetext.setText("Upload failed.");
+					break;
+				case Network.STATUS_WAIT:
+					err_codetext.setText("Wait for upload.");
+					break;
+			
+				default:
+					break;
+			}
+			super.bindView(view, context, cursor);
+
+	
+
+		}
+
+	}
+
+	@Override
+	protected void onDestroy()
+	{
+		unregisterReceiver(UploadQueueReceiver);
+//		dbUtil.CloseDB(m_db);
+		super.onDestroy();
+	}
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu)
+	{
+		// Inflate the menu; this adds items to the action bar if it is present.
+		getMenuInflater().inflate(R.menu.uploadqueue, menu);
+		return true;
+	}
+	
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item)
+	{
+		// TODO Auto-generated method stub
+		switch (item.getItemId())
+		{
+			case R.id.action_clearfailed:
+				dbgUtil.fileLog("menu item clear click , clear...");
+			//	clear();
+				
+				
+				new AlertDialog.Builder(
+						UploadQueueActivity.this)
+						.setIconAttribute(
+								android.R.attr.alertDialogIcon)
+						.setTitle(
+								R.string.confirm_to_delete)
+						.setMessage(
+								"Are you sure to clear error records?")
+						.setPositiveButton(
+								android.R.string.ok,
+								new DialogInterface.OnClickListener()
+								{
+									public void onClick(
+											DialogInterface dialog,
+											int whichButton)
+									{
+										
+//										SQLiteDatabase dbr = dbUtil.OpenDB(UploadQueueActivity.this, null, false);
+//										Cursor cursor = dbr.query("pics", new String[] { "_id",
+//												"local_path" }, "try_count>=3", null, null, null, "_id", null);
+//										while (cursor.moveToNext())
+//										{
+//											int _id = cursor.getInt(0);
+//											String path = cursor.getString(1);
+//
+//
+//											RedAntApplication.writeLock.lock();
+//
+//											// write sql process
+//											SQLiteDatabase dbw = dbUtil.OpenDB(UploadQueueActivity.this,
+//													null, true);
+//											dbw.execSQL("delete from pics where _id= "+_id);
+//
+//											String timeStamp = new SimpleDateFormat("yyyy_MM_dd")
+//													.format(new Date());
+//
+//											File storageDir = new File(Environment
+//													.getExternalStorageDirectory().getPath()
+//													+ "/redant/pop/done/" + timeStamp);
+//
+//											if (!storageDir.exists())
+//												storageDir.mkdirs();
+//
+//											File pic = new File(path);
+//
+//											pic.delete();
+//											dbUtil.CloseDB(dbw);
+//											RedAntApplication.writeLock.unlock();
+//
+//										}
+//
+//										dbUtil.CloseCursor(cursor);
+//										dbUtil.CloseDB(dbr);
+
+										sendBroadcast(new Intent("REDANT.POP.UPDATE_QUEUE_VIEW"));
+										sendBroadcast(new Intent("REDANT.POP.CLEAR_UPLOAD_QUEUE"));
+									}
+								})
+						.setNegativeButton(
+								android.R.string.cancel,
+								new DialogInterface.OnClickListener()
+								{
+									public void onClick(
+											DialogInterface dialog,
+											int whichButton)
+									{
+										// debug
+										// update_location();
+									}
+								})
+						.create()
+						.show();
+				break;
+
+			default:
+				break;
+		}
+		return super.onOptionsItemSelected(item);
+	}
+	@Override
+	protected void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+//		user = ApexTrackingApplication.get_user();
+//		
+//		password = ApexTrackingApplication.get_pass();
+//		function_name = getIntent().getStringExtra("function_name");
+		setContentView(R.layout.activity_search);
+//		m_db = dbUtil.OpenDB(this, null, true);
+		// m_TextView = (TextView) findViewById(R.id.summarytext);
+		// m_TextView.setText(getString(m_Activityinfo.TextViewValue));
+		// m_ListView = (ListView) findViewById(android.R.id.list);
+		m_cursor = m_db.query("pics", new String[] { "picker",
+				"err_code", "pid", "local_path","_id" }, null, null, null, null,
+				"_id", null);
+		startManagingCursor(m_cursor);
+		m_listadapter = new RecordsAdapter(this,
+		// Use a template that displays a text view
+				R.layout.search_lvitem_edit,
+				// Give the cursor to the list adatper
+				m_cursor,
+				// Map the NAME column in the people database to...
+				new String[] { "pid",  "picker" },
+				// The "text1" view defined in the XML template
+				new int[] { R.id.pidval, R.id.picker });
+		setListAdapter(m_listadapter);
+//		Button btnok = (Button) findViewById(R.id.btnok);
+//		btnok.setOnClickListener(this);
+//		Button btncancel = (Button) findViewById(R.id.btncancel);
+//		btncancel.setOnClickListener(this);
+//
+//		SharedPreferences RunOnce = getSharedPreferences("Apex", 0);
+
+//		String vername;
+//		try
+//		{
+//			vername = getPackageManager().getPackageInfo("com.usai.apex", 0).versionName;
+//			boolean bFirstRun = RunOnce.getBoolean("FirstRun" + vername
+//					+ "_search", true);
+//			if (bFirstRun)
+//			{
+//				SharedPreferences.Editor editor = RunOnce.edit();
+//				editor.putBoolean("FirstRun" + vername + "_search", false);
+//				// Don't forget to commit your edits!!!
+//				editor.commit();
+//				Intent intent = new Intent();
+//				intent.setClass(this, HelpActivity.class);
+//				intent.putExtra("caller", "search");
+//				startActivity(intent);
+//
+//			}
+//		}
+//		catch (NameNotFoundException e)
+//		{
+//			// TODO Auto-generated catch block
+//			e.printStackTrace();
+//		}
+		// initlist();
+
+		// m_ListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+
+		// m_listadapter = new FieldsAdapter(this, data, resource, from, to);
+
+		// m_listadapter = new RecordsAdapter(this,
+		// // Use a template that displays a text view
+		// m_iListItemID,
+		// // Give the cursor to the list adatper
+		// m_cursor,
+		// // Map the NAME column in the people database to...
+		// m_sDispFields,
+		// // The "text1" view defined in the XML template
+		// m_iViewIDs);
+		IntentFilter msgFilter = new IntentFilter();
+		
+		msgFilter.addAction("REDANT.POP.UPDATE_QUEUE_VIEW");
+		msgFilter.addAction("REDANT.POP.UPLOAD_STATE_TRUE");
+		msgFilter.addAction("REDANT.POP.UPLOAD_STATE_FALSE");
+		msgFilter.addAction("REDANT.POP.FINISH_UPLOAD_QUEUE");
+		
+		registerReceiver(UploadQueueReceiver, msgFilter);
+		
+		m_tvalert = (TextView) findViewById(R.id.tvalert);
+		m_tvalert.setSelected(true);
+
+		
+		//timer.schedule(task, 1, 300); // 参数分别是delay(多长时间后执行),duration(执行间隔)
+		sendBroadcast(new Intent("REDANT.POP.QUERY_UPLOAD_STATE"));
+		
+	}
+
+//	private void RefreshList()
+//	{
+//		// if (dbUtil.isRecordExist(m_db,
+//		// "user_numberlist","type = "+m_Activityinfo.NumberType))
+//		// {
+//		// m_TextView.setVisibility(ListView.INVISIBLE);
+//		// m_ListView.setVisibility(ListView.VISIBLE);
+//		//
+//		// }
+//		// else
+//		// {
+//		// m_TextView.setVisibility(ListView.VISIBLE);
+//		// m_ListView.setVisibility(ListView.INVISIBLE);
+//		// }
+//		hashMap.clear();
+//		m_cursor.requery();
+//	}
+
+	// private void initlist()
+	// {
+	// m_ListView = (ListView) findViewById(android.R.id.list);
+	// ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String,
+	// Object>>();
+	// HashMap<String, Object> map = null;
+	//
+	// String[] strings = { "alias", "type", "name" };// Map的key集合数组
+	// int[] ids = { R.id.aliasName, R.id.tv_type };// 对应布局文件的id
+	// SimpleAdapter simpleAdapter = new SimpleAdapter(this, list,
+	// R.layout.search_lvitem_edit, strings, ids);
+	//
+	// // listView1.setAdapter(simpleAdapter);//绑定适配器
+	// setListAdapter(simpleAdapter);
+	// }
+
+//	@Override
+//	public boolean onCreateOptionsMenu(Menu menu)
+//	{
+//		// Inflate the menu; this adds items to the action bar if it is present.
+//		getMenuInflater().inflate(R.menu.search, menu);
+//		return true;
+//	}
+
+//	@Override
+//	public boolean onOptionsItemSelected(MenuItem item)
+//	{
+//		Intent intent = new Intent();
+//		switch (item.getItemId())
+//		{
+//		case R.id.action_custom_fields:
+//			intent.setClass(this, CustomizeFieldsActivity.class);
+//			intent.putExtra("user", user);
+//			// intent.putExtra("password", password);
+//			intent.putExtra("function_name", function_name);
+//			intent.putExtra("behavior", Network.BEHAVIOR_SEARCH);
+//			startActivity(intent);
+//			break;
+//		case R.id.action_help:
+//			// Intent intent = new Intent();
+//			intent.setClass(this, HelpActivity.class);
+//			intent.putExtra("caller", "search");
+//			// // intent.putExtra("password", password);
+//			// intent.putExtra("function_name", function_name);
+//			// intent.putExtra("behavior", Network.BEHAVIOR_SEARCH);
+//			startActivity(intent);
+//			break;
+//		default:
+//			break;
+//		}
+//		return super.onOptionsItemSelected(item);
+//	}
+	private final BroadcastReceiver UploadQueueReceiver	= new BroadcastReceiver()
+	{
+
+		public void onReceive(
+				Context context,
+				Intent intent)
+		{
+			String action = intent
+					.getAction();
+			// 如果捕捉到的action是ACTION_BATTERY_CHANGED
+
+			if ("REDANT.POP.UPDATE_QUEUE_VIEW"
+					.equals(action))
+			{
+				m_cursor.requery();
+				
+
+			}
+			else if ("REDANT.POP.UPLOAD_STATE_FALSE"
+					.equals(action))
+			{
+				timer.cancel();
+				m_tvalert.setText("");
+//				m_tvalert.setTextColor(getResources().getColor(
+//						R.color.message_success));
+				
+				
+				
+			}
+			else if ("REDANT.POP.UPLOAD_STATE_TRUE"
+					.equals(action))
+			{
+				m_tvalert.setText("Uploading ...");
+				timer.schedule(task, 1, 300);
+				
+				
+			}
+			else if ("REDANT.POP.FINISH_UPLOAD_QUEUE"
+					.equals(action))
+			{
+				timer.cancel();
+				m_tvalert.setText("Finish upload.");
+				m_tvalert.setTextColor(getResources().getColor(
+						R.color.message_success));
+				
+				
+			}
+			
+		}
+	};
+	
+}

+ 552 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/UploadService.java

@@ -0,0 +1,552 @@
+package com.usai.redant.raimage;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.usai.redant.redantmobile.RedAntApplication;
+import com.usai.redant.util.RAUploadManager;
+import com.usai.redant.util.dbgUtil;
+
+import java.util.ArrayList;
+
+//import com.usai.redant.util.RAUploadManager;
+//import com.usai.redant.util.dbgUtil;
+
+public class UploadService extends Service
+{
+
+//	private UploadThread	uploadThread;
+
+    private boolean queue_changed = false;
+//	LocationManager			locationManager;
+//	LocationListener		locationListener;
+
+    public RAUploadManager uploadManager = new RAUploadManager();
+
+    // private boolean location_changed = false;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        // TODO Auto-generated method stub
+        Log.d("", "onBind: bind service");
+        return new MyBinder();
+    }
+
+
+    public class MyBinder extends Binder {
+        /**
+         * 获取当前Service的实例
+         *
+         * @return
+         */
+        public UploadService getService() {
+            return UploadService.this;
+        }
+    }
+
+    @Override
+    public void onCreate() {
+
+        Log.d("_SERVICE", "create upload Service!!!");
+//		if (uploadThread == null)
+//		{
+//			uploadThread = new UploadThread();
+//			Log.d("", "create upload thread!!!");
+//			// upleadThread.start();
+//
+//		}
+
+
+        // 初始化异常捕获器
+        CrashHandler.getSharedInstance().init(getApplicationContext());
+        CrashHandler.getSharedInstance().preserver = new CrashHandler.InfoPreserver() {
+            @Override
+            public void saveUserInformation() {
+                if (uploadManager != null) {
+                    uploadManager.saveTasks();
+                }
+            }
+
+            @Override
+            public void handleCrashInfo(String deviceInfo, String exception) {
+                dbgUtil.fileLog("============================ app crash ============================");
+                dbgUtil.fileLog("DEVICE");
+                dbgUtil.fileLog(deviceInfo);
+                dbgUtil.fileLog("EXCEPTION");
+                dbgUtil.fileLog(exception);
+                dbgUtil.fileLog("=============================== end ===============================");
+                Log.d("_SERVICE", "Device Info: " + deviceInfo);
+                Log.d("_SERVICE", "Crash Info: " + exception);
+            }
+        };
+
+        IntentFilter msgFilter = new IntentFilter();
+
+        msgFilter.addAction("REDANT.POP.MODIFY_QUEUE");
+//		msgFilter.addAction("REDANT.POP.GPS_ON");
+//		msgFilter.addAction("REDANT.POP.GPS_OFF");
+//		msgFilter.addAction("REDANT.POP.REQUEST_LOCATION");
+        msgFilter.addAction("REDANT.POP.RESET_LOCATION");
+        msgFilter.addAction("REDANT.POP.QUERY_UPLOAD_STATE");
+        msgFilter.addAction("REDANT.RAImage.ADD_TASK");
+        msgFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        msgFilter.addAction("REDANT.POP.RETRY_UPLOAD");
+
+        registerReceiver(uploadReceiver, msgFilter);
+        // registerReceiver(uploadReceiver,
+        // new IntentFilter("modify upload queue"));
+
+//		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+
+//		locationListener = new LocationListener()
+//		{
+//
+//			// Provider的状态在可用、暂时不可用和无服务三个状态直接切换时触发此函数
+//			@Override
+//			public void onStatusChanged(String provider, int status,
+//					Bundle extras)
+//			{
+//
+//			}
+//
+//			// Provider被enable时触发此函数,比如GPS被打开
+//			@Override
+//			public void onProviderEnabled(String provider)
+//			{
+//
+//			}
+//
+//			// Provider被disable时触发此函数,比如GPS被关闭
+//			@Override
+//			public void onProviderDisabled(String provider)
+//			{
+//
+//			}
+//
+//			// 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发
+//			@Override
+//			public void onLocationChanged(Location location)
+//			{
+//				// if (location != null)
+//				// {
+//				// location_changed = true;
+//				// Log.d("Map",
+//				// "Location changed : Lat: " + location.getLatitude()
+//				// + " Lng: " + location.getLongitude());
+//				// }
+//			}
+//		};
+
+        super.onCreate();
+
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.e("_SERVICE", "onDestroy: ");
+        uploadManager.saveTasks();
+    }
+//	void gps_off()
+//	{
+//		locationManager.removeUpdates(locationListener);
+//	}
+//
+//	void gps_on()
+//	{
+//		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
+//		{
+//
+////            RedAntApplication.getInstance()
+//
+////            if(!RAUtil.checkPermission(this.getApplicationContext(),"android.permission.ACCESS_FINE_LOCATION"))
+////                return;
+//
+//
+//
+//			locationManager.requestLocationUpdates(
+//					LocationManager.GPS_PROVIDER, 60 * 1000, 50,
+//					locationListener);
+//
+//		}
+//		else if (locationManager
+//				.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
+//		{
+//
+//			locationManager.requestLocationUpdates(
+//					LocationManager.NETWORK_PROVIDER, 30 * 1000, 50,
+//					locationListener);
+//
+//		}
+//	}
+
+//	void update_location()
+//	{
+//
+//		Location location = null;
+//		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
+//		{
+//
+//			location = locationManager
+//					.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+//
+//		}
+//		else if (locationManager
+//				.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
+//		{
+//
+//			location = locationManager
+//					.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+//
+//		}
+//
+//		SharedPreferences pref = RedAntApplication.getInstance()
+//				.getSharedPreferences("RA Image", 0);
+//
+//		SharedPreferences.Editor editor = pref.edit();
+//		if (location != null)
+//		{
+//
+//			editor.putFloat("Lat", (float) location.getLatitude());
+//			editor.putFloat("Lon", (float) location.getLongitude());
+//
+//		}
+//		editor.commit();
+//
+//	}
+//
+//	void check_location()
+//	{
+//
+//		Location location = null;
+//		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
+//		{
+//
+//			location = locationManager
+//					.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+//
+//		}
+//		else if (locationManager
+//				.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
+//		{
+//
+//			location = locationManager
+//					.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+//
+//		}
+//
+//		SharedPreferences pref = RedAntApplication.getInstance()
+//				.getSharedPreferences("RA Image", 0);
+//		double lat = pref.getFloat("Lat", 9999);
+//		double lon = pref.getFloat("Lon", 9999);
+//
+//		// SharedPreferences.Editor editor = pref.edit();
+//		if (location != null)
+//		{
+//			float[] result = new float[1];
+//			if (lat != 9999 && lon != 9999)
+//			{
+//				Location.distanceBetween(lat, lon, location.getLatitude(),
+//						location.getLongitude(), result);
+//				if (result[0] > 1000)
+//				{
+//					sendBroadcast(new Intent("REDANT.POP.STATION_CHANGE"));
+//					return;
+//				}
+//				else
+//				{
+//					sendBroadcast(new Intent("REDANT.POP.STATION_NOT_CHANGE"));
+//					return;
+//				}
+//			}
+//			sendBroadcast(new Intent("REDANT.POP.STATION_NOT_CHANGE"));
+//			return;
+//			// new Location();
+//			//
+//			// Location.distanceBetween(lat, lon, endLatitude, endLongitude,
+//			// results)
+//			//
+//			// editor.putFloat("Lat", (float) location.getLatitude());
+//			// editor.putFloat("Lon", (float) location.getLongitude());
+//
+//		}
+//		else
+//		{
+//			sendBroadcast(new Intent("REDANT.POP.STATION_NOT_CHANGE"));
+//			return;
+//		}
+//		// editor.commit();
+//
+//		// Log.d("location:", "lat:" + latitude + "lon:" + longitude);
+//	}
+
+    // void loadlist()
+    // {
+    //
+    // }
+
+//	public class UploadThread extends Thread
+//	{
+//		@Override
+//		public void run()
+//		{
+//
+//			Log.d("", "upload thread running");
+//
+//			super.run();
+//			doupload();
+//			Log.d("", "upload thread stop");
+//
+//		}
+//
+//		private void doupload()
+//		{
+//			boolean error = false;
+//			boolean didupload = false;
+//			// int verifyresult = Network.VerifyUser(RedAntApplication.user,
+//			// RedAntApplication.password);
+//			// if (verifyresult == Network.RESULT_TRUE)
+//			// {
+//			SQLiteDatabase dbr = dbUtil.OpenDB(UploadService.this, null, false);
+//			Cursor cursor = dbr.query("pics", new String[] { "_id", "pid",
+//					"local_path", "picker", "server" }, "err_code!="
+//					+ Network.AP_UPLOAD_SUCCESS+" and err_code!="+ Network.RESULT_LOCALFILE_ERROR+" and try_count<3 ", null, null, null, "_id", null);
+//			while (cursor.moveToNext())
+//			{
+//				didupload = true;
+//				if (queue_changed)
+//				{
+//					queue_changed = false;
+//					dbUtil.CloseCursor(cursor);
+//					cursor = dbr.query("pics", new String[] { "_id", "pid",
+//							"local_path", "picker", "server" }, "err_code!="
+//							+ Network.AP_UPLOAD_SUCCESS+" and err_code!="+ Network.RESULT_LOCALFILE_ERROR +" and try_count<3 ", null, null, null,
+//							"_id", null);
+//					if (!cursor.moveToNext())
+//						break;
+//
+//				}
+//				int _id = cursor.getInt(0);
+//				String pid = cursor.getString(1);
+//				String path = cursor.getString(2);
+//				String picker = cursor.getString(3);
+//				String server = cursor.getString(4);
+//
+//				String encryptUser = "";
+//
+//				try
+//				{
+//					encryptUser = AES.encrypt("apexu", picker);
+//
+//				}
+//				catch (Exception e1)
+//				{
+//					// TODO Auto-generated catch block
+//					e1.printStackTrace();
+//				}
+//
+//				Cursor cursor_user = dbr.query("users",
+//						new String[] { "pass" }, "name='" + encryptUser + "'",
+//						null, null, null, "_id", null);
+//				String pass = "";
+//				if (cursor_user.moveToNext())
+//					pass = cursor_user.getString(0);
+//				try
+//				{
+//					pass = AES.decrypt("apexp", pass);
+//				}
+//				catch (Exception e)
+//				{
+//					// TODO Auto-generated catch block
+//					e.printStackTrace();
+//				}
+//
+//				int uploadresult = Network.UploadImage(path, picker, pass, pid,
+//						server);
+//				if (uploadresult == Network.RESULT_TRUE)
+//				{
+//
+//					RedAntApplication.writeLock.lock();
+//
+//					// write sql process
+//					SQLiteDatabase dbw = dbUtil.OpenDB(UploadService.this,
+//							null, true);
+//					// String sql = "update pics set err_code ="
+//					// + Network.AP_UPLOAD_SUCCESS + " where _id="
+//					// + _id;
+//					String sql = "delete from pics  where _id=" + _id;
+//					dbw.execSQL(sql);
+//
+//					String timeStamp = new SimpleDateFormat("yyyy_MM_dd")
+//							.format(new Date());
+//
+//					File storageDir = new File(Environment
+//							.getExternalStorageDirectory().getPath()
+//							+ "/redant/pop/done/" + timeStamp);
+//
+//					if (!storageDir.exists())
+//						storageDir.mkdirs();
+//
+//					File pic = new File(path);
+//					// pic.delete();
+//
+//					dbUtil.CloseDB(dbw);
+//					RedAntApplication.writeLock.unlock();
+//					dbgUtil.fileLog("upload success move file "
+//							+ pic.getName()
+//							+ " to "
+//							+ Environment.getExternalStorageDirectory()
+//									.getPath() + "/redant/pop/done/"
+//							+ timeStamp + File.separator);
+//					pic.renameTo(new File(Environment
+//							.getExternalStorageDirectory().getPath()
+//							+ "/redant/pop/done/"
+//							+ timeStamp
+//							+ File.separator
+//							+ pic.getName()));
+//
+//
+//				}
+//				else
+//				{
+//					error = true;
+//					RedAntApplication.writeLock.lock();
+//
+//					{
+//						// write sql process
+//						SQLiteDatabase dbw = dbUtil.OpenDB(UploadService.this,
+//								null, true);
+//						String sql = "update pics set err_code ="
+//								+ uploadresult + ", try_count = try_count+1 where _id=" + _id;
+//
+//						dbw.execSQL(sql);
+//						dbUtil.CloseDB(dbw);
+//					}
+//					RedAntApplication.writeLock.unlock();
+//					dbgUtil.fileLog("upload failed pid:" + pid + " file:"
+//							+ path + " server:" + server + " err_code:"
+//							+ uploadresult);
+//
+//				}
+//
+//				sendBroadcast(new Intent("REDANT.POP.UPDATE_QUEUE_VIEW"));
+//			}
+//
+//			dbUtil.CloseCursor(cursor);
+//			dbUtil.CloseDB(dbr);
+//
+//			// }
+//			// else
+//			// {
+//			// Log.d("upload thread", "user check failed!");
+//			//
+//			// sendBroadcast(new Intent("REDANT.POP.USER_CHECK_FAILED"));
+//			// }
+//
+//			if (queue_changed)
+//			{
+//				queue_changed = false;
+//				doupload();
+//			}
+//			if (didupload)
+//			{
+//				if (error)
+//				{
+//					sendBroadcast(new Intent(
+//							"REDANT.POP.FINISH_UPLOAD_QUEUE_WITH_ERROR"));
+//					RedAntApplication.startalarm();
+//				}
+//				else
+//				{
+//					sendBroadcast(new Intent("REDANT.POP.FINISH_UPLOAD_QUEUE"));
+//					RedAntApplication.cancelalarm();
+//				}
+//			}
+//		}
+//	}
+
+    private BroadcastReceiver uploadReceiver = new BroadcastReceiver() {
+
+        public void onReceive(Context context, Intent intent) {
+            String action = intent
+                    .getAction();
+            // 如果捕捉到的action是ACTION_BATTERY_CHANGED
+
+            if ("REDANT.RAImage.ADD_TASK".equals(action)) {
+
+                ArrayList<Bundle> tasks = intent.getParcelableArrayListExtra("tasks");
+
+
+                uploadManager.addTasks(tasks);
+            } else if ("REDANT.RAImage.SAVE_TASK".equals(action)) {
+                uploadManager.stopAllTasks();
+            } else if (intent
+                    .getAction()
+                    .equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+
+                ConnectivityManager connManager = (ConnectivityManager) context
+                        .getSystemService(Context.CONNECTIVITY_SERVICE);
+
+                NetworkInfo networkInfo = connManager
+                        .getActiveNetworkInfo();
+                if (networkInfo == null) {
+                    dbgUtil.Logd(
+                            "Current Network info",
+                            "can not get Active NetworkInfo!");
+                    return;
+                }
+                NetworkInfo.State netState = networkInfo
+                        .getState();
+                if (netState != NetworkInfo.State.CONNECTED) {
+                    dbgUtil.Logd(
+                            "Current Network info",
+                            "not Connected!State="
+                                    + netState);
+                    return;
+                } else {
+                    int iconntype = -1;
+                    iconntype = networkInfo
+                            .getType();
+                    SharedPreferences pref = RedAntApplication
+                            .getInstance()
+                            .getSharedPreferences(
+                                    "UploadManager",
+                                    0);
+
+
+                    boolean
+                            wifi_only
+                            = pref.getBoolean("wifi_only",
+                            false);
+
+                    if
+                            (wifi_only
+                            == true
+                            && iconntype !=
+                            ConnectivityManager.TYPE_WIFI
+                            && iconntype !=
+                            9/* earthnet */) {
+                        uploadManager.stopAllTasks();
+//															 dbgUtil.Log(Log.DEBUG,
+//															 "Current Network info",
+//															 "not allowed!Connection type="
+//															 +
+//															 networkInfo.getTypeName());
+                        return;
+                    }
+                }
+
+
+            }
+        }
+    };
+}

+ 35 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/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.raimage;
+
+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.camera.CameraManager;
+import com.usai.redant.redantmobile.R;
+
+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();
+      }
+    }
+  }
+
+}

+ 197 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/raimage/uploadSettingActivity.java

@@ -0,0 +1,197 @@
+package com.usai.redant.raimage;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.EditText;
+import android.widget.Switch;
+
+import com.usai.redant.redantmobile.R;
+import com.usai.redant.redantmobile.RedAntApplication;
+import com.usai.redant.util.RAUploadManager;
+
+//import com.usai.redant.util.RAUploadManager;
+
+public class uploadSettingActivity extends AppCompatActivity {
+
+//    private Switch auto_start_swt;
+//    private Switch auto_rm_fs_swt;
+//    private Switch auto_rm_er_swt;
+    private Switch compress_swt;
+    private Switch sw_wifiOnly;
+    private EditText retry_count_et;
+    private EditText retry_waiting_et;
+
+    private ServiceConnection serviceConnection;
+    private boolean serviceConnectionFlag = false; // 绑定服务标识
+    private UploadService.MyBinder binder;
+    private UploadService uploadServiceservice;
+
+    public void initSetting() {
+//        boolean auto_upload = true;
+//        boolean auto_rm_fs = true;
+//        boolean auto_rm_er = false;
+        boolean compress = true;
+
+        boolean wifionly = false;
+        int retry_count = 5;
+
+        int retry_waiting = 300;
+//        SharedPreferences preferences = getSharedPreferences("uploadSetting", Context.MODE_PRIVATE);
+        SharedPreferences preferences = RedAntApplication.getInstance().getSharedPreferences("UploadManager", 0);
+        if (preferences != null) {
+
+//            auto_upload = preferences.getBoolean("auto_upload",true);
+//            auto_rm_fs = preferences.getBoolean("auto_rm_finish",true);
+//            auto_rm_er = preferences.getBoolean("auto_rm_error",false);
+
+            wifionly = preferences.getBoolean("wifi_only",false);
+            compress = preferences.getBoolean("compress",true);
+            retry_count = preferences.getInt("retry_count",5);
+            retry_waiting = preferences.getInt("retry_waiting",300);
+
+        } else  {
+
+        }
+
+
+        sw_wifiOnly.setChecked(wifionly);
+//        auto_start_swt.setChecked(auto_upload);
+//        auto_rm_fs_swt.setChecked(auto_rm_fs);
+//        auto_rm_er_swt.setChecked(auto_rm_er);
+        compress_swt.setChecked(compress);
+        retry_count_et.setText(String.valueOf(retry_count));
+        // 移动光标到末尾
+        retry_count_et.setSelection(retry_count_et.getText().length());
+
+        retry_waiting_et.setText(String.valueOf(retry_waiting));
+        // 移动光标到末尾
+        retry_waiting_et.setSelection(retry_waiting_et.getText().length());
+    }
+
+    /** Service */
+    private void bindService() {
+        Intent intent = new Intent(uploadSettingActivity.this, UploadService.class);
+
+        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+    }
+
+    public void saveSetting() {
+
+//        SharedPreferences preferences = getSharedPreferences("uploadSetting",Context.MODE_PRIVATE);
+        SharedPreferences preferences = RedAntApplication.getInstance().getSharedPreferences("UploadManager", 0);
+        SharedPreferences.Editor editor = preferences.edit();
+
+//        final boolean auto_upload = auto_start_swt.isChecked();
+//        final boolean auto_rm_fs = auto_rm_fs_swt.isChecked();
+//        final boolean auto_rm_er = auto_rm_er_swt.isChecked();
+
+        final boolean wifi_only = sw_wifiOnly.isChecked();
+        boolean compress = compress_swt.isChecked();
+        final int retry_count = Integer.parseInt(retry_count_et.getText().toString());
+        final int retry_waiting = Integer.parseInt(retry_waiting_et.getText().toString());
+
+//        editor.putBoolean("auto_upload",auto_upload);
+//        editor.putBoolean("auto_rm_finish",auto_rm_fs);
+//        editor.putBoolean("auto_rm_error",auto_rm_er);
+        editor.putBoolean("compress",compress);
+        editor.putInt("retry_count",retry_count);
+        editor.putInt("retry_waiting",retry_waiting);
+        editor.putBoolean("wifi_only",wifi_only);
+
+        editor.commit();
+
+        if (serviceConnectionFlag == true && uploadServiceservice != null) {
+            RAUploadManager uploadManager = uploadServiceservice.uploadManager;
+//            uploadManager.autoStart = auto_upload;
+//            uploadManager.removeFinish = auto_rm_fs;
+//            uploadManager.removeError = auto_rm_er;
+            uploadManager.maxRetry = retry_count;
+            uploadManager.retryWaiting = retry_waiting;
+            uploadManager.wifiOnly = wifi_only;
+        }
+
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_upload_setting);
+
+        // 同时修改 Upload Manager
+        serviceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                serviceConnectionFlag = true;
+
+                binder = (UploadService.MyBinder)service;
+                uploadServiceservice = binder.getService();
+
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                serviceConnectionFlag = false;
+            }
+        };
+
+        bindService();
+
+
+        sw_wifiOnly = (Switch)findViewById(R.id.sw_wifyonly);
+//        auto_start_swt = (Switch)findViewById(R.id.auto_start_swt);
+//        auto_rm_fs_swt = (Switch)findViewById(R.id.auto_rm_fs_swt);
+//        auto_rm_er_swt = (Switch)findViewById(R.id.auto_rm_er_swt);
+        compress_swt = (Switch)findViewById(R.id.compress_swt);
+        retry_count_et = (EditText)findViewById(R.id.retry_et);
+        retry_waiting_et = (EditText)findViewById(R.id.waiting_et);
+
+        initSetting();
+
+        ActionBar mActionBar=getSupportActionBar();
+        mActionBar.setHomeButtonEnabled(true);
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+        mActionBar.setTitle("RA Image");
+    }
+
+    @Override
+    protected void onDestroy() {
+        unbindService(serviceConnection);
+        super.onDestroy();
+    }
+
+    @Override
+    public boolean onSupportNavigateUp() {
+        return super.onSupportNavigateUp();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.upload_setting_menu,menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.save_upload_setting_item : {
+                saveSetting();
+                finish();
+            }
+            break;
+            case android.R.id.home : {
+                finish();
+            }
+            break;
+        }
+        return true;
+    }
+}

+ 684 - 2
RedAnt Mobile/app/src/main/java/com/usai/redant/redantmobile/LoginActivity.java

@@ -1,13 +1,695 @@
 package com.usai.redant.redantmobile;
 
-import android.support.v7.app.AppCompatActivity;
+import android.Manifest;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.TargetApi;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+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.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.EditText;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.usai.redant.raimage.ModeActivity;
+import com.usai.redant.raimage.ServerSettingActivity;
+import com.usai.redant.util.AES;
+import com.usai.redant.util.Network;
+import com.usai.redant.util.RAUtil;
+import com.usai.redant.util.dbgUtil;
+
+import org.json.JSONObject;
+
+import java.util.HashSet;
 
 public class LoginActivity extends AppCompatActivity {
 
+
+    private UserLoginTask			mAuthTask	= null;
+//    ArrayAdapter<String> adapter		= null;
+
+    // Values for email and password at the time of the login attempt.
+    private String					m_sName;
+    private String					m_sPassword;
+
+    // UI references.
+    private AutoCompleteTextView m_etName;
+    private EditText m_etPassword;
+    private EditText	m_etServer;
+    //    private View					mLoginFormView;
+    private View mLoginStatusView;
+    private TextView mLoginStatusMessageView;
+    private Switch m_swSave;
+    /**
+     * Represents an asynchronous login/registration task used to authenticate
+     * the user.
+     * the user.
+     */
+    public class UserLoginTask extends AsyncTask<Void, Void, Boolean>
+    {
+        // int err_code = ERR_CODE_NONE;
+        JSONObject json	= null;
+
+        // int netconnect;
+
+        @Override
+        protected Boolean doInBackground(Void... params)
+        {
+
+            json = Network.Login(m_sName, m_sPassword);
+            try {
+                if (json.getInt("result") == Network.RESULT_TRUE)
+                    return true;
+                else
+                    return false;
+            } catch (Exception e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+
+        @Override
+        protected void onPostExecute(final Boolean success)
+        {
+            Log.i("onPostExecute", "entry");
+            mAuthTask = null;
+            showProgress(false);
+
+            if (success)
+            {
+                String encryptUser = "";
+                String encryptPass = "";
+                try
+                {
+                    encryptUser = AES.encrypt("usai2010", m_sName);
+                    encryptPass = AES.encrypt("usai2010", m_sPassword);
+                }
+                catch (Exception e1)
+                {
+                    // TODO Auto-generated catch block
+                    e1.printStackTrace();
+                }
+
+                /*SQLiteDatabase db = dbUtil.OpenDB(LoginActivity.this, null,
+                        true);
+                Cursor cursor = db.query("users", new String[] { "_id" },
+                        "name='" + encryptUser + "'", null, null, null, "_id",
+                        null);
+                if (cursor.moveToNext())
+                {
+                    int _id = cursor.getInt(0);
+                    String sql = "update users set pass='" + encryptPass
+                            + "' where _id=" + _id;
+                    db.execSQL(sql);
+                }
+                else
+                {
+                    String sql = "insert into users(name,pass) values('"
+                            + encryptUser + "','" + encryptPass + "')";
+                    db.execSQL(sql);
+                }
+                dbUtil.CloseCursor(cursor);
+                dbUtil.CloseDB(db);*/
+
+                SharedPreferences pref = RedAntApplication.getInstance()
+                        .getSharedPreferences("RA Image", 0);
+                SharedPreferences.Editor editor = pref.edit();
+
+                if (m_swSave.isChecked()&&!TextUtils.isEmpty(encryptPass)&&!TextUtils.isEmpty(encryptUser))
+                {
+                    editor.putString("user", encryptUser);
+                    editor.putString("password", encryptPass);
+                    editor.putBoolean("kepppass", true);
+                }
+                else
+                {
+                    editor.putString("user", null);
+                    editor.putString("password", null);
+                    editor.putBoolean("kepppass", false);
+                }
+
+
+
+
+
+                HashSet<String> user_list= (HashSet<String>) pref.getStringSet("user_list",new HashSet<String>());
+                user_list.add(m_sName);
+                editor.putStringSet("user_list",user_list);
+
+                editor.commit();
+
+                RedAntApplication.user = m_sName;
+                RedAntApplication.password = m_sPassword;
+                RedAntApplication.server_info = json;
+                Intent intent = new Intent();
+                intent.setClass(LoginActivity.this, ModeActivity.class);
+
+                dbgUtil.fileLog("user "+m_sName+" login @server "+RedAntApplication.active_address);
+                startActivity(intent);
+                finish();
+            }
+            else
+            {
+                int result = 0;
+                try {
+                    result = json.getInt("result");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    result = Network.RESULT_NET_ERROR;
+
+                }
+                switch (result)
+                {
+                    case Network.RESULT_NET_ERROR:
+                    case Network.RESULT_NET_NOTAVAILABLE:
+                    {
+
+                        {// user not exist
+                            Toast toast = Toast.makeText(
+                                    getApplicationContext(),
+                                    getText(R.string.msg_net_error),
+                                    Toast.LENGTH_LONG);
+                            toast.setGravity(Gravity.CENTER, 0, 0);
+                            toast.show();
+                            m_etPassword
+                                    .setError(null);
+                            m_etPassword.requestFocus();
+                          /*  dbUtil.CloseCursor(cursor);
+                            dbUtil.CloseDB(db);*/
+
+                        }
+
+                        break;
+                    }
+                    default:
+//                    case Network.RESULT_FALSE:
+                    {
+                        Toast toast = Toast.makeText(getApplicationContext(),
+                                getText(R.string.msg_user_wrong),
+                                Toast.LENGTH_LONG);
+                        toast.setGravity(Gravity.CENTER, 0, 0);
+                        toast.show();
+                        m_etPassword
+                                .setError(getString(R.string.error_incorrect_password));
+                        m_etPassword.requestFocus();
+                        return;
+                    }
+
+                }
+
+            }
+        }
+
+        @Override
+        protected void onCancelled()
+        {
+            mAuthTask = null;
+            showProgress(false);
+        }
+    }
+
+
+    /**
+     * 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);
+        }
+    }
+    /**
+     * 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 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_sName = m_etName.getText().toString();
+        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_sName))
+        {
+            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 LoginActivity.UserLoginTask();
+            mAuthTask.execute((Void) null);
+        }
+    }
+
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (resultCode == 1001 && data != null) {
+            String server=data.getStringExtra("server");
+            m_etServer.setText(server);
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState)
+    {
+
+
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_login);
+
+//        ActionBar actionBar = getActionBar();
+//        if (actionBar != null) {
+//            actionBar.hide();
+//        }
+
+
+        TextView tv_ver = (TextView) findViewById(R.id.tv_ver);
+        try
+        {
+
+            tv_ver.setText(getText(R.string.str_ver)
+                    + RedAntApplication.getInstance()
+                    .getPackageManager()
+                    .getPackageInfo("com.usai.redant.redantmobile", 0).versionName);
+        }
+        catch (PackageManager.NameNotFoundException e1)
+        {
+            // TODO Auto-generated catch block
+            e1.printStackTrace();
+        }
+
+
+
+        m_etServer = (EditText) findViewById(R.id.et_server);
+        // m_etName.setText(m_sName);
+
+        m_etPassword = (EditText) findViewById(R.id.et_pwd);
+
+        m_swSave = (Switch) findViewById(R.id.sw_save);
+
+        m_etName = (AutoCompleteTextView) findViewById(R.id.et_user);
+
+        SharedPreferences pref = RedAntApplication.getInstance()
+                .getSharedPreferences("RA Image", 0);
+
+
+        HashSet<String> user_list= (HashSet<String>) pref.getStringSet("user_list",new HashSet<String>());
+        user_list.toArray(new String[0]);
+
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, user_list.toArray(new String[0]));
+        m_etName.setAdapter(adapter);
+
+
+        m_etName.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                m_etPassword.setText("");
+            }
+        });
+//        m_etName.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+//            @Override
+//            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+//
+//                m_etPassword.setText("");
+//            }
+//
+//            @Override
+//            public void onNothingSelected(AdapterView<?> parent) {
+//
+//            }
+//        });
+
+
+
+        String u = pref.getString("user", null);
+        String p = pref.getString("password", null);
+        String s = pref.getString("aa", null);
+        if (u != null && p != null)
+        {
+            try
+            {
+                m_etName.setText(AES.decrypt("usai2010", u));
+                m_etPassword.setText(AES.decrypt("usai2010", p));
+                m_swSave.setChecked(true);
+            }
+            catch (Exception e)
+            {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+
+        }
+
+        m_etServer.setText(s);
+
+        m_etPassword
+                .setOnEditorActionListener(new TextView.OnEditorActionListener()
+                {
+                    @Override
+                    public boolean onEditorAction(TextView textView, int id,
+                                                  KeyEvent keyEvent)
+                    {
+                        if (id == R.id.bt_login
+                                || id == EditorInfo.IME_ACTION_DONE)
+                        {
+                            InputMethodManager inputMethodManager = (InputMethodManager) getApplicationContext()
+                                    .getSystemService(INPUT_METHOD_SERVICE);
+
+                            // EditText editText =
+                            // (EditText)findViewById(R.id.xxxx);
+                            inputMethodManager.hideSoftInputFromWindow(
+                                    m_etPassword.getWindowToken(), 0); // ����
+                            attemptLogin();
+                            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.bt_login).setOnClickListener(
+                new View.OnClickListener()
+                {
+                    @Override
+                    public void onClick(View view)
+                    {
+
+                        attemptLogin();
+                    }
+                });
+
+
+        findViewById(R.id.bt_server).setOnClickListener(
+                new View.OnClickListener()
+                {
+                    @Override
+                    public void onClick(View view)
+                    {
+                        Intent intent = new Intent();
+                        intent.setClass(LoginActivity.this,ServerSettingActivity.class);
+//                        startActivity(intent);
+
+//                        Intent intent = new Intent(MainActivity.this,
+//                                PhotoPreviewActivity.class);
+//                        intent.putExtra("pic_list", (Serializable) photoList);
+                        startActivityForResult(intent, 0);
+
+                    }
+                });
+
+
+//        if(TextUtils.isEmpty(RedAntApplication.station_name))
+//        {
+//            Intent intent = new Intent();
+//            intent.setClass(FullScreenLoginActivity.this,ServerSettingActivity.class);
+////            startActivity(intent);
+//            startActivityForResult(intent, 0);
+//        }
+        boolean pop = checkAllPermission();
+        if(!pop)
+        {
+            if(TextUtils.isEmpty(RedAntApplication.station_name))
+            {
+                Intent intent = new Intent();
+                intent.setClass(LoginActivity.this,ServerSettingActivity.class);
+//            startActivity(intent);
+                startActivityForResult(intent, 0);
+            }
+        }
+
     }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+
+//        if (!granted) {
+////            new AlertDialog.Builder(this)
+////                    .setTitle("Warning")
+////                    .setMessage("RA Image need some permission")
+////                    .setPositiveButton("Setting", new DialogInterface.OnClickListener() {
+////                        @Override
+////                        public void onClick(DialogInterface dialog, int which) {
+////                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+////                            intent.setData(Uri.parse("package:" + getPackageName()));
+////                            startActivity(intent);
+////                        }
+////                    })
+////                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
+////                        @Override
+////                        public void onClick(DialogInterface dialog, int which) {
+////                            finish();
+////                        }
+////                    })
+////                    .show();
+//        }
+
+    }
+
+    public boolean checkAllPermission() {
+
+
+
+        String[] permissions = {
+                Manifest.permission.CAMERA,
+//                Manifest.permission.VIBRATE,
+                Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                Manifest.permission.READ_EXTERNAL_STORAGE,
+//                Manifest.permission.RECEIVE_BOOT_COMPLETED,
+//                Manifest.permission.ACCESS_NETWORK_STATE,
+//                Manifest.permission.ACCESS_WIFI_STATE,
+//                Manifest.permission.INTERNET,
+//                Manifest.permission.ACCESS_FINE_LOCATION,
+//
+//                Manifest.permission.CHANGE_CONFIGURATION
+
+
+
+        };
+
+
+
+//        RAUtil.checkPermissions1(this,permissions);
+        boolean ret = true;
+//        for(String permission : permissions) {
+//            boolean granted = ;
+//            if (!granted) {
+//                ret= false;
+//            }
+//        }
+
+
+        return RAUtil.checkPermissions(this,permissions);
+
+//        return ret;
+    }
+
+
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
+    {
+
+        if (requestCode == RAUtil.MY_PERMISSIONS_REQUEST)
+        {
+            boolean missing=false;
+            boolean request = false;
+            for(int i=0;i<grantResults.length;i++)
+            {
+
+                if(grantResults[i]!=PackageManager.PERMISSION_GRANTED)
+                    missing=true;
+                boolean bshow= ActivityCompat.shouldShowRequestPermissionRationale(this,permissions[i]);
+                if(bshow)
+                    request = true;
+            }
+
+            String msg=null;
+            if(request)
+                msg="RA Image needs some essential permissions.";
+            else
+                msg="RA Image will quit because missing some essential permissions.\nPlease check your system setting.";
+
+            if(missing) {
+                final boolean finalRequest = request;
+                new AlertDialog.Builder(this)
+                        .setTitle("Warning")
+                        .setMessage(msg)
+                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+//                                checkAllPermission();
+                                if (finalRequest)
+                                    checkAllPermission();
+                                else
+                                    finish();
+                            }
+                        })
+//                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
+//                        @Override
+//                        public void onClick(DialogInterface dialog, int which) {
+//                            finish();
+//                        }
+//                    })
+                        .show();
+            }
+            else
+            {
+                if(TextUtils.isEmpty(RedAntApplication.station_name))
+                {
+                    Intent intent = new Intent();
+                    intent.setClass(LoginActivity.this,ServerSettingActivity.class);
+//            startActivity(intent);
+                    startActivityForResult(intent, 0);
+                }
+            }
+//            if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
+//            {
+//               // callPhone();
+//            } else
+//            {
+//
+//
+//                            new AlertDialog.Builder(this)
+//                    .setTitle("Warning")
+//                    .setMessage("RA Image missing essential permission")
+//                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+//                        @Override
+//                        public void onClick(DialogInterface dialog, int which) {
+//                            checkAllPermission();
+//                        }
+//                    })
+////                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
+////                        @Override
+////                        public void onClick(DialogInterface dialog, int which) {
+////                            finish();
+////                        }
+////                    })
+//                    .show();
+//
+//                // Permission Denied
+//               // Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
+//            }
+            return;
+        }
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+    }
+
+//    public boolean checkPermission(String per) {
+//        int permission = ContextCompat.checkSelfPermission(FullScreenLoginActivity.this, per);
+//        if (permission == PackageManager.PERMISSION_DENIED) {
+//
+//            return false;
+//        }
+//        return true;
+//    }
 }

+ 129 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/redantmobile/RedAntApplication.java

@@ -0,0 +1,129 @@
+package com.usai.redant.redantmobile;
+
+import android.app.AlarmManager;
+import android.app.Application;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.usai.redant.raimage.UploadService;
+
+import org.json.JSONObject;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class RedAntApplication extends Application
+{
+    private static RedAntApplication instance;  
+    public static ReadWriteLock lock = new ReentrantReadWriteLock(true);
+    public static ReadWriteLock loglock = new ReentrantReadWriteLock(true);
+    public static Lock logwritelock   = loglock.writeLock();
+    public static Lock writeLock   = lock.writeLock();
+    public static String user;
+    public static String password;
+    public static String active_address;
+    public static String station_name;
+	public static String device_id;
+	public static JSONObject server_info;
+
+    public static RedAntApplication getInstance() {  
+        return instance;  
+    }  
+	public static void startalarm()
+	{
+
+		Intent iAlarm = new Intent("REDANT.POP.RETRY_UPLOAD");
+		//iAlarm.putExtra("caller", caller);
+//		iAlarm.setAction("com.usai.apex.push");
+		PendingIntent sender = PendingIntent.getBroadcast(getInstance(), 0,
+				iAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
+
+		long firstime = SystemClock.elapsedRealtime();
+//		UpdateLastAlermTime();
+		AlarmManager am = (AlarmManager) getInstance().getSystemService(
+				Context.ALARM_SERVICE);
+
+		// 5分钟一个周期,不停的发送广播
+		am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstime,
+				300 * 1000, sender);
+		Log.d("redant pop","start alarm");
+	}
+
+	public static void cancelalarm()
+	{
+
+		// 启动完成
+		Intent iAlarm = new Intent("REDANT.POP.RETRY_UPLOAD");
+//		iAlarm.setAction("com.usai.apex.push");
+		PendingIntent sender = PendingIntent.getBroadcast(getInstance(), 0,
+				iAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
+
+		AlarmManager am = (AlarmManager) getInstance().getSystemService(
+				Context.ALARM_SERVICE);
+
+		am.cancel(sender);
+		Log.d("redant pop","cancel alarm");
+	}
+    @Override
+    public void onCreate() {  
+        // TODO Auto-generated method stub
+		Log.d("_RAIMAGE", "onCreate: RedAntApplication");
+		super.onCreate();
+        instance = this;
+
+
+
+//		TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
+//		String DEVICE_ID = tm.getDeviceId();
+//		if(TextUtils.isEmpty(RedAntApplication.user))
+//			DEVICE_ID= Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID);
+
+
+		device_id= Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
+        
+		SharedPreferences pref = RedAntApplication.getInstance()
+				.getSharedPreferences("RA Image", 0);
+
+		String aa = pref.getString("aa", null);
+		String name = pref.getString("station name", null);
+		if(!TextUtils.isEmpty(aa))
+			active_address = aa;
+		if(!TextUtils.isEmpty(name))
+			station_name = name;
+        
+        
+		Intent intentservice = new Intent();
+		intentservice.setClass( this, UploadService.class);
+//		if (intent.getExtras() != null)
+//			intentservice.putExtras(intent.getExtras());
+//		intentservice.setAction(intent.getAction());
+		startService(intentservice);
+		
+
+
+
+
+		
+		
+    }
+
+	@Override
+	public void onTerminate() {
+		Log.d("_RAIMAGE", "onTerminate: RedAntApplication");
+		super.onTerminate();
+	}
+
+	@Override
+	protected void finalize() throws Throwable {
+
+		Log.d("_RAIMAGE", "finalize: RedAntApplication");
+		super.finalize();
+	}
+}

+ 242 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/AES.java

@@ -0,0 +1,242 @@
+package com.usai.redant.util;
+
+import android.util.Base64;
+import android.util.Log;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.util.Arrays;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import static android.content.ContentValues.TAG;
+
+/**
+ * Created by ray on 07/06/2017.
+ * AES128 算法
+ *
+ * CBC 模式
+ *
+ * PKCS7Padding 填充模式
+ *
+ * CBC模式需要添加一个参数iv
+ *
+ * 介于java 不支持PKCS7Padding,只支持PKCS5Padding 但是PKCS7Padding 和 PKCS5Padding 没有什么区别
+ * 要实现在java端用PKCS7Padding填充,需要用到bouncycastle组件来实现
+ */
+
+public class AES {
+    // 算法名称
+    final static String KEY_ALGORITHM = "AES";
+    // 加解密算法/模式/填充方式
+    final static String algorithmStr = "AES/CBC/PKCS7Padding";
+    //
+//    private Key key;
+//    private Cipher cipher;
+//    boolean isInited = false;
+
+    static byte[] iv = new byte[16];//{ 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38 };
+//    private static void init(byte[] keyBytes) {
+//
+//        // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
+//        int base = 16;
+//        if (keyBytes.length % base != 0) {
+//            int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
+//            byte[] temp = new byte[groups * base];
+//            Arrays.fill(temp, (byte) 0);
+//            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
+//            keyBytes = temp;
+//        }
+//        // 初始化
+//        Security.addProvider(new BouncyCastleProvider());
+//        // 转化成JAVA的密钥格式
+//        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
+//        try {
+//            // 初始化cipher
+//            cipher = Cipher.getInstance(algorithmStr, "BC");
+//        } catch (NoSuchAlgorithmException e) {
+//            // TODO Auto-generated catch block
+//            e.printStackTrace();
+//        } catch (NoSuchPaddingException e) {
+//            // TODO Auto-generated catch block
+//            e.printStackTrace();
+//        } catch (NoSuchProviderException e) {
+//            // TODO Auto-generated catch block
+//            e.printStackTrace();
+//        }
+//    }
+
+    private static String toHex(byte[] buf)
+    {
+        if (buf == null)
+            return "";
+        StringBuffer result = new StringBuffer(2 * buf.length);
+        for (int i = 0; i < buf.length; i++)
+        {
+            appendHex(result, buf[i]);
+        }
+        return result.toString();
+    }
+    private static void appendHex(StringBuffer sb, byte b)
+    {
+        sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
+    }
+    private final static String HEX = "0123456789ABCDEF";
+
+    public static String encrypt(String key, String content)
+    {
+        byte[] result=encrypt(content.getBytes(),key.getBytes());
+        Log.d(TAG, "encrypt: "+toHex(result));
+        return Base64.encodeToString(result, Base64.DEFAULT);
+    }
+
+    public static String decrypt(String key, String content)
+    {
+        byte[] buffer = Base64.decode(content, Base64.DEFAULT);
+
+        byte[] result = decrypt(buffer,key.getBytes());
+
+        return new String(result);
+    }
+
+    /**
+     * 加密方法
+     *
+     * @param content
+     *            要加密的字符串
+     * @param keyBytes
+     *            加密密钥
+     * @return
+     */
+    private static byte[] encrypt(byte[] content, byte[] keyBytes) {
+        byte[] encryptedText = null;
+//        init(keyBytes);
+
+     Key key;
+     Cipher cipher;
+        // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
+        int base = 16;
+        if (keyBytes.length % base != 0) {
+            int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
+            byte[] temp = new byte[groups * base];
+            Arrays.fill(temp, (byte) 0);
+            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
+            keyBytes = temp;
+        }
+        // 初始化
+        Security.addProvider(new BouncyCastleProvider());
+        // 转化成JAVA的密钥格式
+        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
+        try {
+            // 初始化cipher
+            cipher = Cipher.getInstance(algorithmStr, "BC");
+
+
+            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
+            encryptedText = cipher.doFinal(content);
+
+        } catch (NoSuchAlgorithmException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (NoSuchPaddingException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (NoSuchProviderException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (BadPaddingException e) {
+            e.printStackTrace();
+        } catch (InvalidKeyException e) {
+            e.printStackTrace();
+        } catch (IllegalBlockSizeException e) {
+            e.printStackTrace();
+        } catch (InvalidAlgorithmParameterException e) {
+            e.printStackTrace();
+        }
+
+
+//        System.out.println("IV:" + new String(iv));
+//        try {
+//
+//        } catch (Exception e) {
+//            // TODO Auto-generated catch block
+//            e.printStackTrace();
+//        }
+        return encryptedText;
+    }
+    /**
+     * 解密方法
+     *
+     * @param encryptedData
+     *            要解密的字符串
+     * @param keyBytes
+     *            解密密钥
+     * @return
+     */
+    private static byte[] decrypt(byte[] encryptedData, byte[] keyBytes) {
+        byte[] encryptedText = null;
+//        init(keyBytes);
+
+        Key key;
+        Cipher cipher;
+                // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
+        int base = 16;
+        if (keyBytes.length % base != 0) {
+            int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
+            byte[] temp = new byte[groups * base];
+            Arrays.fill(temp, (byte) 0);
+            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
+            keyBytes = temp;
+        }
+        // 初始化
+        Security.addProvider(new BouncyCastleProvider());
+        // 转化成JAVA的密钥格式
+        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
+        try {
+            // 初始化cipher
+            cipher = Cipher.getInstance(algorithmStr, "BC");
+            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
+            encryptedText = cipher.doFinal(encryptedData);
+        } catch (NoSuchAlgorithmException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (NoSuchPaddingException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (NoSuchProviderException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (BadPaddingException e) {
+            e.printStackTrace();
+        } catch (InvalidKeyException e) {
+            e.printStackTrace();
+        } catch (IllegalBlockSizeException e) {
+            e.printStackTrace();
+        } catch (InvalidAlgorithmParameterException e) {
+            e.printStackTrace();
+        }
+
+//        System.out.println("IV:" + new String(iv));
+//        try {
+//
+//        } catch (Exception e) {
+//            // TODO Auto-generated catch block
+//            e.printStackTrace();
+//        }
+
+        return encryptedText;
+    }
+
+
+}

+ 43 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/MD5.java

@@ -0,0 +1,43 @@
+package com.usai.redant.util;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.security.MessageDigest;
+
+public class MD5 {
+    private static final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+'A', 'B', 'C', 'D', 'E', 'F' };
+
+    public static void main(String[] args)
+    {
+        System.out.println(md5sum("/init.rc"));
+    }
+
+    public static String toHexString(byte[] b) {
+        StringBuilder sb = new StringBuilder(b.length * 2);
+        for (int i = 0; i < b.length; i++) {
+            sb.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]);
+            sb.append(HEX_DIGITS[b[i] & 0x0f]);
+        }
+        return sb.toString();
+    }
+
+    public static String md5sum(String filename) {
+        InputStream fis;
+        byte[] buffer = new byte[1024];
+        int numRead = 0;
+        MessageDigest md5;
+        try{
+            fis = new FileInputStream(filename);
+            md5 = MessageDigest.getInstance("MD5");
+            while((numRead=fis.read(buffer)) > 0) {
+                md5.update(buffer,0,numRead);
+            }
+            fis.close();
+            return toHexString(md5.digest());  
+        } catch (Exception e) {
+            System.out.println("error");
+            return null;
+        }
+    }
+}

+ 1627 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/Network.java

@@ -0,0 +1,1627 @@
+package com.usai.redant.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.usai.redant.redantmobile.RedAntApplication;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+public class Network
+{
+	private static final int	REQUEST_TIMEOUT					= 15 * 1000;			// request
+																						// time
+																						// out
+																						// 20
+																						// secs
+	private static final int	SO_TIMEOUT						= 15 * 1000;			// so
+																						// time
+																						// out
+																						// 20
+																						// secs;
+
+	private static final int	UPLOAD_TIMEOUT						= 30 * 1000;
+	public static int			AP_USER_AUTH					= 1;
+	public static int			AP_USER_NOT_AUTH				= 2;
+	public static int			AP_USER_NOT_EXIST				= 3;
+	public static int			AP_UPLOAD_SUCCESS				= 4;
+	public static int			AP_UPLOAD_FAIL					= 5;
+	//
+	// public static final int RESULT_FALSE = 0;
+	// public static final int RESULT_TRUE = 1;
+	// public static final int RESULT_NET_ERROR = 3;
+	// public static final int RESULT_ERROR = 5;
+	// public static final int RESULT_LOCALFILE_ERROR= 7;
+	// public static final int RESULT_USERAUTH_ERROR = 9;
+
+	public static int			AP_MESSAGE_NEW					= 5;
+	public static int			AP_MESSAGE_NONE					= 6;
+	//
+	public static final int		RESULT_FALSE					= 0;
+	public static final int		RESULT_TRUE						= 2;
+	public static final int		RESULT_NET_ERROR				= -3;
+	public static final int		RESULT_NET_NOTAVAILABLE			= -4;
+	public static final int		RESULT_ERROR					= -5;
+	public static final int		RESULT_LOCALFILE_ERROR			= -7;
+	public static final int		RESULT_USERAUTH_ERROR			= -9;
+	public static final int		RESULT_UPDATE_USERAUTH_ERROR	= -11;
+	public static final int		RESULT_SESSION_EXPIRED			= -13;
+	public static final int		RESULT_VER_LOW					= -15;
+	public static final int		STATUS_WAIT						= -17;
+	static String URL_UPLOAD_PHOTO				= "handset.php";
+	@Deprecated
+	static String URL_VERIFY_USER					= "handset_login.php";
+	static String URL_LOGIN					= "index.php?_action=handset_new";
+	static String URL_UPLOAD					= "index.php?_action=handset_new";
+	static String URL_VERIFY_CODE					= "index.php?_action=handset_new";
+	static String URL_QUERY_MANUFACTURER				= "index.php?_action=handset_new";
+	public static class SSLSocketFactoryEx extends SSLSocketFactory
+	{
+
+		SSLContext sslContext	= SSLContext.getInstance("TLS");
+
+		public SSLSocketFactoryEx(KeyStore truststore)
+				throws NoSuchAlgorithmException, KeyManagementException,
+                KeyStoreException, UnrecoverableKeyException
+		{
+			super(truststore);
+
+			TrustManager tm = new X509TrustManager()
+			{
+				public java.security.cert.X509Certificate[] getAcceptedIssuers()
+				{
+					return null;
+				}
+
+				@Override
+				public void checkClientTrusted(
+						java.security.cert.X509Certificate[] chain,
+						String authType)
+						throws java.security.cert.CertificateException
+				{
+				}
+
+				@Override
+				public void checkServerTrusted(
+						java.security.cert.X509Certificate[] chain,
+						String authType)
+						throws java.security.cert.CertificateException
+				{
+				}
+			};
+			sslContext.init(null, new TrustManager[] { tm }, null);
+		}
+
+		@Override
+		public Socket createSocket(Socket socket, String host, int port,
+                                   boolean autoClose) throws IOException {
+			return sslContext.getSocketFactory().createSocket(socket, host,
+					port, autoClose);
+		}
+
+		@Override
+		public Socket createSocket() throws IOException
+		{
+			return sslContext.getSocketFactory().createSocket();
+		}
+	}
+
+/*	private static HttpURLConnection getNewHttpConnection()
+{
+
+
+
+}*/
+	private static HttpClient getNewHttpClient()
+	{
+		try
+		{
+			KeyStore trustStore = KeyStore.getInstance(KeyStore
+					.getDefaultType());
+			trustStore.load(null, null);
+
+			SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
+			sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+
+			HttpParams params = new BasicHttpParams();
+			HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+			HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
+			HttpConnectionParams.setConnectionTimeout(params, REQUEST_TIMEOUT);
+			HttpConnectionParams.setSoTimeout(params, SO_TIMEOUT);
+			SchemeRegistry registry = new SchemeRegistry();
+			registry.register(new Scheme("http", PlainSocketFactory
+					.getSocketFactory(), 80));
+			registry.register(new Scheme("https", sf, 443));
+
+			ClientConnectionManager ccm = new ThreadSafeClientConnManager(
+					params, registry);
+
+			return new DefaultHttpClient(ccm, params);
+		}
+		catch (Exception e)
+		{
+			dbgUtil.fileLog(e.toString());
+			return new DefaultHttpClient();
+		}
+	}
+	private static String createPostParameters(Bundle parms) throws UnsupportedEncodingException {
+		StringBuilder result = new StringBuilder();
+		boolean first = true;
+		for(String key : parms.keySet()){
+			if (first)
+				first = false;
+			else
+				result.append("&");
+
+			result.append(URLEncoder.encode(key, "UTF-8"));
+			result.append("=");
+			result.append(URLEncoder.encode(parms.get(key).toString(), "UTF-8"));
+		}
+
+		return result.toString();
+	}
+	public static String getJson(String url, Bundle parms)
+	{
+		String TAG = "net_dbg@GetJson";
+		Log.d(TAG, "entry");
+		String ret=null;
+
+		HttpURLConnection connection = null;
+
+		try {
+
+
+			URL _url;
+			_url = new URL(url);
+			connection = (HttpURLConnection) _url.openConnection();
+			connection.setReadTimeout(SO_TIMEOUT);
+			connection.setConnectTimeout(SO_TIMEOUT);
+			// 设置请求方式
+			connection.setRequestMethod("POST");
+			// 设置编码格式
+			connection.setRequestProperty("Charset", "UTF-8");
+			// 传递自定义参数
+//			connection.setRequestProperty("MyProperty", "this is me!");
+
+			if(!TextUtils.isEmpty(RedAntApplication.user))
+				parms.putString("user", AES.encrypt("usai", RedAntApplication.user));
+			if(!TextUtils.isEmpty(RedAntApplication.password))
+				parms.putString("password", AES.encrypt("usai", RedAntApplication.password));
+
+			parms.putString("app_ver", RedAntApplication.getInstance()
+					.getPackageManager()
+					.getPackageInfo("com.usai.redant.raimage", 0).versionName);
+			parms.putInt("app_short_ver", RedAntApplication.getInstance()
+					.getPackageManager()
+					.getPackageInfo("com.usai.redant.raimage", 0).versionCode);
+
+			parms.putString("deviceid",RedAntApplication.device_id);
+
+
+
+
+			Set<String> keys = parms.keySet();
+			Log.d(TAG, "================parms============");
+			for (String key : keys)
+			{
+				if (key.contains("_file"))
+				{
+				}
+				else
+				{
+//					connection.setRequestProperty(key, parms.get(key).toString());
+					Log.d(TAG, "key=" + key + "    val="
+							+ parms.get(key).toString());
+				}
+//					reqEntity.addPart(key, new StringBody());
+
+			}
+			Log.d(TAG, "================parms============");
+
+			Log.d(TAG,"URL: "+url);
+			// 设置容许输出
+			connection.setDoInput(true);
+			connection.setDoOutput(true);
+
+
+			OutputStream os = connection.getOutputStream();
+			BufferedWriter writer = new BufferedWriter(
+					new OutputStreamWriter(os, "UTF-8"));
+			writer.write(createPostParameters(parms));
+
+			writer.flush();
+			writer.close();
+			os.close();
+
+		/*// 上传一张图片
+		FileInputStream file = new FileInputStream(Environment.getExternalStorageDirectory().getPath()
+				+ "/Pictures/Screenshots/Screenshot_2015-12-19-08-40-18.png");
+		OutputStream os = connection.getOutputStream();
+		int count = 0;
+		while((count=file.read()) != -1){
+			os.write(count);
+		}
+		os.flush();
+		os.close();
+*/
+			// 获取返回数据
+			if(connection.getResponseCode() == 200){
+				InputStream is = connection.getInputStream();
+
+				BufferedReader br = new BufferedReader(
+						new InputStreamReader(is, "utf-8"), 8);
+				StringBuilder sb = new StringBuilder();
+				String line = null;
+				while ((line = br.readLine()) != null)
+				{
+					sb.append(line + "\n");
+				}
+
+				Log.d(TAG, "Response: content begin");
+				Log.d(TAG, sb.toString());
+				Log.d(TAG, "Response: content end");
+
+				if (sb.length() <= 0)
+				{
+
+					ret= null;
+				}
+				ret= sb.toString();
+
+//				Message msg = Message.obtain();
+//				msg.what = 0;
+//				postHandler.sendMessage(msg);
+			}
+
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+			dbgUtil.fileLog(e.toString());
+			Log.e(TAG, e.toString());
+
+		} catch (ProtocolException e) {
+			e.printStackTrace();
+			dbgUtil.fileLog(e.toString());
+			Log.e(TAG, e.toString());
+
+		} catch (MalformedURLException e) {
+			e.printStackTrace();
+			dbgUtil.fileLog(e.toString());
+			Log.e(TAG, e.toString());
+
+		} catch (IOException e) {
+			e.printStackTrace();
+			dbgUtil.fileLog(e.toString());
+			Log.e(TAG, e.toString());
+
+		} catch (PackageManager.NameNotFoundException e) {
+			e.printStackTrace();
+		} finally {
+
+			if(connection!=null){
+				connection.disconnect();
+			}
+		}
+		return ret;
+
+	}
+	@Deprecated
+	public static String getJson_d(String url, Bundle parms)
+	{
+		String TAG = "net_dbg@GetJson";
+		Log.d(TAG, "entry");
+
+		// parms.putString("sessionid",
+		// ApexTrackingApplication.get_sessionid());
+
+		// if (true)
+		// return fakegetJson(url);
+		try
+		{
+			// BasicHttpParams httpParams = new BasicHttpParams();
+			// HttpConnectionParams.setConnectionTimeout(httpParams,
+			// REQUEST_TIMEOUT);
+			// HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);
+			HttpClient client = getNewHttpClient();// new
+													// DefaultHttpClient(httpParams);
+			HttpPost post = new HttpPost(url);
+			MultipartEntity reqEntity = new MultipartEntity(
+					HttpMultipartMode.BROWSER_COMPATIBLE);
+
+			Set<String> keys = parms.keySet();
+			Log.d(TAG, "================parms============");
+			for (String key : keys)
+			{
+				if (key.contains("_file"))
+				{
+				}
+				else
+					reqEntity.addPart(key, new StringBody(parms.get(key)
+							.toString()));
+				Log.d(TAG, "key=" + key + "    val="
+						+ parms.get(key).toString());
+			}
+			Log.d(TAG, "================parms============");
+
+			post.setEntity(reqEntity);
+			HttpResponse response = client.execute(post);
+			int statucode = response.getStatusLine().getStatusCode();
+			if (statucode == HttpStatus.SC_OK)
+			{
+				HttpEntity resEntity = response.getEntity();
+				if (resEntity != null)
+				{
+					Log.d(TAG,
+							"Response: content len==>"
+									+ resEntity.getContentLength());
+					InputStream is = resEntity.getContent();
+					try
+					{
+
+						BufferedReader br = new BufferedReader(
+								new InputStreamReader(is, "utf-8"), 8);
+						StringBuilder sb = new StringBuilder();
+						String line = null;
+						while ((line = br.readLine()) != null)
+						{
+							sb.append(line + "\n");
+						}
+
+						Log.d(TAG, "Response: content begin");
+						Log.d(TAG, sb.toString());
+						Log.d(TAG, "Response: content end");
+
+						if (sb.length() <= 0)
+						{
+
+							return null;
+						}
+						return sb.toString();
+
+					}
+					catch (Exception e)
+					{
+						dbgUtil.fileLog(e.toString());
+						Log.e(TAG, e.toString());
+						return null;
+						// TODO: handle exception
+					}
+					finally
+					{
+						is.close();
+
+					}
+
+				}
+				else
+				{
+					/*
+					 * resEntity is null
+					 */
+					Log.d(TAG, "RESPONSE ENTITY IS NULL");
+					return null;
+				}
+
+			}
+			else
+			{
+				/*
+				 * Http error; out put error code;
+				 */
+				Log.d(TAG, "HTTP " + statucode);
+
+				HttpEntity resEntity = response.getEntity();
+				if (resEntity != null)
+				{
+
+					InputStream is = resEntity.getContent();
+					try
+					{
+
+						BufferedReader br = new BufferedReader(
+								new InputStreamReader(is, "utf-8"), 8);
+						StringBuilder sb = new StringBuilder();
+						String line = null;
+						while ((line = br.readLine()) != null)
+						{
+							sb.append(line + "\n");
+						}
+
+						Log.d(TAG, "Response: content begin");
+						Log.d(TAG, sb.toString());
+						Log.d(TAG, "Response: content end");
+						return null;
+					}
+					catch (Exception e)
+					{
+						dbgUtil.fileLog(e.toString());
+						Log.e(TAG, e.toString());
+						return null;
+						// TODO: handle exception
+					}
+					finally
+					{
+						is.close();
+
+					}
+
+				}
+				else
+				{
+					/*
+					 * resEntity is null
+					 */
+					Log.e(TAG, "RESPONSE ENTITY IS NULL");
+					return null;
+				}
+			}
+
+		}
+		catch (ConnectTimeoutException e)
+		{
+			Log.d(TAG, "request time out");
+			dbgUtil.fileLog(e.toString());
+			return null;
+
+		}
+		catch (SocketTimeoutException e)
+		{
+			Log.d(TAG, "socket time out");
+			dbgUtil.fileLog(e.toString());
+			return null;
+		}
+		catch (UnknownHostException e)
+		{
+			Log.d(TAG, e.toString());
+			dbgUtil.fileLog(e.toString());
+			return null;
+		}
+		catch (HttpHostConnectException e)
+		{
+			Log.d(TAG, e.toString());
+			dbgUtil.fileLog(e.toString());
+			return null;
+		}
+		catch (Exception e)
+		{
+			Log.d(TAG, e.toString());
+			dbgUtil.fileLog(e.toString());
+			return null;
+		}
+
+	}
+
+	public static boolean NetworkIsAvailable()// Context context)
+	{
+		String TAG = "net_dbg@CheckNetwork";
+
+		ConnectivityManager connManager = (ConnectivityManager) RedAntApplication
+				.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
+		// .getSystemService(Context.CONNECTIVITY_SERVICE);
+
+		NetworkInfo networkInfo = connManager.getActiveNetworkInfo();
+		if (networkInfo == null)
+		{
+			Log.d(TAG, "can not get Active NetworkInfo!");
+			// dbgUtil.Log(Log.DEBUG, "Current Network info",
+			// "can not get Active NetworkInfo!");
+			return false;
+		}
+		NetworkInfo.State netState = networkInfo.getState();
+		if (netState != NetworkInfo.State.CONNECTED)
+		{
+			Log.d(TAG, "not Connected!State=" + netState);
+			// dbgUtil.Log(Log.DEBUG, "Current Network info",
+			// "not Connected!State=" + netState);
+			return false;
+		}
+
+		boolean bavailable = networkInfo.isAvailable();
+		String strtype = networkInfo.getTypeName();
+
+		Log.d(TAG, " type = " + strtype + " abailable = " + bavailable
+				+ " state " + netState);
+
+		return bavailable;
+	}
+	public static JSONObject Login(String user, String password) {
+		String TAG = "net_dbg@Login";
+		Log.d(TAG, "u:" + user + ";p:" + password);
+		if (!Network.NetworkIsAvailable())
+		{
+
+			Log.d(TAG, "network not available!");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_NOTAVAILABLE+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+
+
+		Bundle parms = new Bundle();
+		try {
+
+			parms.putString("user", AES.encrypt("usai", user));
+			parms.putString("password", AES.encrypt("usai", password));
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		parms.putString("_operate","handset_login");
+		// parms.putString("action", "handset_login");
+		// int ver = ApexTrackingApplication
+		// .get_instance()
+		// .getSharedPreferences(name + "_Apex_auth", Context.MODE_PRIVATE)
+		// .getInt("AuthInfoVer", 0);
+		// parms.putString("auth_ver", ver + "");
+		String jstr = getJson(RedAntApplication.active_address
+				+ Network.URL_LOGIN, 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");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		JSONObject jsobj;
+		try
+		{
+			jsobj = new JSONObject(jstr);
+			if (jsobj.length() > 0)
+			{
+				return jsobj;
+			}
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		catch (JSONException e)
+		{
+			// TODO Auto-generated catch block
+			dbgUtil.fileLog(e.toString());
+			e.printStackTrace();
+//			try {
+//				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+//			} catch (JSONException e1) {
+//				e.printStackTrace();
+//			}
+			return null;
+		}
+
+//		JSONObject ret =new JSONObject();
+//		ret.put("result",Network.RESULT_NET_ERROR);
+		return null;
+	}
+	@Deprecated
+	public static int VerifyUser(String user, String password)
+	{
+		String TAG = "net_dbg@get_Auth";
+		Log.d(TAG, "u:" + user + ";p:" + password);
+		if (!Network.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("password", password);
+		// parms.putString("action", "handset_login");
+		// int ver = ApexTrackingApplication
+		// .get_instance()
+		// .getSharedPreferences(name + "_Apex_auth", Context.MODE_PRIVATE)
+		// .getInt("AuthInfoVer", 0);
+		// parms.putString("auth_ver", ver + "");
+		String jstr = getJson(RedAntApplication.active_address
+				+ Network.URL_VERIFY_USER, 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;
+		try
+		{
+			jsobj = new JSONObject(jstr);
+			if (jsobj.length() > 0)
+			{
+				int iresult = jsobj.getInt("result");
+				if (iresult == Network.AP_USER_AUTH)
+				{
+					return RESULT_TRUE;
+				}
+
+				else
+				{
+
+					return RESULT_FALSE;
+				}
+			}
+			return RESULT_NET_ERROR;
+		}
+		catch (JSONException e)
+		{
+			// TODO Auto-generated catch block
+			dbgUtil.fileLog(e.toString());
+			e.printStackTrace();
+			return RESULT_NET_ERROR;
+		}
+
+		// return parse_authinfo(jstr, name, password);
+		// if(true)
+		// return RESULT_TRUE;
+		// String TAG = "net_dbg@VerifyUser";
+		// Log.d(TAG, "entry");
+		// try
+		// {
+		// BasicHttpParams httpParams = new BasicHttpParams();
+		// HttpConnectionParams.setConnectionTimeout(httpParams,
+		// REQUEST_TIMEOUT);
+		// HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);
+		// HttpClient client = new DefaultHttpClient(httpParams);
+		// HttpPost post = new HttpPost(URL_VERIFY_USER);
+		// MultipartEntity reqEntity = new MultipartEntity(
+		// HttpMultipartMode.BROWSER_COMPATIBLE);
+		// reqEntity.addPart("user", new StringBody(user));
+		// reqEntity.addPart("password", new StringBody(password));
+		//
+		// post.setEntity(reqEntity);
+		// HttpResponse response = client.execute(post);
+		// int statucode = response.getStatusLine().getStatusCode();
+		// if (statucode == HttpStatus.SC_OK)
+		// {
+		// HttpEntity resEntity = response.getEntity();
+		// if (resEntity != null)
+		// {
+		// Log.d(TAG,
+		// "Response: content len==>"
+		// + resEntity.getContentLength());
+		// InputStream is = resEntity.getContent();
+		// try
+		// {
+		//
+		// BufferedReader br = new BufferedReader(
+		// new InputStreamReader(is, "utf-8"), 8);
+		// StringBuilder sb = new StringBuilder();
+		// String line = null;
+		// while ((line = br.readLine()) != null)
+		// {
+		// sb.append(line + "\n");
+		// }
+		//
+		// Log.d(TAG, "Response: content begin");
+		// Log.d(TAG, sb.toString());
+		// Log.d(TAG, "Response: content end");
+		//
+		// if (sb.length()<=0)
+		// {
+		//
+		// return RESULT_NET_ERROR;
+		// }
+		// JSONObject obj = new JSONObject(sb.toString());
+		// if (obj.length() > 0)
+		// {
+		// // JSONObject obj = array.getJSONObject(0);
+		// try
+		// {
+		// int verifyresult = Integer.parseInt(obj
+		// .getString("result"));
+		// if (verifyresult == Network.AP_USER_AUTH)
+		// {
+		// return RESULT_TRUE;
+		// }
+		// else
+		// {
+		// return RESULT_FALSE;
+		// }
+		// }
+		// catch (Exception e)
+		// {
+		// Log.e(TAG, e.toString());
+		// return RESULT_ERROR;
+		// }
+		// }
+		// }
+		// catch (Exception e)
+		// {
+		// Log.e(TAG, e.toString());
+		// return RESULT_ERROR;
+		// // TODO: handle exception
+		// }
+		// finally
+		// {
+		// is.close();
+		//
+		// }
+		//
+		// }
+		// else
+		// {
+		// /*
+		// * resEntity is null
+		// */
+		// Log.d(TAG, "RESPONSE ENTITY IS NULL");
+		// return RESULT_NET_ERROR;
+		// }
+		//
+		// }
+		// else
+		// {
+		// /*
+		// * Http error; out put error code;
+		// */
+		// Log.d(TAG, "HTTP " + statucode);
+		//
+		// HttpEntity resEntity = response.getEntity();
+		// if (resEntity != null)
+		// {
+		//
+		// InputStream is = resEntity.getContent();
+		// try
+		// {
+		//
+		// BufferedReader br = new BufferedReader(
+		// new InputStreamReader(is, "utf-8"), 8);
+		// StringBuilder sb = new StringBuilder();
+		// String line = null;
+		// while ((line = br.readLine()) != null)
+		// {
+		// sb.append(line + "\n");
+		// }
+		//
+		// Log.d(TAG, "Response: content begin");
+		// Log.d(TAG, sb.toString());
+		// Log.d(TAG, "Response: content end");
+		// return RESULT_ERROR;
+		// }
+		// catch (Exception e)
+		// {
+		// Log.e(TAG, e.toString());
+		// return RESULT_ERROR;
+		// // TODO: handle exception
+		// }
+		// finally
+		// {
+		// is.close();
+		//
+		// }
+		//
+		// }
+		// else
+		// {
+		// /*
+		// * resEntity is null
+		// */
+		// Log.e(TAG, "RESPONSE ENTITY IS NULL");
+		// return RESULT_NET_ERROR;
+		// }
+		// }
+		//
+		// }
+		// catch (ConnectTimeoutException e)
+		// {
+		// Log.d(TAG, "request time out");
+		// return RESULT_NET_ERROR;
+		//
+		// }
+		// catch (Exception e)
+		// {
+		// Log.d(TAG, e.toString());
+		// return RESULT_ERROR;
+		// }
+		// return RESULT_ERROR;
+	}
+
+	public static JSONObject Query_Manufacturer(Bundle Params)
+	{
+		String TAG = "net_dbg@Verify_Code";
+		if (!Network.NetworkIsAvailable())
+		{
+
+			Log.d(TAG, "network not available!");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_NOTAVAILABLE+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		Params.putString("_operate","handset_get_manufacturer");
+		String jstr = getJson(RedAntApplication.active_address
+				+ Network.URL_QUERY_MANUFACTURER,Params);
+//		file.delete();
+		if (jstr == null || jstr.length() <= 0)
+		{
+			Log.d(TAG, "json is null");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		Log.d(TAG, "json string:"+jstr);
+		JSONObject jsobj;
+		try
+		{
+			jsobj = new JSONObject(jstr);
+			if (jsobj.length() > 0)
+			{
+				return jsobj;
+			}
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		catch (JSONException e)
+		{
+			// TODO Auto-generated catch block
+			Log.d(TAG, "json format wrong:"+jstr);
+			e.printStackTrace();
+//			try {
+//				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+//			} catch (JSONException e1) {
+//				e.printStackTrace();
+//			}
+			return null;
+		}
+		return null;
+	}
+	public static JSONObject Verify_Code(Bundle Params)
+	{
+		String TAG = "net_dbg@Verify_Code";
+		if (!Network.NetworkIsAvailable())
+		{
+
+			Log.d(TAG, "network not available!");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_NOTAVAILABLE+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		Params.putString("_operate","valid_upload");
+		String jstr = getJson(RedAntApplication.active_address
+                + Network.URL_VERIFY_CODE,Params);
+//		file.delete();
+		if (jstr == null || jstr.length() <= 0)
+		{
+			Log.d(TAG, "json is null");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		Log.d(TAG, "json string:"+jstr);
+		JSONObject jsobj;
+		try
+		{
+			jsobj = new JSONObject(jstr);
+			if (jsobj.length() > 0)
+			{
+				return jsobj;
+			}
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		catch (JSONException e)
+		{
+			// TODO Auto-generated catch block
+			Log.d(TAG, "json format wrong:"+jstr);
+			e.printStackTrace();
+//			try {
+//				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+//			} catch (JSONException e1) {
+//				e.printStackTrace();
+//			}
+			return null;
+		}
+		return null;
+	}
+	public static JSONObject UploadImage(String path, Bundle Params, String server, FileUploadListener listener)
+	{
+		String TAG = "net_dbg@UploadImage";
+		if (!Network.NetworkIsAvailable())
+		{
+
+			Log.d(TAG, "network not available!");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_NOTAVAILABLE+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+//		Bitmap source = BitmapFactory.decodeFile(path);
+//
+//		int originWidth = source.getWidth();
+//		int originHeight = source.getHeight();
+//
+//		int width = originWidth, height = originHeight;
+//
+//		if (originHeight > 1024 || originWidth > 1024)
+//		{
+//			if (originWidth > originHeight)
+//			{
+//				width = 1024;
+//				height = originHeight * 1024 / originWidth;
+//
+//			}
+//			else
+//			{
+//
+//				height = 1024;
+//				width = originWidth * 1024 / originHeight;
+//
+//			}
+//		}
+//		Bitmap scaled = Bitmap.createScaledBitmap(source, width, height, true);
+//		OutputStream fOutputStream = null;
+//		String scaledPath = path.replace(".jpg", "_scaled.jpg");
+//		File file = new File(scaledPath);
+//		try
+//		{
+//			fOutputStream = new FileOutputStream(file);
+//
+//			scaled.compress(Bitmap.CompressFormat.JPEG, 95, fOutputStream);
+//
+//			fOutputStream.flush();
+//			fOutputStream.close();
+//
+//			// MediaStore.Images.Media.insertImage(RedAntApplication.getInstance().getContentResolver(),
+//			// file.getAbsolutePath(), file.getName(), file.getName());
+//		}
+//		catch (FileNotFoundException e)
+//		{
+//			e.printStackTrace();
+//
+//			dbgUtil.fileLog(e.toString());
+//			return RESULT_LOCALFILE_ERROR;
+//		}
+//		catch (IOException e)
+//		{
+//			e.printStackTrace();
+//
+//			dbgUtil.fileLog(e.toString());
+//			return RESULT_LOCALFILE_ERROR;
+//		}
+		String jstr = UploadFile(path,server, Params,listener);
+//		file.delete();
+		if (jstr == null || jstr.length() <= 0)
+		{
+			Log.d(TAG, "json is null");
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		Log.d(TAG, "json string:"+jstr);
+		JSONObject jsobj;
+		try
+		{
+			jsobj = new JSONObject(jstr);
+			if (jsobj.length() > 0)
+			{
+				return jsobj;
+			}
+			try {
+				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+		}
+		catch (JSONException e)
+		{
+			// TODO Auto-generated catch block
+			Log.d(TAG, "json format wrong:"+jstr);
+			e.printStackTrace();
+//			try {
+//				return new JSONObject("{result:" + Network.RESULT_NET_ERROR+ "}");
+//			} catch (JSONException e1) {
+//				e.printStackTrace();
+//			}
+			return null;
+		}
+		return null;
+	}
+
+	public static String UploadFile(String path , String host, Bundle params, FileUploadListener listener){
+
+
+
+		try {
+			params.putString("app_ver", RedAntApplication.getInstance()
+                    .getPackageManager()
+                    .getPackageInfo("com.usai.redant.raimage", 0).versionName);
+			params.putInt("app_short_ver", RedAntApplication.getInstance()
+					.getPackageManager()
+					.getPackageInfo("com.usai.redant.raimage", 0).versionCode);
+			params.putString("deviceid",RedAntApplication.device_id);
+
+
+			if(!TextUtils.isEmpty(RedAntApplication.user))
+				params.putString("user", AES.encrypt("usai", RedAntApplication.user));
+			if(!TextUtils.isEmpty(RedAntApplication.password))
+				params.putString("password", AES.encrypt("usai", RedAntApplication.password));
+		} catch (PackageManager.NameNotFoundException e) {
+			e.printStackTrace();
+		}
+
+
+
+
+
+		File file = new File(path);
+		if(!file.exists())
+		{
+			String result="{\"result\":0,\"msg\":\"file does not exist\"}";
+			listener.onFinish(200,result);
+
+			return result;
+		}
+		String TAG = "net_dbg@UploadFile";
+		   String CHARSET = "utf-8"; //设置编码
+		   String PREFIX = "--";
+		   String LINE_END = "\r\n";
+		String BOUNDARY = UUID.randomUUID().toString(); //边界标识 随机生成 String PREFIX = "--" , LINE_END = "\r\n";
+		String CONTENT_TYPE = "multipart/form-data"; //内容类型
+
+		HttpURLConnection conn = null;
+		try {
+			URL url = new URL(host);
+			conn = (HttpURLConnection) url.openConnection();
+			conn.setReadTimeout(UPLOAD_TIMEOUT);
+			conn.setConnectTimeout(UPLOAD_TIMEOUT);
+			conn.setRequestMethod("POST"); //请求方式
+			conn.setRequestProperty("Charset", "utf-8");//设置编码
+			conn.setRequestProperty("connection", "keep-alive");
+			conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
+			conn.setDoInput(true); //允许输入流
+			conn.setDoOutput(true); //允许输出流
+			conn.setUseCaches(false); //不允许使用缓存
+			if(file!=null) {
+				/** * 当文件不为空,把文件包装并且上传 */
+				OutputStream outputSteam=conn.getOutputStream();
+				DataOutputStream dos = new DataOutputStream(outputSteam);
+				StringBuffer sb = new StringBuffer();
+				sb.append(LINE_END);
+				if(params!=null){//根据格式,开始拼接文本参数
+
+
+					Set<String> keys = params.keySet();
+					Log.d(TAG, "================parms============");
+					for (String key : keys)
+					{
+
+						sb.append(PREFIX).append(BOUNDARY).append(LINE_END);//分界符
+						sb.append("Content-Disposition: form-data; name=\"" + key + "\"" + LINE_END);
+						sb.append("Content-Type: text/plain; charset=" + CHARSET + LINE_END);
+						sb.append("Content-Transfer-Encoding: 8bit" + LINE_END);
+						sb.append(LINE_END);
+						sb.append(params.get(key).toString());
+						sb.append(LINE_END);//换行!
+
+//					connection.setRequestProperty(key, parms.get(key).toString());
+							Log.d(TAG, "key=" + key + "    val="
+									+ params.get(key).toString());
+
+//					reqEntity.addPart(key, new StringBody());
+
+					}
+
+					Log.d(TAG, "================parms============");
+
+				}
+				sb.append(PREFIX);//开始拼接文件参数
+				sb.append(BOUNDARY); sb.append(LINE_END);
+				/**
+				 * 这里重点注意:
+				 * name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
+				 * filename是文件的名字,包含后缀名的 比如:abc.png
+				 */
+				sb.append("Content-Disposition: form-data; name=\"upfile\"; filename=\""+file.getName()+"\""+LINE_END);
+				sb.append("Content-Type: application/octet-stream; charset="+CHARSET+LINE_END);
+				sb.append(LINE_END);
+				//写入文件数据
+				dos.write(sb.toString().getBytes());
+				InputStream is = new FileInputStream(file);
+				byte[] bytes = new byte[1024];
+				long totalbytes = file.length();
+				long curbytes = 0;
+				Log.i("cky","total="+totalbytes);
+				int len = 0;
+				double oldprogress=0.0;
+				while((len=is.read(bytes))!=-1){
+					if(listener.interupt())
+					{
+						is.close();
+						if(conn!=null)
+						conn.disconnect();
+						String result="{\"result\":"+0+",\"msg\":\"user cancel\"}";
+						listener.onFinish(200,result);
+
+						return result;
+					}
+					curbytes += len;
+					dos.write(bytes, 0, len);
+					double newprogress =1.0d*curbytes/totalbytes;
+					if(newprogress-oldprogress>=listener.percent_step()/100.0||newprogress>=1.0)
+					{
+						listener.onProgress(curbytes,newprogress);
+						oldprogress = newprogress;
+					}
+					else
+					{
+//						Log.d(TAG, "UploadFile: skiped "+newprogress);
+					}
+
+				}
+				is.close();
+				dos.write(LINE_END.getBytes());//一定还有换行
+				byte[] end_data = (PREFIX+BOUNDARY+PREFIX+LINE_END).getBytes();
+				dos.write(end_data);
+				dos.flush();
+				/**
+				 * 获取响应码 200=成功
+				 * 当响应成功,获取响应的流
+				 */
+				int code = conn.getResponseCode();
+				sb.setLength(0);
+				BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+				String line;
+				while((line=br.readLine())!=null){
+
+					if(listener.interupt())
+					{
+
+						if(conn!=null)
+						conn.disconnect();
+//						br.close();
+						String result="{\"result\":"+0+",\"msg\":\"user cancel\"}";
+						listener.onFinish(200,result);
+						return result;
+					}
+
+					sb.append(line);
+				}
+				if(conn!=null)
+				conn.disconnect();
+				listener.onFinish(code,sb.toString()/*,conn.getHeaderFields()*/);
+				return sb.toString();
+			}
+		} catch (MalformedURLException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		finally {
+			if(conn!=null){
+				conn.disconnect();
+			}
+		}
+
+		Log.e(TAG, "UploadFile: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
+		return null;
+	}
+
+	public interface FileUploadListener {
+
+//		void FileUploadListener(double percent_step);
+
+		double percent_step();
+
+		boolean interupt();
+		void onProgress(long pro, double percentage);
+
+		void onFinish(int code, String res/*, HashMap<String, List<String>> headers*/);
+	}
+
+	@Deprecated
+	public static int UploadFiled(String path, String user, String password,
+                                  String pid, String server)
+	{
+		String TAG = "net_dbg@UploadFile";
+		Log.d(TAG, "entry");
+
+		Log.d(TAG, "sourcefile:" + path);
+		File file = new File(path);
+
+		if (file.exists() == false)
+		{
+			dbgUtil.fileLog("file "+ path +" not found!");
+			return RESULT_LOCALFILE_ERROR;
+		}
+		String md5 = MD5.md5sum(path);
+		Log.d(TAG, "MD5:" + md5);
+		if (md5 == null)
+		{
+			Log.d(TAG, "md5 sum failed");
+			dbgUtil.fileLog("md5 sum failed");
+			return RESULT_LOCALFILE_ERROR;
+
+		}
+		try
+		{
+			BasicHttpParams httpParams = new BasicHttpParams();
+			HttpConnectionParams.setConnectionTimeout(httpParams,
+					REQUEST_TIMEOUT);
+			HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);
+			HttpClient client = new DefaultHttpClient(httpParams);
+			HttpPost post = new HttpPost(server
+					+ URL_UPLOAD_PHOTO);
+			MultipartEntity reqEntity = new MultipartEntity(
+					HttpMultipartMode.BROWSER_COMPATIBLE);
+			reqEntity.addPart("user", new StringBody(user));
+			reqEntity.addPart("password", new StringBody(password));
+			reqEntity.addPart("pid", new StringBody(pid));
+			reqEntity.addPart("md5", new StringBody(md5));
+
+			FileBody bin = new FileBody(file);
+			reqEntity.addPart("imagefile", bin);
+			post.setEntity(reqEntity);
+			HttpResponse response = client.execute(post);
+			int statucode = response.getStatusLine().getStatusCode();
+			if (statucode == HttpStatus.SC_OK)
+			{
+				HttpEntity resEntity = response.getEntity();
+				if (resEntity != null)
+				{
+					Log.d(TAG,
+							"Response: content len==>"
+									+ resEntity.getContentLength());
+					InputStream is = resEntity.getContent();
+					try
+					{
+
+						BufferedReader br = new BufferedReader(
+								new InputStreamReader(is, "utf-8"), 8);
+						StringBuilder sb = new StringBuilder();
+						String line = null;
+						while ((line = br.readLine()) != null)
+						{
+							sb.append(line + "\n");
+						}
+
+						Log.d(TAG, "Response: content begin");
+						Log.d(TAG, sb.toString());
+						Log.d(TAG, "Response: content end");
+
+						if (sb.length() <= 0)
+						{
+
+							return RESULT_NET_ERROR;
+						}
+						JSONObject obj = new JSONObject(sb.toString());
+						if (obj.length() > 0)
+						{
+							// JSONObject obj = array.getJSONObject(0);
+							try
+							{
+								int uploadresult = Integer.parseInt(obj
+										.getString("result"));
+								if (uploadresult == Network.AP_UPLOAD_SUCCESS)
+								{
+									return RESULT_TRUE;
+								}
+								else if (uploadresult == Network.AP_USER_NOT_AUTH)
+								{
+									Log.d(TAG, "RESULT_ERR_USERAUTH");
+									return RESULT_USERAUTH_ERROR;
+								}
+								else
+								{
+									return RESULT_FALSE;
+								}
+							}
+							catch (Exception e)
+							{
+								Log.e(TAG, e.toString()+1);
+								dbgUtil.fileLog(e.toString());
+								return RESULT_FALSE;
+							}
+						}
+					}
+					catch (Exception e)
+					{
+						Log.e(TAG, e.toString());
+						dbgUtil.fileLog(e.toString());
+						return RESULT_NET_ERROR;
+						// TODO: handle exception
+					}
+					finally
+					{
+						is.close();
+
+					}
+
+				}
+				else
+				{
+					/*
+					 * resEntity is null
+					 */
+					Log.d(TAG, "RESPONSE ENTITY IS NULL");
+					return RESULT_NET_ERROR;
+				}
+
+			}
+			else
+			{
+				/*
+				 * Http error; out put error code;
+				 */
+				Log.d(TAG, "HTTP " + statucode);
+
+				HttpEntity resEntity = response.getEntity();
+				if (resEntity != null)
+				{
+
+					InputStream is = resEntity.getContent();
+					try
+					{
+
+						BufferedReader br = new BufferedReader(
+								new InputStreamReader(is, "utf-8"), 8);
+						StringBuilder sb = new StringBuilder();
+						String line = null;
+						while ((line = br.readLine()) != null)
+						{
+							sb.append(line + "\n");
+						}
+
+						Log.d(TAG, "Response: content begin");
+						Log.d(TAG, sb.toString());
+						Log.d(TAG, "Response: content end");
+						return RESULT_NET_ERROR;
+					}
+					catch (Exception e)
+					{
+						Log.e(TAG, e.toString());
+						dbgUtil.fileLog(e.toString());
+						return RESULT_NET_ERROR;
+						
+						// TODO: handle exception
+					}
+					finally
+					{
+						is.close();
+
+					}
+
+				}
+				else
+				{
+					/*
+					 * resEntity is null
+					 */
+					Log.e(TAG, "RESPONSE ENTITY IS NULL");
+					return RESULT_NET_ERROR;
+				}
+			}
+
+		}
+		catch (ConnectTimeoutException e)
+		{
+			Log.d(TAG, "request time out");
+			dbgUtil.fileLog(e.toString());
+			return RESULT_NET_ERROR;
+
+		}
+		catch (SocketTimeoutException e)
+		{
+			Log.d(TAG, "socket time out");
+			dbgUtil.fileLog(e.toString());
+			return RESULT_NET_ERROR;
+		}
+		catch (UnknownHostException e)
+		{
+			Log.d(TAG, e.toString());
+			dbgUtil.fileLog(e.toString());
+			return RESULT_NET_ERROR;
+		}
+		catch (HttpHostConnectException e)
+		{
+			Log.d(TAG, e.toString());
+			dbgUtil.fileLog(e.toString());
+			return RESULT_NET_ERROR;
+		}
+		catch (Exception e)
+		{
+			Log.d(TAG, e.toString()+" RESULT_ERROR!!");
+			dbgUtil.fileLog(e.toString());
+			return RESULT_ERROR;
+		}
+
+		return RESULT_FALSE;
+
+		// try
+		// {
+		// HttpClient client = new DefaultHttpClient();
+		// HttpPost post = new HttpPost(url);
+		// MultipartEntity reqEntity = new MultipartEntity(
+		// HttpMultipartMode.BROWSER_COMPATIBLE);
+		// reqEntity.addPart("user", new StringBody(user));
+		// reqEntity.addPart("password", new StringBody(password));
+		// reqEntity.addPart("pid", new StringBody(pid));
+		// FileBody bin = new FileBody(file);
+		// reqEntity.addPart("imagefile", bin);
+		// post.setEntity(reqEntity);
+		// HttpResponse response = client.execute(post);
+		// HttpEntity resEntity = response.getEntity();
+		// if (resEntity != null)
+		// {
+		//
+		// String result = EntityUtils.toString(resEntity);
+		// Log.d(TAG, "Response:" + result);
+		// return Integer.parseInt(result);
+		// // if(Boolean.parseBoolean(result)==true)
+		// // return true;
+		// // else
+		// // return false;
+		// }
+		//
+		// }
+		// catch (Exception e)
+		// {
+		// e.printStackTrace();
+		// }
+		// return 0;
+	}
+
+	public static boolean NetworkIsAvailable(Context context)
+	{
+		String TAG = "net_dbg@CheckNetwork";
+		ConnectivityManager connManager = (ConnectivityManager) context
+				.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+		NetworkInfo networkInfo = connManager.getActiveNetworkInfo();
+		if (networkInfo == null)
+		{
+			Log.d(TAG, "can not get Active NetworkInfo!");
+			// dbgUtil.Log(Log.DEBUG, "Current Network info",
+			// "can not get Active NetworkInfo!");
+			return false;
+		}
+		NetworkInfo.State netState = networkInfo.getState();
+		if (netState != NetworkInfo.State.CONNECTED)
+		{
+			Log.d(TAG, "not Connected!State=" + netState);
+			// dbgUtil.Log(Log.DEBUG, "Current Network info",
+			// "not Connected!State=" + netState);
+			return false;
+		}
+		// int iconntype = -1;
+		// iconntype = networkInfo.getType();
+
+		// boolean bUseMobileNetwork = context.getSharedPreferences(
+		// "PhoneAsstPref", 0).getBoolean("UseMobileNetwork", false);
+		//
+		// if (bUseMobileNetwork == false
+		// && iconntype != ConnectivityManager.TYPE_WIFI && iconntype != 9/*
+		// earthnet */)
+		// {
+		// Log.d(TAG,);
+		// dbgUtil.Log(Log.DEBUG, "Current Network info",
+		// "not allowed!Connection type=" + networkInfo.getTypeName());
+		// return false;
+		// }
+		boolean bavailable = networkInfo.isAvailable();
+		String strtype = networkInfo.getTypeName();
+
+		Log.d(TAG, " type = " + strtype + " abailable = " + bavailable
+				+ " state " + netState);
+		// dbgUtil.Log(Log.INFO, "Current Network info", " type = " + strtype
+		// + " abailable = " + bavailable + " state " + netState);
+		return bavailable;
+	}
+
+	public static Bitmap getImageFromLink(String link) {
+		HttpURLConnection connection = null;
+		Bitmap img = null;
+		try {
+
+			URL url = new URL(link);
+			connection = (HttpURLConnection)url.openConnection();
+			connection.setRequestMethod("GET");
+			img = BitmapFactory.decodeStream(connection.getInputStream());
+
+		} catch (IOException e) {
+			e.printStackTrace();
+		} finally {
+			if (connection != null) {
+				connection.disconnect();
+			}
+		}
+		return img;
+	}
+}

+ 129 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/RAOperationQueue.java

@@ -0,0 +1,129 @@
+package com.usai.redant.util;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.usai.redant.redantmobile.RedAntApplication;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * Created by ray on 28/06/2017.
+ */
+
+public class RAOperationQueue {
+
+    public interface OperationCallback {
+        /**
+            每个具体任务执行的回调
+         */
+        public Boolean operate(Bundle taskinfo);
+        public void operateFinish(Bundle taskinfo);
+    }
+
+    OperationCallback execCallback;
+    public void setCallback(OperationCallback callback)
+    {
+        execCallback=callback;
+    }
+    //并发队列
+    private ConcurrentLinkedQueue<Bundle> queue = new ConcurrentLinkedQueue<Bundle>();
+    // 最大并发数
+    public int MaxThread = 3;
+    //线程池
+    private ExecutorService es = Executors.newCachedThreadPool();
+
+
+//    public RAOperation runThread;
+    public void addOperation(final Bundle taskinfo)
+    {
+
+
+        queue.offer(taskinfo);
+        while (((ThreadPoolExecutor)es).getActiveCount()< MaxThread) {
+
+
+            es.submit(new Runnable() {
+                boolean wrong = false;
+                @Override
+                public void run() {
+
+                    while (!queue.isEmpty()) {
+                        Bundle task=queue.poll();
+
+                        System.out.println("running  tid="+ Thread.currentThread().getId());
+                        task.putLong("tid", Thread.currentThread().getId());
+//                        int min=1000;
+//                        int max=5000;
+//                        int sleep=new Random().nextInt(max)%(max-min+1) + min;
+//                        try{
+//                            Thread.currentThread().sleep(sleep);
+//                        }catch(InterruptedException ie){
+//                            ie.printStackTrace();
+//                        }
+                        boolean retry=execCallback.operate(task);
+                        if(retry)
+                            queue.offer(task);
+                        else
+                        {
+                            task.remove("tid");
+                            execCallback.operateFinish(task);
+
+                            RAUploadManager.TaskStatus status= RAUploadManager.TaskStatus.values()[task.getInt("status",0)];
+
+                            if (status== RAUploadManager.TaskStatus.TaskStatusError)
+                                wrong=true;
+
+                        }
+                        System.out.println("     finish  tid="+ Thread.currentThread().getId());
+                    }
+
+                    synchronized (this)
+                    {
+                        if(((ThreadPoolExecutor) es).getActiveCount()==1)
+                        {
+
+
+                            Intent intent = new Intent("REDANT.RAImage.UPLOAD_COMPLETE");
+
+
+
+
+                            if(wrong)
+                            {
+                                intent.putExtra("result","error");
+                            }
+                            else
+                            {
+                                intent.putExtra("result","finish");
+                            }
+
+                            RedAntApplication.getInstance().getApplicationContext().sendBroadcast(intent);
+
+                            //getApplicationContext()
+                            Log.e("Finish_msg", "run: -----------task finish" );
+
+//                                                        Toast toast = Toast.makeText(getApplicationContext(),
+//                                    "Piid must be a number",
+//                                    Toast.LENGTH_LONG);
+//                            toast.setGravity(Gravity.CENTER, 0, 0);
+//                            toast.show();;
+
+                        }
+                    }
+
+                }
+            });
+
+        }
+    }
+    public void stopQueue()
+    {
+        queue.clear();
+        es.shutdown();
+    }
+}

+ 725 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/RAUploadManager.java

@@ -0,0 +1,725 @@
+package com.usai.redant.util;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.util.Base64;
+import android.util.Log;
+
+import com.usai.redant.redantmobile.RedAntApplication;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.usai.redant.util.Network.URL_UPLOAD;
+
+/**
+ * Created by ray on 13/06/2017.
+ */
+
+public class RAUploadManager {
+    public int maxThread = 3;
+    public int activeThread;
+    public int maxRetry = 5;
+    public int retryWaiting = 300;
+
+
+    public Boolean wifiOnly = false;
+    //    public Boolean autoStart=true;
+//    public Boolean removeFinish=true;
+//    public Boolean removeError=false;
+    public QueueStatus queue_status;
+
+
+    public static final int RESULT_BARCODE_ERROR = -50;
+
+    public TaskStatus newtaskStatus = TaskStatus.TaskStatusWait;
+    private ArrayList<Bundle> arr_queue;
+
+    public ArrayList<Bundle> get_arr_queue() {
+        return arr_queue;
+    }
+
+    //    private List<Bundle> operation_queue;
+//    private ExecutorService es = Executors.newFixedThreadPool(3);//
+    // .newFixedThreadPool();
+//    private CountDownLatch latch = new CountDownLatch(maxThread);
+    private RAOperationQueue operation_queue;
+
+    public enum QueueStatus {
+        QueueStatusDefault,
+        QueueStatusAdd,
+        QueueStatusError,
+        QueueStatusFinishWithError,
+        QueueStatusFinish
+    }
+
+    public enum TaskStatus {
+        TaskStatusStop,
+        TaskStatusStart,
+        TaskStatusError,
+        TaskStatusWait,
+        TaskStatusFinish,
+        //TaskStatusCancel,
+    }
+
+    public UIUpdateListener uiUpdateListener;
+
+    public interface UIUpdateListener {
+        //        void onProgress(long index, double percentage);
+        void updateCell(long index, Bundle taskinfo);
+//        void updateList();
+
+        void updateList(ArrayList<Bundle> newlist);
+//        void addTasks(ArrayList<Bundle> tasks);
+//        void RemoveTasks(ArrayList<Bundle> tasks);
+
+//        void onFinish(int code, String res/*, HashMap<String, List<String>> headers*/);
+    }
+
+
+//    class Poll implements Runnable {
+//        public void run() {
+//            // while (queue.size()>0) {
+//            while (!operation_queue.isEmpty()) {
+//                System.out.println(operation_queue.poll());
+//            }
+//            latch.countDown();
+//        }
+//    }
+
+    public RAUploadManager() {
+        queue_status = QueueStatus.QueueStatusDefault;
+
+
+        SharedPreferences UMSetting = RedAntApplication.getInstance()
+                .getSharedPreferences("UploadManager", 0);
+
+        if (UMSetting != null) {
+//            autoStart = UMSetting.getBoolean("auto_upload",false);
+//            removeFinish = UMSetting.getBoolean("auto_rm_finish",false);
+//            removeError = UMSetting.getBoolean("auto_rm_error",false);
+            maxRetry = UMSetting.getInt("retry_count", 5);
+            newtaskStatus = TaskStatus.values()[UMSetting.getInt("newtask_status", TaskStatus.TaskStatusWait.ordinal())];
+
+            maxThread = UMSetting.getInt("max_thread", 3);
+
+            wifiOnly = UMSetting.getBoolean("wifi_only", false);
+
+        }
+        operation_queue = new RAOperationQueue();
+        operation_queue.setCallback(new RAOperationQueue.OperationCallback() {
+            @Override
+            public Boolean operate(final Bundle taskinfo) {
+
+
+//
+//                ConnectivityManager connManager = (ConnectivityManager) context
+//                        .getSystemService(Context.CONNECTIVITY_SERVICE);
+//
+//                NetworkInfo networkInfo = connManager
+//                        .getActiveNetworkInfo();
+//                if (networkInfo == null)
+//                {
+//                    dbgUtil.Logd(
+//                            "Current Network info",
+//                            "can not get Active NetworkInfo!");
+//                    false;
+//                }
+//                NetworkInfo.State netState = networkInfo
+//                        .getState();
+//                if (netState != NetworkInfo.State.CONNECTED)
+//                {
+//                    dbgUtil.Logd(
+//                            "Current Network info",
+//                            "not Connected!State="
+//                                    + netState);
+//                    return;
+//                }
+//                int iconntype = -1;
+//                iconntype = networkInfo
+//                        .getType();
+//                SharedPreferences pref = RedAntApplication
+//                        .getInstance()
+//                        .getSharedPreferences(
+//                                "UploadManager",
+//                                0);
+//
+////															String aa = pref
+////																	.getString(
+////																			"aa",
+////																			null);
+////															String ea = pref
+////																	.getString(
+////																			"ea",
+////																			null);
+////															if (iconntype == ConnectivityManager.TYPE_WIFI)
+////															{
+////																if (!TextUtils
+////																		.isEmpty(aa))
+////																	RedAntApplication.active_address = aa;
+////															}
+////															else
+////															{
+////																if (!TextUtils
+////																		.isEmpty(ea))
+////																	RedAntApplication.active_address = ea;
+////															}
+//                boolean
+//                        wifi_only
+//                        =pref.getBoolean("wifi_only",
+//                        true);
+//
+//                if
+//                        (wifi_only
+//                        == true
+//                        && iconntype !=
+//                        ConnectivityManager.TYPE_WIFI
+//                        && iconntype !=
+//                        9/* earthnet */)
+//
+
+                boolean ret = false;
+                String path = taskinfo.getString("path");
+                taskinfo.putInt("status", TaskStatus.TaskStatusStart.ordinal());
+                String url = taskinfo.getString("url") + "" + URL_UPLOAD;
+
+                int waiting = taskinfo.getInt("retry_waiting", 0);
+
+                int newwaiting = waiting;
+                if (newwaiting / 60.0 < 20)
+                    newwaiting += retryWaiting;
+                if (newwaiting > 1200)
+                    newwaiting = 1200;
+                taskinfo.putInt("retry_waiting", newwaiting);
+
+                //                try{
+                try {
+                    Thread.currentThread().sleep(waiting * 1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+//                }catch(InterruptedException ie){
+//                    ie.printStackTrace();
+//                }
+                JSONObject result = Network.UploadImage(path, taskinfo.getBundle("params"), url, new Network.FileUploadListener() {
+                    @Override
+                    public double percent_step() {
+                        //进度刷新步进 3%
+                        return 3.0;
+                    }
+
+                    @Override
+                    public boolean interupt() {
+//                        if(taskinfo.getBoolean("iscancel",false))
+//                            return false;
+                        return taskinfo.getBoolean("iscancel", false);
+                    }
+
+                    @Override
+                    public void onProgress(long pro, double percentage) {
+
+
+                        synchronized (this) {
+                            Log.d("_synchronized", "UploadImage onProgress: " + percentage);
+                            long timeStart = System.currentTimeMillis();
+                            taskinfo.putDouble("progress", percentage);
+                            if (uiUpdateListener != null) {
+                                int index = arr_queue.indexOf(taskinfo);
+//                            uiUpdateListener.onProgress(index,percentage);
+
+                                uiUpdateListener.updateCell(index, taskinfo);
+                            }
+                            Log.d("_synchronized", "UploadImage onProgress: end" + (System.currentTimeMillis() - timeStart));
+                        }
+
+
+                    }
+
+                    @Override
+                    public void onFinish(int code, String res) {
+                        Log.d("", "onFinish: ");
+
+                    }
+                });
+                int r = 0;
+                try {
+                    r = result.getInt("result");
+
+
+                    if (r == 2 || r == RESULT_BARCODE_ERROR) {
+                        taskinfo.putInt("status", TaskStatus.TaskStatusFinish.ordinal());
+                        if (r == 2)
+                            taskinfo.putString("msg", "upload successful");
+                        else {
+                            String rmsg = result.getString("msg");
+                            taskinfo.putString("msg", "warning: " + rmsg);
+                        }
+                    } else {
+                        if (taskinfo.getInt("retry", 0) >= maxRetry) {
+                            taskinfo.putInt("status", TaskStatus.TaskStatusError.ordinal());
+                            taskinfo.putDouble("progress", 0.0);
+                            String rmsg = result.getString("msg");
+                            taskinfo.putString("msg", rmsg);
+                        } else {
+                            taskinfo.putInt("retry", taskinfo.getInt("retry", 0) + 1);
+                            taskinfo.putInt("status", TaskStatus.TaskStatusWait.ordinal());
+                            taskinfo.putDouble("progress", 0.0);
+                            taskinfo.putString("msg", "connection lost, retry...");
+                            ret = true;
+
+                        }
+                    }
+
+
+                } catch (JSONException e) {
+//                    String rmsg=result.getString("msg");
+                    taskinfo.putInt("status", TaskStatus.TaskStatusError.ordinal());
+                    taskinfo.putDouble("progress", 0.0);
+                    taskinfo.putString("msg", "can not upload, please contact administrator.");
+                    e.printStackTrace();
+                } finally {
+                    synchronized (this) {
+                        Log.d("_synchronized", "UploadImage finally ");
+
+                        long timeStart = System.currentTimeMillis();
+                        if (uiUpdateListener != null) {
+                            int index = arr_queue.indexOf(taskinfo);
+
+                            uiUpdateListener.updateCell(index, taskinfo);
+                        }
+                        Log.d("_synchronized", "UploadImage finally finish" + (System.currentTimeMillis() - timeStart));
+
+                    }
+                }
+
+                return ret;
+//                int a=0;
+//                System.out.println(a+"running  tid="+Thread.currentThread().getId());
+//                int min=1000;
+//                int max=5000;
+//                int sleep=new Random().nextInt(max)%(max-min+1) + min;
+//                try{
+//                    Thread.currentThread().sleep(sleep);
+//                }catch(InterruptedException ie){
+//                    ie.printStackTrace();
+//                }
+//                System.out.println(a+"   "+sleep+"     finish  tid="+Thread.currentThread().getId());
+
+            }
+
+            @Override
+            public void operateFinish(Bundle taskinfo) {
+
+                TaskStatus status = TaskStatus.values()[taskinfo.getInt("status", 0)];
+
+                //新增逻辑,对于成功上传的图片,从书记删除
+                //taskinfo.getString("msg").indexOf("warning:")<0 没有匹配错误
+                String path = filePath(taskinfo);
+                File file = new File(path);
+                //只有finish的task 可以删除图片
+
+                if (file.exists() && taskinfo.getInt("status") == TaskStatus.TaskStatusFinish.ordinal() && taskinfo.getString("msg").indexOf("warning:") < 0) {
+                    String filepath = file.getAbsolutePath();
+                    file.delete();
+                    RAUtil.updateGallery(filepath);
+                }
+                ///////////////////////////////////////////////
+
+                boolean removefromlist = false;
+//                if (status==TaskStatus.TaskStatusFinish&&removeFinish)
+//                    removefromlist=true;
+//                else if (status==TaskStatus.TaskStatusError&&removeError)
+//                    removefromlist=true;
+
+                synchronized (this) {
+
+                    Log.d("_synchronized", "OperationCallback operateFinish: ");
+                    long timeStart = System.currentTimeMillis();
+                    if (removefromlist) {
+
+                        removeTask(taskinfo);
+//                            arr_queue.remove(taskinfo);
+//                        if(uiUpdateListener!=null)
+//                            uiUpdateListener.updateList();
+
+
+                    } else {
+                        saveTasks();
+                    }
+
+                    Log.d("_synchronized", "OperationCallback operateFinish: end" + (System.currentTimeMillis() - timeStart));
+
+
+//                        saveTasks();
+
+
+                }
+
+
+            }
+        });
+
+        //            operation_queue = new List<Bundle>() {};
+
+        loadTask();
+
+    }
+
+    private void loadTask() {
+        stopAllTasks();
+        arr_queue = new ArrayList<Bundle>();
+
+
+        Log.d("_RAIMAGE", "saveTasks: RAUploadManager");
+
+        SharedPreferences pref = RedAntApplication.getInstance()
+                .getSharedPreferences("RA Image", 0);
+        try {
+            String tasksBase64 = pref.getString("task_list", "");
+
+
+//            ArrayList<String> wrap_arr = new ArrayList<String>();
+//            for( Bundle b:arr_queue)
+//            {
+//                String sjson=RAUtil.Bundle2Json(b).toString();
+//                Log.d("_RAIMAGE", "saveTasks: "+sjson);
+//                wrap_arr.add(sjson);
+//            }
+//
+//            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+//            ObjectOutputStream oos = new ObjectOutputStream(baos);
+//            oos.writeObject(wrap_arr);
+//
+//            String tasksBase64 = android.util.Base64.encodeToString(baos.toByteArray(), android.util.Base64.DEFAULT);//new String(Base64.encodeBase64(baos.toByteArray()));
+//
+//
+//            editor.putString("task_list", tasksBase64);
+//
+//
+//            editor.commit();
+
+            if (tasksBase64.length() > 0) {
+                byte[] decode = Base64.decode(tasksBase64, Base64.DEFAULT);
+                ByteArrayInputStream bais = new ByteArrayInputStream(decode);
+
+                ObjectInputStream ois = null;
+
+                ois = new ObjectInputStream(bais);
+
+                ArrayList<String> arr_load = (ArrayList<String>) ois.readObject();
+                for (String s : arr_load) {
+                    Log.d("_RAIMAGE", "loadTask: " + s);
+                    JSONObject jsobj = new JSONObject(s);
+                    Bundle b = RAUtil.Json2Bundle(jsobj);
+                    arr_queue.add(b);
+//                                String sjson=RAUtil.Bundle2Json(b).toString();
+
+//                wrap_arr.add(sjson);
+                }
+            }
+
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+        for (Bundle b : arr_queue) {
+
+            TaskStatus status = TaskStatus.values()[b.getInt("status", 0)];
+
+            if (status != TaskStatus.TaskStatusFinish && status != TaskStatus.TaskStatusError)
+                startTask(b);
+        }
+//            int a = 0;
+        // 此处缺少读取持久话保存任务队列的实现。
+    }
+
+    public void addTask(Bundle task) {
+
+        synchronized (this) {
+            Log.d("_synchronized", "addTask: ");
+            long timeStart = System.currentTimeMillis();
+            arr_queue.add(task);
+            saveTasks();
+            Log.d("_synchronized", "addTask: end" + (System.currentTimeMillis() - timeStart));
+        }
+        if (newtaskStatus == TaskStatus.TaskStatusWait) {
+            startTask(task);
+        }
+    }
+
+    ;
+
+    public void addTasks(ArrayList<Bundle> tasks) {
+
+        synchronized (this) {
+            Log.d("_synchronized", "addTasks: ");
+            long timeStart = System.currentTimeMillis();
+            arr_queue.addAll(tasks);
+            saveTasks();
+
+            Log.d("_synchronized", "addTasks: end" + (System.currentTimeMillis() - timeStart));
+
+        }
+        if (newtaskStatus == TaskStatus.TaskStatusWait) {
+            for (Bundle task : tasks) {
+                startTask(task);
+            }
+
+        }
+
+    }
+
+    ;
+
+    public void startTask(Bundle task) {
+
+        task.putBoolean("iscancel", false);
+
+
+        boolean canstart = true;
+
+        ConnectivityManager connManager = (ConnectivityManager) RedAntApplication.getInstance()
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        NetworkInfo networkInfo = connManager
+                .getActiveNetworkInfo();
+        if (networkInfo == null) {
+            dbgUtil.Logd(
+                    "Current Network info",
+                    "can not get Active NetworkInfo!");
+            canstart = false;
+        } else {
+            NetworkInfo.State netState = networkInfo
+                    .getState();
+            if (netState != NetworkInfo.State.CONNECTED) {
+                dbgUtil.Logd(
+                        "Current Network info",
+                        "not Connected!State="
+                                + netState);
+                canstart = false;
+            }
+            int iconntype = -1;
+            iconntype = networkInfo
+                    .getType();
+
+            if (wifiOnly == true
+                    && iconntype !=
+                    ConnectivityManager.TYPE_WIFI
+                    && iconntype !=
+                    9/* earthnet */) {
+                canstart = false;
+            }
+        }
+
+        if (canstart) {
+
+            task.putInt("retry_waiting", 0);
+            task.putInt("status", TaskStatus.TaskStatusWait.ordinal());
+            operation_queue.addOperation(task);
+        } else {
+            task.putInt("status", TaskStatus.TaskStatusStop.ordinal());
+            if (uiUpdateListener != null) {
+                int index = arr_queue.indexOf(task);
+//                            uiUpdateListener.onProgress(index,percentage);
+
+                uiUpdateListener.updateCell(index, task);
+            }
+
+        }
+
+
+    }
+
+    ;
+
+    public void clearTask() {
+        ArrayList<Bundle> remove = new ArrayList<Bundle>();
+        for (Bundle b : arr_queue) {
+//            if(TaskStatus.values()[b.getInt("status",0)]==TaskStatus.TaskStatusStart||TaskStatus.values()[b.getInt("status",0)]==TaskStatus.TaskStatusWait)
+//                continue;
+
+            if (TaskStatus.values()[b.getInt("status", 0)] == TaskStatus.TaskStatusFinish || TaskStatus.values()[b.getInt("status", 0)] == TaskStatus.TaskStatusError)
+                remove.add(b);
+//            removeTask(b);
+        }
+        removeTasks(remove);
+
+
+    }
+
+    public void removeTask(Bundle task) {
+
+
+        synchronized (this) {
+            Log.d("_synchronized", "removeTask");
+            long timeStart = System.currentTimeMillis();
+            arr_queue.remove(task);
+            saveTasks();
+
+
+            String path = filePath(task);
+            File file = new File(path);
+            //只有finish的task 可以删除图片
+            if (file.exists() && task.getInt("status") == TaskStatus.TaskStatusFinish.ordinal()) {
+                String filepath = file.getAbsolutePath();
+                file.delete();
+                RAUtil.updateGallery(filepath);
+            }
+
+            if (uiUpdateListener != null)
+                uiUpdateListener.updateList(arr_queue);
+
+            Log.d("_synchronized", "removeTask: end" + (System.currentTimeMillis() - timeStart));
+        }
+
+
+    }
+
+    ;
+
+    public void removeTasks(List<Bundle> tasks) {
+
+        synchronized (this) {
+            Log.d("_synchronized", "removeTasks: ");
+            long timeStart = System.currentTimeMillis();
+            arr_queue.removeAll(tasks);
+            saveTasks();
+            for (Bundle task : tasks) {
+
+                String path = filePath(task);
+                File file = new File(path);
+                if (file.exists() && task.getInt("status") == TaskStatus.TaskStatusFinish.ordinal()) {
+                    String filepath = file.getAbsolutePath();
+                    file.delete();
+                    RAUtil.updateGallery(filepath);
+                }
+            }
+            if (uiUpdateListener != null)
+                uiUpdateListener.updateList(arr_queue);
+
+
+            Log.d("_synchronized", "removeTasks: end" + (System.currentTimeMillis() - timeStart));
+        }
+
+    }
+
+    ;
+
+    public void stopAllTasks() {
+        if (arr_queue == null)
+            return;
+        for (Bundle task : arr_queue) {
+            stopTask(task);
+        }
+    }
+
+    ;
+
+    public void stopTask(Bundle task) {
+        if (task.getInt("status") != TaskStatus.TaskStatusStart.ordinal() && task.getInt("status") != TaskStatus.TaskStatusWait.ordinal())
+            return;
+
+        task.putBoolean("iscancel", true);
+//        long tid=task.getLong("tid",-1);
+//        if(tid>0)
+//        {
+//
+//
+//        }
+//        task.tet("tid",Thread.currentThread().getId());
+
+//        RAUploadOperation
+
+
+    }
+
+    public void saveTasks() {
+
+        Log.d("_RAIMAGE", "saveTasks: RAUploadManager");
+
+        SharedPreferences pref = RedAntApplication.getInstance()
+                .getSharedPreferences("RA Image", 0);
+        SharedPreferences.Editor editor = pref.edit();
+
+        try {
+
+            ArrayList<String> wrap_arr = new ArrayList<String>();
+            for (Bundle b : arr_queue) {
+                String sjson = RAUtil.Bundle2Json(b).toString();
+                Log.d("_RAIMAGE", "saveTasks: " + sjson);
+                wrap_arr.add(sjson);
+            }
+
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(wrap_arr);
+
+            String tasksBase64 = android.util.Base64.encodeToString(baos.toByteArray(), android.util.Base64.DEFAULT);//new String(Base64.encodeBase64(baos.toByteArray()));
+
+
+            editor.putString("task_list", tasksBase64);
+
+
+            editor.commit();
+
+//            byte[] decode=Base64.decode(personBase64,Base64.DEFAULT);
+//            ByteArrayInputStream bais= new ByteArrayInputStream(decode);
+//
+//            ObjectInputStream ois = new ObjectInputStream(bais);
+//            ArrayList<String> arr_load=(ArrayList<String>)ois.readObject();
+//            int a = 0;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+
+        }
+
+
+//        if (m_swSave.isChecked()&&!TextUtils.isEmpty(encryptPass)&&!TextUtils.isEmpty(encryptUser))
+//        {
+//            editor.putString("user", encryptUser);
+//            editor.putString("password", encryptPass);
+//            editor.putBoolean("kepppass", true);
+//        }
+//        else
+//        {
+//            editor.putString("user", null);
+//            editor.putString("password", null);
+//            editor.putBoolean("kepppass", false);
+//        }
+//
+//        editor.puts
+//
+//        editor.commit();
+
+    }
+
+    ;
+
+
+    private String filePath(Bundle task) {
+//        String path = Environment.getExternalStorageDirectory().getPath();
+//        path+="/"+task.getString("path");
+//        path+="/"+task.getString("file");
+
+        return task.getString("path", "");
+    }
+
+
+}

+ 569 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/RAUtil.java

@@ -0,0 +1,569 @@
+package com.usai.redant.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.media.ExifInterface;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.PermissionChecker;
+import android.util.Log;
+
+import com.usai.redant.redantmobile.RedAntApplication;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by ray on 27/06/2017.
+ */
+
+
+public class RAUtil {
+    public static final int MY_PERMISSIONS_REQUEST= 1;
+//    public static void checkPermissions1(Activity activity, String[] permissions)
+//    {
+//        Log.d("_RAIMAGE", "checkPermissions1:==================================== ");
+//        for(String permission : permissions) {
+//            boolean bshow=ActivityCompat.shouldShowRequestPermissionRationale(activity,permission);
+//            boolean granted= ContextCompat.checkSelfPermission(activity,
+//                    Manifest.permission.ACCESS_FINE_LOCATION)
+//                    == PackageManager.PERMISSION_GRANTED;
+//            boolean pc = PermissionChecker.checkSelfPermission(activity,permission)==PermissionChecker.PERMISSION_GRANTED;
+//            Log.d("_RAIMAGE", "checkPermissions1: "+permission+"  SHOW  "+bshow+"  granted  "+granted +","+pc);
+//        }
+//        Log.d("_RAIMAGE", "checkPermissions1:==================================== ");
+//    }
+    public static boolean isNumeric(String str){
+        for (int i = 0; i < str.length(); i++){
+            System.out.println(str.charAt(i));
+            if (!Character.isDigit(str.charAt(i))){
+                return false;
+            }
+        }
+        return true;
+    }
+    public static Boolean checkPermissions(Activity activity, String[] permissions)
+    {
+        if (Build.VERSION.SDK_INT >= 23)
+        {
+            return checkPermissions_23(activity,permissions);
+        }
+        else
+        {
+            return false;
+//            return checkPermissions_23(activity,permissions);
+        }
+    }
+
+    public static Boolean checkPermissions_23(String[] permissions)
+    {
+        Log.d("_RAIMAGE", "checkPermissions23:==================================== ");
+        ArrayList<String> request_list = new ArrayList<String>();
+        Context context = RedAntApplication.getInstance().getApplicationContext();
+        for(String permission : permissions) {
+
+            boolean pc = PermissionChecker.checkSelfPermission(context,permission)== PermissionChecker.PERMISSION_GRANTED;
+            if(!pc)
+                return false;
+        }
+        Log.d("_RAIMAGE", "checkPermissions23:==================================== ");
+
+
+
+        return true;
+
+    }
+
+    public static void updateGallery(String filename)//filename是我们的文件全名,包括后缀哦
+    {
+
+        Context context = RedAntApplication.getInstance().getApplicationContext();
+        MediaScannerConnection.scanFile(context,
+                new String[] { filename }, null,
+                new MediaScannerConnection.OnScanCompletedListener() {
+                    public void onScanCompleted(String path, Uri uri) {
+                        Log.i("ExternalStorage", "Scanned " + path + ":");
+                        Log.i("ExternalStorage", "-> uri=" + uri);
+                    }
+                });
+    }
+
+    public static Boolean checkPermissions_23(Activity activity, String[] permissions)
+    {
+        Log.d("_RAIMAGE", "checkPermissions23:==================================== ");
+        ArrayList<String> request_list = new ArrayList<String>();
+        for(String permission : permissions) {
+            boolean bshow= ActivityCompat.shouldShowRequestPermissionRationale(activity,permission);
+//            boolean granted= ContextCompat.checkSelfPermission(activity,
+//                    Manifest.permission.ACCESS_FINE_LOCATION)
+//                    == PackageManager.PERMISSION_GRANTED;
+            boolean pc = PermissionChecker.checkSelfPermission(activity,permission)== PermissionChecker.PERMISSION_GRANTED;
+//            Log.d("_RAIMAGE", "checkPermissions23: "+permission+"  SHOW  "+bshow+"  granted  "+granted +","+pc);
+
+            if(!pc)
+                request_list.add(permission);
+        }
+        Log.d("_RAIMAGE", "checkPermissions23:==================================== ");
+
+
+        if(request_list.isEmpty())
+            return false;
+        ActivityCompat.requestPermissions(activity,
+                request_list.toArray(new String[0]),
+                MY_PERMISSIONS_REQUEST);
+
+
+        return true;
+
+    }
+    public static Boolean checkPermissions_24(Activity activity, String[] permissions)
+    {
+
+
+
+
+//        ArrayList<String> request_list = new ArrayList<String>();
+//        for(String permission : permissions) {
+//
+//
+////            boolean bshow=ActivityCompat.shouldShowRequestPermissionRationale(activity,permission);
+////
+////
+////            AppOpsManager appOpsManager = (AppOpsManager) activity.getSystemService(Context.APP_OPS_SERVICE);
+////            String opsName = AppOpsManager.permissionToOp(permission);
+////            if (opsName == null) {
+////                return true;
+////            }
+////            int opsMode = appOpsManager.checkOpNoThrow(opsName, Process.myUid(), activity.getPackageName());
+//////            return opsMode == AppOpsManager.MODE_ALLOWED;
+//
+//
+////            if (ContextCompat.checkSelfPermission(activity,
+////                    Manifest.permission.ACCESS_FINE_LOCATION)
+////                    != PackageManager.PERMISSION_GRANTED||opsMode != AppOpsManager.MODE_ALLOWED)
+//
+//                request_list.add(permission);
+//
+//        }
+
+//        File logfile = new File(Environment.getExternalStorageDirectory()
+//                .getPath() + "/redant/pop/" + "debug" + ".log");
+//
+//        // int mode = Application.MODE_APPEND;
+//        if (!logfile.exists())
+//        {
+//            // mode = Application.MODE_PRIVATE;
+//            try
+//            {
+//                logfile.createNewFile();
+//            }
+//            catch (IOException e)
+//            {
+//                // TODO Auto-generated catch block
+//                e.printStackTrace();
+//
+//            }
+//        }
+        if(permissions.length==0)
+            return true;
+        ActivityCompat.requestPermissions(activity,
+                permissions,
+                MY_PERMISSIONS_REQUEST);
+
+
+        return true;
+
+//
+//        if (ContextCompat.checkSelfPermission(activity,
+//                Manifest.permission.ACCESS_FINE_LOCATION)
+//                != PackageManager.PERMISSION_GRANTED)
+//        {
+//
+//
+////            if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
+////                    permission))
+////            {
+////                return false;
+////            }
+////            else
+//            {
+//                ActivityCompat.requestPermissions(activity,
+//                        new String[]{permission},
+//                        MY_PERMISSIONS_REQUEST);
+//                return true;
+//            }
+//        } else
+//        {
+//           return true;
+//        }
+//        if(true)
+//        return true;
+        // 调用Context的checkCallingOrSelfPermission来检查权限
+
+//        Activity activity1 = (Activity) activity;
+//        if(activity==null)
+//            return false;
+//        if (PackageManager.PERMISSION_GRANTED!= context.checkCallingOrSelfPermission(permission)) {
+//
+////            String[] tmp = permission.split("\\.");
+////            String permission_name = tmp[tmp.length - 1];
+////            permission_name = permission_name.replace("_"," ");
+////
+////
+////            new AlertDialog.Builder(context)
+////                    .setTitle("Warning")
+////                    .setMessage("RA Image need " + permission_name.toLowerCase() + " permission")
+////                    .setPositiveButton("OK", null)
+////                    .show();
+////
+////            return false;
+//
+//
+//             if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
+//                    permission)) {
+//
+//                Log.d("_RAIMAGE", "checkPermission: shouldShowRequestPermissionRationale TRUE   " + permission);
+//                // Show an expanation to the user *asynchronously* -- don't block
+//                // this thread waiting for the user's response! After the user
+//                // sees the explanation, try again to request the permission.
+//
+//            } else {
+//
+//                // No explanation needed, we can request the permission.
+//
+//
+//                Log.d("_RAIMAGE", "checkPermission: shouldShowRequestPermissionRationale false   "+ permission);
+//                ActivityCompat.requestPermissions(activity,
+//                        new String[]{permission},
+//                        123);
+//
+//                // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
+//                // app-defined int constant. The callback method gets the
+//                // result of the request.
+//            }
+//
+//        }
+//        return true;
+    }
+
+    public static String lastPathComponent(String path){
+
+        int start=path.lastIndexOf("/");
+        int end=path.lastIndexOf(".");
+        if(start!=-1 && end!=-1){
+            return path.substring(start+1,end);
+        }else{
+            return null;
+        }
+
+    }
+
+    public static File routeBitmap(File sourceFile, String file_name)
+    {
+        /**
+         * 获取图片的旋转角度,有些系统把拍照的图片旋转了,有的没有旋转
+         */
+        int degree = RAUtil.readPictureDegree(sourceFile.getAbsolutePath());
+
+        BitmapFactory.Options opts=new BitmapFactory.Options();//获取缩略图显示到屏幕上
+        opts.inSampleSize=1;
+        Bitmap cbitmap= BitmapFactory.decodeFile(sourceFile.getAbsolutePath(),opts);
+
+        /**
+         * 把图片旋转为正的方向
+         */
+        Bitmap newbitmap = RAUtil.rotaingImageView(degree, cbitmap);
+
+        //sourceFile.get
+        String routedPath = "";
+        if(file_name==null) {
+            String path = sourceFile.getPath();
+
+            routedPath=path.replace(".jpg", "_routed.jpg");
+        }
+        else
+        {
+            String path = sourceFile.getParent();
+            routedPath = path+"/"+file_name;
+        }
+        File routedFile = new File(routedPath);
+        try {
+
+            FileOutputStream outputStream = new FileOutputStream(routedFile);
+            newbitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
+
+            outputStream.flush();
+            outputStream.close();
+
+            String filepath = sourceFile.getAbsolutePath();
+            sourceFile.delete();
+            RAUtil.updateGallery(filepath);
+//				scaleFile.renameTo(new File(path));
+            return routedFile;
+
+        } catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+    /**
+     * 读取图片属性:旋转的角度
+     * @param path 图片绝对路径
+     * @return degree旋转的角度
+     */
+    public static int readPictureDegree(String path) {
+        int degree  = 0;
+        try {
+            ExifInterface exifInterface = new ExifInterface(path);
+            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
+            switch (orientation) {
+                case ExifInterface.ORIENTATION_ROTATE_90:
+                    degree = 90;
+                    break;
+                case ExifInterface.ORIENTATION_ROTATE_180:
+                    degree = 180;
+                    break;
+                case ExifInterface.ORIENTATION_ROTATE_270:
+                    degree = 270;
+                    break;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return degree;
+    }
+    /*
+     * 旋转图片
+     * @param angle
+     * @param bitmap
+     * @return Bitmap
+     */
+    public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
+        //旋转图片 动作
+        Matrix matrix = new Matrix();;
+        matrix.postRotate(angle);
+        System.out.println("angle2=" + angle);
+        // 创建新的图片
+        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
+                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+        return resizedBitmap;
+    }
+    public static JSONObject Bundle2Json(Bundle bundle)
+    {
+        JSONObject json = new JSONObject();
+        Set<String> keys = bundle.keySet();
+        for (String key : keys) {
+            try {
+                Log.d("", "Bundle2Json: key:"+key+"  val: "+wrap(bundle.get(key)));
+                 json.put(key, wrap(bundle.get(key))); //see edit below
+//                json.put(key, JSONObject.wrap(bundle.get(key)));
+            } catch(JSONException e) {
+                //Handle exception here
+            }
+        }
+        return json;
+    }
+
+    private static Object wrap(Object o) {
+        if (o == null) {
+            return JSONObject.NULL;
+        }
+        if (o instanceof JSONArray || o instanceof JSONObject) {
+            return o;
+        }
+        if (o.equals(JSONObject.NULL)) {
+            return o;
+        }
+        try {
+            if (o instanceof Bundle)
+            {
+                return Bundle2Json((Bundle) o);
+
+            }
+            if (o instanceof Collection) {
+                return new JSONArray((Collection) o);
+            } else if (o.getClass().isArray()) {
+                return toJSONArray(o);
+            }
+            if (o instanceof Map) {
+                return new JSONObject((Map) o);
+            }
+            if (o instanceof Boolean ||
+                    o instanceof Byte ||
+                    o instanceof Character ||
+                    o instanceof Double ||
+                    o instanceof Float ||
+                    o instanceof Integer ||
+                    o instanceof Long ||
+                    o instanceof Short ||
+                    o instanceof String) {
+                return o;
+            }
+            if (o.getClass().getPackage().getName().startsWith("java.")) {
+                return o.toString();
+            }
+        } catch (Exception ignored) {
+        }
+        return null;
+    }
+
+    private static JSONArray toJSONArray(Object array) throws JSONException {
+        JSONArray result = new JSONArray();
+        if (!array.getClass().isArray()) {
+            throw new JSONException("Not a primitive array: " + array.getClass());
+        }
+        final int length = Array.getLength(array);
+        for (int i = 0; i < length; ++i) {
+            result.put(wrap(Array.get(array, i)));
+        }
+        return result;
+    }
+    public static Bundle Json2Bundle(JSONObject s) {
+        Bundle bundle = new Bundle();
+
+        for (Iterator<String> it = s.keys(); it.hasNext(); ) {
+            String key = it.next();
+            try {
+                Object o = s.get(key);
+
+
+
+                if (o == null) {
+                    continue;
+                }
+                else if ( o instanceof JSONObject) {
+                    bundle.putBundle(key,Json2Bundle((JSONObject) o));
+                }
+                else if(o instanceof JSONArray)
+                {
+                    throw new JSONException("Json2Bundle does not support Json array: " + o.getClass());// bundle.putarr
+                }
+                else if (o.equals(JSONObject.NULL)) {
+                    continue;
+                }
+                else if (o instanceof Boolean)
+                {
+                    bundle.putBoolean(key,((Boolean) o).booleanValue());
+                }
+                else if(o instanceof Byte)
+                {
+                    bundle.putByte(key, ((Byte) o).byteValue());
+                }
+                else if(o instanceof Character)
+                {
+                    bundle.putChar(key, ((Character) o).charValue());
+                }
+                else if(o instanceof Double)
+                {
+                    bundle.putDouble(key, ((Double) o).doubleValue());
+                }
+                else if(o instanceof Float)
+                {
+                    bundle.putFloat(key, ((Float) o).floatValue());
+                }
+                else if(o instanceof Integer)
+                {
+                    bundle.putInt(key, ((Integer) o).intValue());
+                }
+                else if(o instanceof Long)
+                {
+                    bundle.putLong(key, ((Long) o).longValue());
+                }
+                else if(o instanceof Short)
+                {
+                    bundle.putShort(key, ((Short) o).shortValue());
+                }
+                else if(o instanceof String)
+                {
+                    bundle.putString(key, o.toString());
+                }
+
+//                ArrayList<Parcelable> a = new ArrayList<>();
+//                a.add("");
+//                a.add(1);
+//                bundle.putParcelableArrayList("arr", a);
+
+
+
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+        return bundle;
+    }
+    public static Bundle Json2Bundle1(JSONObject s) {
+        Bundle bundle = new Bundle();
+
+        for (Iterator<String> it = s.keys(); it.hasNext(); ) {
+            String key = it.next();
+            JSONArray arr = s.optJSONArray(key);
+            Double num = s.optDouble(key);
+//            Integer i = s.optInt(key);
+            String str = s.optString(key);
+            JSONObject obj = s.optJSONObject(key);
+            if (arr != null && arr.length() <= 0)
+            {
+                bundle.putStringArray(key, new String[]{});
+            }
+
+            else if (arr != null && !Double.isNaN(arr.optDouble(0))) {
+                double[] newarr = new double[arr.length()];
+                for (int i=0; i<arr.length(); i++)
+                    newarr[i] = arr.optDouble(i);
+                bundle.putDoubleArray(key, newarr);
+            }
+
+            else if (arr != null && arr.optString(0) != null) {
+                String[] newarr = new String[arr.length()];
+                for (int i=0; i<arr.length(); i++)
+                    newarr[i] = arr.optString(i);
+                bundle.putStringArray(key, newarr);
+            }
+
+
+            else if (obj != null)
+            {
+                Bundle b=Json2Bundle(obj);
+                bundle.putBundle(key, b);
+            }
+
+            else if (!num.isNaN())
+                bundle.putDouble(key, num);
+
+            else if (str != null)
+                bundle.putString(key, str);
+
+            else
+                System.err.println("unable to transform json to bundle " + key);
+        }
+        return bundle;
+    }
+//    public static Bundle Json2Bundle(JSONObject jsonObject) throws JSONException {
+//        Bundle bundle = new Bundle();
+//        Iterator iter = jsonObject.keys();
+//        while(iter.hasNext()){
+//            String key = (String)iter.next();
+//            String value = jsonObject.getString(key);
+//            bundle.putString(key,value);
+//        }
+//        return bundle;
+//    }
+}

+ 69 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/SqlOpenHelper.java

@@ -0,0 +1,69 @@
+package com.usai.redant.util;
+
+//import android.R.array;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import java.util.ArrayList;
+
+public class SqlOpenHelper extends SQLiteOpenHelper {
+
+	private ArrayList<String> initSQL = new ArrayList<String>();
+	public void addInitSQL(String sql)
+	{
+		initSQL.add(sql);
+		
+	}
+	public int get_RecordCount(String tablename)
+	{
+		return 0;
+		
+	}
+	public SQLiteDatabase OpenDB(boolean writable)
+	{
+		if (writable)
+			return getWritableDatabase();
+		else
+			return getReadableDatabase();
+	}
+	
+	private void initDB(SQLiteDatabase db)
+	{
+		for(int i=0;i<initSQL.size();i++)
+		{
+			db.execSQL(initSQL.get(i));
+		}
+	
+		
+	}
+	public SqlOpenHelper(Context context, String name, CursorFactory factory,
+                         int version) {
+		super(context, name, factory, version);
+		// TODO Auto-generated constructor stub
+	}
+
+	@Override
+	public void onCreate(SQLiteDatabase db) {
+		// TODO Auto-generated method stub
+		initDB(db);
+		
+	}
+
+	@Override
+	public void onOpen(SQLiteDatabase db) {
+		// TODO Auto-generated method stub
+		super.onOpen(db);
+	}
+
+	@Override
+	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+		// TODO Auto-generated method stub
+		db.execSQL("ALTER TABLE pics ADD try_count INTEGER DEFAULT (0)");
+//		String sql="alter table pics add field try_count INTEGER";
+		
+	}
+
+}

+ 262 - 0
RedAnt Mobile/app/src/main/java/com/usai/redant/util/dbgUtil.java

@@ -0,0 +1,262 @@
+package com.usai.redant.util;
+
+import android.Manifest;
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Environment;
+import android.util.Log;
+
+import com.usai.redant.redantmobile.RedAntApplication;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+//import java.util.Calendar;
+
+public class dbgUtil
+{
+
+
+
+	// static boolean ENABLE_DEBUG = true;
+	// static boolean ENABLE_SQL_DEBUG = true;
+	// final int DEBUG_LEVEL_NONE = 8;
+	// static int DEBUG_LEVEL = Log.VERBOSE;
+
+	// private static boolean m_dbgFlag = true;
+	/*
+	 * public dbgUtil(Context context) {
+	 * 
+	 * m_dbgFlag = Boolean.parseBoolean(context.getString(R.string.flag_debug));
+	 * 
+	 * }
+	 * 
+	 * public dbgUtil(Context context) { m_dbgFlag =
+	 * Boolean.parseBoolean(context.getString(R.string.flag_debug)); return
+	 * this; }
+	 */
+	public static void fileLog(String content)
+	{
+
+
+		String[] permissions = {
+				Manifest.permission.WRITE_EXTERNAL_STORAGE,
+				Manifest.permission.READ_EXTERNAL_STORAGE,
+		};
+
+
+
+
+		boolean result= RAUtil.checkPermissions_23(permissions);
+
+		if(!result)
+			return;
+		
+		File dir = new File(Environment.getExternalStorageDirectory().getPath()
+				+ "/redant/pop");
+		if (!dir.exists())
+			dir.mkdirs();
+
+		Calendar c = Calendar.getInstance();
+		c.add(Calendar.MONDAY, -1);
+
+		String newtime = new SimpleDateFormat("yyyy-MM-dd").format(c
+				.getTimeInMillis());
+
+		File[] f = dir.listFiles();
+		if(f==null)
+		    return;
+		for (int i = 0; i < f.length; i++)
+		{
+			if(!f[i].isFile())
+				continue;
+			String n = f[i].getName();
+			if ((n != null) && (n.length() > 0))
+			{
+				int dot = n.lastIndexOf('.');
+				if ((dot > -1) && (dot < (n.length())))
+				{
+					n = n.substring(0, dot);
+				}
+				if(newtime.compareTo(n)>0)
+					f[i].delete();
+				
+
+
+			}
+		}
+
+		// dir.listfiles
+
+		String file = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
+		String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
+				.format(new Date());
+
+		FileOutputStream outputStream = null;
+		// try
+		// {
+
+		// dir.createNewFile()
+		File logfile = new File(Environment.getExternalStorageDirectory()
+				.getPath() + "/redant/pop/" + file + ".log");
+
+		// int mode = Application.MODE_APPEND;
+		if (!logfile.exists())
+		{
+			// mode = Application.MODE_PRIVATE;
+			try
+			{
+				logfile.createNewFile();
+			}
+			catch (IOException e)
+			{
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		// outputStream
+		// =RedAntApplication.getInstance().openFileOutput("pop.log", mode);
+
+		String logtextString = timeStamp + "   " + content;
+
+		FileWriter fw = null;
+		BufferedWriter bw = null;
+		String datetime = "";
+		try
+		{
+			RedAntApplication.loglock.writeLock().lock();
+
+			fw = new FileWriter(Environment.getExternalStorageDirectory()
+					.getPath() + "/redant/pop/" + file + ".log", true);//
+			// 创建FileWriter对象,用来写入字符流
+			bw = new BufferedWriter(fw); // 将缓冲对文件的输出
+			// String myreadline = datetime + "[]" + str;
+
+			bw.write(logtextString + "\n"); // 写入文件
+			bw.newLine();
+			bw.flush(); // 刷新该流的缓冲
+			bw.close();
+			fw.close();
+			RedAntApplication.loglock.writeLock().unlock();
+		}
+		catch (IOException e)
+		{
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			try
+			{
+				bw.close();
+				fw.close();
+			}
+			catch (IOException e1)
+			{
+				// TODO Auto-generated catch block
+			}
+		}
+
+	}
+
+	public static void Logd(String tag, String msg)
+	{
+		String pos = getTracePos();
+		Log.d(tag, msg + pos);
+	}
+
+	// public static void Log(int type, String tag, String msg)
+	// {
+	// // if (ENABLE_DEBUG == false)
+	// // return;
+	// // if (type < DEBUG_LEVEL)
+	// // return;
+	// String pos= getTracePos();
+	// switch (type)
+	// {
+	// case Log.ASSERT:
+	// Log.wtf(tag, msg+pos);
+	// break;
+	// case Log.DEBUG:
+	// Log.d(tag, msg+pos);
+	// break;
+	// case Log.ERROR:
+	// Log.e(tag, msg+pos);
+	// break;
+	// case Log.INFO:
+	// Log.i(tag, msg+pos);
+	// break;
+	// case Log.VERBOSE:
+	// Log.v(tag, msg+pos);
+	// break;
+	// case Log.WARN:
+	// Log.w(tag, msg+pos);
+	// break;
+	// default:
+	// Log.wtf("dbgUtil", "LOG TYPE ERROR!"+pos);
+	// break;
+	// }
+	//
+	// }
+
+	private static String getTracePos()
+	{
+		// StackTraceElement[] elements =
+		// Thread.currentThread().getStackTrace();
+		StackTraceElement element = Thread.currentThread().getStackTrace()[4];
+
+		return " at " + element.getClassName() + "." + element.getMethodName()
+				+ "(" + element.getFileName() + ":" + element.getLineNumber()
+				+ ")";
+	}
+
+	public static void dbgCursorInfo(Cursor cursor, Context context/*
+																	 * , String
+																	 * TracePos
+																	 */)
+	{
+		// if (ENABLE_SQL_DEBUG == false)
+		// return;
+
+		// ----------------------debug cursor-----------------------------------
+		Log.d("sql_dbg@dbgCursorInfo",
+				getTracePos() + "Cursor size:	" + cursor.getCount()
+						+ ";	columns count:	" + cursor.getColumnCount() + ";");
+		// dbgUtil.Log(Log.DEBUG,"sql_dbg", getTracePos() + "Cursor size:	" +
+		// cursor.getCount()
+		// + ";	columns count:	" + cursor.getColumnCount() + ";");
+		for (int i = 0; i < cursor.getColumnCount(); i++)
+		{
+			Log.d("sql_dbg@dbgCursorInfo", "column idx:	" + i
+					+ ";		column name:	" + cursor.getColumnName(i) + ";");
+			// dbgUtil.Log(Log.DEBUG,"sql_dbg",
+			// "column idx:	" + i + ";		column name:	"
+			// + cursor.getColumnName(i) + ";");
+		}
+		// ----------------------debug cursor-----------------------------------
+
+	}
+	// public static void dbgCursorMoreInfo(Cursor cursor /*, String TracePos*/)
+	// {
+	// if(Boolean.parseBoolean(context.getString(R.string.flag_debug))==false)
+	// return;
+	//
+	//
+	// //----------------------debug cursor-----------------------------------
+	// dbgUtil.Log(Log.DEBUG,"sql_dbg",Log.getStackTraceString(new Throwable())
+	// +"Cursor size:	"+cursor.getCount()
+	// +";	columns count:	"+cursor.getColumnCount()
+	// +";");
+	// for (int i =0;i<cursor.getColumnCount();i++)
+	// {
+	// dbgUtil.Log(Log.DEBUG,"sql_dbg","column idx:	"+i
+	// +";		column name:	"+cursor.getColumnName(i)
+	// +";");
+	// }
+	// //----------------------debug cursor-----------------------------------
+	//
+	// }
+}

BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/bar2.png


BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_camera.png


BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_reload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_scan.png


BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_action_upload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/ic_launcher.png


+ 20 - 0
RedAnt Mobile/app/src/main/res/drawable-hdpi/imagebutton.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+           <shape android:shape="rectangle" >
+            <!-- 填充的颜色 -->
+            <solid android:color="#33C0C0C0" />
+            <!-- 设置按钮的四个角为弧形 -->
+            <!-- android:radius 弧形的半径 -->
+            <corners android:radius="15dip" />
+            <!-- padding:Button里面的文字与Button边界的间隔 -->
+            <padding android:bottom="0dp" android:left="0dp" android:right="0dp" android:top="0dp" />
+        </shape>
+    </item>
+    <item android:state_pressed="false">
+     <shape android:shape="rectangle">
+            <solid android:color="#33808080" />
+            <corners android:radius="15dip" />
+         </shape>
+    </item> 
+</selector>

BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/no_pic.png


BIN
RedAnt Mobile/app/src/main/res/drawable-hdpi/picture_frame.png


BIN
RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_camera.png


BIN
RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_reload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_scan.png


BIN
RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_action_upload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-mdpi/ic_launcher.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_camera.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_reload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_scan.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_action_upload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xhdpi/ic_launcher.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_camera.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_reload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_scan.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_action_upload.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xxhdpi/ic_launcher.png


BIN
RedAnt Mobile/app/src/main/res/drawable-xxhdpi/red_ant_logo.png


+ 18 - 0
RedAnt Mobile/app/src/main/res/drawable/black_border.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!--背景色-->
+    <solid android:color="#FFFFFF" />
+
+    <!--边框颜色-->
+    <stroke
+        android:width="0.01dp"
+        android:color="#000000" />
+
+    <padding
+        android:bottom="1dp"
+        android:left="1dp"
+        android:right="1dp"
+        android:top="1dp" />
+
+</shape>

BIN
RedAnt Mobile/app/src/main/res/drawable/check_check.png


BIN
RedAnt Mobile/app/src/main/res/drawable/check_none.png


+ 13 - 0
RedAnt Mobile/app/src/main/res/drawable/preview_index_corner.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <corners android:radius="20dp"/>
+
+    <solid android:color="@color/white_color"/>
+
+    <stroke
+        android:width="1dp"
+        android:color="@color/white_color"
+        />
+
+</shape>

+ 9 - 0
RedAnt Mobile/app/src/main/res/drawable/switch_thumb.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!--<item android:state_pressed="true" android:drawable="@drawable/thumb_on"/>-->
+    <item android:state_checked="true" android:drawable="@drawable/thumb_on"/>
+
+    <item android:drawable="@drawable/thumb_off"/>
+
+</selector>

+ 8 - 0
RedAnt Mobile/app/src/main/res/drawable/switch_track.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!--<item android:state_focused="true" android:drawable="@drawable/track_on"/>-->
+    <item android:state_checked="true" android:drawable="@drawable/track_on"/>
+    <item android:drawable="@drawable/track_off"/>
+
+</selector>

+ 15 - 0
RedAnt Mobile/app/src/main/res/drawable/thumb_off.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <size android:width="30dp"
+        android:height="30dp"/>
+
+    <corners android:radius="20dp"
+        />
+
+    <solid android:color="#eeeeee" />
+
+    <stroke android:width="1dp"
+        android:color="#666666"/>
+</shape>

+ 17 - 0
RedAnt Mobile/app/src/main/res/drawable/thumb_on.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <!-- 高度40 -->
+    <size android:height="30dp" android:width="30dp"/>
+    <!-- 圆角弧度 20 -->
+    <corners android:radius="20dp"/>
+
+
+
+
+    <stroke android:width="1dp"
+        android:color="#33da33"/>
+
+    <solid android:color="#eeeeee" />
+</shape>

+ 15 - 0
RedAnt Mobile/app/src/main/res/drawable/track_off.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <size
+
+        android:height="10dp"
+        android:width="30dp"/>
+
+    <corners android:radius="20dp" />
+
+
+
+    <solid android:color="#888888" />
+</shape>

Неке датотеке нису приказане због велике количине промена