Browse Source

提交类型 添加人脸识别库
提交内容 处理相关问题

Bitliker 7 years ago
parent
commit
b3a33417f3
66 changed files with 3517 additions and 17 deletions
  1. 1 0
      WeiChat/build.gradle
  2. 2 0
      WeiChat/src/main/AndroidManifest.xml
  3. 2 0
      WeiChat/src/main/assets/idl-license.face-android
  4. 5 2
      WeiChat/src/main/java/com/xzjmyk/pm/activity/ui/MainActivity.java
  5. 19 2
      WeiChat/src/main/java/com/xzjmyk/pm/activity/ui/message/MessageFragment.java
  6. 0 1
      app_core/common/src/main/java/com/core/base/BaseActivity.java
  7. 0 10
      app_modular/appmessages/src/main/java/com/modular/appmessages/widget/SignRefreshLayout.java
  8. 8 1
      app_modular/apputils/src/main/java/com/modular/apputils/utils/SignUtils.java
  9. 74 0
      app_modular/apputils/src/main/res/layout/common_prompt_dialog.xml
  10. 10 0
      app_modular/apputils/src/main/res/values/style.xml
  11. 2 0
      app_modular/faceplatform-release/build.gradle
  12. BIN
      app_modular/faceplatform-release/faceplatform-release.aar
  13. 1 0
      app_modular/faceplatform-ui/.gitignore
  14. 30 0
      app_modular/faceplatform-ui/build.gradle
  15. BIN
      app_modular/faceplatform-ui/libs/ast.jar
  16. 17 0
      app_modular/faceplatform-ui/proguard-rules.pro
  17. 11 0
      app_modular/faceplatform-ui/src/main/AndroidManifest.xml
  18. 521 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceDetectActivity.java
  19. 526 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceLivenessActivity.java
  20. 62 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceSDKResSettings.java
  21. 231 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceVeriftyActivity.java
  22. 136 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/config/FaceConfig.java
  23. 54 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/model/FaceVerify.java
  24. 89 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/Base64.java
  25. 123 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/BrightnessTools.java
  26. 25 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/CameraUtils.java
  27. 130 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/DeviceUuidFactory.java
  28. 50 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/EncryptUtils.java
  29. 68 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/VolumeUtils.java
  30. 175 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/FaceDetectRoundView.java
  31. 242 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/VeriftyDialog.java
  32. 86 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/WaveHelper.java
  33. 334 0
      app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/WaveView.java
  34. BIN
      app_modular/faceplatform-ui/src/main/jniLibs/arm64-v8a/libFaceSDK.so
  35. BIN
      app_modular/faceplatform-ui/src/main/jniLibs/arm64-v8a/libidl_license.so
  36. BIN
      app_modular/faceplatform-ui/src/main/jniLibs/armeabi-v7a/libFaceSDK.so
  37. BIN
      app_modular/faceplatform-ui/src/main/jniLibs/armeabi-v7a/libidl_license.so
  38. BIN
      app_modular/faceplatform-ui/src/main/jniLibs/x86/libFaceSDK.so
  39. BIN
      app_modular/faceplatform-ui/src/main/jniLibs/x86/libidl_license.so
  40. 25 0
      app_modular/faceplatform-ui/src/main/res/drawable/bg_tips.xml
  41. 22 0
      app_modular/faceplatform-ui/src/main/res/drawable/bg_tips_no.xml
  42. 107 0
      app_modular/faceplatform-ui/src/main/res/layout/activity_face_detect.xml
  43. 96 0
      app_modular/faceplatform-ui/src/main/res/layout/activity_face_detect_v3100.xml
  44. 107 0
      app_modular/faceplatform-ui/src/main/res/layout/activity_face_liveness.xml
  45. 95 0
      app_modular/faceplatform-ui/src/main/res/layout/activity_face_liveness_v3100.xml
  46. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/bg_face_round.png
  47. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/ic_close.png
  48. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/ic_disable_sound.png
  49. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/ic_enable_sound.png
  50. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_close_ext.png
  51. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_disable_sound_ext.png
  52. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_enable_sound_ext.png
  53. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_success.png
  54. BIN
      app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_warning.png
  55. BIN
      app_modular/faceplatform-ui/src/main/res/raw/detect_face_in.mp3
  56. BIN
      app_modular/faceplatform-ui/src/main/res/raw/face_good.mp3
  57. BIN
      app_modular/faceplatform-ui/src/main/res/raw/liveness_eye.mp3
  58. BIN
      app_modular/faceplatform-ui/src/main/res/raw/liveness_head_down.mp3
  59. BIN
      app_modular/faceplatform-ui/src/main/res/raw/liveness_head_left.mp3
  60. BIN
      app_modular/faceplatform-ui/src/main/res/raw/liveness_head_left_right.mp3
  61. BIN
      app_modular/faceplatform-ui/src/main/res/raw/liveness_head_right.mp3
  62. BIN
      app_modular/faceplatform-ui/src/main/res/raw/liveness_head_up.mp3
  63. BIN
      app_modular/faceplatform-ui/src/main/res/raw/liveness_mouth.mp3
  64. 26 0
      app_modular/faceplatform-ui/src/main/res/values/strings.xml
  65. 4 0
      settings.gradle
  66. 1 1
      version.gradle

+ 1 - 0
WeiChat/build.gradle

@@ -180,6 +180,7 @@ dependencies {
     compile project(':appbooking')
     compile project(':appmusic')
     compile project(':apputils')
+    compile project(':faceplatform-ui')
     compile 'com.android.support.constraint:constraint-layout:1.0.2'
     compile 'com.android.support:support-v4:26.+'
 }

+ 2 - 0
WeiChat/src/main/AndroidManifest.xml

@@ -2,6 +2,7 @@
 <manifest package="com.xzjmyk.pm.activity"
           xmlns:android="http://schemas.android.com/apk/res/android"
           android:versionCode="158"
+    xmlns:tools="http://schemas.android.com/tools"
           android:versionName="6.1.9">
 
     <uses-sdk
@@ -113,6 +114,7 @@
         android:hardwareAccelerated="true"
         android:icon="@drawable/uuu"
         android:label="@string/app_name"
+        tools:replace="android:icon,android:theme"
         android:largeHeap="true"
         android:persistent="true"
         android:theme="@style/MainBaseTheme">

+ 2 - 0
WeiChat/src/main/assets/idl-license.face-android

@@ -0,0 +1,2 @@
+12FC7A335BD844EDBBD1EA4126E56711B566D8B330517DBEEA5F799B276BBD1D86E66DD18CC8954685C50564BA6349EC9431C61BAA42A80AB51FD2FB5F51DCCA8DF3A4BCFE928CEDAD17C9A2654E9B320A91C8711CF766B62CB0BA84F5012B1D8679B9FD1579DF2C708B0CE26A865AEDDA0D3A7A3D05E04C9AE3B4C92EF0E4118833379E0AC0DCC1F23E63E0C404CB9B54E465445DEF37D0012B8CB6B54A542C8C04CDDC752DD7A73BD16434BA142B558EDE20B65E64309913417BCB45533936699818911F35DEF0B6B595CF48805CCF0502EE733FE7C810B7B6C6D6DF5DFBE4273363F96B3A9C04182C9F21EAAABCF22F130F37E1FD82EE612C87F37EF96DD9
+04FAD27C007D9FF1C9B3A504BA23B7F18219D38C66CE88D2C2679BE5764D5643C3E631F822EFABDC36187749CB15D000AC2BB670FB173B8466E28050BB10868AE8FAF0F1A7F70E68B06AB86ED294F42531DE50D42E38C06F127149C205215AE2F811A4F2096FDB0A998B8FC522BD2A51E362362ECFF564B6CEBD0573DBDA86E53B6B9A9169D3FD40B005EF64B9220890626710A1BCBF0431EECDC78FD39CFAED0514BEA57BC831FF3C773B42EFF33F10D9D183CCBA13AA4D3C6E087F7B5F2778F9C1BD014845C68EE34A768F3B7862C2166C6977D27B0CFF9F9F42EB2AF9E3A357CD793B9836D50CE97994FA1C31B05D5D1C5F65BB29947416A7A9F620ADA960

+ 5 - 2
WeiChat/src/main/java/com/xzjmyk/pm/activity/ui/MainActivity.java

@@ -14,7 +14,6 @@ import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PersistableBundle;
@@ -44,6 +43,7 @@ import com.baidu.android.pushservice.PushConstants;
 import com.baidu.android.pushservice.PushManager;
 import com.baidu.autoupdatesdk.BDAutoUpdateSDK;
 import com.baidu.autoupdatesdk.UICheckUpdateCallback;
+import com.baidu.idl.face.platform.ui.config.FaceConfig;
 import com.common.LogUtil;
 import com.common.data.DateFormatUtil;
 import com.common.data.ListUtils;
@@ -293,7 +293,7 @@ public class MainActivity extends BaseActivity implements ImStatusListener, NetW
     }
 
     private Timer delayTimer;
-    private Runnable uiRunnable=new Runnable() {
+    private Runnable uiRunnable = new Runnable() {
         @Override
         public void run() {
             if (main_tab_three != null) {
@@ -633,6 +633,9 @@ public class MainActivity extends BaseActivity implements ImStatusListener, NetW
 //		startService(new Intent(MainActivity.this, AutoErpService.class));
         LogUtil.d("OnCreate end:" + DateFormatUtil.long2Str(DateFormatUtil.YMD_HMS));
 
+        //初始化面部识别
+        FaceConfig.initFace(ct);
+
     }
 
     private AutoPresenter autoPresenter;

+ 19 - 2
WeiChat/src/main/java/com/xzjmyk/pm/activity/ui/message/MessageFragment.java

@@ -19,6 +19,8 @@ import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
 
+import com.baidu.idl.face.platform.ui.FaceVeriftyActivity;
+import com.common.config.BaseConfig;
 import com.common.data.DateFormatUtil;
 import com.common.data.ListUtils;
 import com.common.data.StringUtil;
@@ -110,7 +112,11 @@ public class MessageFragment extends SupportToolBarFragment implements IMessageV
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (item.getItemId() == R.id.quick_sign) {
-            setSignViewData(false);
+            if (BaseConfig.isDebug()){
+                startActivityForResult(new Intent(ct,FaceVeriftyActivity.class),0x223);
+            }else{
+                setSignViewData(false);
+            }
         }
         return super.onOptionsItemSelected(item);
     }
@@ -203,6 +209,17 @@ public class MessageFragment extends SupportToolBarFragment implements IMessageV
         }
     }
 
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == 0x223) {
+            if (resultCode == getActivity().RESULT_OK) {
+                sign(true);
+            }
+        }
+
+    }
+
     public void showProgress() {
         if (mContext != null && mContext.progressDialog != null) {
             mContext.progressDialog.show();
@@ -319,7 +336,7 @@ public class MessageFragment extends SupportToolBarFragment implements IMessageV
                 break;
 
             case R.id.itemSignImage:
-                sign(true);
+                startActivityForResult(new Intent(ct, FaceVeriftyActivity.class), 0x223);
                 break;
         }
 

+ 0 - 1
app_core/common/src/main/java/com/core/base/BaseActivity.java

@@ -92,7 +92,6 @@ public abstract class BaseActivity extends ActionBackActivity {
         mFastVolley = MyApplication.getInstance().getFastVolley();
         Intent intent = getIntent();
         if (intent == null || intent.getBooleanExtra("ORIENTATION_PORTRAIT", true)) {
-            LogUtil.i("ORIENTATION_PORTRAIT");
             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏
         }
         progressDialog = CustomProgressDialog.createDialog(this);

+ 0 - 10
app_modular/appmessages/src/main/java/com/modular/appmessages/widget/SignRefreshLayout.java

@@ -7,7 +7,6 @@ import android.os.Message;
 import android.support.v7.widget.AppCompatCheckBox;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -22,7 +21,6 @@ import android.widget.ScrollView;
 import android.widget.Scroller;
 import android.widget.TextView;
 
-import com.common.LogUtil;
 import com.common.preferences.PreferenceUtils;
 import com.common.system.DisplayUtil;
 import com.modular.appmessages.R;
@@ -192,7 +190,6 @@ public class SignRefreshLayout extends ViewGroup {
             }
         }
         mLastYIntercept = y;
-        LogUtil.i("gong","intercept="+intercept);
         return intercept;
     }
     private boolean rvPullUpIntercept(View child) {
@@ -295,7 +292,6 @@ public class SignRefreshLayout extends ViewGroup {
             }
             case MotionEvent.ACTION_UP: {
                 // 判断本次触摸系列事件结束时,Layout的状态
-                LogUtil.i("gong", "status=" + status);
                 switch (status) {
                     case NORMAL:
                         upWithStatusNormal();
@@ -331,7 +327,6 @@ public class SignRefreshLayout extends ViewGroup {
         if (headerView != null) {
             upStatus(status);
         }
-        LogUtil.i("gong", "updateStatus=" + status);
         if (status != NORMAL) {
             this.status = status;
         }
@@ -344,7 +339,6 @@ public class SignRefreshLayout extends ViewGroup {
     private void upWithStatusTryRefresh() {
         // 取消本次的滑动
         mLayoutScroller.startScroll(0, getScrollY(), 0, -getScrollY(), SCROLL_SPEED);
-        LogUtil.i("gong", "upWithStatusTryRefresh=" + status);
         status = NORMAL;
         if (headerView != null) {
             stopAnim();
@@ -380,7 +374,6 @@ public class SignRefreshLayout extends ViewGroup {
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case STOP_REFRESH: {
-                    LogUtil.i("gong", "handleMessage=" + status);
                     mLayoutScroller.startScroll(0, getScrollY(), 0, -getScrollY(), SCROLL_SPEED);
                     status = NORMAL;
                     if (headerView != null) {
@@ -403,7 +396,6 @@ public class SignRefreshLayout extends ViewGroup {
         if (status == REFRESH) {
             stopTryRefresh();
         }
-        LogUtil.i("gong", "stopRefresh=" + status);
         status = NORMAL;
     }
 
@@ -506,7 +498,6 @@ public class SignRefreshLayout extends ViewGroup {
     }
 
     private void stopAnim() {
-        Log.i("gong", "stopAnim");
         statusImg.setAnimation(null);
         statusImg.setImageResource(R.drawable.ic_refresh_pull_down);
         statusTV.setText(R.string.pull_down_to_refresh);
@@ -514,7 +505,6 @@ public class SignRefreshLayout extends ViewGroup {
     }
 
     private void startAnim() {
-        Log.i("gong", "startAnim");
         statusTV.setText(R.string.refreshing);
         statusImg.setImageResource(R.drawable.ic_baseutil_simple_load);
         statusImg.setAnimation(getImgAnimation());

+ 8 - 1
app_modular/apputils/src/main/java/com/modular/apputils/utils/SignUtils.java

@@ -127,7 +127,14 @@ public class SignUtils implements OnHttpResultListener {
 
     //签到,判断是否第一次和当前mac地址时候存在问题
     public void sign(final boolean isB2b, WorkModel model) {
-        loadMacInNet(isB2b, model);
+        if (SwitchUtil.needMacForSign()) {
+            loadMacInNet(isB2b, model);
+        }else{
+            Bundle bundle = new Bundle();
+            bundle.putBoolean(KEY.IS_B2B, isB2b);
+            bundle.putParcelable(KEY.WORK, model);
+            signFristMac(bundle);
+        }
     }
 
     /*判断mac地址是否符合*/

+ 74 - 0
app_modular/apputils/src/main/res/layout/common_prompt_dialog.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    android:paddingLeft="@dimen/dp_10"
+    android:paddingTop="@dimen/dp_10"
+    android:paddingRight="@dimen/dp_10"
+    android:paddingBottom="@dimen/dp_4">
+
+    <TextView
+        android:id="@+id/title_tv"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"
+        android:textStyle="bold"
+        android:gravity="center"
+        android:text="@string/common_dialog_title"
+        android:textColor="@color/text_main"
+        android:textSize="@dimen/text_main" />
+
+
+    <TextView
+        android:id="@+id/message_tv"
+        android:layout_width="match_parent"
+        android:layout_height="60dp"
+        android:layout_marginTop="5dp"
+        android:paddingLeft="@dimen/dp_10"
+        android:paddingRight="@dimen/dp_10"
+        android:ellipsize="end"
+        android:gravity="left|center_vertical"
+        android:maxLines="2"
+        android:textColor="@color/text_hine"
+        android:textSize="@dimen/text_main" />
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:orientation="horizontal"
+        android:paddingLeft="@dimen/dp_10"
+        android:paddingRight="@dimen/dp_10"
+        android:padding="@dimen/dp_4"
+        android:textColor="@color/text_main"
+        android:textSize="@dimen/text_main">
+
+        <TextView
+            android:id="@+id/goto_tv"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:textColor="@color/titleBlue"
+            android:background="@drawable/selector_cancel_bg"
+            android:gravity="center"
+            android:layout_marginLeft="@dimen/padding"
+            android:layout_marginRight="@dimen/padding"
+            android:text="@string/common_cancel"
+            android:textSize="@dimen/text_hine" />
+
+
+        <TextView
+            android:id="@+id/sure_tv"
+            android:layout_width="0dp"
+            android:layout_marginLeft="@dimen/padding"
+            android:layout_marginRight="@dimen/padding"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:background="@drawable/selector_confirm_bg"
+            android:text="@string/common_sure"
+            android:textColor="@color/white"
+            android:textSize="@dimen/text_hine" />
+    </LinearLayout>
+</LinearLayout>

+ 10 - 0
app_modular/apputils/src/main/res/values/style.xml

@@ -24,4 +24,14 @@
        
        
     </style>
+    <style name="PromptDialogStyle" >
+        <item name="android:padding">@dimen/padding</item>
+        <item name="android:windowFrame">@null</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+        <item name="android:backgroundDimEnabled">true</item>
+    </style>
 </resources>

+ 2 - 0
app_modular/faceplatform-release/build.gradle

@@ -0,0 +1,2 @@
+configurations.maybeCreate("default")
+artifacts.add("default", file('faceplatform-release.aar'))

BIN
app_modular/faceplatform-release/faceplatform-release.aar


+ 1 - 0
app_modular/faceplatform-ui/.gitignore

@@ -0,0 +1 @@
+/build

+ 30 - 0
app_modular/faceplatform-ui/build.gradle

@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion rootProject.ext.android.compileSdkVersion
+    buildToolsVersion rootProject.ext.android.buildToolsVersion
+
+    defaultConfig {
+        minSdkVersion rootProject.ext.android.minSdkVersion
+        targetSdkVersion rootProject.ext.android.targetSdkVersion
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+
+
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile project(':apputils')
+    compile project(path: ':faceplatform-release')
+}

BIN
app_modular/faceplatform-ui/libs/ast.jar


+ 17 - 0
app_modular/faceplatform-ui/proguard-rules.pro

@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/baidu/Documents/android/android_sdk_mac/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific detect_keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}

+ 11 - 0
app_modular/faceplatform-ui/src/main/AndroidManifest.xml

@@ -0,0 +1,11 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.baidu.idl.face.platform.ui">
+
+    <application android:label="@string/app_name" >
+
+
+        <activity android:name=".FaceLivenessActivity"/>
+        <activity android:name=".FaceVeriftyActivity"/>
+    </application>
+
+</manifest>

+ 521 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceDetectActivity.java

@@ -0,0 +1,521 @@
+/**
+ * Copyright (C) 2017 Baidu Inc. All rights reserved.
+ */
+package com.baidu.idl.face.platform.ui;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.hardware.Camera;
+import android.media.AudioManager;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.baidu.aip.face.stat.Ast;
+import com.baidu.idl.face.platform.FaceConfig;
+import com.baidu.idl.face.platform.FaceSDKManager;
+import com.baidu.idl.face.platform.FaceStatusEnum;
+import com.baidu.idl.face.platform.IDetectStrategy;
+import com.baidu.idl.face.platform.IDetectStrategyCallback;
+import com.baidu.idl.face.platform.ui.utils.CameraUtils;
+import com.baidu.idl.face.platform.ui.utils.VolumeUtils;
+import com.baidu.idl.face.platform.ui.widget.FaceDetectRoundView;
+import com.baidu.idl.face.platform.utils.APIUtils;
+import com.baidu.idl.face.platform.utils.Base64Utils;
+import com.baidu.idl.face.platform.utils.CameraPreviewUtils;
+import com.common.LogUtil;
+import com.modular.apputils.activity.BaseNetActivity;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 人脸采集接口
+ */
+public abstract class FaceDetectActivity extends BaseNetActivity implements
+        SurfaceHolder.Callback,
+        Camera.PreviewCallback,
+        Camera.ErrorCallback,
+        VolumeUtils.VolumeCallback,
+        IDetectStrategyCallback {
+
+
+    // View
+    protected View mRootView;
+    protected FrameLayout mFrameLayout;
+    protected SurfaceView mSurfaceView;
+    protected SurfaceHolder mSurfaceHolder;
+    protected ImageView mCloseView;
+    protected ImageView mSoundView;
+    protected ImageView mSuccessView;
+    protected TextView mTipsTopView;
+    protected TextView mTipsBottomView;
+    protected FaceDetectRoundView mFaceDetectRoundView;
+    protected LinearLayout mImageLayout;
+    // 人脸信息
+    protected FaceConfig mFaceConfig;
+    protected IDetectStrategy mIDetectStrategy;
+    // 显示Size
+    private Rect mPreviewRect = new Rect();
+    protected int mDisplayWidth = 0;
+    protected int mDisplayHeight = 0;
+    protected int mSurfaceWidth = 0;
+    protected int mSurfaceHeight = 0;
+    protected Drawable mTipsIcon;
+    // 状态标识
+    protected volatile boolean mIsEnableSound = true;
+    protected HashMap<String, String> mBase64ImageMap = new HashMap<String, String>();
+    protected boolean mIsCreateSurface = false;
+    protected volatile boolean mIsCompletion = false;
+    // 相机
+    protected Camera mCamera;
+    protected Camera.Parameters mCameraParam;
+    protected int mCameraId;
+    protected int mPreviewWidth;
+    protected int mPreviewHight;
+    protected int mPreviewDegree;
+    // 监听系统音量广播
+    protected BroadcastReceiver mVolumeReceiver;
+
+
+    @Override
+    protected int getLayoutId() {
+        return R.layout.activity_face_detect_v3100;
+    }
+
+    @Override
+    protected void init() throws Exception {
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        Ast.getInstance().init(getApplicationContext(), "3.1.0.0", "facenormal");
+        DisplayMetrics dm = new DisplayMetrics();
+        Display display = this.getWindowManager().getDefaultDisplay();
+        display.getMetrics(dm);
+        mDisplayWidth = dm.widthPixels;
+        mDisplayHeight = dm.heightPixels;
+        FaceSDKResSettings.initializeResId();
+        mFaceConfig = FaceSDKManager.getInstance().getFaceConfig();
+
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        int vol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
+        mIsEnableSound = vol > 0 ? mFaceConfig.isSound : false;
+
+        mRootView = this.findViewById(R.id.detect_root_layout);
+        mFrameLayout = (FrameLayout) mRootView.findViewById(R.id.detect_surface_layout);
+
+        mSurfaceView = new SurfaceView(this);
+        mSurfaceHolder = mSurfaceView.getHolder();
+        mSurfaceHolder.setSizeFromLayout();
+        mSurfaceHolder.addCallback(this);
+        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+
+        int w = mDisplayWidth;
+        int h = mDisplayHeight;
+
+        FrameLayout.LayoutParams cameraFL = new FrameLayout.LayoutParams(
+                (int) (w * FaceDetectRoundView.SURFACE_RATIO), (int) (h * FaceDetectRoundView.SURFACE_RATIO),
+                Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
+
+        mSurfaceView.setLayoutParams(cameraFL);
+        mFrameLayout.addView(mSurfaceView);
+
+        mRootView.findViewById(R.id.detect_close).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onBackPressed();
+            }
+        });
+
+        mFaceDetectRoundView = (FaceDetectRoundView) mRootView.findViewById(R.id.detect_face_round);
+        mCloseView = (ImageView) mRootView.findViewById(R.id.detect_close);
+        mSoundView = (ImageView) mRootView.findViewById(R.id.detect_sound);
+        mSoundView.setImageResource(mIsEnableSound ?
+                R.mipmap.ic_enable_sound_ext : R.mipmap.ic_disable_sound_ext);
+        mSoundView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mIsEnableSound = !mIsEnableSound;
+                mSoundView.setImageResource(mIsEnableSound ?
+                        R.mipmap.ic_enable_sound_ext : R.mipmap.ic_disable_sound_ext);
+                if (mIDetectStrategy != null) {
+                    mIDetectStrategy.setDetectStrategySoundEnable(mIsEnableSound);
+                }
+            }
+        });
+        mTipsTopView = (TextView) mRootView.findViewById(R.id.detect_top_tips);
+        mTipsBottomView = (TextView) mRootView.findViewById(R.id.detect_bottom_tips);
+        mSuccessView = (ImageView) mRootView.findViewById(R.id.detect_success_image);
+
+        mImageLayout = (LinearLayout) mRootView.findViewById(R.id.detect_result_image_layout);
+        if (mBase64ImageMap != null) {
+            mBase64ImageMap.clear();
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        setVolumeControlStream(AudioManager.STREAM_MUSIC);
+        mVolumeReceiver = VolumeUtils.registerVolumeReceiver(this, this);
+        if (mTipsTopView != null) {
+            mTipsTopView.setText(R.string.detect_face_in);
+        }
+        startPreview();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        stopPreview();
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        VolumeUtils.unRegisterVolumeReceiver(this, mVolumeReceiver);
+        mVolumeReceiver = null;
+        if (mIDetectStrategy != null) {
+            mIDetectStrategy.reset();
+        }
+        stopPreview();
+        Ast.getInstance().immediatelyUpload();
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+    }
+
+    @Override
+    public void volumeChanged() {
+        try {
+            AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
+            if (am != null) {
+                int cv = am.getStreamVolume(AudioManager.STREAM_MUSIC);
+                mIsEnableSound = cv > 0;
+                mSoundView.setImageResource(mIsEnableSound
+                        ? R.mipmap.ic_enable_sound_ext : R.mipmap.ic_disable_sound_ext);
+                if (mIDetectStrategy != null) {
+                    mIDetectStrategy.setDetectStrategySoundEnable(mIsEnableSound);
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    private Camera open() {
+        Camera camera;
+        int numCameras = Camera.getNumberOfCameras();
+        if (numCameras == 0) {
+            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_FRONT) {
+                break;
+            }
+            index++;
+        }
+
+        if (index < numCameras) {
+            camera = Camera.open(index);
+            mCameraId = index;
+        } else {
+            camera = Camera.open(0);
+            mCameraId = 0;
+        }
+        return camera;
+    }
+
+    protected void startPreview() {
+        if (mSurfaceView != null && mSurfaceView.getHolder() != null) {
+            mSurfaceHolder = mSurfaceView.getHolder();
+            mSurfaceHolder.addCallback(this);
+        }
+
+        if (mCamera == null) {
+            try {
+                mCamera = open();
+            } catch (RuntimeException e) {
+                e.printStackTrace();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (mCamera == null) {
+            return;
+        }
+        if (mCameraParam == null) {
+            mCameraParam = mCamera.getParameters();
+        }
+
+        mCameraParam.setPictureFormat(PixelFormat.JPEG);
+        int degree = displayOrientation(this);
+        mCamera.setDisplayOrientation(degree);
+        // 设置后无效,camera.setDisplayOrientation方法有效
+        mCameraParam.set("rotation", degree);
+        mPreviewDegree = degree;
+        if (mIDetectStrategy != null) {
+            mIDetectStrategy.setPreviewDegree(degree);
+        }
+
+        Point point = CameraPreviewUtils.getBestPreview(mCameraParam,
+                new Point(mDisplayWidth, mDisplayHeight));
+        mPreviewWidth = point.x;
+        mPreviewHight = point.y;
+        // Preview 768,432
+        mPreviewRect.set(0, 0, mPreviewHight, mPreviewWidth);
+
+        mCameraParam.setPreviewSize(mPreviewWidth, mPreviewHight);
+        mCamera.setParameters(mCameraParam);
+
+        try {
+            mCamera.setPreviewDisplay(mSurfaceHolder);
+            mCamera.stopPreview();
+            mCamera.setErrorCallback(this);
+            mCamera.setPreviewCallback(this);
+            mCamera.startPreview();
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+            CameraUtils.releaseCamera(mCamera);
+            mCamera = null;
+        } catch (Exception e) {
+            e.printStackTrace();
+            CameraUtils.releaseCamera(mCamera);
+            mCamera = null;
+        }
+
+    }
+
+    protected void stopPreview() {
+        if (mCamera != null) {
+            try {
+                mCamera.setErrorCallback(null);
+                mCamera.setPreviewCallback(null);
+                mCamera.stopPreview();
+            } catch (RuntimeException e) {
+                e.printStackTrace();
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                CameraUtils.releaseCamera(mCamera);
+                mCamera = null;
+            }
+        }
+        if (mSurfaceHolder != null) {
+            mSurfaceHolder.removeCallback(this);
+        }
+        if (mIDetectStrategy != null) {
+            mIDetectStrategy = null;
+        }
+    }
+
+    private int displayOrientation(Context context) {
+        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        int rotation = windowManager.getDefaultDisplay().getRotation();
+        int degrees = 0;
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                degrees = 0;
+                break;
+            case Surface.ROTATION_90:
+                degrees = 90;
+                break;
+            case Surface.ROTATION_180:
+                degrees = 180;
+                break;
+            case Surface.ROTATION_270:
+                degrees = 270;
+                break;
+            default:
+                degrees = 0;
+                break;
+        }
+        int result = (0 - degrees + 360) % 360;
+        if (APIUtils.hasGingerbread()) {
+            Camera.CameraInfo info = new Camera.CameraInfo();
+            Camera.getCameraInfo(mCameraId, info);
+            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+                result = (info.orientation + degrees) % 360;
+                result = (360 - result) % 360;
+            } else {
+                result = (info.orientation - degrees + 360) % 360;
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        mIsCreateSurface = true;
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder,
+                               int format,
+                               int width,
+                               int height) {
+        mSurfaceWidth = width;
+        mSurfaceHeight = height;
+        if (holder.getSurface() == null) {
+            return;
+        }
+        startPreview();
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        mIsCreateSurface = false;
+    }
+
+    @Override
+    public void onPreviewFrame(byte[] data, Camera camera) {
+
+        if (mIsCompletion) {
+            return;
+        }
+
+        if (mIDetectStrategy == null && mFaceDetectRoundView != null && mFaceDetectRoundView.getRound() > 0) {
+            mIDetectStrategy = FaceSDKManager.getInstance().getDetectStrategyModule();
+            mIDetectStrategy.setPreviewDegree(mPreviewDegree);
+            mIDetectStrategy.setDetectStrategySoundEnable(mIsEnableSound);
+
+            Rect detectRect = FaceDetectRoundView.getPreviewDetectRect(mDisplayWidth, mPreviewHight, mPreviewWidth);
+            mIDetectStrategy.setDetectStrategyConfig(mPreviewRect, detectRect, this);
+        }
+        if (mIDetectStrategy != null) {
+            mIDetectStrategy.detectStrategy(data);
+        }
+    }
+
+
+    @Override
+    public void onError(int error, Camera camera) {
+    }
+
+    @Override
+    public void onDetectCompletion(FaceStatusEnum status, String message,
+                                   HashMap<String, String> base64ImageMap) {
+        LogUtil.i("gong","onDetectCompletion");
+        if (mIsCompletion) {
+            return;
+        }
+        onRefreshView(status, message);
+        if (status == FaceStatusEnum.OK) {
+            Ast.getInstance().faceHit();
+            mIsCompletion = true;
+            saveImage(base64ImageMap);
+        }
+    }
+
+    private void onRefreshView(FaceStatusEnum status, String message) {
+        switch (status) {
+            case OK:
+                onRefreshTipsView(false, message);
+                mTipsBottomView.setText("");
+                mFaceDetectRoundView.processDrawState(false);
+                onRefreshSuccessView(true);
+                break;
+            case Detect_PitchOutOfUpMaxRange:
+            case Detect_PitchOutOfDownMaxRange:
+            case Detect_PitchOutOfLeftMaxRange:
+            case Detect_PitchOutOfRightMaxRange:
+                onRefreshTipsView(true, message);
+                mTipsBottomView.setText(message);
+                mFaceDetectRoundView.processDrawState(true);
+                onRefreshSuccessView(false);
+                break;
+            default:
+                onRefreshTipsView(false, message);
+                mTipsBottomView.setText("");
+                mFaceDetectRoundView.processDrawState(true);
+                onRefreshSuccessView(false);
+        }
+    }
+
+    private void onRefreshTipsView(boolean isAlert, String message) {
+        if (isAlert) {
+            if (mTipsIcon == null) {
+                mTipsIcon = getResources().getDrawable(R.mipmap.ic_warning);
+                mTipsIcon.setBounds(0, 0, (int) (mTipsIcon.getMinimumWidth() * 0.7f),
+                        (int) (mTipsIcon.getMinimumHeight() * 0.7f));
+                mTipsTopView.setCompoundDrawablePadding(15);
+            }
+            mTipsTopView.setBackgroundResource(R.drawable.bg_tips);
+            mTipsTopView.setText(R.string.detect_standard);
+            mTipsTopView.setCompoundDrawables(mTipsIcon, null, null, null);
+        } else {
+            mTipsTopView.setBackgroundResource(R.drawable.bg_tips_no);
+            mTipsTopView.setCompoundDrawables(null, null, null, null);
+            if (!TextUtils.isEmpty(message)) {
+                mTipsTopView.setText(message);
+            }
+        }
+    }
+
+    private void onRefreshSuccessView(boolean isShow) {
+        if (mSuccessView.getTag() == null) {
+            Rect rect = mFaceDetectRoundView.getFaceRoundRect();
+            RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) mSuccessView.getLayoutParams();
+            rlp.setMargins(
+                    rect.centerX() - (mSuccessView.getWidth() / 2),
+                    rect.top - (mSuccessView.getHeight() / 2),
+                    0,
+                    0);
+            mSuccessView.setLayoutParams(rlp);
+            mSuccessView.setTag("setlayout");
+        }
+        mSuccessView.setVisibility(isShow ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    private void saveImage(HashMap<String, String> imageMap) {
+        Set<Map.Entry<String, String>> sets = imageMap.entrySet();
+        Bitmap bmp = null;
+        mImageLayout.removeAllViews();
+        for (Map.Entry<String, String> entry : sets) {
+            String bmpBase64 = entry.getValue();
+            if (!TextUtils.isEmpty(bmpBase64)) {
+                saveBmpBase64Ok(bmpBase64);
+                break;
+            }
+//            bmp = base64ToBitmap();
+//            ImageView iv = new ImageView(this);
+//            iv.setImageBitmap(bmp);
+//            mImageLayout.addView(iv, new LinearLayout.LayoutParams(100, 100));
+        }
+    }
+
+    private static Bitmap base64ToBitmap(String base64Data) {
+        byte[] bytes = Base64Utils.decode(base64Data, Base64Utils.NO_WRAP);
+        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
+    }
+
+    public abstract void saveBmpBase64Ok(String bmpBase64);
+
+
+
+
+}
+

+ 526 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceLivenessActivity.java

@@ -0,0 +1,526 @@
+/**
+ * Copyright (C) 2017 Baidu Inc. All rights reserved.
+ */
+package com.baidu.idl.face.platform.ui;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.hardware.Camera;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.baidu.aip.face.stat.Ast;
+import com.baidu.idl.face.platform.FaceConfig;
+import com.baidu.idl.face.platform.FaceSDKManager;
+import com.baidu.idl.face.platform.FaceStatusEnum;
+import com.baidu.idl.face.platform.ILivenessStrategy;
+import com.baidu.idl.face.platform.ILivenessStrategyCallback;
+import com.baidu.idl.face.platform.ui.utils.CameraUtils;
+import com.baidu.idl.face.platform.ui.utils.VolumeUtils;
+import com.baidu.idl.face.platform.ui.widget.FaceDetectRoundView;
+import com.baidu.idl.face.platform.utils.APIUtils;
+import com.baidu.idl.face.platform.utils.Base64Utils;
+import com.baidu.idl.face.platform.utils.CameraPreviewUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 活体检测接口
+ */
+public class FaceLivenessActivity extends Activity implements
+        SurfaceHolder.Callback,
+        Camera.PreviewCallback,
+        Camera.ErrorCallback,
+        VolumeUtils.VolumeCallback,
+        ILivenessStrategyCallback {
+
+    public static final String TAG = FaceLivenessActivity.class.getSimpleName();
+
+    // View
+    protected View mRootView;
+    protected FrameLayout mFrameLayout;
+    protected SurfaceView mSurfaceView;
+    protected SurfaceHolder mSurfaceHolder;
+    protected ImageView mCloseView;
+    protected ImageView mSoundView;
+    protected ImageView mSuccessView;
+    protected TextView mTipsTopView;
+    protected TextView mTipsBottomView;
+    protected FaceDetectRoundView mFaceDetectRoundView;
+    protected LinearLayout mImageLayout;
+    // 人脸信息
+    protected FaceConfig mFaceConfig;
+    protected ILivenessStrategy mILivenessStrategy;
+    // 显示Size
+    private Rect mPreviewRect = new Rect();
+    protected int mDisplayWidth = 0;
+    protected int mDisplayHeight = 0;
+    protected int mSurfaceWidth = 0;
+    protected int mSurfaceHeight = 0;
+    protected Drawable mTipsIcon;
+    // 状态标识
+    protected volatile boolean mIsEnableSound = true;
+    protected HashMap<String, String> mBase64ImageMap = new HashMap<String, String>();
+    protected boolean mIsCreateSurface = false;
+    protected boolean mIsCompletion = false;
+    // 相机
+    protected Camera mCamera;
+    protected Camera.Parameters mCameraParam;
+    protected int mCameraId;
+    protected int mPreviewWidth;
+    protected int mPreviewHight;
+    protected int mPreviewDegree;
+    // 监听系统音量广播
+    protected BroadcastReceiver mVolumeReceiver;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        Ast.getInstance().init(getApplicationContext(), "3.1.0.0", "facenormal");
+        setContentView(R.layout.activity_face_liveness_v3100);
+        DisplayMetrics dm = new DisplayMetrics();
+        Display display = this.getWindowManager().getDefaultDisplay();
+        display.getMetrics(dm);
+        mDisplayWidth = dm.widthPixels;
+        mDisplayHeight = dm.heightPixels;
+
+        FaceSDKResSettings.initializeResId();
+        mFaceConfig = FaceSDKManager.getInstance().getFaceConfig();
+
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        int vol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
+        mIsEnableSound = vol > 0 ? mFaceConfig.isSound : false;
+
+        mRootView = this.findViewById(R.id.liveness_root_layout);
+        mFrameLayout = (FrameLayout) mRootView.findViewById(R.id.liveness_surface_layout);
+
+        mSurfaceView = new SurfaceView(this);
+        mSurfaceHolder = mSurfaceView.getHolder();
+        mSurfaceHolder.setSizeFromLayout();
+        mSurfaceHolder.addCallback(this);
+        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+
+        int w = mDisplayWidth;
+        int h = mDisplayHeight;
+
+        FrameLayout.LayoutParams cameraFL = new FrameLayout.LayoutParams(
+                (int) (w * FaceDetectRoundView.SURFACE_RATIO), (int) (h * FaceDetectRoundView.SURFACE_RATIO),
+                Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
+
+        mSurfaceView.setLayoutParams(cameraFL);
+        mFrameLayout.addView(mSurfaceView);
+
+        mRootView.findViewById(R.id.liveness_close).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onBackPressed();
+            }
+        });
+
+        mFaceDetectRoundView = (FaceDetectRoundView) mRootView.findViewById(R.id.liveness_face_round);
+        mCloseView = (ImageView) mRootView.findViewById(R.id.liveness_close);
+        mSoundView = (ImageView) mRootView.findViewById(R.id.liveness_sound);
+        mSoundView.setImageResource(mIsEnableSound ?
+                R.mipmap.ic_enable_sound_ext : R.mipmap.ic_disable_sound_ext);
+        mSoundView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mIsEnableSound = !mIsEnableSound;
+                mSoundView.setImageResource(mIsEnableSound ?
+                        R.mipmap.ic_enable_sound_ext : R.mipmap.ic_disable_sound_ext);
+                if (mILivenessStrategy != null) {
+                    mILivenessStrategy.setLivenessStrategySoundEnable(mIsEnableSound);
+                }
+            }
+        });
+        mTipsTopView = (TextView) mRootView.findViewById(R.id.liveness_top_tips);
+        mTipsBottomView = (TextView) mRootView.findViewById(R.id.liveness_bottom_tips);
+        mSuccessView = (ImageView) mRootView.findViewById(R.id.liveness_success_image);
+
+        mImageLayout = (LinearLayout) mRootView.findViewById(R.id.liveness_result_image_layout);
+        if (mBase64ImageMap != null) {
+            mBase64ImageMap.clear();
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        setVolumeControlStream(AudioManager.STREAM_MUSIC);
+        mVolumeReceiver = VolumeUtils.registerVolumeReceiver(this, this);
+        if (mTipsTopView != null) {
+            mTipsTopView.setText(R.string.detect_face_in);
+        }
+        startPreview();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        stopPreview();
+    }
+
+    @Override
+    public void onStop() {
+        if (mILivenessStrategy != null) {
+            mILivenessStrategy.reset();
+        }
+        VolumeUtils.unRegisterVolumeReceiver(this, mVolumeReceiver);
+        mVolumeReceiver = null;
+        super.onStop();
+        stopPreview();
+        Ast.getInstance().immediatelyUpload();
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+    }
+
+    @Override
+    public void volumeChanged() {
+        try {
+            AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
+            if (am != null) {
+                int cv = am.getStreamVolume(AudioManager.STREAM_MUSIC);
+                mIsEnableSound = cv > 0;
+                mSoundView.setImageResource(mIsEnableSound
+                        ? R.mipmap.ic_enable_sound_ext : R.mipmap.ic_disable_sound_ext);
+                if (mILivenessStrategy != null) {
+                    mILivenessStrategy.setLivenessStrategySoundEnable(mIsEnableSound);
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    private Camera open() {
+        Camera camera;
+        int numCameras = Camera.getNumberOfCameras();
+        if (numCameras == 0) {
+            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_FRONT) {
+                break;
+            }
+            index++;
+        }
+
+        if (index < numCameras) {
+            camera = Camera.open(index);
+            mCameraId = index;
+        } else {
+            camera = Camera.open(0);
+            mCameraId = 0;
+        }
+        return camera;
+    }
+
+    protected void startPreview() {
+        if (mSurfaceView != null && mSurfaceView.getHolder() != null) {
+            mSurfaceHolder = mSurfaceView.getHolder();
+            mSurfaceHolder.addCallback(this);
+        }
+
+        if (mCamera == null) {
+            try {
+                mCamera = open();
+            } catch (RuntimeException e) {
+                e.printStackTrace();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (mCamera == null) {
+            return;
+        }
+
+        if (mCameraParam == null) {
+            mCameraParam = mCamera.getParameters();
+        }
+
+        mCameraParam.setPictureFormat(PixelFormat.JPEG);
+        int degree = displayOrientation(this);
+        mCamera.setDisplayOrientation(degree);
+        // 设置后无效,camera.setDisplayOrientation方法有效
+        mCameraParam.set("rotation", degree);
+        mPreviewDegree = degree;
+
+        Point point = CameraPreviewUtils.getBestPreview(mCameraParam,
+                new Point(mDisplayWidth, mDisplayHeight));
+
+        mPreviewWidth = point.x;
+        mPreviewHight = point.y;
+        // Preview 768,432
+
+        if (mILivenessStrategy != null) {
+            mILivenessStrategy.setPreviewDegree(degree);
+        }
+
+        mPreviewRect.set(0, 0, mPreviewHight, mPreviewWidth);
+
+        mCameraParam.setPreviewSize(mPreviewWidth, mPreviewHight);
+        mCamera.setParameters(mCameraParam);
+
+        try {
+            mCamera.setPreviewDisplay(mSurfaceHolder);
+            mCamera.stopPreview();
+            mCamera.setErrorCallback(this);
+            mCamera.setPreviewCallback(this);
+            mCamera.startPreview();
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+            CameraUtils.releaseCamera(mCamera);
+            mCamera = null;
+        } catch (Exception e) {
+            e.printStackTrace();
+            CameraUtils.releaseCamera(mCamera);
+            mCamera = null;
+        }
+    }
+
+    protected void stopPreview() {
+        if (mCamera != null) {
+            try {
+                mCamera.setErrorCallback(null);
+                mCamera.setPreviewCallback(null);
+                mCamera.stopPreview();
+            } catch (RuntimeException e) {
+                e.printStackTrace();
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                CameraUtils.releaseCamera(mCamera);
+                mCamera = null;
+            }
+        }
+        if (mSurfaceHolder != null) {
+            mSurfaceHolder.removeCallback(this);
+        }
+        if (mILivenessStrategy != null) {
+            mILivenessStrategy = null;
+        }
+    }
+
+    private int displayOrientation(Context context) {
+        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        int rotation = windowManager.getDefaultDisplay().getRotation();
+        int degrees = 0;
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                degrees = 0;
+                break;
+            case Surface.ROTATION_90:
+                degrees = 90;
+                break;
+            case Surface.ROTATION_180:
+                degrees = 180;
+                break;
+            case Surface.ROTATION_270:
+                degrees = 270;
+                break;
+            default:
+                degrees = 0;
+                break;
+        }
+        int result = (0 - degrees + 360) % 360;
+        if (APIUtils.hasGingerbread()) {
+            Camera.CameraInfo info = new Camera.CameraInfo();
+            Camera.getCameraInfo(mCameraId, info);
+            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+                result = (info.orientation + degrees) % 360;
+                result = (360 - result) % 360;
+            } else {
+                result = (info.orientation - degrees + 360) % 360;
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        mIsCreateSurface = true;
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder,
+                               int format,
+                               int width,
+                               int height) {
+        mSurfaceWidth = width;
+        mSurfaceHeight = height;
+        if (holder.getSurface() == null) {
+            return;
+        }
+        startPreview();
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        mIsCreateSurface = false;
+    }
+
+    @Override
+    public void onPreviewFrame(byte[] data, Camera camera) {
+
+        if (mIsCompletion) {
+            return;
+        }
+
+        if (mILivenessStrategy == null) {
+            mILivenessStrategy = FaceSDKManager.getInstance().getLivenessStrategyModule();
+            mILivenessStrategy.setPreviewDegree(mPreviewDegree);
+            mILivenessStrategy.setLivenessStrategySoundEnable(mIsEnableSound);
+
+            Rect detectRect = FaceDetectRoundView.getPreviewDetectRect(
+                    mDisplayWidth, mPreviewHight, mPreviewWidth);
+            mILivenessStrategy.setLivenessStrategyConfig(
+                    mFaceConfig.getLivenessTypeList(), mPreviewRect, detectRect, this);
+        }
+        mILivenessStrategy.livenessStrategy(data);
+    }
+
+    @Override
+    public void onError(int error, Camera camera) {
+    }
+
+    @Override
+    public void onLivenessCompletion(FaceStatusEnum status, String message,
+                                     HashMap<String, String> base64ImageMap) {
+        if (mIsCompletion) {
+            return;
+        }
+
+        onRefreshView(status, message);
+
+        if (status == FaceStatusEnum.OK) {
+            Ast.getInstance().faceHit();
+            mIsCompletion = true;
+            saveImage(base64ImageMap);
+        }
+    }
+
+    private void onRefreshView(FaceStatusEnum status, String message) {
+        switch (status) {
+            case OK:
+            case Liveness_OK:
+            case Liveness_Completion:
+                onRefreshTipsView(false, message);
+                mTipsBottomView.setText("");
+                mFaceDetectRoundView.processDrawState(false);
+                onRefreshSuccessView(true);
+                break;
+            case Detect_DataNotReady:
+            case Liveness_Eye:
+            case Liveness_Mouth:
+            case Liveness_HeadUp:
+            case Liveness_HeadDown:
+            case Liveness_HeadLeft:
+            case Liveness_HeadRight:
+            case Liveness_HeadLeftRight:
+                onRefreshTipsView(false, message);
+                mTipsBottomView.setText("");
+                mFaceDetectRoundView.processDrawState(false);
+                onRefreshSuccessView(false);
+                break;
+            case Detect_PitchOutOfUpMaxRange:
+            case Detect_PitchOutOfDownMaxRange:
+            case Detect_PitchOutOfLeftMaxRange:
+            case Detect_PitchOutOfRightMaxRange:
+                onRefreshTipsView(true, message);
+                mTipsBottomView.setText(message);
+                mFaceDetectRoundView.processDrawState(true);
+                onRefreshSuccessView(false);
+                break;
+            default:
+                onRefreshTipsView(false, message);
+                mTipsBottomView.setText("");
+                mFaceDetectRoundView.processDrawState(true);
+                onRefreshSuccessView(false);
+        }
+    }
+
+    private void onRefreshTipsView(boolean isAlert, String message) {
+        if (isAlert) {
+            if (mTipsIcon == null) {
+                mTipsIcon = getResources().getDrawable(R.mipmap.ic_warning);
+                mTipsIcon.setBounds(0, 0, (int) (mTipsIcon.getMinimumWidth() * 0.7f),
+                        (int) (mTipsIcon.getMinimumHeight() * 0.7f));
+                mTipsTopView.setCompoundDrawablePadding(15);
+            }
+            mTipsTopView.setBackgroundResource(R.drawable.bg_tips);
+            mTipsTopView.setText(R.string.detect_standard);
+            mTipsTopView.setCompoundDrawables(mTipsIcon, null, null, null);
+        } else {
+            mTipsTopView.setBackgroundResource(R.drawable.bg_tips_no);
+            mTipsTopView.setCompoundDrawables(null, null, null, null);
+            if (!TextUtils.isEmpty(message)) {
+                mTipsTopView.setText(message);
+            }
+        }
+    }
+
+    private void onRefreshSuccessView(boolean isShow) {
+        if (mSuccessView.getTag() == null) {
+            Rect rect = mFaceDetectRoundView.getFaceRoundRect();
+            RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) mSuccessView.getLayoutParams();
+            rlp.setMargins(
+                    rect.centerX() - (mSuccessView.getWidth() / 2),
+                    rect.top - (mSuccessView.getHeight() / 2),
+                    0,
+                    0);
+            mSuccessView.setLayoutParams(rlp);
+            mSuccessView.setTag("setlayout");
+        }
+        mSuccessView.setVisibility(isShow ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    private void saveImage(HashMap<String, String> imageMap) {
+        Set<Map.Entry<String, String>> sets = imageMap.entrySet();
+        Bitmap bmp = null;
+        mImageLayout.removeAllViews();
+        for (Map.Entry<String, String> entry : sets) {
+            bmp = base64ToBitmap(entry.getValue());
+            ImageView iv = new ImageView(this);
+            iv.setImageBitmap(bmp);
+            mImageLayout.addView(iv, new LinearLayout.LayoutParams(300, 300));
+        }
+    }
+
+    private static Bitmap base64ToBitmap(String base64Data) {
+        byte[] bytes = Base64Utils.decode(base64Data, Base64Utils.NO_WRAP);
+        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
+    }
+
+}

+ 62 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceSDKResSettings.java

@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) 2017 Baidu Inc. All rights reserved.
+ */
+package com.baidu.idl.face.platform.ui;
+
+import com.baidu.idl.face.platform.FaceEnvironment;
+import com.baidu.idl.face.platform.FaceStatusEnum;
+
+/**
+ * sdk使用Res资源设置功能
+ */
+public class FaceSDKResSettings {
+
+    public static void initializeResId() {
+
+        // Sound Res Id
+        FaceEnvironment.setSoundId(FaceStatusEnum.Detect_NoFace, R.raw.detect_face_in);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Detect_FacePointOut, R.raw.detect_face_in);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_Eye, R.raw.liveness_eye);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_Mouth, R.raw.liveness_mouth);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_HeadUp, R.raw.liveness_head_up);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_HeadDown, R.raw.liveness_head_down);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_HeadLeft, R.raw.liveness_head_left);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_HeadRight, R.raw.liveness_head_right);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_HeadLeftRight, R.raw.liveness_head_left_right);
+        FaceEnvironment.setSoundId(FaceStatusEnum.Liveness_OK, R.raw.face_good);
+        FaceEnvironment.setSoundId(FaceStatusEnum.OK, R.raw.face_good);
+
+        // Tips Res Id
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_NoFace, R.string.detect_no_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_FacePointOut, R.string.detect_face_in);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_PoorIllumintion, R.string.detect_low_light);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_ImageBlured, R.string.detect_keep);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_OccLeftEye, R.string.detect_occ_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_OccRightEye, R.string.detect_occ_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_OccNose, R.string.detect_occ_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_OccMouth, R.string.detect_occ_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_OccLeftContour, R.string.detect_occ_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_OccRightContour, R.string.detect_occ_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_OccChin, R.string.detect_occ_face);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_PitchOutOfUpMaxRange, R.string.detect_head_down);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_PitchOutOfDownMaxRange, R.string.detect_head_up);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_PitchOutOfLeftMaxRange, R.string.detect_head_right);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_PitchOutOfRightMaxRange, R.string.detect_head_left);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_FaceZoomIn, R.string.detect_zoom_in);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Detect_FaceZoomOut, R.string.detect_zoom_out);
+
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_Eye, R.string.liveness_eye);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_Mouth, R.string.liveness_mouth);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_HeadUp, R.string.liveness_head_up);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_HeadDown, R.string.liveness_head_down);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_HeadLeft, R.string.liveness_head_left);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_HeadRight, R.string.liveness_head_right);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_HeadLeftRight, R.string.liveness_head_left_right);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Liveness_OK, R.string.liveness_good);
+        FaceEnvironment.setTipsId(FaceStatusEnum.OK, R.string.liveness_good);
+
+        FaceEnvironment.setTipsId(FaceStatusEnum.Error_Timeout, R.string.detect_timeout);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Error_DetectTimeout, R.string.detect_timeout);
+        FaceEnvironment.setTipsId(FaceStatusEnum.Error_LivenessTimeout, R.string.detect_timeout);
+    }
+}

+ 231 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/FaceVeriftyActivity.java

@@ -0,0 +1,231 @@
+package com.baidu.idl.face.platform.ui;
+
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baidu.idl.face.platform.ui.config.FaceConfig;
+import com.baidu.idl.face.platform.ui.model.FaceVerify;
+import com.baidu.idl.face.platform.ui.widget.VeriftyDialog;
+import com.common.LogUtil;
+import com.common.data.JSONUtil;
+import com.common.data.ListUtils;
+import com.core.app.MyApplication;
+import com.core.utils.CommonUtil;
+import com.me.network.app.http.HttpClient;
+import com.me.network.app.http.Method;
+import com.me.network.app.http.rx.Result2Listener;
+import com.me.network.app.http.rx.ResultSubscriber;
+
+public class FaceVeriftyActivity extends FaceDetectActivity {
+
+
+    @Override
+    protected String getBaseUrl() {
+        return "https://aip.baidubce.com/";
+    }
+
+
+    //成功获取到Base64数据
+    @Override
+    public void saveBmpBase64Ok(String bmpBase64) {
+        String master = CommonUtil.getMaster();
+        String imid = MyApplication.getInstance().getLoginUserId();
+        verify(bmpBase64, master, imid);
+    }
+
+
+    private void showRegisterDialog(final String faceBase64, final String group_id_list, final String user_id) {
+        new VeriftyDialog.Builder(this)
+                .setCanceledOnTouchOutside(false)
+                .setContent("该账号还未注册,是否确认使用该脸部信息作为该账号面部校验?")
+                .build(new VeriftyDialog.OnDialogClickListener() {
+                    @Override
+                    public void result(boolean clickSure) {
+                        if (clickSure) {
+                            String userInfo = "";
+                            if (MyApplication.getInstance().mLoginUser != null) {
+                                userInfo = MyApplication.getInstance().mLoginUser.getTelephone() + "_";
+                            }
+                            userInfo += CommonUtil.getName();
+                            register(faceBase64, group_id_list, user_id, userInfo);
+                        } else {
+                            setResult(0);
+                            finish();
+                        }
+                    }
+                });
+
+    }
+
+    /**
+     * 验证后返回弹出窗口
+     *
+     * @param message
+     */
+    private void showDialog(final boolean isPass, final String message) {
+        new VeriftyDialog.Builder(this)
+                .setCanceledOnTouchOutside(false)
+                .setContent(message)
+                .setShowCancel(false)
+                .build(new VeriftyDialog.OnDialogClickListener() {
+                    @Override
+                    public void result(boolean clickSure) {
+                        if (isPass) {
+                            setResult(clickSure ? RESULT_OK : 0);
+                            finish();
+                        } else {
+                            setResult(0);
+                            finish();
+                        }
+                    }
+                });
+
+    }
+
+
+    private void showErrorDialog(String result) {
+        String message = "";
+        if (result.contains("liveness check fail")) {
+            message = "活体检测未通过,是否重新验证?";
+        } else {
+            message = result;
+        }
+        final boolean needReset = message.equals("活体检测未通过,是否重新验证?");
+        new VeriftyDialog.Builder(this)
+                .setCanceledOnTouchOutside(false)
+                .setContent(message)
+                .setShowCancel(true)
+                .build(new VeriftyDialog.OnDialogClickListener() {
+                    @Override
+                    public void result(boolean clickSure) {
+                        if (needReset && clickSure) {
+                            mIsCompletion = false;
+                        } else {
+                            //TODO 其他情况
+                        }
+                    }
+                });
+    }
+
+    /**
+     * 校验身份
+     *
+     * @param faceBase64    脸部信息
+     * @param group_id_list 组Id
+     * @param user_id       用户Id
+     */
+    private void verify(final String faceBase64, final String group_id_list, final String user_id) {
+        showProgress();
+        FaceConfig.loadToken(new FaceConfig.FaceTokenListener() {
+            @Override
+            public void callBack(String accessToken) {
+                LogUtil.i("gong", "accessToken=" + accessToken);
+                httpClient.Api().send(new HttpClient.Builder()
+                        .url("rest/2.0/face/v3/search")
+                        .add("access_token", accessToken)
+                        .header("Content-Type", "application/json")
+                        .add("image", faceBase64)
+                        .add("image_type", "BASE64")
+                        .add("liveness_control", "HIGH")
+                        .add("user_id", user_id)
+                        .isDebug(true)
+                        .add("group_id_list", group_id_list)
+                        .method(Method.POST).build(), new ResultSubscriber<>(new Result2Listener<Object>() {
+                    @Override
+                    public void onResponse(Object o) {
+                        LogUtil.i("gong", "verify onResponse=" + o.toString());
+                        try {
+                            JSONObject object = JSON.parseObject(o.toString());
+                            String error_msg = JSONUtil.getText(object, "error_msg");
+                            if (TextUtils.isEmpty(error_msg) || error_msg.equals("SUCCESS")) {
+                                JSONObject result = JSONUtil.getJSONObject(object, "result");
+                                JSONArray user_list = JSONUtil.getJSONArray(result, "user_list");
+                                if (ListUtils.isEmpty(user_list)) {
+                                    showRegisterDialog(faceBase64, group_id_list, user_id);
+                                } else {
+                                    FaceVerify mFaceVerify = new FaceVerify();
+                                    for (int i = 0; i < user_list.size(); i++) {
+                                        JSONObject userObject = user_list.getJSONObject(i);
+                                        float score = JSONUtil.getFloat(userObject, "score");
+                                        if (mFaceVerify.getScore() < score) {
+                                            mFaceVerify.setScore(score);
+                                            mFaceVerify.setUserId(JSONUtil.getText(userObject, "user_id"));
+                                            mFaceVerify.setUserInfo(JSONUtil.getText(userObject, "user_info"));
+                                            mFaceVerify.setGroupId(JSONUtil.getText(userObject, "group_id"));
+                                            if (mFaceVerify.isPass()) {
+                                                break;
+                                            }
+                                        }
+                                    }
+                                    showDialog(mFaceVerify.isPass(), mFaceVerify.isPass() ? "验证成功" : "验证失败,本次不能为您打卡!");
+                                }
+                            } else {
+                                showErrorDialog(error_msg);
+                            }
+                        } catch (Exception e) {
+                        }
+                        dismissProgress();
+                    }
+
+                    @Override
+                    public void onFailure(Object t) {
+                        dismissProgress();
+                        LogUtil.i("gong", "verify onFailure=" + t.toString());
+                    }
+                }));
+            }
+        });
+    }
+
+    private void register(final String faceBase64, final String group_id, final String user_id, final String user_info) {
+        showProgress();
+        FaceConfig.loadToken(new FaceConfig.FaceTokenListener() {
+            @Override
+            public void callBack(String accessToken) {
+                LogUtil.i("gong", "accessToken=" + accessToken);
+                httpClient.Api().send(new HttpClient.Builder()
+                        .url("rest/2.0/face/v3/faceset/user/add")
+                        .add("access_token", accessToken)
+                        .header("Content-Type", "application/json")
+                        .add("image", faceBase64)
+                        .add("image_type", "BASE64")
+                        .add("quality_control", "HIGH")
+                        .add("liveness_control", "HIGH")
+                        .add("user_id", user_id)
+                        .add("user_info", user_info)
+                        .isDebug(true)
+                        .add("group_id", group_id)
+                        .method(Method.POST).build(), new ResultSubscriber<>(new Result2Listener<Object>() {
+                    @Override
+                    public void onResponse(Object o) {
+                        LogUtil.i("gong", "verify onResponse=" + o.toString());
+                        try {
+                            JSONObject object = JSON.parseObject(o.toString());
+
+                            String error_msg = JSONUtil.getText(object, "error_msg");
+
+                            if (TextUtils.isEmpty(error_msg) || error_msg.equals("SUCCESS")) {
+                                setResult(RESULT_OK);
+                                finish();
+                            } else {
+                                showErrorDialog(error_msg);
+                            }
+                        } catch (Exception e) {
+                        }
+                        dismissProgress();
+                    }
+
+                    @Override
+                    public void onFailure(Object t) {
+                        dismissProgress();
+                        LogUtil.i("gong", "verify onFailure=" + t.toString());
+                    }
+                }));
+            }
+        });
+    }
+
+
+}

+ 136 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/config/FaceConfig.java

@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+package com.baidu.idl.face.platform.ui.config;
+
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.baidu.idl.face.platform.FaceSDKManager;
+import com.baidu.idl.face.platform.LivenessTypeEnum;
+import com.common.LogUtil;
+import com.common.config.BaseConfig;
+import com.common.data.JSONUtil;
+import com.me.network.app.http.HttpClient;
+import com.me.network.app.http.Method;
+import com.me.network.app.http.rx.Result2Listener;
+import com.me.network.app.http.rx.ResultSubscriber;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FaceConfig {
+    public static final float VALUE_BRIGHTNESS = 40.0F;
+    public static final float VALUE_BLURNESS = 0.7F;
+    public static final float VALUE_OCCLUSION = 0.6F;
+    public static final int VALUE_HEAD_PITCH = 15;
+    public static final int VALUE_HEAD_YAW = 15;
+    public static final int VALUE_HEAD_ROLL = 15;
+    public static final int VALUE_CROP_FACE_SIZE = 400;
+    public static final int VALUE_MIN_FACE_SIZE = 120;
+    public static final float VALUE_NOT_FACE_THRESHOLD = 0.6F;
+
+    // 为了apiKey,secretKey为您调用百度人脸在线接口的,如注册,识别等。
+    // 为了的安全,建议放在您的服务端,端把人脸传给服务器,在服务端端进行人脸注册、识别放在示例里面是为了您快速看到效果
+    public static String apiKey = "8B4k81ViOG3XWAoG4dDgSB2I";
+    public static String secretKey = "hryH0Lhmmt0yvGSXTveTwcMIRCA7rfIK";
+    public static String licenseID = "UUFaceID-face-android";
+    public static String licenseFileName = "idl-license.face-android";
+    public static String accessToken;
+
+    public static void initFace(Context context) {
+        FaceSDKManager.getInstance().initialize(context, licenseID, licenseFileName);
+        com.baidu.idl.face.platform.FaceConfig config = FaceSDKManager.getInstance().getFaceConfig();
+        // SDK初始化已经设置完默认参数(推荐参数),您也根据实际需求进行数值调整
+        // 设置活体动作,通过设置list LivenessTypeEnum.Eye,LivenessTypeEnum.Mouth,LivenessTypeEnum.HeadUp,
+        // LivenessTypeEnum.HeadDown,LivenessTypeEnum.HeadLeft, LivenessTypeEnum.HeadRight,
+        // LivenessTypeEnum.HeadLeftOrRight
+        List<LivenessTypeEnum> livenessList = new ArrayList<>();
+        livenessList.add(LivenessTypeEnum.Mouth);
+        livenessList.add(LivenessTypeEnum.Eye);
+        livenessList.add(LivenessTypeEnum.HeadUp);
+        livenessList.add(LivenessTypeEnum.HeadDown);
+        livenessList.add(LivenessTypeEnum.HeadLeft);
+        livenessList.add(LivenessTypeEnum.HeadRight);
+        config.setLivenessTypeList(livenessList);
+        // 设置 活体动作是否随机 boolean
+        config.setLivenessRandom(true);
+        config.setLivenessRandomCount(2);
+        // 模糊度范围 (0-1) 推荐小于0.7
+        config.setBlurnessValue(VALUE_BLURNESS);
+        // 光照范围 (0-1) 推荐大于40
+        config.setBrightnessValue(VALUE_BRIGHTNESS);
+        // 裁剪人脸大小
+        config.setCropFaceValue(VALUE_CROP_FACE_SIZE);
+        // 人脸yaw,pitch,row 角度,范围(-45,45),推荐-15-15
+        config.setHeadPitchValue(VALUE_HEAD_PITCH);
+        config.setHeadRollValue(VALUE_HEAD_ROLL);
+        config.setHeadYawValue(VALUE_HEAD_YAW);
+        // 最小检测人脸(在图片人脸能够被检测到最小值)80-200, 越小越耗性能,推荐120-200
+        config.setMinFaceSize(VALUE_MIN_FACE_SIZE);
+        // 人脸置信度(0-1)推荐大于0.6
+        config.setNotFaceValue(VALUE_NOT_FACE_THRESHOLD);
+        // 人脸遮挡范围 (0-1) 推荐小于0.5
+        config.setOcclusionValue(VALUE_OCCLUSION);
+        // 是否进行质量检测
+        config.setCheckFaceQuality(true);
+        // 人脸检测使用线程数
+        config.setFaceDecodeNumberOfThreads(2);
+        // 是否开启提示音
+        config.setSound(true);
+
+        FaceSDKManager.getInstance().setFaceConfig(config);
+
+    }
+
+
+    public static void loadToken(FaceTokenListener mFaceTokenListener) {
+        if (mFaceTokenListener != null) {
+            if (1 == 2) {
+                initToken(mFaceTokenListener);
+            } else if (!TextUtils.isEmpty(accessToken)) {
+                mFaceTokenListener.callBack(accessToken);
+            } else {
+                initToken(mFaceTokenListener);
+            }
+        }
+    }
+
+    public static void initToken(final FaceTokenListener mFaceTokenListener) {
+        HttpClient httpClient = new HttpClient.Builder("https://aip.baidubce.com/").isDebug(BaseConfig.isDebug())
+                .connectTimeout(5000)
+                .readTimeout(5000).build();
+        httpClient.Api().get(new HttpClient.Builder()
+                .add("grant_type", "client_credentials")
+                .add("client_id", apiKey)
+                .method(Method.GET)
+                .url("oauth/2.0/token")
+                .add("client_secret", secretKey).build(), new ResultSubscriber<>(new Result2Listener<Object>() {
+            @Override
+            public void onResponse(Object o) {
+                LogUtil.i("gong", "initToken onResponse=" + o.toString());
+                try {
+                    String message = o.toString();
+                    accessToken = JSONUtil.getText(message, "access_token");
+                    if (mFaceTokenListener != null) {
+                        mFaceTokenListener.callBack(accessToken);
+                    }
+                } catch (Exception e) {
+
+                }
+            }
+
+            @Override
+            public void onFailure(Object t) {
+                LogUtil.i("gong", "initToken onFailure=" + t.toString());
+            }
+        }));
+    }
+
+
+    public interface FaceTokenListener {
+        void callBack(String accessToken);
+    }
+
+}

+ 54 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/model/FaceVerify.java

@@ -0,0 +1,54 @@
+package com.baidu.idl.face.platform.ui.model;
+
+public class FaceVerify {
+    private final int SCORE_PASS = 85;
+
+    private String mpbBase64;
+    private String userId;
+    private String groupId;
+    private String userInfo;
+    private float score;
+
+    public String getMpbBase64() {
+        return mpbBase64;
+    }
+
+    public void setMpbBase64(String mpbBase64) {
+        this.mpbBase64 = mpbBase64;
+    }
+
+    public boolean isPass(){
+        return score>=SCORE_PASS;
+    }
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getUserInfo() {
+        return userInfo;
+    }
+
+    public void setUserInfo(String userInfo) {
+        this.userInfo = userInfo;
+    }
+
+    public float getScore() {
+        return score;
+    }
+
+    public void setScore(float score) {
+        this.score = score;
+    }
+}

+ 89 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/Base64.java

@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+package com.baidu.idl.face.platform.ui.utils;
+
+/**
+ * Created by wangtianfei01 on 17/4/6.
+ */
+
+public class Base64 {
+
+    private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+            .toCharArray();
+    private static byte[] codes = new byte[256];
+
+    public static char[] encode(byte[] data) {
+        char[] out = new char[((data.length + 2) / 3) * 4];
+        for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
+            boolean quad = false;
+            boolean trip = false;
+            int val = (0xFF & (int) data[i]);
+            val <<= 8;
+            if ((i + 1) < data.length) {
+                val |= (0xFF & (int) data[i + 1]);
+                trip = true;
+            }
+            val <<= 8;
+            if ((i + 2) < data.length) {
+                val |= (0xFF & (int) data[i + 2]);
+                quad = true;
+            }
+            out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
+            val >>= 6;
+            out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
+            val >>= 6;
+            out[index + 1] = alphabet[val & 0x3F];
+            val >>= 6;
+            out[index + 0] = alphabet[val & 0x3F];
+        }
+        return out;
+    }
+
+    public static byte[] decode(char[] data) {
+        int len = ((data.length + 3) / 4) * 3;
+        if (data.length > 0 && data[data.length - 1] == '=') {
+            --len;
+        }
+        if (data.length > 1 && data[data.length - 2] == '=') {
+            --len;
+        }
+        byte[] out = new byte[len];
+        int shift = 0;
+        int accum = 0;
+        int index = 0;
+        for (int ix = 0; ix < data.length; ix++) {
+            int value = codes[data[ix] & 0xFF];
+            if (value >= 0) {
+                accum <<= 6;
+                shift += 6;
+                accum |= value;
+                if (shift >= 8) {
+                    shift -= 8;
+                    out[index++] = (byte) ((accum >> shift) & 0xff);
+                }
+            }
+        }
+        if (index != out.length) {
+            throw new Error("miscalculated data length!");
+        }
+        return out;
+    }
+
+    static {
+        for (int i = 0; i < 256; i++) {
+            codes[i] = -1;
+        }
+        for (int i = 'A'; i <= 'Z'; i++) {
+            codes[i] = (byte) (i - 'A');
+        }
+        for (int i = 'a'; i <= 'z'; i++) {
+            codes[i] = (byte) (26 + i - 'a');
+        }
+        for (int i = '0'; i <= '9'; i++) {
+            codes[i] = (byte) (52 + i - '0');
+        }
+        codes['+'] = 62;
+        codes['/'] = 63;
+    }
+}

+ 123 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/BrightnessTools.java

@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+package com.baidu.idl.face.platform.ui.utils;
+
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Log;
+import android.view.WindowManager;
+
+
+public class BrightnessTools {
+
+    /**
+     * 判断是否开启了自动亮度调节
+     */
+
+    public static boolean isAutoBrightness(ContentResolver aContentResolver) {
+        boolean automicBrightness = false;
+        try {
+            automicBrightness = Settings.System.getInt(aContentResolver,
+                    Settings.System.SCREEN_BRIGHTNESS_MODE) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
+        } catch (SettingNotFoundException e) {
+            e.printStackTrace();
+        }
+        return automicBrightness;
+    }
+
+    /**
+     * 获取屏幕的亮度
+     *
+     * @param activity
+     * @return
+     */
+    public static int getScreenBrightness(Activity activity) {
+        int nowBrightnessValue = 0;
+        ContentResolver resolver = activity.getContentResolver();
+        try {
+            nowBrightnessValue = Settings.System.getInt(
+                    resolver, Settings.System.SCREEN_BRIGHTNESS);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return nowBrightnessValue;
+    }
+
+    /**
+     * 设置亮度
+     *
+     * @param activity
+     * @param brightness
+     */
+    public static void setBrightness(Activity activity, int brightness) {
+        // Settings.System.putInt(activity.getContentResolver(),
+
+        // Settings.System.SCREEN_BRIGHTNESS_MODE,
+
+        // Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+
+        WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
+
+        lp.screenBrightness = Float.valueOf(brightness) * (1f / 255f);
+        Log.d("lxy", "set  lp.screenBrightness == " + lp.screenBrightness);
+
+        activity.getWindow().setAttributes(lp);
+    }
+
+    // 那么,能设置了,但是为什么还是会出现,设置了,没反映呢?
+
+    // 嘿嘿,那是因为,开启了自动调节功能了,那如何关闭呢?这才是最重要的:
+
+    /**
+     * 停止自动亮度调节
+     *
+     * @param activity
+     */
+    public static void stopAutoBrightness(Activity activity) {
+
+        Settings.System.putInt(activity.getContentResolver(),
+
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+
+                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+    }
+
+
+    /**
+     * 开启亮度自动调节
+     *
+     * @param activity
+     */
+    public static void startAutoBrightness(Activity activity) {
+
+        Settings.System.putInt(activity.getContentResolver(),
+
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+    }
+
+    // 至此,应该说操作亮度的差不多都有了,结束!
+    // 哎,本来认为是应该结束了,但是悲剧得是,既然像刚才那样设置的话,只能在当前的activity中有作用,一段退出的时候,会发现毫无作用,悲剧,原来是忘记了保存了。汗!
+
+    /**
+     * 保存亮度设置状态
+     *
+     * @param resolver
+     * @param brightness
+     */
+    public static void saveBrightness(ContentResolver resolver, int brightness) {
+        Uri uri = Settings.System
+                .getUriFor("screen_brightness");
+
+        Settings.System.putInt(resolver, "screen_brightness",
+                brightness);
+        // resolver.registerContentObserver(uri, true, myContentObserver);
+        resolver.notifyChange(uri, null);
+    }
+}

+ 25 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/CameraUtils.java

@@ -0,0 +1,25 @@
+/**
+ * Copyright (C) 2017 Baidu Inc. All rights reserved.
+ */
+package com.baidu.idl.face.platform.ui.utils;
+
+import android.hardware.Camera;
+
+/**
+ * CameraUtils
+ */
+public class CameraUtils {
+
+    public static final String TAG = CameraUtils.class.getSimpleName();
+
+    public static void releaseCamera(Camera camera) {
+        try {
+            camera.release();
+        } catch (RuntimeException e2) {
+            e2.printStackTrace();
+        } catch (Exception e1) {
+            e1.printStackTrace();
+        } finally {
+        }
+    }
+}

+ 130 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/DeviceUuidFactory.java

@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+package com.baidu.idl.face.platform.ui.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Environment;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.UUID;
+
+/**
+ * Created by wangtianfei01 on 17/4/6.
+ */
+
+public class DeviceUuidFactory {
+    protected static final String PREFS_FILE = "dev_id.xml";
+    protected static final String DEVICE_UUID_FILE_NAME = ".dev_id.txt";
+    protected static final String PREFS_DEVICE_ID = "dev_id";
+    protected static final String KEY = "cyril'98";
+    protected static UUID uuid;
+
+    public static String init(Context context) {
+        if (uuid == null) {
+            synchronized (DeviceUuidFactory.class) {
+                if (uuid == null) {
+                    final SharedPreferences prefs = context.getSharedPreferences(PREFS_FILE, 0);
+                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
+                    if (id != null) {
+                        uuid = UUID.fromString(id);
+                    } else {
+                        if (recoverDeviceUuidFromSD() != null) {
+                            uuid = UUID.fromString(recoverDeviceUuidFromSD());
+                        } else {
+                            final String androidId =
+                                    Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
+                            try {
+                                if (!"9774d56d682e549c".equals(androidId)) {
+                                    uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
+                                    try {
+                                        saveDeviceUuidToSD(EncryptUtils.encryptDES(uuid.toString(), KEY));
+                                    } catch (Exception e) {
+                                        e.printStackTrace();
+                                    }
+                                } else {
+                                    @SuppressLint("MissingPermission") String deviceId = ((TelephonyManager) context
+                                            .getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
+                                    uuid = deviceId != null ? UUID.nameUUIDFromBytes(deviceId.getBytes("utf8")) :
+                                            UUID.randomUUID();
+                                    try {
+                                        saveDeviceUuidToSD(EncryptUtils.encryptDES(uuid.toString(), KEY));
+                                    } catch (Exception e) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                            } catch (UnsupportedEncodingException e) {
+                                throw new RuntimeException(e);
+                            }
+                        }
+                        prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString()).commit();
+                    }
+                }
+            }
+        }
+        return uuid.toString();
+    }
+
+    private static String recoverDeviceUuidFromSD() {
+        try {
+            String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath();
+            File dir = new File(dirPath);
+            File uuidFile = new File(dir, DEVICE_UUID_FILE_NAME);
+            if (!dir.exists() || !uuidFile.exists()) {
+                return null;
+            }
+            FileReader fileReader = new FileReader(uuidFile);
+            StringBuilder sb = new StringBuilder();
+            char[] buffer = new char[100];
+            int readCount;
+            while ((readCount = fileReader.read(buffer)) > 0) {
+                sb.append(buffer, 0, readCount);
+            }
+            // 通过UUID.fromString来检查uuid的格式正确性
+            UUID uuid = UUID.fromString(EncryptUtils.decryptDES(sb.toString(), KEY));
+            return uuid.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    private static void saveDeviceUuidToSD(String uuid) {
+        String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath();
+        File targetFile = new File(dirPath, DEVICE_UUID_FILE_NAME);
+        if (targetFile != null) {
+            if (targetFile.exists()) {
+                OutputStreamWriter osw;
+                try {
+                    osw = new OutputStreamWriter(new FileOutputStream(targetFile), "utf-8");
+                    try {
+                        osw.write(uuid);
+                        osw.flush();
+                        osw.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                } catch (UnsupportedEncodingException e) {
+                    e.printStackTrace();
+                } catch (FileNotFoundException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+    }
+
+    public static UUID getUuid() {
+        return uuid;
+    }
+}

+ 50 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/EncryptUtils.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+package com.baidu.idl.face.platform.ui.utils;
+
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Created by wangtianfei01 on 17/4/6.
+ */
+
+public class EncryptUtils {
+    public static String encryptDES(String encryptString, String encryptKey) throws Exception {
+        // 返回实现指定转换的Cipher对象 "算法/模式/填充"
+        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
+        // 创建一个DESKeySpec对象,使用8个字节的key作为DES密钥的内容
+        DESKeySpec desKeySpec = new DESKeySpec(encryptKey.getBytes("UTF-8"));
+        // 返回转换指定算法的秘密密钥的SecretKeyFactory对象
+        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+        // 根据提供的密钥生成SecretKey对象
+        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
+        // 使用iv中的字节作为iv来构造一个iv ParameterSpec对象。复制该缓冲区的内容来防止后续修改
+        IvParameterSpec iv = new IvParameterSpec(encryptKey.getBytes());
+        // 用密钥和一组算法参数初始化此 Cipher;Cipher:加密、解密、密钥包装或密钥解包,具体取决于 opmode 的值。
+        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
+        // 加密同时解码成字符串返回
+        return new String(Base64.encode(cipher.doFinal(encryptString.getBytes("UTF-8"))));
+    }
+
+    public static String decryptDES(String decodeString, String decodeKey) throws Exception {
+        // 使用指定密钥构造IV
+        IvParameterSpec iv = new IvParameterSpec(decodeKey.getBytes());
+        // 根据给定的字节数组和指定算法构造一个密钥。
+        SecretKeySpec skeySpec = new SecretKeySpec(decodeKey.getBytes(), "DES");
+        // 返回实现指定转换的 Cipher 对象
+        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
+        // 解密初始化
+        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
+        // 解码返回
+        byte[] byteMi = Base64.decode(decodeString.toCharArray());
+        byte[] decryptedData = cipher.doFinal(byteMi);
+        return new String(decryptedData);
+    }
+}

+ 68 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/utils/VolumeUtils.java

@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2017 Baidu Inc. All rights reserved.
+ */
+package com.baidu.idl.face.platform.ui.utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+/**
+ * VolumeUtils
+ * 描述:系统音量监听
+ */
+public class VolumeUtils {
+
+    public static final String TAG = VolumeUtils.class.getSimpleName();
+
+    public interface VolumeCallback {
+        void volumeChanged();
+    }
+
+    public static class VolumeReceiver extends BroadcastReceiver {
+
+        private VolumeCallback callback;
+
+        public VolumeReceiver(VolumeCallback cb) {
+            callback = cb;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")
+                    && callback != null) {
+                Log.e(TAG, "android.media.VOLUME_CHANGED_ACTION");
+                callback.volumeChanged();
+            }
+        }
+    }
+
+    public static BroadcastReceiver registerVolumeReceiver(Context context, VolumeCallback callback) {
+        VolumeReceiver mVolumeReceiver = null;
+        try {
+            mVolumeReceiver = new VolumeReceiver(callback);
+            IntentFilter filter = new IntentFilter();
+            filter.addAction("android.media.VOLUME_CHANGED_ACTION");
+            context.registerReceiver(mVolumeReceiver, filter);
+        } catch (IllegalArgumentException ex1) {
+            ex1.printStackTrace();
+        } catch (Exception ex2) {
+            ex2.printStackTrace();
+        }
+        return mVolumeReceiver;
+    }
+
+    public static void unRegisterVolumeReceiver(Context context, BroadcastReceiver receiver) {
+        try {
+            if (context != null && receiver != null) {
+                context.unregisterReceiver(receiver);
+            }
+        } catch (IllegalArgumentException ex1) {
+            ex1.printStackTrace();
+        } catch (Exception ex2) {
+            ex2.printStackTrace();
+        }
+    }
+}

+ 175 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/FaceDetectRoundView.java

@@ -0,0 +1,175 @@
+/**
+ * Copyright (C) 2017 Baidu Inc. All rights reserved.
+ */
+package com.baidu.idl.face.platform.ui.widget;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint;
+import android.graphics.PathEffect;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+
+import com.baidu.idl.face.platform.utils.DensityUtils;
+
+/**
+ * 人脸检测区域View
+ */
+public class FaceDetectRoundView extends View {
+
+    private static final String TAG = FaceDetectRoundView.class.getSimpleName();
+
+    public static final float SURFACE_HEIGHT = 1000f;
+    public static final float SURFACE_RATIO = 0.75f;
+    public static final float WIDTH_SPACE_RATIO = 0.33f;
+    public static final float HEIGHT_RATIO = 0.1f;
+    public static final float HEIGHT_EXT_RATIO = 0.2f;
+    public static final int CIRCLE_SPACE = 5;
+    public static final int PATH_SPACE = 16;
+    public static final int PATH_SMALL_SPACE = 12;
+    public static final int PATH_WIDTH = 4;
+
+    public static final int COLOR_BG = Color.parseColor("#2F2F33");
+    public static final int COLOR_RECT = Color.parseColor("#FFFFFF");
+    public static final int COLOR_ROUND = Color.parseColor("#FFA800");
+
+    private PathEffect mFaceRoundPathEffect = null;
+    // new DashPathEffect(new float[]{PATH_SPACE, PATH_SPACE}, 1);
+    private Paint mBGPaint;
+    private Paint mPathPaint;
+    private Paint mFaceRectPaint;
+    private Paint mFaceRoundPaint;
+    private Rect mFaceRect;
+    private Rect mFaceDetectRect;
+
+    private float mX;
+    private float mY;
+    private float mR;
+    private boolean mIsDrawDash = true;
+
+    public FaceDetectRoundView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+        DisplayMetrics dm = context.getResources().getDisplayMetrics();
+        float pathSpace = DensityUtils.dip2px(context, PATH_SPACE);
+        float pathSmallSpace = DensityUtils.dip2px(context, PATH_SMALL_SPACE);
+        float pathWidth = DensityUtils.dip2px(context, PATH_WIDTH);
+        mFaceRoundPathEffect = new DashPathEffect(
+                new float[]{pathSpace, dm.heightPixels < SURFACE_HEIGHT
+                        ? pathSmallSpace : pathSpace}, 1);
+
+        mBGPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBGPaint.setColor(COLOR_BG);
+        mBGPaint.setStyle(Paint.Style.FILL);
+        mBGPaint.setAntiAlias(true);
+        mBGPaint.setDither(true);
+
+        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mPathPaint.setColor(COLOR_ROUND);
+        mPathPaint.setStrokeWidth(pathWidth);
+        mPathPaint.setStyle(Paint.Style.STROKE);
+        mPathPaint.setAntiAlias(true);
+        mPathPaint.setDither(true);
+
+        mFaceRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mFaceRectPaint.setColor(COLOR_RECT);
+        mFaceRectPaint.setStrokeWidth(pathWidth);
+        mFaceRectPaint.setStyle(Paint.Style.STROKE);
+        mFaceRectPaint.setAntiAlias(true);
+        mFaceRectPaint.setDither(true);
+
+        mFaceRoundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mFaceRoundPaint.setColor(COLOR_ROUND);
+        mFaceRoundPaint.setStyle(Paint.Style.FILL);
+        mFaceRoundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+        mFaceRoundPaint.setAntiAlias(true);
+        mFaceRoundPaint.setDither(true);
+    }
+
+    public void processDrawState(boolean isDrawDash) {
+        mIsDrawDash = isDrawDash;
+        postInvalidate();
+    }
+
+    public float getRound() {
+        return mR;
+    }
+
+    public Rect getFaceRoundRect() {
+        if (mFaceRect != null) {
+            Log.e(TAG, mFaceRect.toString());
+        }
+        return mFaceRect;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        float canvasWidth = right - left;
+        float canvasHeight = bottom - top;
+
+        float x = canvasWidth / 2;
+        float y = (canvasHeight / 2) - ((canvasHeight / 2) * HEIGHT_RATIO);
+        float r = (canvasWidth / 2) - ((canvasWidth / 2) * WIDTH_SPACE_RATIO);
+
+        if (mFaceRect == null) {
+            mFaceRect = new Rect((int) (x - r),
+                    (int) (y - r),
+                    (int) (x + r),
+                    (int) (y + r));
+        }
+        if (mFaceDetectRect == null) {
+            float hr = r + (r * HEIGHT_EXT_RATIO);
+            mFaceDetectRect = new Rect((int) (x - r),
+                    (int) (y - hr),
+                    (int) (x + r),
+                    (int) (y + hr));
+        }
+        mX = x;
+        mY = y;
+        mR = r;
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        canvas.drawColor(Color.TRANSPARENT);
+        canvas.drawPaint(mBGPaint);
+        if (mIsDrawDash) {
+            mPathPaint.setPathEffect(mFaceRoundPathEffect);
+        } else {
+            mPathPaint.setPathEffect(null);
+        }
+        canvas.drawCircle(mX, mY, mR + CIRCLE_SPACE, mPathPaint);
+        canvas.drawCircle(mX, mY, mR, mFaceRoundPaint);
+//        if (mFaceRect != null) {
+//            canvas.drawRect(mFaceRect, mFaceRectPaint);
+//        }
+//        if (mFaceDetectRect != null) {
+//            canvas.drawRect(mFaceDetectRect, mFaceRectPaint);
+//        }
+    }
+
+    public static Rect getPreviewDetectRect(int w, int pw, int ph) {
+        float round = (w / 2) - ((w / 2) * WIDTH_SPACE_RATIO);
+        float x = pw / 2;
+        float y = (ph / 2) - ((ph / 2) * HEIGHT_RATIO);
+        float r = (pw / 2) > round ? round : (pw / 2);
+        float hr = r + (r * HEIGHT_EXT_RATIO);
+        Rect rect = new Rect((int) (x - r),
+                (int) (y - hr),
+                (int) (x + r),
+                (int) (y + hr));
+//        Log.e(TAG, "FaceRoundView getPreviewDetectRect " + pw + "-" + ph + "-" + rect.toString());
+        return rect;
+    }
+
+}

+ 242 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/VeriftyDialog.java

@@ -0,0 +1,242 @@
+package com.baidu.idl.face.platform.ui.widget;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.TextView;
+
+import com.baidu.idl.face.platform.ui.R;
+
+import java.io.Serializable;
+
+public class VeriftyDialog extends DialogFragment {
+    private final String KEY_TITLE = "title";
+    private final String KEY_CONTENT = "content";
+    private final String KEY_CANCEL_TEXT = "cancelText";
+    private final String KEY_SURE_TEXT = "sureText";
+    private final String KEY_GRAVITY = "gravity";
+    private final String KEY_CANCELED_ON_TOUCH_OUTSIDE = "canceledOnTouchOutside";
+    private final String KEY_LISTENER = "Listener";
+    private final String KEY_ANIMATIONS_STYLE = "AnimationsStyle";
+    private final String KEY_DIALOG_STYLE = "DialogStyle";
+    private final String KEY_SHOW_CANCEL = "showCancel";
+
+    private TextView titleTv;
+    private TextView messageTv;
+    private TextView cancelTv;
+    private TextView sureTv;
+    private OnDialogClickListener dialogClickListener;
+
+
+    public static VeriftyDialog newInstance(Bundle args) {
+        VeriftyDialog fragment = new VeriftyDialog();
+        fragment.setArguments(args);
+        return fragment;
+    }
+    @Override
+    public void onStart() {
+        super.onStart();
+        Dialog dialog = getDialog();
+        if (dialog != null) {
+            DisplayMetrics dm = new DisplayMetrics();
+            //设置弹框的占屏宽
+            getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
+            dialog.getWindow().setLayout((int) (dm.widthPixels * 0.8), ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+        return LayoutInflater.from(getActivity()).inflate(R.layout.common_prompt_dialog, null);
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        titleTv = (TextView) view.findViewById(R.id.title_tv);
+        messageTv = (TextView) view.findViewById(R.id.message_tv);
+        cancelTv = (TextView) view.findViewById(R.id.goto_tv);
+        sureTv = (TextView) view.findViewById(R.id.sure_tv);
+        initView();
+    }
+
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        int animationsStyle = -1;
+        int dialogStyle = -1;
+        int gravity = -1;
+        boolean canceledOnTouchOutside = true;
+        Bundle args = getArguments();
+        if (args != null) {
+            gravity = args.getInt(KEY_GRAVITY, -1);
+            animationsStyle = args.getInt(KEY_ANIMATIONS_STYLE, -1);
+            dialogStyle = args.getInt(KEY_DIALOG_STYLE, -1);
+            canceledOnTouchOutside = args.getBoolean(KEY_CANCELED_ON_TOUCH_OUTSIDE, true);
+        }
+        Dialog dialog = new Dialog(getActivity(), dialogStyle == -1 ? R.style.PromptDialogStyle : dialogStyle);
+        dialog.setCanceledOnTouchOutside(canceledOnTouchOutside);
+        dialog.setCancelable(canceledOnTouchOutside);
+        dialog.getWindow().setBackgroundDrawable(getResources().getDrawable(R.drawable.pop_round_bg));
+        if (animationsStyle > 0) {
+            dialog.getWindow().setWindowAnimations(animationsStyle);
+        }
+        Window window = dialog.getWindow();
+        window.setGravity(gravity);
+        return dialog;
+    }
+
+    private void initView() {
+        String title = getString(R.string.app_name);
+        String content = "";
+        String cancelText = getString(R.string.common_cancel);
+        String sureText = getString(R.string.common_sure);
+        boolean showCancel = true;
+        Bundle args = getArguments();
+        if (args != null) {
+            title = args.getString(KEY_TITLE, title);
+            content = args.getString(KEY_CONTENT, content);
+            cancelText = args.getString(KEY_CANCEL_TEXT, cancelText);
+            sureText = args.getString(KEY_SURE_TEXT, sureText);
+            showCancel = args.getBoolean(KEY_SHOW_CANCEL, true);
+            if (args.getSerializable(KEY_LISTENER) != null && args.getSerializable(KEY_LISTENER) instanceof OnDialogClickListener) {
+                dialogClickListener = (OnDialogClickListener) args.getSerializable(KEY_LISTENER);
+            }
+        }
+        titleTv.setText(title);
+        messageTv.setText(content);
+        sureTv.setText(sureText);
+        if (showCancel) {
+            cancelTv.setVisibility(View.VISIBLE);
+            cancelTv.setOnClickListener(mOnClickListener);
+            cancelTv.setText(cancelText);
+        } else {
+            cancelTv.setVisibility(View.GONE);
+        }
+        sureTv.setOnClickListener(mOnClickListener);
+    }
+
+    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View view) {
+            if (dialogClickListener != null) {
+                dialogClickListener.result(view == sureTv);
+            }
+            dismiss();
+        }
+    };
+
+    public static class Builder {
+
+        private final String KEY_SHOW_CANCEL = "showCancel";
+        private final String KEY_TITLE = "title";
+        private final String KEY_CONTENT = "content";
+        private final String KEY_CANCEL_TEXT = "cancelText";
+        private final String KEY_SURE_TEXT = "sureText";
+        private final String KEY_GRAVITY = "gravity";
+        private final String KEY_CANCELED_ON_TOUCH_OUTSIDE = "canceledOnTouchOutside";
+        private final String KEY_LISTENER = "Listener";
+        private final String KEY_ANIMATIONS_STYLE = "AnimationsStyle";
+        private final String KEY_DIALOG_STYLE = "DialogStyle";
+
+        private String title;
+        private String content;
+        private String cancelText;
+        private String sureText;
+        private int gravity;
+        private int animationsStyle;
+        private int dialogStyle;
+        private boolean canceledOnTouchOutside;
+        private boolean showCancel;
+        private Context ct;
+
+
+        public Builder(Context ct) {
+            this.ct = ct;
+            this.showCancel = true;
+            this.canceledOnTouchOutside = true;
+        }
+
+        public Builder setShowCancel(boolean showCancel) {
+            this.showCancel = showCancel;
+            return this;
+        }
+
+        public Builder setCanceledOnTouchOutside(boolean canceledOnTouchOutside) {
+            this.canceledOnTouchOutside = canceledOnTouchOutside;
+            return this;
+        }
+
+        public Builder setDialogStyle(int dialogStyle) {
+            this.dialogStyle = dialogStyle;
+            return this;
+        }
+
+        public Builder setGravity(int gravity) {
+            this.gravity = gravity;
+            return this;
+        }
+
+        public Builder setAnimationsStyle(int animationsStyle) {
+            this.animationsStyle = animationsStyle;
+            return this;
+        }
+
+        public Builder setTitle(String title) {
+            this.title = title;
+            return this;
+        }
+
+        public Builder setContent(String content) {
+            this.content = content;
+            return this;
+        }
+
+        public Builder setCancelText(String cancelText) {
+            this.cancelText = cancelText;
+            return this;
+        }
+
+        public Builder setSureText(String sureText) {
+            this.sureText = sureText;
+            return this;
+        }
+
+        public VeriftyDialog build(OnDialogClickListener mOnClickListener) {
+            Bundle args = new Bundle();
+            args.putString(KEY_TITLE, title);
+            args.putString(KEY_CONTENT, content);
+            args.putString(KEY_CANCEL_TEXT, cancelText);
+            args.putString(KEY_SURE_TEXT, sureText);
+            args.putString(KEY_SURE_TEXT, sureText);
+            args.putBoolean(KEY_CANCELED_ON_TOUCH_OUTSIDE, canceledOnTouchOutside);
+            args.putInt(KEY_GRAVITY, gravity);
+            args.putInt(KEY_ANIMATIONS_STYLE, animationsStyle);
+            args.putInt(KEY_DIALOG_STYLE, dialogStyle);
+            args.putBoolean(KEY_SHOW_CANCEL, showCancel);
+            if (mOnClickListener != null) {
+                args.putSerializable(KEY_LISTENER, mOnClickListener);
+            }
+            VeriftyDialog mVeriftyDialog = VeriftyDialog.newInstance(args);
+            if (ct != null && ct instanceof FragmentActivity) {
+                mVeriftyDialog.show(((FragmentActivity) ct).getSupportFragmentManager(), "prompt");
+            }
+            return mVeriftyDialog;
+        }
+
+
+    }
+
+    public interface OnDialogClickListener extends Serializable {
+        void result(boolean clickSure);
+    }
+}

+ 86 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/WaveHelper.java

@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+package com.baidu.idl.face.platform.ui.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 人脸识别登录波纹动画
+ *
+ * @author liujinhui
+ * @date 2017/11/28
+ */
+
+public class WaveHelper {
+    private WaveView mWaveView;
+    private AnimatorSet mAnimatorSet;
+
+    /**
+     * 构造
+     *
+     * @param waveView
+     */
+    public WaveHelper(WaveView waveView) {
+        mWaveView = waveView;
+        initAnimation();
+    }
+
+    /**
+     * 动画开始
+     */
+    public void start() {
+        mWaveView.setShowWave(true);
+        if (mAnimatorSet != null) {
+            mAnimatorSet.start();
+        }
+    }
+
+    /**
+     * 动画初始化
+     */
+    private void initAnimation() {
+        List<Animator> animators = new ArrayList<>();
+
+        ObjectAnimator waveShiftAnim = ObjectAnimator.ofFloat(
+                mWaveView, "waveShiftRatio", 0f, 1f);
+        waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE);
+        waveShiftAnim.setDuration(500);
+        waveShiftAnim.setInterpolator(new LinearInterpolator());
+        animators.add(waveShiftAnim);
+
+        ObjectAnimator waterLevelAnim = ObjectAnimator.ofFloat(
+                mWaveView, "waterLevelRatio", 0.25f, 0.25f);
+        waterLevelAnim.setDuration(1000);
+        waterLevelAnim.setInterpolator(new DecelerateInterpolator());
+        animators.add(waterLevelAnim);
+
+        ObjectAnimator amplitudeAnim = ObjectAnimator.ofFloat(
+                mWaveView, "amplitudeRatio", 0.05f, 0.05f);
+        amplitudeAnim.setRepeatCount(ValueAnimator.REVERSE);
+        amplitudeAnim.setRepeatMode(ValueAnimator.REVERSE);
+        amplitudeAnim.setDuration(1000);
+        amplitudeAnim.setInterpolator(new LinearInterpolator());
+        animators.add(amplitudeAnim);
+
+        mAnimatorSet = new AnimatorSet();
+        mAnimatorSet.playTogether(animators);
+    }
+
+    /**
+     * 动画取消
+     */
+    public void cancel() {
+        if (mAnimatorSet != null) {
+            mAnimatorSet.end();
+        }
+    }
+}

+ 334 - 0
app_modular/faceplatform-ui/src/main/java/com/baidu/idl/face/platform/ui/widget/WaveView.java

@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
+ */
+package com.baidu.idl.face.platform.ui.widget;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * sin函数绘制人脸识别登录波浪纹
+ *
+ * @author liujinhui
+ * @date 2017/11/28
+ */
+
+public class WaveView extends View {
+
+    private static final float DEFAULT_AMPLITUDE_RATIO = 0.05f;
+    private static final float DEFAULT_WATER_LEVEL_RATIO = 0.5f;
+    private static final float DEFAULT_WAVE_LENGTH_RATIO = 1.0f;
+    private static final float DEFAULT_WAVE_SHIFT_RATIO = 0.0f;
+    private static final int DEFAULT_STROKE_WIDTH = 2;
+
+    private static final int DEFAULT_BEHIND_WAVE_COLOR = Color.parseColor("#28FFFFFF");
+    private static final int DEFAULT_FRONT_WAVE_COLOR = Color.parseColor("#3CFFFFFF");
+    private static final ShapeType DEFAULT_WAVE_SHAPE = ShapeType.CIRCLE;
+
+    private boolean mShowWave;
+    private BitmapShader mWaveShader;
+    private Matrix mShaderMatrix;
+    private Paint mViewPaint;
+    private Paint mBorderPaint;
+    private float mDefaultAmplitude;
+    private float mDefaultWaterLevel;
+    private float mDefaultWaveLength;
+    private double mDefaultAngularFrequency;
+    private float mAmplitudeRatio = DEFAULT_AMPLITUDE_RATIO;
+    private float mWaveLengthRatio = DEFAULT_WAVE_LENGTH_RATIO;
+    private float mWaterLevelRatio = DEFAULT_WATER_LEVEL_RATIO;
+    private float mWaveShiftRatio = DEFAULT_WAVE_SHIFT_RATIO;
+
+    private int mBehindWaveColor = DEFAULT_BEHIND_WAVE_COLOR;
+    private int mFrontWaveColor = DEFAULT_FRONT_WAVE_COLOR;
+    private ShapeType mShapeType = DEFAULT_WAVE_SHAPE;
+
+    public enum ShapeType {
+        CIRCLE,
+        SQUARE
+    }
+
+    public WaveView(Context context) {
+        super(context);
+        init();
+    }
+
+    public WaveView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public WaveView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    /**
+     * 初始化
+     */
+    private void init() {
+        mShaderMatrix = new Matrix();
+        mViewPaint = new Paint();
+        mViewPaint.setAntiAlias(true);
+    }
+
+    /**
+     * 获取波纹摆动频率 (0-1,默认为0)
+     *
+     * @return
+     */
+    public float getWaveShiftRatio() {
+        return mWaveShiftRatio;
+    }
+
+    /**
+     * 设置波纹水平摆动频率
+     *
+     * @param waveShiftRatio (0-1,默认为0)
+     */
+    public void setWaveShiftRatio(float waveShiftRatio) {
+        if (mWaveShiftRatio != waveShiftRatio) {
+            mWaveShiftRatio = waveShiftRatio;
+            invalidate();
+        }
+    }
+
+    /**
+     * 获取波纹垂直摆动频率(0-1,默认为0.5)
+     *
+     * @return
+     */
+    public float getWaterLevelRatio() {
+        return mWaterLevelRatio;
+    }
+
+    /**
+     * 设置波纹垂直摆动频率 (0-1,默认为0.5)
+     *
+     * @param waterLevelRatio
+     */
+    public void setWaterLevelRatio(float waterLevelRatio) {
+        if (mWaterLevelRatio != waterLevelRatio) {
+            mWaterLevelRatio = waterLevelRatio;
+            invalidate();
+        }
+    }
+
+    /**
+     * 获取波纹振幅频率(0-1之间)
+     *
+     * @return
+     */
+    public float getAmplitudeRatio() {
+        return mAmplitudeRatio;
+    }
+
+    /**
+     * 设置波纹振幅频率(0-1之间)
+     *
+     * @param amplitudeRatio
+     */
+    public void setAmplitudeRatio(float amplitudeRatio) {
+        if (mAmplitudeRatio != amplitudeRatio) {
+            mAmplitudeRatio = amplitudeRatio;
+            invalidate();
+        }
+    }
+
+    /**
+     * 获取波纹水平方向的长度比率(0-1之间)
+     *
+     * @return
+     */
+    public float getWaveLengthRatio() {
+        return mWaveLengthRatio;
+    }
+
+    /**
+     * 设置波纹水平方向的长度比率 (0-1之间)
+     *
+     * @param waveLengthRatio
+     */
+    public void setWaveLengthRatio(float waveLengthRatio) {
+        mWaveLengthRatio = waveLengthRatio;
+    }
+
+    /**
+     * 是否显示
+     *
+     * @return
+     */
+    public boolean isShowWave() {
+        return mShowWave;
+    }
+
+    /**
+     * 设置是否显示
+     *
+     * @param showWave
+     */
+    public void setShowWave(boolean showWave) {
+        mShowWave = showWave;
+    }
+
+    /**
+     * 设置圆形或矩形外框边界
+     *
+     * @param width
+     * @param color
+     */
+    public void setBorder(int width, int color) {
+        if (mBorderPaint == null) {
+            mBorderPaint = new Paint();
+            mBorderPaint.setAntiAlias(true);
+            mBorderPaint.setStyle(Style.STROKE);
+        }
+        mBorderPaint.setColor(color);
+        mBorderPaint.setStrokeWidth(width);
+
+        invalidate();
+    }
+
+    /**
+     * 设置波纹颜色
+     *
+     * @param behindWaveColor
+     * @param frontWaveColor
+     */
+    public void setWaveColor(int behindWaveColor, int frontWaveColor) {
+        mBehindWaveColor = behindWaveColor;
+        mFrontWaveColor = frontWaveColor;
+
+        if (getWidth() > 0 && getHeight() > 0) {
+            mWaveShader = null;
+            createShader();
+            invalidate();
+        }
+    }
+
+    /**
+     * 设置外框样式
+     *
+     * @param shapeType
+     */
+    public void setShapeType(ShapeType shapeType) {
+        mShapeType = shapeType;
+        invalidate();
+    }
+
+    /**
+     * 重载尺寸改变
+     *
+     * @param w
+     * @param h
+     * @param oldw
+     * @param oldh
+     */
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        createShader();
+    }
+
+    /**
+     * 通过sin函数计算x及y的波动和振幅
+     */
+    private void createShader() {
+        mDefaultAngularFrequency = 2.0f * Math.PI / DEFAULT_WAVE_LENGTH_RATIO / getWidth();
+        mDefaultAmplitude = getHeight() * DEFAULT_AMPLITUDE_RATIO;
+        mDefaultWaterLevel = getHeight() * DEFAULT_WATER_LEVEL_RATIO;
+        mDefaultWaveLength = getWidth();
+
+        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+
+        Paint wavePaint = new Paint();
+        wavePaint.setStrokeWidth(DEFAULT_STROKE_WIDTH);
+        wavePaint.setAntiAlias(true);
+
+        // 通过sin函数计算y
+        final int endX = getWidth() + 1;
+        final int endY = getHeight() + 1;
+        float[] waveY = new float[endX];
+
+        wavePaint.setColor(mBehindWaveColor);
+        for (int beginX = 0; beginX < endX; beginX++) {
+            double wx = beginX * mDefaultAngularFrequency;
+            float beginY = (float) (mDefaultWaterLevel + mDefaultAmplitude * Math.sin(wx));
+            canvas.drawLine(beginX, beginY, beginX, endY, wavePaint);
+
+            waveY[beginX] = beginY;
+        }
+
+        wavePaint.setColor(mFrontWaveColor);
+        final int wave2Shift = (int) (mDefaultWaveLength / 4);
+        for (int beginX = 0; beginX < endX; beginX++) {
+            canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint);
+        }
+
+        mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
+        mViewPaint.setShader(mWaveShader);
+    }
+
+    /**
+     * canvas绘制
+     *
+     * @param canvas
+     */
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mShowWave && mWaveShader != null) {
+            if (mViewPaint.getShader() == null) {
+                mViewPaint.setShader(mWaveShader);
+            }
+
+            mShaderMatrix.setScale(
+                    mWaveLengthRatio / DEFAULT_WAVE_LENGTH_RATIO,
+                    mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO,
+                    0,
+                    mDefaultWaterLevel);
+
+            mShaderMatrix.postTranslate(
+                    mWaveShiftRatio * getWidth(),
+                    (DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight());
+
+            mWaveShader.setLocalMatrix(mShaderMatrix);
+
+            float borderWidth = mBorderPaint == null ? 0f : mBorderPaint.getStrokeWidth();
+            switch (mShapeType) {
+                case CIRCLE:
+                    if (borderWidth > 0) {
+                        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f,
+                                (getWidth() - borderWidth) / 2f - 1f, mBorderPaint);
+                    }
+                    float radius = getWidth() / 2f - borderWidth;
+                    canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, mViewPaint);
+                    break;
+                case SQUARE:
+                    if (borderWidth > 0) {
+                        canvas.drawRect(
+                                borderWidth / 2f,
+                                borderWidth / 2f,
+                                getWidth() - borderWidth / 2f - 0.5f,
+                                getHeight() - borderWidth / 2f - 0.5f,
+                                mBorderPaint);
+                    }
+                    canvas.drawRect(borderWidth, borderWidth, getWidth() - borderWidth,
+                            getHeight() - borderWidth, mViewPaint);
+                    break;
+            }
+        } else {
+            mViewPaint.setShader(null);
+        }
+    }
+}

BIN
app_modular/faceplatform-ui/src/main/jniLibs/arm64-v8a/libFaceSDK.so


BIN
app_modular/faceplatform-ui/src/main/jniLibs/arm64-v8a/libidl_license.so


BIN
app_modular/faceplatform-ui/src/main/jniLibs/armeabi-v7a/libFaceSDK.so


BIN
app_modular/faceplatform-ui/src/main/jniLibs/armeabi-v7a/libidl_license.so


BIN
app_modular/faceplatform-ui/src/main/jniLibs/x86/libFaceSDK.so


BIN
app_modular/faceplatform-ui/src/main/jniLibs/x86/libidl_license.so


+ 25 - 0
app_modular/faceplatform-ui/src/main/res/drawable/bg_tips.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape>
+            <stroke android:width="1dp" android:color="#F6A623" />
+            <corners android:radius="18dp" />
+            <solid android:color="#0000" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape>
+            <stroke android:width="1dp" android:color="#F6A623" />
+            <corners android:radius="18dp" />
+            <solid android:color="#0000" />
+        </shape>
+    </item>
+    <item>
+        <shape>
+            <stroke android:width="1dp" android:color="#F6A623" />
+            <corners android:radius="18dp" />
+            <solid android:color="#0000" />
+        </shape>
+    </item>
+</selector>  
+

+ 22 - 0
app_modular/faceplatform-ui/src/main/res/drawable/bg_tips_no.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape>
+            <corners android:radius="15dp" />
+            <solid android:color="#0000" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape>
+            <corners android:radius="15dp" />
+            <solid android:color="#0000" />
+        </shape>
+    </item>
+    <item>
+        <shape>
+            <corners android:radius="15dp" />
+            <solid android:color="#0000" />
+        </shape>
+    </item>
+</selector>  
+

+ 107 - 0
app_modular/faceplatform-ui/src/main/res/layout/activity_face_detect.xml

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/detect_root_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/detect_surface_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <SurfaceView
+            android:id="@+id/detect_surface_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+        <ImageView
+            android:id="@+id/detect_surface_overlay_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_centerHorizontal="true"
+            android:background="@mipmap/bg_face_round" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/detect_surface_overlay_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.8" />
+
+        <TextView
+            android:id="@+id/detect_tips"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_above="@id/detect_surface_overlay_layout"
+            android:layout_centerHorizontal="true"
+            android:layout_gravity="center_horizontal"
+            android:gravity="center"
+            android:text="@string/detect_face_in"
+            android:textColor="#00E5EE"
+            android:textSize="16sp" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="3"
+            android:orientation="horizontal">
+
+            <View
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="0.05" />
+
+            <ImageView
+                android:id="@+id/detect_surface_overlay"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="0.9"
+                android:background="#09ffffff"
+                android:visibility="visible" />
+
+            <View
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="0.05" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/detect_close"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="20dp"
+        android:src="@mipmap/ic_close" />
+
+    <ImageView
+        android:id="@+id/detect_sound"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_margin="20dp"
+        android:src="@mipmap/ic_enable_sound" />
+
+    <HorizontalScrollView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true">
+
+        <LinearLayout
+            android:id="@+id/detect_result_image_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal"></LinearLayout>
+    </HorizontalScrollView>
+</RelativeLayout>

+ 96 - 0
app_modular/faceplatform-ui/src/main/res/layout/activity_face_detect_v3100.xml

@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/detect_root_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/detect_surface_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+    <com.baidu.idl.face.platform.ui.widget.FaceDetectRoundView
+        android:id="@+id/detect_face_round"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <LinearLayout
+        android:id="@+id/detect_surface_overlay_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.15" />
+
+        <TextView
+            android:id="@+id/detect_top_tips"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_gravity="center_horizontal"
+            android:gravity="center"
+            android:paddingLeft="12dp"
+            android:paddingRight="12dp"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:text="@string/detect_face_in"
+            android:textColor="#F6A623"
+            android:textSize="18sp" />
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.65" />
+
+        <TextView
+            android:id="@+id/detect_bottom_tips"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_centerHorizontal="true"
+            android:layout_gravity="center_horizontal"
+            android:layout_weight="0.36"
+            android:gravity="center|top"
+            android:text=""
+            android:textColor="#D0D0D0"
+            android:textSize="16sp" />
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/detect_close"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="20dp"
+        android:visibility="gone"
+        android:src="@mipmap/ic_close_ext" />
+
+    <ImageView
+        android:id="@+id/detect_sound"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_margin="@dimen/padding"
+        android:src="@mipmap/ic_enable_sound_ext" />
+
+    <ImageView
+        android:id="@+id/detect_success_image"
+        android:layout_width="45dp"
+        android:layout_height="45dp"
+        android:src="@mipmap/ic_success"
+        android:visibility="invisible" />
+
+    <HorizontalScrollView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true">
+
+        <LinearLayout
+            android:id="@+id/detect_result_image_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal"></LinearLayout>
+    </HorizontalScrollView>
+</RelativeLayout>

+ 107 - 0
app_modular/faceplatform-ui/src/main/res/layout/activity_face_liveness.xml

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/liveness_root_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/liveness_surface_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <SurfaceView
+            android:id="@+id/liveness_surface_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+        <ImageView
+            android:id="@+id/liveness_surface_overlay_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_centerHorizontal="true"
+            android:background="@mipmap/bg_face_round" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/liveness_surface_overlay_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.8" />
+
+        <TextView
+            android:id="@+id/liveness_tips"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_above="@id/liveness_surface_overlay_layout"
+            android:layout_centerHorizontal="true"
+            android:layout_gravity="center_horizontal"
+            android:gravity="center"
+            android:text="@string/detect_face_in"
+            android:textColor="#00E5EE"
+            android:textSize="16sp" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="3"
+            android:orientation="horizontal">
+
+            <View
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="0.05" />
+
+            <ImageView
+                android:id="@+id/liveness_surface_overlay"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="0.9"
+                android:background="#09ffffff"
+                android:visibility="invisible" />
+
+            <View
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="0.05" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/liveness_close"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="20dp"
+        android:src="@mipmap/ic_close" />
+
+    <ImageView
+        android:id="@+id/liveness_sound"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_margin="20dp"
+        android:src="@mipmap/ic_enable_sound" />
+
+    <HorizontalScrollView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true">
+
+        <LinearLayout
+            android:id="@+id/liveness_result_image_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal"></LinearLayout>
+    </HorizontalScrollView>
+</RelativeLayout>

+ 95 - 0
app_modular/faceplatform-ui/src/main/res/layout/activity_face_liveness_v3100.xml

@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/liveness_root_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/liveness_surface_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"></FrameLayout>
+
+    <com.baidu.idl.face.platform.ui.widget.FaceDetectRoundView
+        android:id="@+id/liveness_face_round"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <LinearLayout
+        android:id="@+id/liveness_surface_overlay_layout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.15" />
+
+        <TextView
+            android:id="@+id/liveness_top_tips"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_gravity="center_horizontal"
+            android:gravity="center"
+            android:paddingBottom="8dp"
+            android:paddingLeft="12dp"
+            android:paddingRight="12dp"
+            android:paddingTop="8dp"
+            android:text="@string/detect_face_in"
+            android:textColor="#F6A623"
+            android:textSize="18sp" />
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.65" />
+
+        <TextView
+            android:id="@+id/liveness_bottom_tips"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_centerHorizontal="true"
+            android:layout_gravity="center_horizontal"
+            android:layout_weight="0.36"
+            android:gravity="center|top"
+            android:text=""
+            android:textColor="#D0D0D0"
+            android:textSize="16sp" />
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/liveness_close"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="20dp"
+        android:src="@mipmap/ic_close_ext" />
+
+    <ImageView
+        android:id="@+id/liveness_sound"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_margin="20dp"
+        android:src="@mipmap/ic_enable_sound_ext" />
+
+    <ImageView
+        android:id="@+id/liveness_success_image"
+        android:layout_width="45dp"
+        android:layout_height="45dp"
+        android:src="@mipmap/ic_success"
+        android:visibility="invisible" />
+
+    <HorizontalScrollView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true">
+
+        <LinearLayout
+            android:id="@+id/liveness_result_image_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal"></LinearLayout>
+    </HorizontalScrollView>
+</RelativeLayout>

BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/bg_face_round.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/ic_close.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/ic_disable_sound.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xhdpi/ic_enable_sound.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_close_ext.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_disable_sound_ext.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_enable_sound_ext.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_success.png


BIN
app_modular/faceplatform-ui/src/main/res/mipmap-xxhdpi/ic_warning.png


BIN
app_modular/faceplatform-ui/src/main/res/raw/detect_face_in.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/face_good.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/liveness_eye.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/liveness_head_down.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/liveness_head_left.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/liveness_head_left_right.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/liveness_head_right.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/liveness_head_up.mp3


BIN
app_modular/faceplatform-ui/src/main/res/raw/liveness_mouth.mp3


+ 26 - 0
app_modular/faceplatform-ui/src/main/res/values/strings.xml

@@ -0,0 +1,26 @@
+<resources>
+    <string name="app_name">Baidu-IDL-FaceSDK</string>
+    <string name="detect_no_face">未检测到人脸</string>
+    <string name="detect_face_in">把脸移入框内</string>
+    <string name="detect_zoom_in">手机拿近一点</string>
+    <string name="detect_zoom_out">手机拿远一点</string>
+    <string name="detect_head_up">建议略微抬头</string>
+    <string name="detect_head_down">建议略微低头</string>
+    <string name="detect_head_left">建议略微向左转头</string>
+    <string name="detect_head_right">建议略微向右转头</string>
+    <string name="detect_occ_face">脸部有遮挡</string>
+    <string name="detect_low_light">光线再亮些</string>
+    <string name="detect_keep">请保持不动</string>
+    <string name="detect_standard">请正对手机</string>
+    <string name="detect_timeout">检测超时</string>
+    <string name="liveness_eye">眨眨眼</string>
+    <string name="liveness_eye_left">请眨眨左边眼睛</string>
+    <string name="liveness_eye_right">请眨眨右边眼睛</string>
+    <string name="liveness_mouth">张张嘴</string>
+    <string name="liveness_head_left">向左缓慢转头</string>
+    <string name="liveness_head_right">向右缓慢转头</string>
+    <string name="liveness_head_left_right">摇摇头</string>
+    <string name="liveness_head_up">缓慢抬头</string>
+    <string name="liveness_head_down">缓慢低头</string>
+    <string name="liveness_good">非常好</string>
+</resources>

+ 4 - 0
settings.gradle

@@ -18,6 +18,8 @@ include ':appmoments'
 include ':apptasks'
 include ':apputils'
 include  ':appmusic'
+include  ':faceplatform-ui'
+include  ':faceplatform-release'
 //第三库模块
 
 include ':lib-zxing'
@@ -50,6 +52,8 @@ project(':appmoments').projectDir = new File('app_modular/appmoments')
 project(':apptasks').projectDir = new File('app_modular/apptasks')
 project(':apputils').projectDir = new File('app_modular/apputils')
 project(':appmusic').projectDir = new File('app_modular/appmusic')
+project(':faceplatform-ui').projectDir = new File('app_modular/faceplatform-ui')
+project(':faceplatform-release').projectDir = new File('app_modular/faceplatform-release')
 //第三库模块
 
 project(':lib-zxing').projectDir = new File('app_third/lib-zxing')

+ 1 - 1
version.gradle

@@ -8,7 +8,7 @@ ext {
     android = [
             compileSdkVersion: 26,
             buildToolsVersion: '27.0.0',
-            minSdkVersion    : 14,
+            minSdkVersion    : 15,
             targetSdkVersion : 26,
             javaVersion      : JavaVersion.VERSION_1_8,
             versionCode      : 158,